From 41b4371b972716ff5bbca0f7516248ac5fee73eb Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Wed, 30 Jan 2013 12:10:38 +0800 Subject: [PATCH] --- yaml --- r: 358420 b: refs/heads/master c: 40064acf0c2ca2fdc78cc6f09c3426be8db38a84 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/arch/frv/mb93090-mb00/pci-frv.h | 1 + trunk/arch/frv/mb93090-mb00/pci-vdk.c | 4 +- trunk/arch/ia64/pci/pci.c | 8 --- trunk/arch/mn10300/unit-asb2305/pci-asb2305.h | 1 + trunk/arch/mn10300/unit-asb2305/pci.c | 4 +- trunk/arch/x86/include/asm/pci.h | 3 - trunk/arch/x86/include/asm/pci_x86.h | 1 + trunk/arch/x86/pci/acpi.c | 9 --- trunk/arch/x86/pci/common.c | 1 + trunk/arch/x86/pci/legacy.c | 2 +- trunk/arch/x86/pci/numaq_32.c | 2 +- trunk/drivers/acpi/pci_root.c | 18 +++++ trunk/drivers/pci/hotplug/cpci_hotplug_pci.c | 29 ++++---- trunk/drivers/pci/hotplug/cpqphp_ctrl.c | 57 ++++++++++------ trunk/drivers/pci/hotplug/pciehp_pci.c | 44 ++++++++----- trunk/drivers/pci/hotplug/sgi_hotplug.c | 63 ++++++++++-------- trunk/drivers/pci/hotplug/shpchp_pci.c | 36 +++++----- trunk/drivers/pci/iov.c | 1 - trunk/drivers/pci/pci-acpi.c | 19 ++++++ trunk/drivers/pci/pci.c | 30 ++++----- trunk/drivers/pci/pci.h | 3 +- trunk/drivers/pci/probe.c | 66 ++++++++----------- trunk/include/acpi/acpi_bus.h | 1 + trunk/include/linux/pci.h | 2 - 25 files changed, 229 insertions(+), 178 deletions(-) diff --git a/[refs] b/[refs] index 9642f94548b0..0664bf0e1738 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 939de1d69c5fb0da0cfe05a1a7c981421cf876f7 +refs/heads/master: 40064acf0c2ca2fdc78cc6f09c3426be8db38a84 diff --git a/trunk/arch/frv/mb93090-mb00/pci-frv.h b/trunk/arch/frv/mb93090-mb00/pci-frv.h index 76c4e73d643d..089eeba4f3bc 100644 --- a/trunk/arch/frv/mb93090-mb00/pci-frv.h +++ b/trunk/arch/frv/mb93090-mb00/pci-frv.h @@ -31,6 +31,7 @@ void pcibios_resource_survey(void); /* pci-vdk.c */ extern int __nongpreldata pcibios_last_bus; +extern struct pci_bus *__nongpreldata pci_root_bus; extern struct pci_ops *__nongpreldata pci_root_ops; /* pci-irq.c */ diff --git a/trunk/arch/frv/mb93090-mb00/pci-vdk.c b/trunk/arch/frv/mb93090-mb00/pci-vdk.c index 1152a1e3cabb..71e9bcf58105 100644 --- a/trunk/arch/frv/mb93090-mb00/pci-vdk.c +++ b/trunk/arch/frv/mb93090-mb00/pci-vdk.c @@ -26,6 +26,7 @@ unsigned int __nongpreldata pci_probe = 1; int __nongpreldata pcibios_last_bus = -1; +struct pci_bus *__nongpreldata pci_root_bus; struct pci_ops *__nongpreldata pci_root_ops; /* @@ -415,7 +416,8 @@ int __init pcibios_init(void) printk("PCI: Probing PCI hardware\n"); pci_add_resource(&resources, &pci_ioport_resource); pci_add_resource(&resources, &pci_iomem_resource); - pci_scan_root_bus(NULL, 0, pci_root_ops, NULL, &resources); + pci_root_bus = pci_scan_root_bus(NULL, 0, pci_root_ops, NULL, + &resources); pcibios_irq_init(); pcibios_fixup_peer_bridges(); diff --git a/trunk/arch/ia64/pci/pci.c b/trunk/arch/ia64/pci/pci.c index 00e59c7ad3c0..5faa66c5c2a8 100644 --- a/trunk/arch/ia64/pci/pci.c +++ b/trunk/arch/ia64/pci/pci.c @@ -396,14 +396,6 @@ pci_acpi_scan_root(struct acpi_pci_root *root) return NULL; } -int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) -{ - struct pci_controller *controller = bridge->bus->sysdata; - - ACPI_HANDLE_SET(&bridge->dev, controller->acpi_handle); - return 0; -} - static int __devinit is_valid_resource(struct pci_dev *dev, int idx) { unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM; diff --git a/trunk/arch/mn10300/unit-asb2305/pci-asb2305.h b/trunk/arch/mn10300/unit-asb2305/pci-asb2305.h index 7fa66a0e4624..1194fe486b01 100644 --- a/trunk/arch/mn10300/unit-asb2305/pci-asb2305.h +++ b/trunk/arch/mn10300/unit-asb2305/pci-asb2305.h @@ -36,6 +36,7 @@ extern void pcibios_resource_survey(void); /* pci.c */ extern int pcibios_last_bus; +extern struct pci_bus *pci_root_bus; extern struct pci_ops *pci_root_ops; extern struct irq_routing_table *pcibios_get_irq_routing_table(void); diff --git a/trunk/arch/mn10300/unit-asb2305/pci.c b/trunk/arch/mn10300/unit-asb2305/pci.c index 426bf51605f3..e2059486d3f8 100644 --- a/trunk/arch/mn10300/unit-asb2305/pci.c +++ b/trunk/arch/mn10300/unit-asb2305/pci.c @@ -24,6 +24,7 @@ unsigned int pci_probe = 1; int pcibios_last_bus = -1; +struct pci_bus *pci_root_bus; struct pci_ops *pci_root_ops; /* @@ -376,7 +377,8 @@ static int __init pcibios_init(void) pci_add_resource_offset(&resources, &pci_ioport_resource, io_offset); pci_add_resource_offset(&resources, &pci_iomem_resource, mem_offset); - pci_scan_root_bus(NULL, 0, &pci_direct_ampci, NULL, &resources); + pci_root_bus = pci_scan_root_bus(NULL, 0, &pci_direct_ampci, NULL, + &resources); pcibios_irq_init(); pcibios_fixup_irqs(); diff --git a/trunk/arch/x86/include/asm/pci.h b/trunk/arch/x86/include/asm/pci.h index 9f437e97e9e8..dba7805176bf 100644 --- a/trunk/arch/x86/include/asm/pci.h +++ b/trunk/arch/x86/include/asm/pci.h @@ -14,9 +14,6 @@ struct pci_sysdata { int domain; /* PCI domain */ int node; /* NUMA node */ -#ifdef CONFIG_ACPI - void *acpi; /* ACPI-specific data */ -#endif #ifdef CONFIG_X86_64 void *iommu; /* IOMMU private data */ #endif diff --git a/trunk/arch/x86/include/asm/pci_x86.h b/trunk/arch/x86/include/asm/pci_x86.h index 0126f104f0a5..73e8eeff22ee 100644 --- a/trunk/arch/x86/include/asm/pci_x86.h +++ b/trunk/arch/x86/include/asm/pci_x86.h @@ -54,6 +54,7 @@ void pcibios_set_cache_line_size(void); /* pci-pc.c */ extern int pcibios_last_bus; +extern struct pci_bus *pci_root_bus; extern struct pci_ops pci_root_ops; void pcibios_scan_specific_bus(int busn); diff --git a/trunk/arch/x86/pci/acpi.c b/trunk/arch/x86/pci/acpi.c index 3d49094ed3e8..0c01261fe5a8 100644 --- a/trunk/arch/x86/pci/acpi.c +++ b/trunk/arch/x86/pci/acpi.c @@ -522,7 +522,6 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) sd = &info->sd; sd->domain = domain; sd->node = node; - sd->acpi = device->handle; /* * Maybe the desired pci bus has been already scanned. In such case * it is unnecessary to scan the pci bus with the given domain,busnum. @@ -594,14 +593,6 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) return bus; } -int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) -{ - struct pci_sysdata *sd = bridge->bus->sysdata; - - ACPI_HANDLE_SET(&bridge->dev, sd->acpi); - return 0; -} - int __init pci_acpi_init(void) { struct pci_dev *dev = NULL; diff --git a/trunk/arch/x86/pci/common.c b/trunk/arch/x86/pci/common.c index 505731b139f4..412e1286d1fc 100644 --- a/trunk/arch/x86/pci/common.c +++ b/trunk/arch/x86/pci/common.c @@ -34,6 +34,7 @@ int noioapicreroute = 1; #endif int pcibios_last_bus = -1; unsigned long pirq_table_addr; +struct pci_bus *pci_root_bus; const struct pci_raw_ops *__read_mostly raw_pci_ops; const struct pci_raw_ops *__read_mostly raw_pci_ext_ops; diff --git a/trunk/arch/x86/pci/legacy.c b/trunk/arch/x86/pci/legacy.c index a9e83083fb85..a1df191129d3 100644 --- a/trunk/arch/x86/pci/legacy.c +++ b/trunk/arch/x86/pci/legacy.c @@ -30,7 +30,7 @@ int __init pci_legacy_init(void) } printk("PCI: Probing PCI hardware\n"); - pcibios_scan_root(0); + pci_root_bus = pcibios_scan_root(0); return 0; } diff --git a/trunk/arch/x86/pci/numaq_32.c b/trunk/arch/x86/pci/numaq_32.c index 00edfe652b72..83e125b95ca6 100644 --- a/trunk/arch/x86/pci/numaq_32.c +++ b/trunk/arch/x86/pci/numaq_32.c @@ -152,7 +152,7 @@ int __init pci_numaq_init(void) raw_pci_ops = &pci_direct_conf1_mq; - pcibios_scan_root(0); + pci_root_bus = pcibios_scan_root(0); if (num_online_nodes() > 1) for_each_online_node(quad) { if (quad == 0) diff --git a/trunk/drivers/acpi/pci_root.c b/trunk/drivers/acpi/pci_root.c index 417487a201fb..fd59f57d3829 100644 --- a/trunk/drivers/acpi/pci_root.c +++ b/trunk/drivers/acpi/pci_root.c @@ -107,6 +107,24 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver) } EXPORT_SYMBOL(acpi_pci_unregister_driver); +acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus) +{ + struct acpi_pci_root *root; + acpi_handle handle = NULL; + + mutex_lock(&acpi_pci_root_lock); + list_for_each_entry(root, &acpi_pci_roots, node) + if ((root->segment == (u16) seg) && + (root->secondary.start == (u16) bus)) { + handle = root->device->handle; + break; + } + mutex_unlock(&acpi_pci_root_lock); + return handle; +} + +EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle); + /** * acpi_is_root_bridge - determine whether an ACPI CA node is a PCI root bridge * @handle - the ACPI CA node in question. diff --git a/trunk/drivers/pci/hotplug/cpci_hotplug_pci.c b/trunk/drivers/pci/hotplug/cpci_hotplug_pci.c index d8add34177f2..dcc75c785443 100644 --- a/trunk/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/trunk/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -252,8 +252,8 @@ int cpci_led_off(struct slot* slot) int __ref cpci_configure_slot(struct slot *slot) { - struct pci_dev *dev; struct pci_bus *parent; + int fn; dbg("%s - enter", __func__); @@ -282,13 +282,18 @@ int __ref cpci_configure_slot(struct slot *slot) } parent = slot->dev->bus; - list_for_each_entry(dev, &parent->devices, bus_list) - if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn)) + for (fn = 0; fn < 8; fn++) { + struct pci_dev *dev; + + dev = pci_get_slot(parent, + PCI_DEVFN(PCI_SLOT(slot->devfn), fn)); + if (!dev) continue; if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) pci_hp_add_bridge(dev); - + pci_dev_put(dev); + } pci_assign_unassigned_bridge_resources(parent->self); @@ -300,7 +305,8 @@ int __ref cpci_configure_slot(struct slot *slot) int cpci_unconfigure_slot(struct slot* slot) { - struct pci_dev *dev, *temp; + int i; + struct pci_dev *dev; dbg("%s - enter", __func__); if (!slot->dev) { @@ -308,12 +314,13 @@ int cpci_unconfigure_slot(struct slot* slot) return -ENODEV; } - list_for_each_entry_safe(dev, temp, &slot->bus->devices, bus_list) { - if (PCI_SLOT(dev->devfn) != PCI_SLOT(slot->devfn)) - continue; - pci_dev_get(dev); - pci_stop_and_remove_bus_device(dev); - pci_dev_put(dev); + for (i = 0; i < 8; i++) { + dev = pci_get_slot(slot->bus, + PCI_DEVFN(PCI_SLOT(slot->devfn), i)); + if (dev) { + pci_stop_and_remove_bus_device(dev); + pci_dev_put(dev); + } } pci_dev_put(slot->dev); slot->dev = NULL; diff --git a/trunk/drivers/pci/hotplug/cpqphp_ctrl.c b/trunk/drivers/pci/hotplug/cpqphp_ctrl.c index d282019cda5f..36112fe212d3 100644 --- a/trunk/drivers/pci/hotplug/cpqphp_ctrl.c +++ b/trunk/drivers/pci/hotplug/cpqphp_ctrl.c @@ -1900,7 +1900,8 @@ static void interrupt_event_handler(struct controller *ctrl) dbg("power fault\n"); } else { /* refresh notification */ - update_slot_info(ctrl, p_slot); + if (p_slot) + update_slot_info(ctrl, p_slot); } ctrl->event_queue[loop].event_type = 0; @@ -2519,28 +2520,44 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func /* If we have IO resources copy them and fill in the bridge's * IO range registers */ - memcpy(hold_IO_node, io_node, sizeof(struct pci_resource)); - io_node->next = NULL; + if (io_node) { + memcpy(hold_IO_node, io_node, sizeof(struct pci_resource)); + io_node->next = NULL; - /* set IO base and Limit registers */ - temp_byte = io_node->base >> 8; - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_BASE, temp_byte); + /* set IO base and Limit registers */ + temp_byte = io_node->base >> 8; + rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_BASE, temp_byte); - temp_byte = (io_node->base + io_node->length - 1) >> 8; - rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte); + temp_byte = (io_node->base + io_node->length - 1) >> 8; + rc = pci_bus_write_config_byte(pci_bus, devfn, PCI_IO_LIMIT, temp_byte); + } else { + kfree(hold_IO_node); + hold_IO_node = NULL; + } - /* Copy the memory resources and fill in the bridge's memory - * range registers. - */ - memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource)); - mem_node->next = NULL; + /* If we have memory resources copy them and fill in the + * bridge's memory range registers. Otherwise, fill in the + * range registers with values that disable them. */ + if (mem_node) { + memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource)); + mem_node->next = NULL; - /* set Mem base and Limit registers */ - temp_word = mem_node->base >> 16; - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word); + /* set Mem base and Limit registers */ + temp_word = mem_node->base >> 16; + rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word); - temp_word = (mem_node->base + mem_node->length - 1) >> 16; - rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); + temp_word = (mem_node->base + mem_node->length - 1) >> 16; + rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); + } else { + temp_word = 0xFFFF; + rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_BASE, temp_word); + + temp_word = 0x0000; + rc = pci_bus_write_config_word(pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); + + kfree(hold_mem_node); + hold_mem_node = NULL; + } memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource)); p_mem_node->next = NULL; @@ -2610,7 +2627,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func /* Return unused bus resources * First use the temporary node to store information for * the board */ - if (bus_node && temp_resources.bus_head) { + if (hold_bus_node && bus_node && temp_resources.bus_head) { hold_bus_node->length = bus_node->base - hold_bus_node->base; hold_bus_node->next = func->bus_head; @@ -2734,7 +2751,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func } /* If we have prefetchable memory space available and there * is some left at the end, return the unused portion */ - if (temp_resources.p_mem_head) { + if (hold_p_mem_node && temp_resources.p_mem_head) { p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head), &hold_p_mem_node, 0x100000); diff --git a/trunk/drivers/pci/hotplug/pciehp_pci.c b/trunk/drivers/pci/hotplug/pciehp_pci.c index aac7a40e4a4a..09cecaf450c5 100644 --- a/trunk/drivers/pci/hotplug/pciehp_pci.c +++ b/trunk/drivers/pci/hotplug/pciehp_pci.c @@ -39,7 +39,7 @@ int pciehp_configure_device(struct slot *p_slot) struct pci_dev *dev; struct pci_dev *bridge = p_slot->ctrl->pcie->port; struct pci_bus *parent = bridge->subordinate; - int num; + int num, fn; struct controller *ctrl = p_slot->ctrl; dev = pci_get_slot(parent, PCI_DEVFN(0, 0)); @@ -57,18 +57,28 @@ int pciehp_configure_device(struct slot *p_slot) return -ENODEV; } - list_for_each_entry(dev, &parent->devices, bus_list) + for (fn = 0; fn < 8; fn++) { + dev = pci_get_slot(parent, PCI_DEVFN(0, fn)); + if (!dev) + continue; if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) pci_hp_add_bridge(dev); + pci_dev_put(dev); + } pci_assign_unassigned_bridge_resources(bridge); - list_for_each_entry(dev, &parent->devices, bus_list) { - if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) + for (fn = 0; fn < 8; fn++) { + dev = pci_get_slot(parent, PCI_DEVFN(0, fn)); + if (!dev) continue; - + if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { + pci_dev_put(dev); + continue; + } pci_configure_slot(dev); + pci_dev_put(dev); } pci_bus_add_devices(parent); @@ -79,9 +89,9 @@ int pciehp_configure_device(struct slot *p_slot) int pciehp_unconfigure_device(struct slot *p_slot) { int ret, rc = 0; + int j; u8 bctl = 0; u8 presence = 0; - struct pci_dev *dev, *temp; struct pci_bus *parent = p_slot->ctrl->pcie->port->subordinate; u16 command; struct controller *ctrl = p_slot->ctrl; @@ -92,31 +102,33 @@ int pciehp_unconfigure_device(struct slot *p_slot) if (ret) presence = 0; - list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) { - pci_dev_get(dev); - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) { - pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bctl); + for (j = 0; j < 8; j++) { + struct pci_dev *temp = pci_get_slot(parent, PCI_DEVFN(0, j)); + if (!temp) + continue; + if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) { + pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl); if (bctl & PCI_BRIDGE_CTL_VGA) { ctrl_err(ctrl, "Cannot remove display device %s\n", - pci_name(dev)); - pci_dev_put(dev); + pci_name(temp)); + pci_dev_put(temp); rc = -EINVAL; break; } } - pci_stop_and_remove_bus_device(dev); + pci_stop_and_remove_bus_device(temp); /* * Ensure that no new Requests will be generated from * the device. */ if (presence) { - pci_read_config_word(dev, PCI_COMMAND, &command); + pci_read_config_word(temp, PCI_COMMAND, &command); command &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_SERR); command |= PCI_COMMAND_INTX_DISABLE; - pci_write_config_word(dev, PCI_COMMAND, command); + pci_write_config_word(temp, PCI_COMMAND, command); } - pci_dev_put(dev); + pci_dev_put(temp); } return rc; diff --git a/trunk/drivers/pci/hotplug/sgi_hotplug.c b/trunk/drivers/pci/hotplug/sgi_hotplug.c index 180e760c1653..ae606b3e991e 100644 --- a/trunk/drivers/pci/hotplug/sgi_hotplug.c +++ b/trunk/drivers/pci/hotplug/sgi_hotplug.c @@ -334,7 +334,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) struct slot *slot = bss_hotplug_slot->private; struct pci_bus *new_bus = NULL; struct pci_dev *dev; - int num_funcs; + int func, num_funcs; int new_ppb = 0; int rc; char *ssdt = NULL; @@ -381,26 +381,29 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) * to the Linux PCI interface and tell the drivers * about them. */ - list_for_each_entry(dev, &slot->pci_bus->devices, bus_list) { - if (PCI_SLOT(dev->devfn) != slot->device_num + 1) - continue; - - /* Need to do slot fixup on PPB before fixup of children - * (PPB's pcidev_info needs to be in pcidev_info list - * before child's SN_PCIDEV_INFO() call to setup - * pdi_host_pcidev_info). - */ - pcibios_fixup_device_resources(dev); - if (SN_ACPI_BASE_SUPPORT()) - sn_acpi_slot_fixup(dev); - else - sn_io_slot_fixup(dev); - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_hp_add_bridge(dev); - if (dev->subordinate) { - new_bus = dev->subordinate; - new_ppb = 1; + for (func = 0; func < num_funcs; func++) { + dev = pci_get_slot(slot->pci_bus, + PCI_DEVFN(slot->device_num + 1, + PCI_FUNC(func))); + if (dev) { + /* Need to do slot fixup on PPB before fixup of children + * (PPB's pcidev_info needs to be in pcidev_info list + * before child's SN_PCIDEV_INFO() call to setup + * pdi_host_pcidev_info). + */ + pcibios_fixup_device_resources(dev); + if (SN_ACPI_BASE_SUPPORT()) + sn_acpi_slot_fixup(dev); + else + sn_io_slot_fixup(dev); + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_hp_add_bridge(dev); + if (dev->subordinate) { + new_bus = dev->subordinate; + new_ppb = 1; + } } + pci_dev_put(dev); } } @@ -478,7 +481,8 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) static int disable_slot(struct hotplug_slot *bss_hotplug_slot) { struct slot *slot = bss_hotplug_slot->private; - struct pci_dev *dev, *temp; + struct pci_dev *dev; + int func; int rc; acpi_owner_id ssdt_id = 0; @@ -538,14 +542,15 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot) } /* Free the SN resources assigned to the Linux device.*/ - list_for_each_entry_safe(dev, temp, &slot->pci_bus->devices, bus_list) { - if (PCI_SLOT(dev->devfn) != slot->device_num + 1) - continue; - - pci_dev_get(dev); - sn_bus_free_data(dev); - pci_stop_and_remove_bus_device(dev); - pci_dev_put(dev); + for (func = 0; func < 8; func++) { + dev = pci_get_slot(slot->pci_bus, + PCI_DEVFN(slot->device_num + 1, + PCI_FUNC(func))); + if (dev) { + sn_bus_free_data(dev); + pci_stop_and_remove_bus_device(dev); + pci_dev_put(dev); + } } /* Remove the SSDT for the slot from the ACPI namespace */ diff --git a/trunk/drivers/pci/hotplug/shpchp_pci.c b/trunk/drivers/pci/hotplug/shpchp_pci.c index b0e83132542e..c627ed9957d1 100644 --- a/trunk/drivers/pci/hotplug/shpchp_pci.c +++ b/trunk/drivers/pci/hotplug/shpchp_pci.c @@ -40,7 +40,7 @@ int __ref shpchp_configure_device(struct slot *p_slot) struct controller *ctrl = p_slot->ctrl; struct pci_dev *bridge = ctrl->pci_dev; struct pci_bus *parent = bridge->subordinate; - int num; + int num, fn; dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0)); if (dev) { @@ -57,20 +57,24 @@ int __ref shpchp_configure_device(struct slot *p_slot) return -ENODEV; } - list_for_each_entry(dev, &parent->devices, bus_list) { - if (PCI_SLOT(dev->devfn) != p_slot->device) + for (fn = 0; fn < 8; fn++) { + dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, fn)); + if (!dev) continue; if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) pci_hp_add_bridge(dev); + pci_dev_put(dev); } pci_assign_unassigned_bridge_resources(bridge); - list_for_each_entry(dev, &parent->devices, bus_list) { - if (PCI_SLOT(dev->devfn) != p_slot->device) + for (fn = 0; fn < 8; fn++) { + dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, fn)); + if (!dev) continue; pci_configure_slot(dev); + pci_dev_put(dev); } pci_bus_add_devices(parent); @@ -81,32 +85,32 @@ int __ref shpchp_configure_device(struct slot *p_slot) int shpchp_unconfigure_device(struct slot *p_slot) { int rc = 0; + int j; u8 bctl = 0; struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; - struct pci_dev *dev, *temp; struct controller *ctrl = p_slot->ctrl; ctrl_dbg(ctrl, "%s: domain:bus:dev = %04x:%02x:%02x\n", __func__, pci_domain_nr(parent), p_slot->bus, p_slot->device); - list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) { - if (PCI_SLOT(dev->devfn) != p_slot->device) + for (j = 0; j < 8 ; j++) { + struct pci_dev *temp = pci_get_slot(parent, + (p_slot->device << 3) | j); + if (!temp) continue; - - pci_dev_get(dev); - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bctl); + if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl); if (bctl & PCI_BRIDGE_CTL_VGA) { ctrl_err(ctrl, "Cannot remove display device %s\n", - pci_name(dev)); - pci_dev_put(dev); + pci_name(temp)); + pci_dev_put(temp); rc = -EINVAL; break; } } - pci_stop_and_remove_bus_device(dev); - pci_dev_put(dev); + pci_stop_and_remove_bus_device(temp); + pci_dev_put(temp); } return rc; } diff --git a/trunk/drivers/pci/iov.c b/trunk/drivers/pci/iov.c index f8720afe0537..4ea7139db1be 100644 --- a/trunk/drivers/pci/iov.c +++ b/trunk/drivers/pci/iov.c @@ -33,7 +33,6 @@ static inline u8 virtfn_devfn(struct pci_dev *dev, int id) static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr) { - int rc; struct pci_bus *child; if (bus->number == busnr) diff --git a/trunk/drivers/pci/pci-acpi.c b/trunk/drivers/pci/pci-acpi.c index 1c2587c40299..42736e213f25 100644 --- a/trunk/drivers/pci/pci-acpi.c +++ b/trunk/drivers/pci/pci-acpi.c @@ -302,6 +302,24 @@ static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) return 0; } +static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle) +{ + int num; + unsigned int seg, bus; + + /* + * The string should be the same as root bridge's name + * Please look at 'pci_scan_bus_parented' + */ + num = sscanf(dev_name(dev), "pci%04x:%02x", &seg, &bus); + if (num != 2) + return -ENODEV; + *handle = acpi_get_pci_rootbridge_handle(seg, bus); + if (!*handle) + return -ENODEV; + return 0; +} + static void pci_acpi_setup(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); @@ -360,6 +378,7 @@ static void pci_acpi_cleanup(struct device *dev) static struct acpi_bus_type acpi_pci_bus = { .bus = &pci_bus_type, .find_device = acpi_pci_find_device, + .find_bridge = acpi_pci_find_root_bridge, .setup = pci_acpi_setup, .cleanup = pci_acpi_cleanup, }; diff --git a/trunk/drivers/pci/pci.c b/trunk/drivers/pci/pci.c index 177a50ff6454..0c4f641b7be1 100644 --- a/trunk/drivers/pci/pci.c +++ b/trunk/drivers/pci/pci.c @@ -1151,7 +1151,8 @@ int pci_reenable_device(struct pci_dev *dev) return 0; } -static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags) +static int __pci_enable_device_flags(struct pci_dev *dev, + resource_size_t flags) { int err; int i, bars = 0; @@ -1195,7 +1196,7 @@ static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags) */ int pci_enable_device_io(struct pci_dev *dev) { - return pci_enable_device_flags(dev, IORESOURCE_IO); + return __pci_enable_device_flags(dev, IORESOURCE_IO); } /** @@ -1208,7 +1209,7 @@ int pci_enable_device_io(struct pci_dev *dev) */ int pci_enable_device_mem(struct pci_dev *dev) { - return pci_enable_device_flags(dev, IORESOURCE_MEM); + return __pci_enable_device_flags(dev, IORESOURCE_MEM); } /** @@ -1224,7 +1225,7 @@ int pci_enable_device_mem(struct pci_dev *dev) */ int pci_enable_device(struct pci_dev *dev) { - return pci_enable_device_flags(dev, IORESOURCE_MEM | IORESOURCE_IO); + return __pci_enable_device_flags(dev, IORESOURCE_MEM | IORESOURCE_IO); } /* @@ -2042,13 +2043,10 @@ void pci_free_cap_save_buffers(struct pci_dev *dev) } /** - * pci_configure_ari - enable or disable ARI forwarding + * pci_enable_ari - enable ARI forwarding if hardware support it * @dev: the PCI device - * - * If @dev and its upstream bridge both support ARI, enable ARI in the - * bridge. Otherwise, disable ARI in the bridge. */ -void pci_configure_ari(struct pci_dev *dev) +void pci_enable_ari(struct pci_dev *dev) { u32 cap; struct pci_dev *bridge; @@ -2056,6 +2054,9 @@ void pci_configure_ari(struct pci_dev *dev) if (pcie_ari_disabled || !pci_is_pcie(dev) || dev->devfn) return; + if (!pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI)) + return; + bridge = dev->bus->self; if (!bridge) return; @@ -2064,15 +2065,8 @@ void pci_configure_ari(struct pci_dev *dev) if (!(cap & PCI_EXP_DEVCAP2_ARI)) return; - if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI)) { - pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2, - PCI_EXP_DEVCTL2_ARI); - bridge->ari_enabled = 1; - } else { - pcie_capability_clear_word(bridge, PCI_EXP_DEVCTL2, - PCI_EXP_DEVCTL2_ARI); - bridge->ari_enabled = 0; - } + pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_ARI); + bridge->ari_enabled = 1; } /** diff --git a/trunk/drivers/pci/pci.h b/trunk/drivers/pci/pci.h index 7346ee68f47d..d295e7b0e64f 100644 --- a/trunk/drivers/pci/pci.h +++ b/trunk/drivers/pci/pci.h @@ -203,8 +203,7 @@ extern int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, struct resource *res, unsigned int reg); extern int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type); -extern void pci_configure_ari(struct pci_dev *dev); - +extern void pci_enable_ari(struct pci_dev *dev); /** * pci_ari_enabled - query ARI forwarding status * @bus: the PCI bus diff --git a/trunk/drivers/pci/probe.c b/trunk/drivers/pci/probe.c index b494066ef32f..281d90f19c7a 100644 --- a/trunk/drivers/pci/probe.c +++ b/trunk/drivers/pci/probe.c @@ -1295,7 +1295,7 @@ static void pci_init_capabilities(struct pci_dev *dev) pci_vpd_pci22_init(dev); /* Alternative Routing-ID Forwarding */ - pci_configure_ari(dev); + pci_enable_ari(dev); /* Single Root I/O Virtualization */ pci_iov_init(dev); @@ -1371,31 +1371,31 @@ struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn) } EXPORT_SYMBOL(pci_scan_single_device); -static unsigned next_fn(struct pci_bus *bus, struct pci_dev *dev, unsigned fn) +static unsigned next_ari_fn(struct pci_dev *dev, unsigned fn) { - int pos; - u16 cap = 0; - unsigned next_fn; - - if (pci_ari_enabled(bus)) { - if (!dev) - return 0; - pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI); - if (!pos) - return 0; + u16 cap; + unsigned pos, next_fn; - pci_read_config_word(dev, pos + PCI_ARI_CAP, &cap); - next_fn = PCI_ARI_CAP_NFN(cap); - if (next_fn <= fn) - return 0; /* protect against malformed list */ + if (!dev) + return 0; - return next_fn; - } + pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI); + if (!pos) + return 0; + pci_read_config_word(dev, pos + 4, &cap); + next_fn = cap >> 8; + if (next_fn <= fn) + return 0; + return next_fn; +} - /* dev may be NULL for non-contiguous multifunction devices */ - if (!dev || dev->multifunction) - return (fn + 1) % 8; +static unsigned next_trad_fn(struct pci_dev *dev, unsigned fn) +{ + return (fn + 1) % 8; +} +static unsigned no_next_fn(struct pci_dev *dev, unsigned fn) +{ return 0; } @@ -1428,6 +1428,7 @@ int pci_scan_slot(struct pci_bus *bus, int devfn) { unsigned fn, nr = 0; struct pci_dev *dev; + unsigned (*next_fn)(struct pci_dev *, unsigned) = no_next_fn; if (only_one_child(bus) && (devfn > 0)) return 0; /* Already scanned the entire slot */ @@ -1438,7 +1439,12 @@ int pci_scan_slot(struct pci_bus *bus, int devfn) if (!dev->is_added) nr++; - for (fn = next_fn(bus, dev, 0); fn > 0; fn = next_fn(bus, dev, fn)) { + if (pci_ari_enabled(bus)) + next_fn = next_ari_fn; + else if (dev->multifunction) + next_fn = next_trad_fn; + + for (fn = next_fn(dev, 0); fn > 0; fn = next_fn(dev, fn)) { dev = pci_scan_single_device(bus, devfn + fn); if (dev) { if (!dev->is_added) @@ -1649,18 +1655,6 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus) return max; } -/** - * pcibios_root_bridge_prepare - Platform-specific host bridge setup. - * @bridge: Host bridge to set up. - * - * Default empty implementation. Replace with an architecture-specific setup - * routine, if necessary. - */ -int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge) -{ - return 0; -} - struct pci_bus *pci_create_root_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata, struct list_head *resources) { @@ -1694,10 +1688,6 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, bridge->dev.parent = parent; bridge->dev.release = pci_release_bus_bridge_dev; dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus); - error = pcibios_root_bridge_prepare(bridge); - if (error) - goto bridge_dev_reg_err; - error = device_register(&bridge->dev); if (error) goto bridge_dev_reg_err; diff --git a/trunk/include/acpi/acpi_bus.h b/trunk/include/acpi/acpi_bus.h index 5ce8d5e86734..d26c0d7a6d19 100644 --- a/trunk/include/acpi/acpi_bus.h +++ b/trunk/include/acpi/acpi_bus.h @@ -408,6 +408,7 @@ struct acpi_pci_root { /* helper */ acpi_handle acpi_get_child(acpi_handle, u64); int acpi_is_root_bridge(acpi_handle); +acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int); struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)ACPI_HANDLE(dev)) diff --git a/trunk/include/linux/pci.h b/trunk/include/linux/pci.h index 056d3d66b976..8ee7e4e46539 100644 --- a/trunk/include/linux/pci.h +++ b/trunk/include/linux/pci.h @@ -379,8 +379,6 @@ void pci_set_host_bridge_release(struct pci_host_bridge *bridge, void (*release_fn)(struct pci_host_bridge *), void *release_data); -int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge); - /* * The first PCI_BRIDGE_RESOURCE_NUM PCI bus resources (those that correspond * to P2P or CardBus bridge windows) go in a table. Additional ones (for