Re: Fix found
Hi Max and Debian Kernel Team
Thanks for all the testing, Max!
To the kernel team:
Is there any chance you could upload a kernel with Max's patch? The relevant
parts are already in the upstream kernel. The other part is a revert of a commit
in the upstream kernel which is incompatible with the X server in lenny. See the
bug log for more details. Is there another upload of linux-2.6 planned before the
release of lenny or do you plan to release with -9?
As this affects a major part of all SPARC machines, I really think this is release
critical and the bug severity should be upgraded again. If you don't disagree strongly
I will upgrade it in the next days.
Gaudenz
On Tue, Nov 04, 2008 at 11:20:09PM +0300, Max Dmitrichenko wrote:
> 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 *);
--
Ever tried. Ever failed. No matter.
Try again. Fail again. Fail better.
~ Samuel Beckett ~
Reply to:
- References:
- Fix found
- From: "Max Dmitrichenko" <dmitrmax@gmail.com>