[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Fix found



Ok!

I've rolled back to the lenny's X.org and applied both patches to the
kernel. It works!

The final patch which incorporates both patches against 2.6.26.6 (i.e.
sid's current kernel) is attached.

--
  Max
diff -urpN linux-source-2.6.26/arch/sparc64/kernel/pci.c linux-source-2.6.26.pci-fix/arch/sparc64/kernel/pci.c
--- linux-source-2.6.26/arch/sparc64/kernel/pci.c	2008-10-18 14:33:11.000000000 +0400
+++ linux-source-2.6.26.pci-fix/arch/sparc64/kernel/pci.c	2008-11-04 18:15:31.000000000 +0300
@@ -350,7 +350,8 @@ static void pci_parse_of_addrs(struct of
 
 struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
 				  struct device_node *node,
-				  struct pci_bus *bus, int devfn)
+				  struct pci_bus *bus, int devfn,
+				  int host_controller)
 {
 	struct dev_archdata *sd;
 	struct pci_dev *dev;
@@ -389,28 +390,43 @@ struct pci_dev *of_create_pci_dev(struct
 	dev->devfn = devfn;
 	dev->multifunction = 0;		/* maybe a lie? */
 
-	dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff);
-	dev->device = of_getintprop_default(node, "device-id", 0xffff);
-	dev->subsystem_vendor =
-		of_getintprop_default(node, "subsystem-vendor-id", 0);
-	dev->subsystem_device =
-		of_getintprop_default(node, "subsystem-id", 0);
-
-	dev->cfg_size = pci_cfg_space_size(dev);
-
-	/* We can't actually use the firmware value, we have
-	 * to read what is in the register right now.  One
-	 * reason is that in the case of IDE interfaces the
-	 * firmware can sample the value before the the IDE
-	 * interface is programmed into native mode.
-	 */
-	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
-	dev->class = class >> 8;
-	dev->revision = class & 0xff;
-
-	sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
-		dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
+	if (host_controller) {
+		if (tlb_type != hypervisor) {
+			pci_read_config_word(dev, PCI_VENDOR_ID,
+					     &dev->vendor);
+			pci_read_config_word(dev, PCI_DEVICE_ID,
+					     &dev->device);
+		} else {
+			dev->vendor = PCI_VENDOR_ID_SUN;
+			dev->device = 0x80f0;
+		}
+		dev->cfg_size = 256;
+		dev->class = PCI_CLASS_BRIDGE_HOST << 8;
+		sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
+			0x00, PCI_SLOT(devfn), PCI_FUNC(devfn));
+	} else {
+		dev->vendor = of_getintprop_default(node, "vendor-id", 0xffff);
+		dev->device = of_getintprop_default(node, "device-id", 0xffff);
+		dev->subsystem_vendor =
+			of_getintprop_default(node, "subsystem-vendor-id", 0);
+		dev->subsystem_device =
+			of_getintprop_default(node, "subsystem-id", 0);
+
+		dev->cfg_size = pci_cfg_space_size(dev);
+
+		/* We can't actually use the firmware value, we have
+		 * to read what is in the register right now.  One
+		 * reason is that in the case of IDE interfaces the
+		 * firmware can sample the value before the the IDE
+		 * interface is programmed into native mode.
+		 */
+		pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
+		dev->class = class >> 8;
+		dev->revision = class & 0xff;
 
+		sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
+			dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
+	}
 	if (ofpci_verbose)
 		printk("    class: 0x%x device name: %s\n",
 		       dev->class, pci_name(dev));
@@ -425,21 +441,26 @@ struct pci_dev *of_create_pci_dev(struct
 	dev->current_state = 4;		/* unknown power state */
 	dev->error_state = pci_channel_io_normal;
 
-	if (!strcmp(node->name, "pci")) {
-		/* a PCI-PCI bridge */
+	if (host_controller) {
 		dev->hdr_type = PCI_HEADER_TYPE_BRIDGE;
 		dev->rom_base_reg = PCI_ROM_ADDRESS1;
-	} else if (!strcmp(type, "cardbus")) {
-		dev->hdr_type = PCI_HEADER_TYPE_CARDBUS;
+		dev->irq = PCI_IRQ_NONE;
 	} else {
-		dev->hdr_type = PCI_HEADER_TYPE_NORMAL;
-		dev->rom_base_reg = PCI_ROM_ADDRESS;
+		if (!strcmp(type, "pci") || !strcmp(type, "pciex")) {
+			/* a PCI-PCI bridge */
+			dev->hdr_type = PCI_HEADER_TYPE_BRIDGE;
+			dev->rom_base_reg = PCI_ROM_ADDRESS1;
+		} else if (!strcmp(type, "cardbus")) {
+			dev->hdr_type = PCI_HEADER_TYPE_CARDBUS;
+		} else {
+			dev->hdr_type = PCI_HEADER_TYPE_NORMAL;
+			dev->rom_base_reg = PCI_ROM_ADDRESS;
 
-		dev->irq = sd->op->irqs[0];
-		if (dev->irq == 0xffffffff)
-			dev->irq = PCI_IRQ_NONE;
+			dev->irq = sd->op->irqs[0];
+			if (dev->irq == 0xffffffff)
+				dev->irq = PCI_IRQ_NONE;
+		}
 	}
-
 	pci_parse_of_addrs(sd->op, node, dev);
 
 	if (ofpci_verbose)
@@ -728,7 +749,7 @@ static void __devinit pci_of_scan_bus(st
 		prev_devfn = devfn;
 
 		/* create a new pci_dev for this device */
-		dev = of_create_pci_dev(pbm, child, bus, devfn);
+		dev = of_create_pci_dev(pbm, child, bus, devfn, 0);
 		if (!dev)
 			continue;
 		if (ofpci_verbose)
@@ -775,9 +796,48 @@ static void __devinit pci_bus_register_o
 		pci_bus_register_of_sysfs(child_bus);
 }
 
+int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev,
+				 unsigned int devfn,
+				 int where, int size,
+				 u32 *value)
+{
+	static u8 fake_pci_config[] = {
+		0x8e, 0x10, /* Vendor: 0x108e (Sun) */
+		0xf0, 0x80, /* Device: 0x80f0 (Fire) */
+		0x46, 0x01, /* Command: 0x0146 (SERR, PARITY, MASTER, MEM) */
+		0xa0, 0x22, /* Status: 0x02a0 (DEVSEL_MED, FB2B, 66MHZ) */
+		0x00, 0x00, 0x00, 0x06, /* Class: 0x06000000 host bridge */
+		0x00, /* Cacheline: 0x00 */
+		0x40, /* Latency: 0x40 */
+		0x00, /* Header-Type: 0x00 normal */
+	};
+
+	*value = 0;
+	if (where >= 0 && where < sizeof(fake_pci_config) &&
+	    (where + size) >= 0 &&
+	    (where + size) < sizeof(fake_pci_config) &&
+	    size <= sizeof(u32)) {
+		while (size--) {
+			*value <<= 8;
+			*value |= fake_pci_config[where + size];
+		}
+	}
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev,
+				  unsigned int devfn,
+				  int where, int size,
+				  u32 value)
+{
+	return PCIBIOS_SUCCESSFUL;
+}
+
 struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
 {
 	struct device_node *node = pbm->prom_node;
+	struct pci_dev *host_pdev;
 	struct pci_bus *bus;
 
 	printk("PCI: Scanning PBM %s\n", node->full_name);
@@ -795,6 +855,10 @@ struct pci_bus * __devinit pci_scan_one_
 	bus->resource[0] = &pbm->io_space;
 	bus->resource[1] = &pbm->mem_space;
 
+	/* Create the dummy host bridge and link it in.  */
+	host_pdev = of_create_pci_dev(pbm, node, bus, 0x00, 1);
+	bus->self = host_pdev;
+
 	pci_of_scan_bus(pbm, node, bus);
 	pci_bus_add_devices(bus);
 	pci_bus_register_of_sysfs(bus);
@@ -1017,6 +1081,7 @@ static int __pci_mmap_make_offset(struct
 
 	for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
 		struct resource *rp = &pdev->resource[i];
+		resource_size_t aligned_end;
 
 		/* Active? */
 		if (!rp->flags)
@@ -1034,8 +1099,15 @@ static int __pci_mmap_make_offset(struct
 				continue;
 		}
 
+		/* Align the resource end to the next page address.
+                 * PAGE_SIZE intentionally added instead of (PAGE_SIZE - 1),
+                 * because actually we need the address of the next byte
+                 * after rp->end.
+                 */
+		aligned_end = (rp->end + PAGE_SIZE) & PAGE_MASK;
+
 		if ((rp->start <= user_paddr) &&
-		    (user_paddr + user_size) <= (rp->end + 1UL))
+		    (user_paddr + user_size) <= aligned_end)
 			break;
 	}
 
diff -urpN linux-source-2.6.26/arch/sparc64/kernel/pci_common.c linux-source-2.6.26.pci-fix/arch/sparc64/kernel/pci_common.c
--- linux-source-2.6.26/arch/sparc64/kernel/pci_common.c	2008-07-14 01:51:29.000000000 +0400
+++ linux-source-2.6.26.pci-fix/arch/sparc64/kernel/pci_common.c	2008-11-04 18:15:27.000000000 +0300
@@ -264,6 +264,9 @@ static int sun4v_read_pci_cfg(struct pci
 	unsigned int func = PCI_FUNC(devfn);
 	unsigned long ret;
 
+	if (!bus && devfn == 0x00)
+		return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
+						    size, value);
 	if (config_out_of_range(pbm, bus, devfn, where)) {
 		ret = ~0UL;
 	} else {
@@ -297,6 +300,9 @@ static int sun4v_write_pci_cfg(struct pc
 	unsigned int func = PCI_FUNC(devfn);
 	unsigned long ret;
 
+	if (!bus && devfn == 0x00)
+		return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
+						     size, value);
 	if (config_out_of_range(pbm, bus, devfn, where)) {
 		/* Do nothing. */
 	} else {
diff -urpN linux-source-2.6.26/arch/sparc64/kernel/pci_impl.h linux-source-2.6.26.pci-fix/arch/sparc64/kernel/pci_impl.h
--- linux-source-2.6.26/arch/sparc64/kernel/pci_impl.h	2008-07-14 01:51:29.000000000 +0400
+++ linux-source-2.6.26.pci-fix/arch/sparc64/kernel/pci_impl.h	2008-11-04 18:15:27.000000000 +0300
@@ -167,6 +167,15 @@ extern void pci_get_pbm_props(struct pci
 extern struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm);
 extern void pci_determine_mem_io_space(struct pci_pbm_info *pbm);
 
+extern int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev,
+					unsigned int devfn,
+					int where, int size,
+					u32 *value);
+extern int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev,
+					 unsigned int devfn,
+					 int where, int size,
+					 u32 value);
+
 /* Error reporting support. */
 extern void pci_scan_for_target_abort(struct pci_pbm_info *, struct pci_bus *);
 extern void pci_scan_for_master_abort(struct pci_pbm_info *, struct pci_bus *);

Reply to: