From 3c449ed0075994b3f3371f8254560428ba787efc Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Sat, 3 Nov 2012 21:39:31 -0700 Subject: PCI/ACPI: Reserve firmware-allocated resources for hot-added root buses Firmware may have assigned PCI BARs for hot-added devices, so reserve those resources before trying to allocate more. [bhelgaas: move empty weak definition here] Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_root.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 7928d4dc7056..dcbe9660e756 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -650,8 +650,10 @@ static int acpi_pci_root_start(struct acpi_device *device) struct acpi_pci_root *root = acpi_driver_data(device); struct acpi_pci_driver *driver; - if (system_state != SYSTEM_BOOTING) + if (system_state != SYSTEM_BOOTING) { + pcibios_resource_survey_bus(root->bus); pci_assign_unassigned_bus_resources(root->bus); + } mutex_lock(&acpi_pci_root_lock); list_for_each_entry(driver, &acpi_pci_drivers, node) -- cgit v1.2.3 From 6c0cc950ae670403a362bdcbf3cde0df33744928 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 9 Jan 2013 22:33:37 +0100 Subject: ACPI / PCI: Set root bridge ACPI handle in advance The ACPI handles of PCI root bridges need to be known to acpi_bind_one(), so that it can create the appropriate "firmware_node" and "physical_node" files for them, but currently the way it gets to know those handles is not exactly straightforward (to put it lightly). This is how it works, roughly: 1. acpi_bus_scan() finds the handle of a PCI root bridge, creates a struct acpi_device object for it and passes that object to acpi_pci_root_add(). 2. acpi_pci_root_add() creates a struct acpi_pci_root object, populates its "device" field with its argument's address (device->handle is the ACPI handle found in step 1). 3. The struct acpi_pci_root object created in step 2 is passed to pci_acpi_scan_root() and used to get resources that are passed to pci_create_root_bus(). 4. pci_create_root_bus() creates a struct pci_host_bridge object and passes its "dev" member to device_register(). 5. platform_notify(), which for systems with ACPI is set to acpi_platform_notify(), is called. So far, so good. Now it starts to be "interesting". 6. acpi_find_bridge_device() is used to find the ACPI handle of the given device (which is the PCI root bridge) and executes acpi_pci_find_root_bridge(), among other things, for the given device object. 7. acpi_pci_find_root_bridge() uses the name (sic!) of the given device object to extract the segment and bus numbers of the PCI root bridge and passes them to acpi_get_pci_rootbridge_handle(). 8. acpi_get_pci_rootbridge_handle() browses the list of ACPI PCI root bridges and finds the one that matches the given segment and bus numbers. Its handle is then used to initialize the ACPI handle of the PCI root bridge's device object by acpi_bind_one(). However, this is *exactly* the ACPI handle we started with in step 1. Needless to say, this is quite embarassing, but it may be avoided thanks to commit f3fd0c8 (ACPI: Allow ACPI handles of devices to be initialized in advance), which makes it possible to initialize the ACPI handle of a device before passing it to device_register(). Accordingly, add a new __weak routine, pcibios_root_bridge_prepare(), defaulting to an empty implementation that can be replaced by the interested architecutres (x86 and ia64 at the moment) with functions that will set the root bridge's ACPI handle before its dev member is passed to device_register(). Make both x86 and ia64 provide such implementations of pcibios_root_bridge_prepare() and remove acpi_pci_find_root_bridge() and acpi_get_pci_rootbridge_handle() that aren't necessary any more. Included is a fix for breakage on systems with non-ACPI PCI host bridges from Bjorn Helgaas. Signed-off-by: Rafael J. Wysocki Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_root.c | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 471b2dcb1c67..bf5108ad4d63 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -107,24 +107,6 @@ 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. -- cgit v1.2.3 From 92d8aff3a317fcd6f78ed9ac13dbbaeae8cb11ed Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Mon, 21 Jan 2013 13:20:47 -0800 Subject: PCI/ACPI: acpiphp: Rename alloc_acpiphp_hp_work() to alloc_acpi_hp_work() Will need to use it for PCI root bridge hotplug support, so rename *acpiphp* to *acpi* and move to osc.c. Also make kacpi_hotplug_wq static after that. Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki CC: Len Brown CC: linux-acpi@vger.kernel.org --- drivers/acpi/osl.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 3ff267861541..59ec5f52e849 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -84,8 +84,7 @@ 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; -struct workqueue_struct *kacpi_hotplug_wq; -EXPORT_SYMBOL(kacpi_hotplug_wq); +static struct workqueue_struct *kacpi_hotplug_wq; /* * This list of permanent mappings is for memory that may be accessed from @@ -1778,3 +1777,24 @@ 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); -- cgit v1.2.3 From 668192b678201d2fff27c6cc76bb003c1ec4a52a Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Mon, 21 Jan 2013 13:20:48 -0800 Subject: PCI: acpiphp: Move host bridge hotplug to pci_root.c The acpiphp driver is confusing because it contains partial support for PCI host bridge hotplug as well as support for hotplug of PCI devices. This patch moves the host bridge hot-add support to pci_root.c and adds hot-remove support in pci_root.c. How to test it: if sci_emu patch is applied, find out root bus number to ACPI root name mapping from dmesg or /sys. To remove root bus: echo "\_SB.PCIB 3" > /sys/kernel/debug/acpi/sci_notify To add back root bus: echo "\_SB.PCIB 1" > /sys/kernel/debug/acpi/sci_notify Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/acpi/internal.h | 1 + drivers/acpi/pci_root.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/scan.c | 3 ++ 3 files changed, 128 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index e050254ae143..0f24148a2b2a 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -68,6 +68,7 @@ struct acpi_ec { extern struct acpi_ec *first_ec; 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/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 471b2dcb1c67..1389811aa21b 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -673,3 +673,127 @@ 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) +{ + 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); + + acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_root, NULL); + printk(KERN_DEBUG "acpi root: %s notify handler 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/drivers/acpi/scan.c b/drivers/acpi/scan.c index 7c43bdc36abc..bc2f33790e83 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1706,5 +1706,8 @@ int __init acpi_scan_init(void) } acpi_update_all_gpes(); + + acpi_pci_root_hp_init(); + return 0; } -- cgit v1.2.3 From 121b090e7d4063b65f40c267ef0fb34fb278dfdf Mon Sep 17 00:00:00 2001 From: Tang Chen Date: Mon, 21 Jan 2013 13:20:49 -0800 Subject: PCI/ACPI: Print info if host bridge notify handler installation fails acpi_install_notify_handler() could fail. So check the exit status and give a better debug info. Signed-off-by: Tang Chen Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/acpi/pci_root.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 1389811aa21b..fd59f57d3829 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -769,6 +769,7 @@ static void handle_hotplug_event_root(acpi_handle handle, u32 type, 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 }; @@ -781,9 +782,14 @@ find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_root, NULL); - printk(KERN_DEBUG "acpi root: %s notify handler installed\n", objname); + 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; } -- cgit v1.2.3 From ab1a2e038ff2336502e95ec6492c0364a9fc70d0 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Sat, 19 Jan 2013 00:07:42 +0800 Subject: ACPI / PCI: Make pci_slot built-in only, not a module As discussed in thread at https://patchwork.kernel.org/patch/1946851/, there's no value in supporting CONFIG_ACPI_PCI_SLOT=m any more. So change Kconfig and code to only support building pci_slot as built-in driver. Signed-off-by: Jiang Liu Signed-off-by: Bjorn Helgaas --- drivers/acpi/Kconfig | 5 +---- drivers/acpi/internal.h | 5 +++++ drivers/acpi/pci_slot.c | 13 +------------ drivers/acpi/scan.c | 1 + 4 files changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 38c5078da11d..27fde5e8d31a 100644 --- a/drivers/acpi/Kconfig +++ b/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/drivers/acpi/internal.h b/drivers/acpi/internal.h index e050254ae143..7374cfc5917a 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -67,6 +67,11 @@ 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); int acpi_ec_init(void); int acpi_ec_ecdt_probe(void); diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index d22585f21aeb..a7d7e7710f9e 100644 --- a/drivers/acpi/pci_slot.c +++ b/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/drivers/acpi/scan.c b/drivers/acpi/scan.c index 7c43bdc36abc..236e476b09c9 100644 --- a/drivers/acpi/scan.c +++ b/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. -- cgit v1.2.3 From 181380b702eee1a9aca51354d7b87c7b08541fcf Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Sat, 16 Feb 2013 11:58:34 -0700 Subject: PCI/ACPI: Don't cache _PRT, and don't associate them with bus numbers Previously, we cached _PRT (PCI routing table, ACPI 5.0 sec 6.2.12) contents and associated each _PRT entry with a PCI bus number. The bus number association means dependencies on PCI device enumeration and bus number assignment, as well as on the PCI/ACPI binding process. After 4f535093cf ("PCI: Put pci_dev in device tree as early as possible"), these dependencies caused the IRQ issues reported by Peter: pci 0000:00:1e.0: PCI bridge to [bus 09] (subtractive decode) pci 0000:00:1e.0: can't derive routing for PCI INT A snd_ctxfi 0000:09:02.0: PCI INT A: no GSI - using ISA IRQ 5 irq 18: nobody cared (try booting with the "irqpoll" option) This patch removes _PRT caching. Instead, we evaluate _PRT as needed in the pci_enable_device() path. This also removes the dependency on PCI bus numbers: we can simply look at the _PRT associated with each bridge as we walk upstream toward the root. [bhelgaas: changelog] Reference: https://bugzilla.kernel.org/show_bug.cgi?id=53561 Reported-and-tested-by: Peter Hurley Suggested-by: Bjorn Helgaas Signed-off-by: Yinghai Lu Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_irq.c | 102 ++++++++++++++++-------------------------------- drivers/acpi/pci_root.c | 18 --------- 2 files changed, 34 insertions(+), 86 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 68a921d03247..41c5e1b799ef 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -53,9 +53,6 @@ struct acpi_prt_entry { u32 index; /* GSI, or link _CRS index */ }; -static LIST_HEAD(acpi_prt_list); -static DEFINE_SPINLOCK(acpi_prt_lock); - static inline char pin_name(int pin) { return 'A' + pin - 1; @@ -65,28 +62,6 @@ static inline char pin_name(int pin) PCI IRQ Routing Table (PRT) Support -------------------------------------------------------------------------- */ -static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(struct pci_dev *dev, - int pin) -{ - struct acpi_prt_entry *entry; - int segment = pci_domain_nr(dev->bus); - int bus = dev->bus->number; - int device = PCI_SLOT(dev->devfn); - - spin_lock(&acpi_prt_lock); - list_for_each_entry(entry, &acpi_prt_list, list) { - if ((segment == entry->id.segment) - && (bus == entry->id.bus) - && (device == entry->id.device) - && (pin == entry->pin)) { - spin_unlock(&acpi_prt_lock); - return entry; - } - } - spin_unlock(&acpi_prt_lock); - return NULL; -} - /* http://bugzilla.kernel.org/show_bug.cgi?id=4773 */ static const struct dmi_system_id medion_md9580[] = { { @@ -184,11 +159,19 @@ static void do_prt_fixups(struct acpi_prt_entry *entry, } } -static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus, - struct acpi_pci_routing_table *prt) +static int acpi_pci_irq_check_entry(acpi_handle handle, struct pci_dev *dev, + int pin, struct acpi_pci_routing_table *prt, + struct acpi_prt_entry **entry_ptr) { + int segment = pci_domain_nr(dev->bus); + int bus = dev->bus->number; + int device = PCI_SLOT(dev->devfn); struct acpi_prt_entry *entry; + if (((prt->address >> 16) & 0xffff) != device || + prt->pin + 1 != pin) + return -ENODEV; + entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -237,43 +220,37 @@ static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus, entry->id.device, pin_name(entry->pin), prt->source, entry->index)); - spin_lock(&acpi_prt_lock); - list_add_tail(&entry->list, &acpi_prt_list); - spin_unlock(&acpi_prt_lock); + *entry_ptr = entry; return 0; } -int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) +static int acpi_pci_irq_find_prt_entry(struct pci_dev *dev, + int pin, struct acpi_prt_entry **entry_ptr) { acpi_status status; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_pci_routing_table *entry; + acpi_handle handle = NULL; - /* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */ - status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - if (ACPI_FAILURE(status)) - return -ENODEV; - - printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n", - (char *) buffer.pointer); - - kfree(buffer.pointer); + if (dev->bus->bridge) + handle = ACPI_HANDLE(dev->bus->bridge); - buffer.length = ACPI_ALLOCATE_BUFFER; - buffer.pointer = NULL; + if (!handle) + return -ENODEV; + /* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */ status = acpi_get_irq_routing_table(handle, &buffer); if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]", - acpi_format_exception(status))); kfree(buffer.pointer); return -ENODEV; } entry = buffer.pointer; while (entry && (entry->length > 0)) { - acpi_pci_irq_add_entry(handle, segment, bus, entry); + if (!acpi_pci_irq_check_entry(handle, dev, pin, + entry, entry_ptr)) + break; entry = (struct acpi_pci_routing_table *) ((unsigned long)entry + entry->length); } @@ -282,23 +259,6 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) return 0; } -void acpi_pci_irq_del_prt(int segment, int bus) -{ - struct acpi_prt_entry *entry, *tmp; - - printk(KERN_DEBUG - "ACPI: Delete PCI Interrupt Routing Table for %04x:%02x\n", - segment, bus); - spin_lock(&acpi_prt_lock); - list_for_each_entry_safe(entry, tmp, &acpi_prt_list, list) { - if (segment == entry->id.segment && bus == entry->id.bus) { - list_del(&entry->list); - kfree(entry); - } - } - spin_unlock(&acpi_prt_lock); -} - /* -------------------------------------------------------------------------- PCI Interrupt Routing Support -------------------------------------------------------------------------- */ @@ -359,12 +319,13 @@ static int acpi_reroute_boot_interrupt(struct pci_dev *dev, static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) { - struct acpi_prt_entry *entry; + struct acpi_prt_entry *entry = NULL; struct pci_dev *bridge; u8 bridge_pin, orig_pin = pin; + int ret; - entry = acpi_pci_irq_find_prt_entry(dev, pin); - if (entry) { + ret = acpi_pci_irq_find_prt_entry(dev, pin, &entry); + if (!ret && entry) { #ifdef CONFIG_X86_IO_APIC acpi_reroute_boot_interrupt(dev, entry); #endif /* CONFIG_X86_IO_APIC */ @@ -373,7 +334,7 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) return entry; } - /* + /* * Attempt to derive an IRQ for this device from a parent bridge's * PCI interrupt routing entry (eg. yenta bridge and add-in card bridge). */ @@ -393,8 +354,8 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) pin = bridge_pin; } - entry = acpi_pci_irq_find_prt_entry(bridge, pin); - if (entry) { + ret = acpi_pci_irq_find_prt_entry(bridge, pin, &entry); + if (!ret && entry) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Derived GSI for %s INT %c from %s\n", pci_name(dev), pin_name(orig_pin), @@ -470,6 +431,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) dev_warn(&dev->dev, "PCI INT %c: no GSI\n", pin_name(pin)); } + return 0; } @@ -477,6 +439,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) if (rc < 0) { dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n", pin_name(pin)); + kfree(entry); return rc; } dev->irq = rc; @@ -491,6 +454,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge", (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq); + kfree(entry); return 0; } @@ -513,6 +477,8 @@ void acpi_pci_irq_disable(struct pci_dev *dev) else gsi = entry->index; + kfree(entry); + /* * TBD: It might be worth clearing dev->irq by magic constant * (e.g. PCI_UNDEFINED_IRQ). diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index fd59f57d3829..8545b1d22811 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -434,7 +434,6 @@ static int acpi_pci_root_add(struct acpi_device *device) acpi_status status; int result; struct acpi_pci_root *root; - acpi_handle handle; struct acpi_pci_driver *driver; u32 flags, base_flags; bool is_osc_granted = false; @@ -489,16 +488,6 @@ static int acpi_pci_root_add(struct acpi_device *device) acpi_device_name(device), acpi_device_bid(device), root->segment, &root->secondary); - /* - * PCI Routing Table - * ----------------- - * Evaluate and parse _PRT, if exists. - */ - status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); - if (ACPI_SUCCESS(status)) - result = acpi_pci_irq_add_prt(device->handle, root->segment, - root->secondary.start); - root->mcfg_addr = acpi_pci_root_get_mcfg_addr(device->handle); /* @@ -623,7 +612,6 @@ out_del_root: list_del(&root->node); mutex_unlock(&acpi_pci_root_lock); - acpi_pci_irq_del_prt(root->segment, root->secondary.start); end: kfree(root); return result; @@ -631,8 +619,6 @@ end: static int acpi_pci_root_remove(struct acpi_device *device, int type) { - acpi_status status; - acpi_handle handle; struct acpi_pci_root *root = acpi_driver_data(device); struct acpi_pci_driver *driver; @@ -647,10 +633,6 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type) device_set_run_wake(root->bus->bridge, false); pci_acpi_remove_bus_pm_notifier(device); - status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle); - if (ACPI_SUCCESS(status)) - acpi_pci_irq_del_prt(root->segment, root->secondary.start); - pci_remove_root_bus(root->bus); mutex_lock(&acpi_pci_root_lock); -- cgit v1.2.3