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 *);