From 42c4b329d6e7b0e892dd5e55fd4317f2837a12bd Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 19 Jan 2013 00:07:42 +0800 Subject: [PATCH] --- yaml --- r: 358439 b: refs/heads/master c: ab1a2e038ff2336502e95ec6492c0364a9fc70d0 h: refs/heads/master i: 358437: 8c682a52bdbebbca4ed9be806880851ded94bbf9 358435: b214ec3d78e58d0dab3f0157f6015865ed98dc4d 358431: 2e1ae716837d4ffd4caaf93327a9e8b5a995c410 v: v3 --- [refs] | 2 +- trunk/Documentation/kernel-parameters.txt | 21 -- 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/Kconfig | 5 +- trunk/drivers/acpi/internal.h | 6 +- trunk/drivers/acpi/osl.c | 24 +- trunk/drivers/acpi/pci_root.c | 148 ++-------- trunk/drivers/acpi/pci_slot.c | 13 +- trunk/drivers/acpi/scan.c | 4 +- trunk/drivers/pci/access.c | 4 +- trunk/drivers/pci/bus.c | 79 +++++- trunk/drivers/pci/hotplug/acpiphp.h | 14 +- trunk/drivers/pci/hotplug/acpiphp_core.c | 23 +- trunk/drivers/pci/hotplug/acpiphp_glue.c | 262 ++++++++++++++---- trunk/drivers/pci/hotplug/cpci_hotplug_pci.c | 29 +- trunk/drivers/pci/hotplug/cpqphp_ctrl.c | 57 ++-- trunk/drivers/pci/hotplug/pciehp_core.c | 2 + 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 | 10 +- trunk/drivers/pci/pci-acpi.c | 19 ++ trunk/drivers/pci/pci-driver.c | 12 +- trunk/drivers/pci/pci.c | 54 ++-- trunk/drivers/pci/pci.h | 4 +- trunk/drivers/pci/pcie/aspm.c | 8 +- trunk/drivers/pci/pcie/portdrv_core.c | 2 +- trunk/drivers/pci/probe.c | 103 +++---- trunk/drivers/pci/remove.c | 4 +- trunk/drivers/pci/search.c | 10 +- trunk/drivers/pci/setup-bus.c | 2 +- trunk/include/acpi/acpi_bus.h | 10 +- trunk/include/acpi/acpiosxf.h | 2 + trunk/include/linux/pci.h | 14 +- 44 files changed, 601 insertions(+), 525 deletions(-) diff --git a/[refs] b/[refs] index 33b546ac50d5..751e94a236cb 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 20f24208f631141bafe57ce5bcc8f2e7f3c41aae +refs/heads/master: ab1a2e038ff2336502e95ec6492c0364a9fc70d0 diff --git a/trunk/Documentation/kernel-parameters.txt b/trunk/Documentation/kernel-parameters.txt index dd80599559a5..363e348bff9b 100644 --- a/trunk/Documentation/kernel-parameters.txt +++ b/trunk/Documentation/kernel-parameters.txt @@ -2227,21 +2227,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. This sorting is done to get a device order compatible with older (<= 2.4) kernels. nobfsort Don't sort PCI devices into breadth-first order. - pcie_bus_tune_off Disable PCIe MPS (Max Payload Size) - tuning and use the BIOS-configured MPS defaults. - pcie_bus_safe Set every device's MPS to the largest value - supported by all devices below the root complex. - pcie_bus_perf Set device MPS to the largest allowable MPS - based on its parent bus. Also set MRRS (Max - Read Request Size) to the largest supported - value (no larger than the MPS that the device - or bus can support) for best performance. - pcie_bus_peer2peer Set every device's MPS to 128B, which - every device is guaranteed to support. This - configuration allows peer-to-peer DMA between - any pair of devices, possibly at the cost of - reduced performance. This also guarantees - that hot-added devices will work. cbiosize=nn[KMG] The fixed amount of bus space which is reserved for the CardBus bridge's IO window. The default value is 256 bytes. @@ -2263,12 +2248,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. the default. off: Turn ECRC off on: Turn ECRC on. - hpiosize=nn[KMG] The fixed amount of bus space which is - reserved for hotplug bridge's IO window. - Default size is 256 bytes. - hpmemsize=nn[KMG] The fixed amount of bus space which is - reserved for hotplug bridge's memory window. - Default size is 2 megabytes. realloc= Enable/disable reallocating PCI bridge resources if allocations done by BIOS are too small to accommodate resources required by all child 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/Kconfig b/trunk/drivers/acpi/Kconfig index 38c5078da11d..27fde5e8d31a 100644 --- a/trunk/drivers/acpi/Kconfig +++ b/trunk/drivers/acpi/Kconfig @@ -308,7 +308,7 @@ config ACPI_DEBUG_FUNC_TRACE is about half of the penalty and is rarely useful. config ACPI_PCI_SLOT - tristate "PCI slot detection driver" + bool "PCI slot detection driver" depends on SYSFS default n help @@ -317,9 +317,6 @@ config ACPI_PCI_SLOT i.e., segment/bus/device/function tuples, with physical slots in the system. If you are unsure, say N. - To compile this driver as a module, choose M here: - the module will be called pci_slot. - config X86_PM_TIMER bool "Power Management Timer Support" if EXPERT depends on X86 diff --git a/trunk/drivers/acpi/internal.h b/trunk/drivers/acpi/internal.h index 0f24148a2b2a..7374cfc5917a 100644 --- a/trunk/drivers/acpi/internal.h +++ b/trunk/drivers/acpi/internal.h @@ -67,8 +67,12 @@ struct acpi_ec { extern struct acpi_ec *first_ec; +#ifdef CONFIG_ACPI_PCI_SLOT +void acpi_pci_slot_init(void); +#else +static inline void acpi_pci_slot_init(void) { } +#endif int acpi_pci_root_init(void); -void acpi_pci_root_hp_init(void); int acpi_ec_init(void); int acpi_ec_ecdt_probe(void); int acpi_boot_ec_enable(void); diff --git a/trunk/drivers/acpi/osl.c b/trunk/drivers/acpi/osl.c index 59ec5f52e849..3ff267861541 100644 --- a/trunk/drivers/acpi/osl.c +++ b/trunk/drivers/acpi/osl.c @@ -84,7 +84,8 @@ static acpi_osd_handler acpi_irq_handler; static void *acpi_irq_context; static struct workqueue_struct *kacpid_wq; static struct workqueue_struct *kacpi_notify_wq; -static struct workqueue_struct *kacpi_hotplug_wq; +struct workqueue_struct *kacpi_hotplug_wq; +EXPORT_SYMBOL(kacpi_hotplug_wq); /* * This list of permanent mappings is for memory that may be accessed from @@ -1777,24 +1778,3 @@ void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state, { __acpi_os_prepare_sleep = func; } - -void alloc_acpi_hp_work(acpi_handle handle, u32 type, void *context, - void (*func)(struct work_struct *work)) -{ - struct acpi_hp_work *hp_work; - int ret; - - hp_work = kmalloc(sizeof(*hp_work), GFP_KERNEL); - if (!hp_work) - return; - - hp_work->handle = handle; - hp_work->type = type; - hp_work->context = context; - - INIT_WORK(&hp_work->work, func); - ret = queue_work(kacpi_hotplug_wq, &hp_work->work); - if (!ret) - kfree(hp_work); -} -EXPORT_SYMBOL_GPL(alloc_acpi_hp_work); diff --git a/trunk/drivers/acpi/pci_root.c b/trunk/drivers/acpi/pci_root.c index 417487a201fb..471b2dcb1c67 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. @@ -655,133 +673,3 @@ int __init acpi_pci_root_init(void) return 0; } -/* Support root bridge hotplug */ - -static void handle_root_bridge_insertion(acpi_handle handle) -{ - struct acpi_device *device; - - if (!acpi_bus_get_device(handle, &device)) { - printk(KERN_DEBUG "acpi device exists...\n"); - return; - } - - if (acpi_bus_scan(handle)) - printk(KERN_ERR "cannot add bridge to acpi list\n"); -} - -static void handle_root_bridge_removal(struct acpi_device *device) -{ - struct acpi_eject_event *ej_event; - - ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL); - if (!ej_event) { - /* Inform firmware the hot-remove operation has error */ - (void) acpi_evaluate_hotplug_ost(device->handle, - ACPI_NOTIFY_EJECT_REQUEST, - ACPI_OST_SC_NON_SPECIFIC_FAILURE, - NULL); - return; - } - - ej_event->device = device; - ej_event->event = ACPI_NOTIFY_EJECT_REQUEST; - - acpi_bus_hot_remove_device(ej_event); -} - -static void _handle_hotplug_event_root(struct work_struct *work) -{ - struct acpi_pci_root *root; - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER }; - struct acpi_hp_work *hp_work; - acpi_handle handle; - u32 type; - - hp_work = container_of(work, struct acpi_hp_work, work); - handle = hp_work->handle; - type = hp_work->type; - - root = acpi_pci_find_root(handle); - - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - /* bus enumerate */ - printk(KERN_DEBUG "%s: Bus check notify on %s\n", __func__, - (char *)buffer.pointer); - if (!root) - handle_root_bridge_insertion(handle); - - break; - - case ACPI_NOTIFY_DEVICE_CHECK: - /* device check */ - printk(KERN_DEBUG "%s: Device check notify on %s\n", __func__, - (char *)buffer.pointer); - if (!root) - handle_root_bridge_insertion(handle); - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - /* request device eject */ - printk(KERN_DEBUG "%s: Device eject notify on %s\n", __func__, - (char *)buffer.pointer); - if (root) - handle_root_bridge_removal(root->device); - break; - default: - printk(KERN_WARNING "notify_handler: unknown event type 0x%x for %s\n", - type, (char *)buffer.pointer); - break; - } - - kfree(hp_work); /* allocated in handle_hotplug_event_bridge */ - kfree(buffer.pointer); -} - -static void handle_hotplug_event_root(acpi_handle handle, u32 type, - void *context) -{ - alloc_acpi_hp_work(handle, type, context, - _handle_hotplug_event_root); -} - -static acpi_status __init -find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - acpi_status status; - char objname[64]; - struct acpi_buffer buffer = { .length = sizeof(objname), - .pointer = objname }; - int *count = (int *)context; - - if (!acpi_is_root_bridge(handle)) - return AE_OK; - - (*count)++; - - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - - status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_root, NULL); - if (ACPI_FAILURE(status)) - printk(KERN_DEBUG "acpi root: %s notify handler is not installed, exit status: %u\n", - objname, (unsigned int)status); - else - printk(KERN_DEBUG "acpi root: %s notify handler is installed\n", - objname); - - return AE_OK; -} - -void __init acpi_pci_root_hp_init(void) -{ - int num = 0; - - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL); - - printk(KERN_DEBUG "Found %d acpi root devices\n", num); -} diff --git a/trunk/drivers/acpi/pci_slot.c b/trunk/drivers/acpi/pci_slot.c index d22585f21aeb..a7d7e7710f9e 100644 --- a/trunk/drivers/acpi/pci_slot.c +++ b/trunk/drivers/acpi/pci_slot.c @@ -330,19 +330,8 @@ static struct dmi_system_id acpi_pci_slot_dmi_table[] __initdata = { {} }; -static int __init -acpi_pci_slot_init(void) +void __init acpi_pci_slot_init(void) { dmi_check_system(acpi_pci_slot_dmi_table); acpi_pci_register_driver(&acpi_pci_slot_driver); - return 0; } - -static void __exit -acpi_pci_slot_exit(void) -{ - acpi_pci_unregister_driver(&acpi_pci_slot_driver); -} - -module_init(acpi_pci_slot_init); -module_exit(acpi_pci_slot_exit); diff --git a/trunk/drivers/acpi/scan.c b/trunk/drivers/acpi/scan.c index bc2f33790e83..236e476b09c9 100644 --- a/trunk/drivers/acpi/scan.c +++ b/trunk/drivers/acpi/scan.c @@ -1687,6 +1687,7 @@ int __init acpi_scan_init(void) acpi_power_init(); acpi_pci_root_init(); + acpi_pci_slot_init(); /* * Enumerate devices in the ACPI namespace. @@ -1706,8 +1707,5 @@ int __init acpi_scan_init(void) } acpi_update_all_gpes(); - - acpi_pci_root_hp_init(); - return 0; } diff --git a/trunk/drivers/pci/access.c b/trunk/drivers/pci/access.c index 5278ac692cbf..3af0478c057b 100644 --- a/trunk/drivers/pci/access.c +++ b/trunk/drivers/pci/access.c @@ -472,7 +472,7 @@ EXPORT_SYMBOL_GPL(pci_cfg_access_unlock); static inline int pcie_cap_version(const struct pci_dev *dev) { - return pcie_caps_reg(dev) & PCI_EXP_FLAGS_VERS; + return dev->pcie_flags_reg & PCI_EXP_FLAGS_VERS; } static inline bool pcie_cap_has_devctl(const struct pci_dev *dev) @@ -497,7 +497,7 @@ static inline bool pcie_cap_has_sltctl(const struct pci_dev *dev) return pcie_cap_version(dev) > 1 || type == PCI_EXP_TYPE_ROOT_PORT || (type == PCI_EXP_TYPE_DOWNSTREAM && - pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT); + dev->pcie_flags_reg & PCI_EXP_FLAGS_SLOT); } static inline bool pcie_cap_has_rtctl(const struct pci_dev *dev) diff --git a/trunk/drivers/pci/bus.c b/trunk/drivers/pci/bus.c index 8647dc6f52d0..847f3ca47bb8 100644 --- a/trunk/drivers/pci/bus.c +++ b/trunk/drivers/pci/bus.c @@ -161,35 +161,68 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { } /** - * pci_bus_add_device - start driver for a single device + * pci_bus_add_device - add a single device * @dev: device to add * - * This adds add sysfs entries and start device drivers + * This adds a single pci device to the global + * device list and adds sysfs and procfs entries */ int pci_bus_add_device(struct pci_dev *dev) { int retval; - /* - * Can not put in pci_device_add yet because resources - * are not assigned yet for some devices. - */ - pci_create_sysfs_dev_files(dev); + pci_fixup_device(pci_fixup_final, dev); - dev->match_driver = true; - retval = device_attach(&dev->dev); - WARN_ON(retval < 0); + retval = pcibios_add_device(dev); + if (retval) + return retval; - dev->is_added = 1; + retval = device_add(&dev->dev); + if (retval) + return retval; + dev->is_added = 1; + pci_proc_attach_device(dev); + pci_create_sysfs_dev_files(dev); return 0; } /** - * pci_bus_add_devices - start driver for PCI devices + * pci_bus_add_child - add a child bus + * @bus: bus to add + * + * This adds sysfs entries for a single bus + */ +int pci_bus_add_child(struct pci_bus *bus) +{ + int retval; + + if (bus->bridge) + bus->dev.parent = bus->bridge; + + retval = device_register(&bus->dev); + if (retval) + return retval; + + bus->is_added = 1; + + /* Create legacy_io and legacy_mem files for this bus */ + pci_create_legacy_files(bus); + + return retval; +} + +/** + * pci_bus_add_devices - insert newly discovered PCI devices * @bus: bus to check for new devices * - * Start driver for PCI devices and add some sysfs entries. + * Add newly discovered PCI devices (which are on the bus->devices + * list) to the global PCI device list, add the sysfs and procfs + * entries. Where a bridge is found, add the discovered bus to + * the parents list of child buses, and recurse (breadth-first + * to be compatible with 2.4) + * + * Call hotplug for each new devices. */ void pci_bus_add_devices(const struct pci_bus *bus) { @@ -202,20 +235,36 @@ void pci_bus_add_devices(const struct pci_bus *bus) if (dev->is_added) continue; retval = pci_bus_add_device(dev); + if (retval) + dev_err(&dev->dev, "Error adding device, continuing\n"); } list_for_each_entry(dev, &bus->devices, bus_list) { BUG_ON(!dev->is_added); child = dev->subordinate; - + /* + * If there is an unattached subordinate bus, attach + * it and then scan for unattached PCI devices. + */ if (!child) continue; + if (list_empty(&child->node)) { + down_write(&pci_bus_sem); + list_add_tail(&child->node, &dev->bus->children); + up_write(&pci_bus_sem); + } pci_bus_add_devices(child); + /* + * register the bus with sysfs as the parent is now + * properly registered. + */ if (child->is_added) continue; - child->is_added = 1; + retval = pci_bus_add_child(child); + if (retval) + dev_err(&dev->dev, "Error adding bus, continuing\n"); } } diff --git a/trunk/drivers/pci/hotplug/acpiphp.h b/trunk/drivers/pci/hotplug/acpiphp.h index b70ac00a117e..a1afb5b39ad4 100644 --- a/trunk/drivers/pci/hotplug/acpiphp.h +++ b/trunk/drivers/pci/hotplug/acpiphp.h @@ -79,6 +79,7 @@ struct acpiphp_bridge { /* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */ struct acpiphp_func *func; + int type; int nr_slots; u32 flags; @@ -145,6 +146,10 @@ struct acpiphp_attention_info /* PCI bus bridge HID */ #define ACPI_PCI_HOST_HID "PNP0A03" +/* PCI BRIDGE type */ +#define BRIDGE_TYPE_HOST 0 +#define BRIDGE_TYPE_P2P 1 + /* ACPI _STA method value (ignore bit 4; battery present) */ #define ACPI_STA_PRESENT (0x00000001) #define ACPI_STA_ENABLED (0x00000002) @@ -153,7 +158,13 @@ struct acpiphp_attention_info #define ACPI_STA_ALL (0x0000000f) /* bridge flags */ -#define BRIDGE_HAS_EJ0 (0x00000001) +#define BRIDGE_HAS_STA (0x00000001) +#define BRIDGE_HAS_EJ0 (0x00000002) +#define BRIDGE_HAS_HPP (0x00000004) +#define BRIDGE_HAS_PS0 (0x00000010) +#define BRIDGE_HAS_PS1 (0x00000020) +#define BRIDGE_HAS_PS2 (0x00000040) +#define BRIDGE_HAS_PS3 (0x00000080) /* slot flags */ @@ -182,6 +193,7 @@ extern void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *slot); /* acpiphp_glue.c */ extern int acpiphp_glue_init (void); extern void acpiphp_glue_exit (void); +extern int acpiphp_get_num_slots (void); typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); extern int acpiphp_enable_slot (struct acpiphp_slot *slot); diff --git a/trunk/drivers/pci/hotplug/acpiphp_core.c b/trunk/drivers/pci/hotplug/acpiphp_core.c index c2fd3095701f..96316b74969f 100644 --- a/trunk/drivers/pci/hotplug/acpiphp_core.c +++ b/trunk/drivers/pci/hotplug/acpiphp_core.c @@ -50,6 +50,7 @@ bool acpiphp_debug; /* local variables */ +static int num_slots; static struct acpiphp_attention_info *attention_info; #define DRIVER_VERSION "0.5" @@ -271,6 +272,25 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) return 0; } +static int __init init_acpi(void) +{ + int retval; + + /* initialize internal data structure etc. */ + retval = acpiphp_glue_init(); + + /* read initial number of slots */ + if (!retval) { + num_slots = acpiphp_get_num_slots(); + if (num_slots == 0) { + acpiphp_glue_exit(); + retval = -ENODEV; + } + } + + return retval; +} + /** * release_slot - free up the memory used by a slot * @hotplug_slot: slot to free @@ -359,8 +379,7 @@ static int __init acpiphp_init(void) return 0; /* read all the ACPI info from the system */ - /* initialize internal data structure etc. */ - return acpiphp_glue_init(); + return init_acpi(); } diff --git a/trunk/drivers/pci/hotplug/acpiphp_glue.c b/trunk/drivers/pci/hotplug/acpiphp_glue.c index 4681d2c9b1dd..9e2b1f6dbe41 100644 --- a/trunk/drivers/pci/hotplug/acpiphp_glue.c +++ b/trunk/drivers/pci/hotplug/acpiphp_glue.c @@ -325,8 +325,8 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) return; } - /* install notify handler for P2P bridges */ - if (!pci_is_root_bus(bridge->pci_bus)) { + /* install notify handler */ + if (bridge->type != BRIDGE_TYPE_HOST) { if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) { status = acpi_remove_notify_handler(bridge->func->handle, ACPI_SYSTEM_NOTIFY, @@ -369,12 +369,27 @@ static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge) { acpi_handle dummy_handle; - struct acpiphp_func *func; if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, - "_EJ0", &dummy_handle))) { + "_STA", &dummy_handle))) + bridge->flags |= BRIDGE_HAS_STA; + + if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, + "_EJ0", &dummy_handle))) bridge->flags |= BRIDGE_HAS_EJ0; + if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, + "_PS0", &dummy_handle))) + bridge->flags |= BRIDGE_HAS_PS0; + + if (ACPI_SUCCESS(acpi_get_handle(bridge->handle, + "_PS3", &dummy_handle))) + bridge->flags |= BRIDGE_HAS_PS3; + + /* is this ejectable p2p bridge? */ + if (bridge->flags & BRIDGE_HAS_EJ0) { + struct acpiphp_func *func; + dbg("found ejectable p2p bridge\n"); /* make link between PCI bridge and PCI function */ @@ -397,6 +412,7 @@ static void add_host_bridge(struct acpi_pci_root *root) if (bridge == NULL) return; + bridge->type = BRIDGE_TYPE_HOST; bridge->handle = handle; bridge->pci_bus = root->bus; @@ -416,6 +432,7 @@ static void add_p2p_bridge(acpi_handle *handle) return; } + bridge->type = BRIDGE_TYPE_P2P; bridge->handle = handle; config_p2p_bridge_flags(bridge); @@ -526,15 +543,13 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) acpi_status status; acpi_handle handle = bridge->handle; - if (!pci_is_root_bus(bridge->pci_bus)) { - status = acpi_remove_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, + status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event_bridge); - if (ACPI_FAILURE(status)) - err("failed to remove notify handler\n"); - } + if (ACPI_FAILURE(status)) + err("failed to remove notify handler\n"); - if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) { + if ((bridge->type != BRIDGE_TYPE_HOST) && + ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)) { status = acpi_install_notify_handler(bridge->func->handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event_func, @@ -615,6 +630,9 @@ static void remove_bridge(struct acpi_pci_root *root) bridge = acpiphp_handle_to_bridge(handle); if (bridge) cleanup_bridge(bridge); + else + acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_bridge); } static int power_on_slot(struct acpiphp_slot *slot) @@ -779,29 +797,6 @@ static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) } } -static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev) -{ - struct acpiphp_func *func; - - if (!dev->subordinate) - return; - - /* quirk, or pcie could set it already */ - if (dev->is_hotplug_bridge) - return; - - if (PCI_SLOT(dev->devfn) != slot->device) - return; - - list_for_each_entry(func, &slot->funcs, sibling) { - if (PCI_FUNC(dev->devfn) == func->function) { - /* check if this bridge has ejectable slots */ - if ((detect_ejectable_slots(func->handle) > 0)) - dev->is_hotplug_bridge = 1; - break; - } - } -} /** * enable_device - enable, configure a slot * @slot: slot to be enabled @@ -821,9 +816,6 @@ static int __ref enable_device(struct acpiphp_slot *slot) if (slot->flags & SLOT_ENABLED) goto err_exit; - list_for_each_entry(func, &slot->funcs, sibling) - acpiphp_bus_add(func); - num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0)); if (num == 0) { /* Maybe only part of funcs are added. */ @@ -839,14 +831,15 @@ static int __ref enable_device(struct acpiphp_slot *slot) if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { max = pci_scan_bridge(bus, dev, max, pass); - if (pass && dev->subordinate) { - check_hotplug_bridge(slot, dev); + if (pass && dev->subordinate) pci_bus_size_bridges(dev->subordinate); - } } } } + list_for_each_entry(func, &slot->funcs, sibling) + acpiphp_bus_add(func); + pci_bus_assign_resources(bus); acpiphp_sanitize_bus(bus); acpiphp_set_hpp_values(bus); @@ -1104,10 +1097,69 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus) } } +/* Program resources in newly inserted bridge */ +static int acpiphp_configure_bridge (acpi_handle handle) +{ + struct pci_bus *bus; + + if (acpi_is_root_bridge(handle)) { + struct acpi_pci_root *root = acpi_pci_find_root(handle); + bus = root->bus; + } else { + struct pci_dev *pdev = acpi_get_pci_dev(handle); + bus = pdev->subordinate; + pci_dev_put(pdev); + } + + pci_bus_size_bridges(bus); + pci_bus_assign_resources(bus); + acpiphp_sanitize_bus(bus); + acpiphp_set_hpp_values(bus); + pci_enable_bridges(bus); + return 0; +} + +static void handle_bridge_insertion(acpi_handle handle, u32 type) +{ + struct acpi_device *device; + + if ((type != ACPI_NOTIFY_BUS_CHECK) && + (type != ACPI_NOTIFY_DEVICE_CHECK)) { + err("unexpected notification type %d\n", type); + return; + } + + if (acpi_bus_scan(handle)) { + err("cannot add bridge to acpi list\n"); + return; + } + if (acpi_bus_get_device(handle, &device)) { + err("ACPI device object missing\n"); + return; + } + if (!acpiphp_configure_bridge(handle)) + add_bridge(handle); + else + err("cannot configure and start bridge\n"); + +} + /* * ACPI event handlers */ +static acpi_status +count_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + int *count = (int *)context; + struct acpiphp_bridge *bridge; + + bridge = acpiphp_handle_to_bridge(handle); + if (bridge) + (*count)++; + return AE_OK ; +} + static acpi_status check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) { @@ -1126,20 +1178,66 @@ check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) return AE_OK ; } +struct acpiphp_hp_work { + struct work_struct work; + acpi_handle handle; + u32 type; + void *context; +}; + +static void alloc_acpiphp_hp_work(acpi_handle handle, u32 type, + void *context, + void (*func)(struct work_struct *work)) +{ + struct acpiphp_hp_work *hp_work; + int ret; + + hp_work = kmalloc(sizeof(*hp_work), GFP_KERNEL); + if (!hp_work) + return; + + hp_work->handle = handle; + hp_work->type = type; + hp_work->context = context; + + INIT_WORK(&hp_work->work, func); + ret = queue_work(kacpi_hotplug_wq, &hp_work->work); + if (!ret) + kfree(hp_work); +} + static void _handle_hotplug_event_bridge(struct work_struct *work) { struct acpiphp_bridge *bridge; char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), .pointer = objname }; - struct acpi_hp_work *hp_work; + struct acpi_device *device; + int num_sub_bridges = 0; + struct acpiphp_hp_work *hp_work; acpi_handle handle; u32 type; - hp_work = container_of(work, struct acpi_hp_work, work); + hp_work = container_of(work, struct acpiphp_hp_work, work); handle = hp_work->handle; type = hp_work->type; - bridge = (struct acpiphp_bridge *)hp_work->context; + + if (acpi_bus_get_device(handle, &device)) { + /* This bridge must have just been physically inserted */ + handle_bridge_insertion(handle, type); + goto out; + } + + bridge = acpiphp_handle_to_bridge(handle); + if (type == ACPI_NOTIFY_BUS_CHECK) { + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, ACPI_UINT32_MAX, + count_sub_bridges, NULL, &num_sub_bridges, NULL); + } + + if (!bridge && !num_sub_bridges) { + err("cannot get bridge info\n"); + goto out; + } acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); @@ -1147,10 +1245,14 @@ static void _handle_hotplug_event_bridge(struct work_struct *work) case ACPI_NOTIFY_BUS_CHECK: /* bus re-enumerate */ dbg("%s: Bus check notify on %s\n", __func__, objname); - dbg("%s: re-enumerating slots under %s\n", __func__, objname); - acpiphp_check_bridge(bridge); - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, - ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL); + if (bridge) { + dbg("%s: re-enumerating slots under %s\n", + __func__, objname); + acpiphp_check_bridge(bridge); + } + if (num_sub_bridges) + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, + ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL, NULL); break; case ACPI_NOTIFY_DEVICE_CHECK: @@ -1167,7 +1269,8 @@ static void _handle_hotplug_event_bridge(struct work_struct *work) case ACPI_NOTIFY_EJECT_REQUEST: /* request device eject */ dbg("%s: Device eject notify on %s\n", __func__, objname); - if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) { + if ((bridge->type != BRIDGE_TYPE_HOST) && + (bridge->flags & BRIDGE_HAS_EJ0)) { struct acpiphp_slot *slot; slot = bridge->func->slot; if (!acpiphp_disable_slot(slot)) @@ -1195,6 +1298,7 @@ static void _handle_hotplug_event_bridge(struct work_struct *work) break; } +out: kfree(hp_work); /* allocated in handle_hotplug_event_bridge */ } @@ -1217,7 +1321,8 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, * For now just re-add this work to the kacpi_hotplug_wq so we * don't deadlock on hotplug actions. */ - alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_bridge); + alloc_acpiphp_hp_work(handle, type, context, + _handle_hotplug_event_bridge); } static void _handle_hotplug_event_func(struct work_struct *work) @@ -1226,17 +1331,20 @@ static void _handle_hotplug_event_func(struct work_struct *work) char objname[64]; struct acpi_buffer buffer = { .length = sizeof(objname), .pointer = objname }; - struct acpi_hp_work *hp_work; + struct acpiphp_hp_work *hp_work; acpi_handle handle; u32 type; + void *context; - hp_work = container_of(work, struct acpi_hp_work, work); + hp_work = container_of(work, struct acpiphp_hp_work, work); handle = hp_work->handle; type = hp_work->type; - func = (struct acpiphp_func *)hp_work->context; + context = hp_work->context; acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + func = (struct acpiphp_func *)context; + switch (type) { case ACPI_NOTIFY_BUS_CHECK: /* bus re-enumerate */ @@ -1289,7 +1397,23 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, * For now just re-add this work to the kacpi_hotplug_wq so we * don't deadlock on hotplug actions. */ - alloc_acpi_hp_work(handle, type, context, _handle_hotplug_event_func); + alloc_acpiphp_hp_work(handle, type, context, + _handle_hotplug_event_func); +} + +static acpi_status +find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) +{ + int *count = (int *)context; + + if (!acpi_is_root_bridge(handle)) + return AE_OK; + + (*count)++; + acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_bridge, NULL); + + return AE_OK ; } static struct acpi_pci_driver acpi_pci_hp_driver = { @@ -1302,7 +1426,15 @@ static struct acpi_pci_driver acpi_pci_hp_driver = { */ int __init acpiphp_glue_init(void) { - acpi_pci_register_driver(&acpi_pci_hp_driver); + int num = 0; + + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL); + + if (num <= 0) + return -1; + else + acpi_pci_register_driver(&acpi_pci_hp_driver); return 0; } @@ -1318,6 +1450,28 @@ void acpiphp_glue_exit(void) acpi_pci_unregister_driver(&acpi_pci_hp_driver); } + +/** + * acpiphp_get_num_slots - count number of slots in a system + */ +int __init acpiphp_get_num_slots(void) +{ + struct acpiphp_bridge *bridge; + int num_slots = 0; + + list_for_each_entry(bridge, &bridge_list, list) { + dbg("Bus %04x:%02x has %d slot%s\n", + pci_domain_nr(bridge->pci_bus), + bridge->pci_bus->number, bridge->nr_slots, + bridge->nr_slots == 1 ? "" : "s"); + num_slots += bridge->nr_slots; + } + + dbg("Total %d slots\n", num_slots); + return num_slots; +} + + /** * acpiphp_enable_slot - power on slot * @slot: ACPI PHP slot 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_core.c b/trunk/drivers/pci/hotplug/pciehp_core.c index 874a3baf1db0..916bf4f53aba 100644 --- a/trunk/drivers/pci/hotplug/pciehp_core.c +++ b/trunk/drivers/pci/hotplug/pciehp_core.c @@ -294,6 +294,7 @@ static void pciehp_remove(struct pcie_device *dev) #ifdef CONFIG_PM static int pciehp_suspend (struct pcie_device *dev) { + dev_info(&dev->device, "%s ENTRY\n", __func__); return 0; } @@ -303,6 +304,7 @@ static int pciehp_resume (struct pcie_device *dev) struct slot *slot; u8 status; + dev_info(&dev->device, "%s ENTRY\n", __func__); ctrl = get_service_data(dev); /* reinitialize the chipset's event detection logic */ 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 4ea7139db1be..bafd2bbcaf65 100644 --- a/trunk/drivers/pci/iov.c +++ b/trunk/drivers/pci/iov.c @@ -33,6 +33,7 @@ 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) @@ -47,7 +48,12 @@ static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr) return NULL; pci_bus_insert_busn_res(child, busnr, busnr); - bus->is_added = 1; + child->dev.parent = bus->bridge; + rc = pci_bus_add_child(child); + if (rc) { + pci_remove_bus(child); + return NULL; + } return child; } @@ -117,6 +123,8 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset) virtfn->is_virtfn = 1; rc = pci_bus_add_device(virtfn); + if (rc) + goto failed1; sprintf(buf, "virtfn%u", id); rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf); if (rc) 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-driver.c b/trunk/drivers/pci/pci-driver.c index 1fa1e482a999..f79cbcd3944b 100644 --- a/trunk/drivers/pci/pci-driver.c +++ b/trunk/drivers/pci/pci-driver.c @@ -392,7 +392,7 @@ static void pci_device_shutdown(struct device *dev) * Turn off Bus Master bit on the device to tell it to not * continue to do DMA */ - pci_clear_master(pci_dev); + pci_disable_device(pci_dev); } #ifdef CONFIG_PM @@ -628,7 +628,6 @@ static int pci_pm_suspend(struct device *dev) goto Fixup; } - pci_dev->state_saved = false; if (pm->suspend) { pci_power_t prev = pci_dev->current_state; int error; @@ -775,7 +774,6 @@ static int pci_pm_freeze(struct device *dev) return 0; } - pci_dev->state_saved = false; if (pm->freeze) { int error; @@ -864,7 +862,6 @@ static int pci_pm_poweroff(struct device *dev) goto Fixup; } - pci_dev->state_saved = false; if (pm->poweroff) { int error; @@ -990,7 +987,6 @@ static int pci_pm_runtime_suspend(struct device *dev) if (!pm || !pm->runtime_suspend) return -ENOSYS; - pci_dev->state_saved = false; pci_dev->no_d3cold = false; error = pm->runtime_suspend(dev); suspend_report_result(pm->runtime_suspend, error); @@ -1190,13 +1186,9 @@ pci_dev_driver(const struct pci_dev *dev) static int pci_bus_match(struct device *dev, struct device_driver *drv) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct pci_driver *pci_drv; + struct pci_driver *pci_drv = to_pci_driver(drv); const struct pci_device_id *found_id; - if (!pci_dev->match_driver) - return 0; - - pci_drv = to_pci_driver(drv); found_id = pci_match_device(pci_drv, pci_dev); if (found_id) return 1; diff --git a/trunk/drivers/pci/pci.c b/trunk/drivers/pci/pci.c index 924e4665bd57..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; @@ -1168,7 +1169,7 @@ static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags) dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK); } - if (atomic_inc_return(&dev->enable_cnt) > 1) + if (atomic_add_return(1, &dev->enable_cnt) > 1) return 0; /* already enabled */ /* only skip sriov related */ @@ -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); } /* @@ -1395,10 +1396,7 @@ pci_disable_device(struct pci_dev *dev) if (dr) dr->enabled = 0; - dev_WARN_ONCE(&dev->dev, atomic_read(&dev->enable_cnt) <= 0, - "disabling already-disabled device"); - - if (atomic_dec_return(&dev->enable_cnt) != 0) + if (atomic_sub_return(1, &dev->enable_cnt) != 0) return; do_pci_disable_device(dev); @@ -2045,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; @@ -2059,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; @@ -2067,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; } /** @@ -3751,6 +3742,18 @@ resource_size_t pci_specified_resource_alignment(struct pci_dev *dev) return align; } +/** + * pci_is_reassigndev - check if specified PCI is target device to reassign + * @dev: the PCI device to check + * + * RETURNS: non-zero for PCI device is a target device to reassign, + * or zero is not. + */ +int pci_is_reassigndev(struct pci_dev *dev) +{ + return (pci_specified_resource_alignment(dev) != 0); +} + /* * This function disables memory decoding and releases memory resources * of the device specified by kernel's boot parameter 'pci=resource_alignment='. @@ -3765,9 +3768,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev) resource_size_t align, size; u16 command; - /* check if specified PCI is target device to reassign */ - align = pci_specified_resource_alignment(dev); - if (!align) + if (!pci_is_reassigndev(dev)) return; if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL && @@ -3783,6 +3784,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev) command &= ~PCI_COMMAND_MEMORY; pci_write_config_word(dev, PCI_COMMAND, command); + align = pci_specified_resource_alignment(dev); for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) { r = &dev->resource[i]; if (!(r->flags & IORESOURCE_MEM)) diff --git a/trunk/drivers/pci/pci.h b/trunk/drivers/pci/pci.h index 7346ee68f47d..adfd172c5b9b 100644 --- a/trunk/drivers/pci/pci.h +++ b/trunk/drivers/pci/pci.h @@ -203,8 +203,8 @@ 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 int pci_bus_add_child(struct pci_bus *bus); +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/pcie/aspm.c b/trunk/drivers/pci/pcie/aspm.c index e8a19772cf52..b52630b8eada 100644 --- a/trunk/drivers/pci/pcie/aspm.c +++ b/trunk/drivers/pci/pcie/aspm.c @@ -556,9 +556,6 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) struct pcie_link_state *link; int blacklist = !!pcie_aspm_sanity_check(pdev); - if (!aspm_support_enabled) - return; - if (!pci_is_pcie(pdev) || pdev->link_state) return; if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT && @@ -637,7 +634,10 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) struct pci_dev *parent = pdev->bus->self; struct pcie_link_state *link, *root, *parent_link; - if (!parent || !parent->link_state) + if (!pci_is_pcie(pdev) || !parent || !parent->link_state) + return; + if ((pci_pcie_type(parent) != PCI_EXP_TYPE_ROOT_PORT) && + (pci_pcie_type(parent) != PCI_EXP_TYPE_DOWNSTREAM)) return; down_read(&pci_bus_sem); diff --git a/trunk/drivers/pci/pcie/portdrv_core.c b/trunk/drivers/pci/pcie/portdrv_core.c index 31063ac30992..b42133afca98 100644 --- a/trunk/drivers/pci/pcie/portdrv_core.c +++ b/trunk/drivers/pci/pcie/portdrv_core.c @@ -272,7 +272,7 @@ static int get_port_device_capability(struct pci_dev *dev) /* Hot-Plug Capable */ if ((cap_mask & PCIE_PORT_SERVICE_HP) && - pcie_caps_reg(dev) & PCI_EXP_FLAGS_SLOT) { + dev->pcie_flags_reg & PCI_EXP_FLAGS_SLOT) { pcie_capability_read_dword(dev, PCI_EXP_SLTCAP, ®32); if (reg32 & PCI_EXP_SLTCAP_HPC) { services |= PCIE_PORT_SERVICE_HP; diff --git a/trunk/drivers/pci/probe.c b/trunk/drivers/pci/probe.c index b494066ef32f..2dcd22d9c816 100644 --- a/trunk/drivers/pci/probe.c +++ b/trunk/drivers/pci/probe.c @@ -623,7 +623,6 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, { struct pci_bus *child; int i; - int ret; /* * Allocate a new bus, and inherit stuff from the parent.. @@ -638,7 +637,8 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, child->bus_flags = parent->bus_flags; /* initialize some portions of the bus device, but don't register it - * now as the parent is not properly set up yet. + * now as the parent is not properly set up yet. This device will get + * registered later in pci_bus_add_devices() */ child->dev.class = &pcibus_class; dev_set_name(&child->dev, "%04x:%02x", pci_domain_nr(child), busnr); @@ -651,14 +651,11 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, child->primary = parent->busn_res.start; child->busn_res.end = 0xff; - if (!bridge) { - child->dev.parent = parent->bridge; - goto add_dev; - } + if (!bridge) + return child; child->self = bridge; child->bridge = get_device(&bridge->dev); - child->dev.parent = child->bridge; pci_set_bus_of_node(child); pci_set_bus_speed(child); @@ -669,13 +666,6 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, } bridge->subordinate = child; -add_dev: - ret = device_register(&child->dev); - WARN_ON(ret < 0); - - /* Create legacy_io and legacy_mem files for this bus */ - pci_create_legacy_files(child); - return child; } @@ -1295,7 +1285,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); @@ -1306,12 +1296,10 @@ static void pci_init_capabilities(struct pci_dev *dev) void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) { - int ret; - device_initialize(&dev->dev); dev->dev.release = pci_release_dev; + pci_dev_get(dev); - set_dev_node(&dev->dev, pcibus_to_node(bus)); dev->dev.dma_mask = &dev->dma_mask; dev->dev.dma_parms = &dev->dma_parms; dev->dev.coherent_dma_mask = 0xffffffffull; @@ -1338,17 +1326,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) down_write(&pci_bus_sem); list_add_tail(&dev->bus_list, &bus->devices); up_write(&pci_bus_sem); - - pci_fixup_device(pci_fixup_final, dev); - ret = pcibios_add_device(dev); - WARN_ON(ret < 0); - - /* Notifier could use PCI capabilities */ - dev->match_driver = false; - ret = device_add(&dev->dev); - WARN_ON(ret < 0); - - pci_proc_attach_device(dev); } struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn) @@ -1371,31 +1348,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; + u16 cap; + unsigned pos, 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; - - 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 +1405,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 +1416,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 +1632,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) { @@ -1673,13 +1644,13 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, char bus_addr[64]; char *fmt; + b = pci_alloc_bus(); if (!b) return NULL; b->sysdata = sysdata; b->ops = ops; - b->number = b->busn_res.start = bus; b2 = pci_find_bus(pci_domain_nr(b), bus); if (b2) { /* If we already got to this bus through a different bridge, ignore it */ @@ -1694,10 +1665,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; @@ -1718,6 +1685,8 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus, /* Create legacy_io and legacy_mem files for this bus */ pci_create_legacy_files(b); + b->number = b->busn_res.start = bus; + if (parent) dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev)); else diff --git a/trunk/drivers/pci/remove.c b/trunk/drivers/pci/remove.c index fc38c4883e1d..7c0fd9252e6f 100644 --- a/trunk/drivers/pci/remove.c +++ b/trunk/drivers/pci/remove.c @@ -22,7 +22,7 @@ static void pci_stop_dev(struct pci_dev *dev) if (dev->is_added) { pci_proc_detach_device(dev); pci_remove_sysfs_dev_files(dev); - device_del(&dev->dev); + device_unregister(&dev->dev); dev->is_added = 0; } @@ -37,7 +37,7 @@ static void pci_destroy_dev(struct pci_dev *dev) up_write(&pci_bus_sem); pci_free_resources(dev); - put_device(&dev->dev); + pci_dev_put(dev); } void pci_remove_bus(struct pci_bus *bus) diff --git a/trunk/drivers/pci/search.c b/trunk/drivers/pci/search.c index d0627fa9f368..bf969ba58e59 100644 --- a/trunk/drivers/pci/search.c +++ b/trunk/drivers/pci/search.c @@ -319,13 +319,13 @@ int pci_dev_present(const struct pci_device_id *ids) WARN_ON(in_interrupt()); while (ids->vendor || ids->subvendor || ids->class_mask) { found = pci_get_dev_by_id(ids, NULL); - if (found) { - pci_dev_put(found); - return 1; - } + if (found) + goto exit; ids++; } - +exit: + if (found) + return 1; return 0; } EXPORT_SYMBOL(pci_dev_present); diff --git a/trunk/drivers/pci/setup-bus.c b/trunk/drivers/pci/setup-bus.c index 7e8739e25b9e..6d3591d57ea0 100644 --- a/trunk/drivers/pci/setup-bus.c +++ b/trunk/drivers/pci/setup-bus.c @@ -283,7 +283,7 @@ static void assign_requested_resources_sorted(struct list_head *head, idx = res - &dev_res->dev->resource[0]; if (resource_size(res) && pci_assign_resource(dev_res->dev, idx)) { - if (fail_head) { + if (fail_head && !pci_is_root_bus(dev_res->dev->bus)) { /* * if the failed res is for ROM BAR, and it will * be enabled later, don't add it to the list diff --git a/trunk/include/acpi/acpi_bus.h b/trunk/include/acpi/acpi_bus.h index 5ce8d5e86734..2c722deb2490 100644 --- a/trunk/include/acpi/acpi_bus.h +++ b/trunk/include/acpi/acpi_bus.h @@ -310,15 +310,6 @@ struct acpi_eject_event { u32 event; }; -struct acpi_hp_work { - struct work_struct work; - acpi_handle handle; - u32 type; - void *context; -}; -void alloc_acpi_hp_work(acpi_handle handle, u32 type, void *context, - void (*func)(struct work_struct *work)); - extern struct kobject *acpi_kobj; extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int); void acpi_bus_private_data_handler(acpi_handle, void *); @@ -408,6 +399,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/acpi/acpiosxf.h b/trunk/include/acpi/acpiosxf.h index 66f1fd70e8c2..43152742b46f 100644 --- a/trunk/include/acpi/acpiosxf.h +++ b/trunk/include/acpi/acpiosxf.h @@ -193,6 +193,8 @@ void acpi_os_fixed_event_count(u32 fixed_event_number); /* * Threads and Scheduling */ +extern struct workqueue_struct *kacpi_hotplug_wq; + acpi_thread_id acpi_os_get_thread_id(void); acpi_status diff --git a/trunk/include/linux/pci.h b/trunk/include/linux/pci.h index 7e87b1ed2175..907b455ab603 100644 --- a/trunk/include/linux/pci.h +++ b/trunk/include/linux/pci.h @@ -286,7 +286,6 @@ struct pci_dev { unsigned int irq; struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */ - bool match_driver; /* Skip attaching driver */ /* These fields are used by common fixups */ unsigned int transparent:1; /* Transparent PCI bridge */ unsigned int multifunction:1;/* Part of multi-function device */ @@ -379,8 +378,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 @@ -1696,22 +1693,13 @@ static inline bool pci_is_pcie(struct pci_dev *dev) return !!pci_pcie_cap(dev); } -/** - * pcie_caps_reg - get the PCIe Capabilities Register - * @dev: PCI device - */ -static inline u16 pcie_caps_reg(const struct pci_dev *dev) -{ - return dev->pcie_flags_reg; -} - /** * pci_pcie_type - get the PCIe device/port type * @dev: PCI device */ static inline int pci_pcie_type(const struct pci_dev *dev) { - return (pcie_caps_reg(dev) & PCI_EXP_FLAGS_TYPE) >> 4; + return (dev->pcie_flags_reg & PCI_EXP_FLAGS_TYPE) >> 4; } void pci_request_acs(void);