ACPI: PCI: simplify _PRT handling
Subsystems (3)
cover ACPI: PCI: simplify _PRT handling
This series simplifies the code that handles ACPI _PRTs (PCI routing tables). My goal is to make this look more like the corresponding code in other architectures, especially in terms of swizzling, e.g., the various implementations of common_swizzle() and simple_swizzle(), and the x86 non-ACPI code in pirq_enable_irq().
There should be no functional changes in this series.
Comments welcome.
Bjorn
---
Bjorn Helgaas (20):
ACPI: PCI: add HP copyright
ACPI: PCI: whitespace and useless initialization cleanup
ACPI: PCI: expand acpi_pci_allocate_irq() and acpi_pci_free_irq() inline
ACPI: PCI: simplify struct acpi_prt_entry
ACPI: PCI: simplify list of _PRT entries
ACPI: PCI: combine lookup and derive
ACPI: PCI: follow typical PCI INTx swizzling pattern
ACPI: PCI: use positive logic to simplify code
ACPI: PCI: remove callback from acpi_pci_irq_lookup & acpi_pci_irq_derive
ACPI: PCI: tweak _PRT lookup debug
ACPI: PCI: lookup _PRT entry by PCI dev and pin, not segment/bus/dev/pin
ACPI: PCI: use 1-based encoding for _PRT quirks
ACPI: PCI: always use the PCI INTx pin values, not the _PRT ones
ACPI: PCI: add a helper to convert _PRT INTx pin number to name
ACPI: PCI: move struct acpi_prt_entry declaration out of public header file
ACPI: PCI: fix GSI/IRQ naming confusion
ACPI: PCI: ignore _PRT function information
ACPI: PCI: simplify buffer management for evaluating _PRT
ACPI: PCI: remove unnecessary null pointer checks
ACPI: PCI: use conventional PCI address format
drivers/acpi/pci_bind.c | 12 + drivers/acpi/pci_irq.c | 416 +++++++++++++++-------------------------------- include/linux/acpi.h | 16 -- 3 files changed, 136 insertions(+), 308 deletions(-)
PATCH 1/20 ACPI: PCI: use conventional PCI address format
Use the conventional format for PCI addresses (%04x:%02x:%02x.%d).
--- drivers/acpi/pci_bind.c | 12 ++++++------ drivers/acpi/pci_irq.c | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-)
drivers/acpi/pci_bind.c +6 -6
@@ -101,7 +101,7 @@ acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id)*/ ACPI_DEBUG_PRINT ((ACPI_DB_INFO , -"Device %s has PCI address %02x:%02x:%02x.%02x\n" , +"Device %s has PCI address %04x:%02x:%02x.%d\n" ,acpi_device_bid (device), id->segment, id->bus, id->device, id->function));
@@ -168,7 +168,7 @@ int acpi_pci_bind(struct acpi_device *device) data->id.device = device->pnp.bus_address >>16 ; data->id.function = device->pnp.bus_address &0xFFFF ; -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"...to %02x:%02x:%02x.%02x\n" , +ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"...to %04x:%02x:%02x.%d\n" , data->id.segment, data->id.bus, data->id.device, data->id.function));
@@ -198,7 +198,7 @@ int acpi_pci_bind(struct acpi_device *device) }if (!data->dev) {ACPI_DEBUG_PRINT ((ACPI_DB_INFO , -"Device %02x:%02x:%02x.%02x not present in PCI namespace\n" , +"Device %04x:%02x:%02x.%d not present in PCI namespace\n" , data->id.segment, data->id.bus, data->id.device, data->id.function)); result = -ENODEV ;
@@ -206,7 +206,7 @@ int acpi_pci_bind(struct acpi_device *device) }if (!data->dev->bus) { printk(KERN_ERR PREFIX -"Device %02x:%02x:%02x.%02x has invalid 'bus' field\n" , +"Device %04x:%02x:%02x.%d has invalid 'bus' field\n" , data->id.segment, data->id.bus, data->id.device, data->id.function); result = -ENODEV ;
@@ -221,7 +221,7 @@ int acpi_pci_bind(struct acpi_device *device)*/ if (data->dev->subordinate) {ACPI_DEBUG_PRINT ((ACPI_DB_INFO , -"Device %02x:%02x:%02x.%02x is a PCI bridge\n" , +"Device %04x:%02x:%02x.%d is a PCI bridge\n" , data->id.segment, data->id.bus, data->id.device, data->id.function)); data->bus = data->dev->subordinate;
@@ -355,7 +355,7 @@ acpi_pci_bind_root(struct acpi_device *device,acpi_get_name (device->handle,ACPI_FULL_PATHNAME , &buffer);ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Binding PCI root bridge [%s] to " -"%02x:%02x\n" , pathname, id->segment, id->bus)); +"%04x:%02x\n" , pathname, id->segment, id->bus)); status =acpi_attach_data (device->handle, acpi_pci_data_handler, data);if (ACPI_FAILURE (status)) {
drivers/acpi/pci_irq.c +5 -5
@@ -224,7 +224,7 @@ acpi_pci_irq_add_entry(acpi_handle handle, entry->link.index = prt->source_index;ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO , -" %02X:%02X:%02X[%c] -> %s[%d]\n" , +" %04x:%02x:%02x[%c] -> %s[%d]\n" , entry->id.segment, entry->id.bus, entry->id.device, ('A' + entry->pin), prt->source, entry->link.index));
@@ -330,8 +330,8 @@ void acpi_pci_irq_del_prt(int segment, int bus) }printk (KERN_DEBUG -"ACPI: Delete PCI Interrupt Routing Table for %x:%x\n" , segment, - bus); +"ACPI: Delete PCI Interrupt Routing Table for %04x:%02x\n" , + segment, bus);spin_lock (&acpi_prt_lock);list_for_each_safe (node, n, &acpi_prt.entries) { entry = list_entry(node, struct acpi_prt_entry, node);
@@ -405,12 +405,12 @@ acpi_pci_irq_lookup(struct pci_bus *bus,ACPI_DEBUG_PRINT ((ACPI_DB_INFO , -"Searching for PRT entry for %02x:%02x:%02x[%c]\n" , +"Searching for _PRT entry for %04x:%02x:%02x[%c]\n" , segment, bus_nr, device, ('A' + pin))); entry =acpi_pci_irq_find_prt_entry (segment, bus_nr, device, pin);if (!entry) { -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"PRT entry not found\n" )); +ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"_PRT entry not found\n" ));return -1 ; }
PATCH 2/20 ACPI: PCI: remove unnecessary null pointer checks
In reply to Bjorn HelgaasBetter to oops and learn about a bug than to silently cover it up.
--- drivers/acpi/pci_irq.c | 18 ------------------ 1 files changed, 0 insertions(+), 18 deletions(-)
drivers/acpi/pci_irq.c +0 -18
@@ -180,10 +180,6 @@ acpi_pci_irq_add_entry(acpi_handle handle, {struct acpi_prt_entry *entry =NULL ; - -if (!prt) -return -EINVAL ; - entry =kzalloc (sizeof (struct acpi_prt_entry ),GFP_KERNEL );if (!entry)return -ENOMEM ;
@@ -434,9 +430,6 @@ acpi_pci_irq_derive(struct pci_dev *dev,u8 bridge_pin =0 , orig_pin = pin; -if (!dev) -return -EINVAL ; -/* * 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).
@@ -493,9 +486,6 @@ int acpi_pci_irq_enable(struct pci_dev *dev)int rc; -if (!dev) -return -EINVAL ; - pin = dev->pin;if (!pin) { ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -505,11 +495,6 @@ int acpi_pci_irq_enable(struct pci_dev *dev) } pin--; -if (!dev->bus) { -dev_err (&dev->dev,"invalid (NULL) 'bus' field\n" ); -return -ENODEV ; - } -/* * First we check the PCI IRQ routing table (PRT) for an IRQ. PRT * values override any BIOS-assigned IRQs set during boot.
@@ -588,9 +573,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev)int polarity =ACPI_ACTIVE_LOW ; -if (!dev || !dev->bus) -return ; - pin = dev->pin;if (!pin)return ;
PATCH 3/20 ACPI: PCI: simplify buffer management for evaluating _PRT
In reply to Bjorn HelgaasPreviously, acpi_pci_irq_add_prt() did all its own buffer management. But now that we have ACPI_ALLOCATE_BUFFER, we no longer need to do that management. And we don't have to call acpi_get_irq_routing_table() twice (once to learn the size of the buffer needed, and again to actually get the table).
--- drivers/acpi/pci_irq.c | 52 +++++++++++------------------------------------- 1 files changed, 12 insertions(+), 40 deletions(-)
drivers/acpi/pci_irq.c +12 -40
@@ -245,55 +245,29 @@ acpi_pci_irq_del_entry(int segment, int bus, struct acpi_prt_entry *entry)int acpi_pci_irq_add_prt (acpi_handle handle,int segment,int bus) { -acpi_status status =AE_OK ; -char *pathname =NULL ; -struct acpi_buffer buffer = {0 ,NULL }; -struct acpi_pci_routing_table *prt =NULL ; -struct acpi_pci_routing_table *entry =NULL ; +acpi_status status; +struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER ,NULL }; +struct acpi_pci_routing_table *entry;static int first_time =1 ; - - pathname =kzalloc (ACPI_PATHNAME_MAX ,GFP_KERNEL ); -if (!pathname) -return -ENOMEM ; -if (first_time) { acpi_prt.count =0 ;INIT_LIST_HEAD (&acpi_prt.entries); first_time =0 ; } -/* -* NOTE: We're given a 'handle' to the _PRT object's parent device -* (either a PCI root bridge or PCI-PCI bridge). -*/ - - buffer.length =ACPI_PATHNAME_MAX ; - buffer.pointer = pathname; -acpi_get_name (handle,ACPI_FULL_PATHNAME , &buffer); +/* '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" , - pathname); + (char *) buffer.pointer); -/* -* Evaluate this _PRT and add its entries to our global list (acpi_prt). -*/ +kfree (buffer.pointer); - buffer.length =0 ; + buffer.length =ACPI_ALLOCATE_BUFFER ; buffer.pointer =NULL ; -kfree (pathname); - status =acpi_get_irq_routing_table (handle, &buffer); -if (status !=AE_BUFFER_OVERFLOW ) { -ACPI_EXCEPTION ((AE_INFO , status,"Evaluating _PRT [%s]" , -acpi_format_exception (status))); -return -ENODEV ; - } - - prt =kzalloc (buffer.length,GFP_KERNEL ); -if (!prt) { -return -ENOMEM ; - } - buffer.pointer = prt; status =acpi_get_irq_routing_table (handle, &buffer);if (ACPI_FAILURE (status)) {
@@ -303,16 +277,14 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)return -ENODEV ; } - entry = prt; - + entry = buffer.pointer;while (entry && (entry->length >0 )) {acpi_pci_irq_add_entry (handle, segment, bus, entry); entry = (struct acpi_pci_routing_table *) ((unsigned long )entry + entry->length); } -kfree (prt); - +kfree (buffer.pointer);return 0 ; }
Len Brown
reviewerPATCH 1/1 ACPI: simplify buffer management for acpi_pci_bind() etc.
From: Len Brown <[email protected]>
Date: Tue, 30 Dec 2008 22:44:33 -0500
use ACPI_ALLOCATE_BUFFER to remove the allocations
within acpi_pci_bind(), acpi_pci_unbind() and acpi_pci_bind_root(). While there, delete some unnecessary param inits from those routines.
Delete concept of ACPI_PATHNAME_MAX, since this was the last use.
---
Bjorn,
That patch was such a good idea, I just had to do the same thing over in pci_bind.c:-)
cheers,
-Len
drivers/acpi/pci_bind.c | 80 ++++++++++++++++----------------------- include/acpi/platform/aclinux.h | 3 - 2 files changed, 33 insertions(+), 50 deletions(-)
drivers/acpi/pci_bind.c +33 -47
@@ -111,12 +111,11 @@ EXPORT_SYMBOL(acpi_get_pci_id);int acpi_pci_bind (struct acpi_device *device) {int result =0 ; -acpi_status status =AE_OK ; -struct acpi_pci_data *data =NULL ; -struct acpi_pci_data *pdata =NULL ; -char *pathname =NULL ; -struct acpi_buffer buffer = {0 ,NULL }; -acpi_handle handle =NULL ; +acpi_status status; +struct acpi_pci_data *data; +struct acpi_pci_data *pdata; +struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER ,NULL }; +acpi_handle handle;struct pci_dev *dev;struct pci_bus *bus;
@@ -124,21 +123,18 @@ int acpi_pci_bind(struct acpi_device *device)if (!device || !device->parent)return -EINVAL ; - pathname =kzalloc (ACPI_PATHNAME_MAX ,GFP_KERNEL ); -if (!pathname) -return -ENOMEM ; - buffer.length =ACPI_PATHNAME_MAX ; - buffer.pointer = pathname; - data =kzalloc (sizeof (struct acpi_pci_data ),GFP_KERNEL ); -if (!data) { -kfree (pathname); +if (!data)return -ENOMEM ; + + status =acpi_get_name (device->handle,ACPI_FULL_PATHNAME , &buffer); +if (ACPI_FAILURE (status)) { +kfree (data); +return -ENODEV ; } -acpi_get_name (device->handle,ACPI_FULL_PATHNAME , &buffer);ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Binding PCI device [%s]...\n" , - pathname)); + (char *)buffer.pointer));/* * Segment & Bus
@@ -262,7 +258,7 @@ int acpi_pci_bind(struct acpi_device *device) } end: -kfree (pathname); +kfree (buffer.pointer);if (result)kfree (data);
@@ -272,25 +268,21 @@ int acpi_pci_bind(struct acpi_device *device)static int acpi_pci_unbind (struct acpi_device *device) {int result =0 ; -acpi_status status =AE_OK ; -struct acpi_pci_data *data =NULL ; -char *pathname =NULL ; -struct acpi_buffer buffer = {0 ,NULL }; +acpi_status status; +struct acpi_pci_data *data; +struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER ,NULL };if (!device || !device->parent)return -EINVAL ; - pathname =kzalloc (ACPI_PATHNAME_MAX ,GFP_KERNEL ); -if (!pathname) -return -ENOMEM ; + status =acpi_get_name (device->handle,ACPI_FULL_PATHNAME , &buffer); +if (ACPI_FAILURE (status)) +return -ENODEV ; - buffer.length =ACPI_PATHNAME_MAX ; - buffer.pointer = pathname; -acpi_get_name (device->handle,ACPI_FULL_PATHNAME , &buffer);ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Unbinding PCI device [%s]...\n" , - pathname)); -kfree (pathname); + (char *) buffer.pointer)); +kfree (buffer.pointer); status = acpi_get_data(device->handle, acpi_pci_data_handler,
@@ -322,50 +314,44 @@ acpi_pci_bind_root(struct acpi_device *device, struct acpi_pci_id *id, struct pci_bus *bus) { int result = 0; -acpi_status status =AE_OK ; +acpi_status status;struct acpi_pci_data *data =NULL ; -char *pathname =NULL ; -struct acpi_buffer buffer = {0 ,NULL }; - - pathname =kzalloc (ACPI_PATHNAME_MAX ,GFP_KERNEL ); -if (!pathname) -return -ENOMEM ; - - buffer.length =ACPI_PATHNAME_MAX ; - buffer.pointer = pathname; +struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER ,NULL };if (!device || !id || !bus) { -kfree (pathname);return -EINVAL ; } data =kzalloc (sizeof (struct acpi_pci_data ),GFP_KERNEL ); -if (!data) { -kfree (pathname); +if (!data)return -ENOMEM ; - } data->id = *id; data->bus = bus; device->ops.bind = acpi_pci_bind; device->ops.unbind = acpi_pci_unbind; -acpi_get_name (device->handle,ACPI_FULL_PATHNAME , &buffer); + status =acpi_get_name (device->handle,ACPI_FULL_PATHNAME , &buffer); +if (ACPI_FAILURE (status)) { +kfree (data); +return -ENODEV ; + }ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Binding PCI root bridge [%s] to " -"%04x:%02x\n" , pathname, id->segment, id->bus)); +"%04x:%02x\n" , (char *)buffer.pointer, + id->segment, id->bus)); status =acpi_attach_data (device->handle, acpi_pci_data_handler, data);if (ACPI_FAILURE (status)) {ACPI_EXCEPTION ((AE_INFO , status,"Unable to attach ACPI-PCI context to device %s" , - pathname)); + (char *)buffer.pointer)); result = -ENODEV ; goto end; } end: -kfree (pathname); +kfree (buffer.pointer);if (result !=0 )kfree (data);
include/acpi/platform/aclinux.h +0 -3
@@ -70,9 +70,6 @@#define ACPI_EXPORT_SYMBOL (symbol) EXPORT_SYMBOL(symbol);#define strtoul simple_strtoul -/* Full namespace pathname length limit - arbitrary */ -#define ACPI_PATHNAME_MAX 256 -#else /* !__KERNEL__ */ #include <stdarg.h>
Signature · 1 line
1.6.1.28.gc32f76
PATCH 4/20 ACPI: PCI: ignore _PRT function information
In reply to Bjorn Helgaas_PRT entries don't contain any useful PCI function information (the function part of the PCI address is supposed to be 0xffff), and we don't ever look at it, so this patch just removes the reference to it.
--- drivers/acpi/pci_irq.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-)
drivers/acpi/pci_irq.c +0 -1
@@ -187,7 +187,6 @@ acpi_pci_irq_add_entry(acpi_handle handle, entry->id.segment = segment; entry->id.bus = bus; entry->id.device = (prt->address >>16 ) &0xFFFF ; - entry->id.function = prt->address &0xFFFF ; entry->pin = prt->pin;do_prt_fixups (entry, prt);
PATCH 5/20 ACPI: PCI: fix GSI/IRQ naming confusion
In reply to Bjorn HelgaasThe interrupt numbers from _PRT entries are GSIs, not Linux IRQs.
--- drivers/acpi/pci_irq.c | 20 ++++++++++---------- 1 files changed, 10 insertions(+), 10 deletions(-)
drivers/acpi/pci_irq.c +10 -10
@@ -335,7 +335,7 @@ acpi_pci_allocate_irq(struct acpi_prt_entry *entry, *polarity =ACPI_ACTIVE_LOW ; } -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Found IRQ %d\n" , irq)); +ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Found GSI %d\n" , irq));return irq; }
@@ -434,7 +434,7 @@ acpi_pci_irq_derive(struct pci_dev *dev,return -1 ; } -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Derive IRQ %d for device %s from %s\n" , +ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Derive GSI %d for device %s from %s\n" , irq,pci_name (dev),pci_name (bridge)));return irq;
@@ -448,7 +448,7 @@ acpi_pci_irq_derive(struct pci_dev *dev,int acpi_pci_irq_enable (struct pci_dev *dev) { -int irq =0 ; +int gsi =0 ;u8 pin =0 ;int triggering =ACPI_LEVEL_SENSITIVE ;int polarity =ACPI_ACTIVE_LOW ;
@@ -470,7 +470,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)* First we check the PCI IRQ routing table (PRT) for an IRQ. PRT * values override any BIOS-assigned IRQs set during boot. */ - irq =acpi_pci_irq_lookup (dev->bus,PCI_SLOT (dev->devfn), pin, + gsi =acpi_pci_irq_lookup (dev->bus,PCI_SLOT (dev->devfn), pin, &triggering, &polarity, &link, acpi_pci_allocate_irq);
@@ -478,12 +478,12 @@ int acpi_pci_irq_enable(struct pci_dev *dev)* If no PRT entry was found, we'll try to derive an IRQ from the * device's parent bridge. */ -if (irq <0 ) - irq =acpi_pci_irq_derive (dev, pin, &triggering, +if (gsi <0 ) + gsi =acpi_pci_irq_derive (dev, pin, &triggering, &polarity, &link, acpi_pci_allocate_irq); -if (irq <0 ) { +if (gsi <0 ) {/* * IDE legacy mode controller IRQs are magic. Why do compat * extensions always make such a nasty mess.
@@ -496,7 +496,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)* No IRQ known to the ACPI subsystem - maybe the BIOS / * driver reported one, then use it. Exit in any case. */ -if (irq <0 ) { +if (gsi <0 ) {dev_warn (&dev->dev,"PCI INT %c: no GSI" ,'A' + pin);/* Interrupt Line values above 0xF are forbidden */ if (dev->irq >0 && (dev->irq <=0xF )) {
@@ -510,7 +510,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) } } - rc =acpi_register_gsi (irq, triggering, polarity); + rc =acpi_register_gsi (gsi, triggering, polarity);if (rc <0 ) {dev_warn (&dev->dev,"PCI INT %c: failed to register GSI\n" ,'A' + pin);
@@ -524,7 +524,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) link_desc[0 ] ='\0' ;dev_info (&dev->dev,"PCI INT %c%s -> GSI %u (%s, %s) -> IRQ %d\n" , -'A' + pin, link_desc, irq, +'A' + pin, link_desc, gsi, (triggering ==ACPI_LEVEL_SENSITIVE ) ?"level" :"edge" , (polarity ==ACPI_ACTIVE_LOW ) ?"low" :"high" , dev->irq);
PATCH 6/20 ACPI: PCI: move struct acpi_prt_entry declaration out of public header file
In reply to Bjorn HelgaasThe struct acpi_prt_entry is used only in pci_irq.c, so there's no need for the declaration to be public. This patch moves it into pci_irq.c.
--- drivers/acpi/pci_irq.c | 16 ++++++++++++++++ include/linux/acpi.h | 16 ---------------- 2 files changed, 16 insertions(+), 16 deletions(-)
drivers/acpi/pci_irq.c +16 -0
@@ -43,6 +43,22 @@#define _COMPONENT ACPI_PCI_COMPONENTACPI_MODULE_NAME ("pci_irq" ); +struct acpi_prt_entry { +struct list_head node; +struct acpi_pci_id id; +u8 pin; +struct { +acpi_handle handle; +u32 index; + } link; +u32 irq; +}; + +struct acpi_prt_list { +int count; +struct list_head entries; +}; +static struct acpi_prt_list acpi_prt;static DEFINE_SPINLOCK (acpi_prt_lock);
include/linux/acpi.h +0 -16
@@ -131,22 +131,6 @@ extern int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity);*/ void acpi_unregister_gsi (u32 gsi); -struct acpi_prt_entry { -struct list_head node; -struct acpi_pci_id id; -u8 pin; -struct { -acpi_handle handle; -u32 index; - } link; -u32 irq; -}; - -struct acpi_prt_list { -int count; -struct list_head entries; -}; -struct pci_dev ;int acpi_pci_irq_enable (struct pci_dev *dev);
PATCH 7/20 ACPI: PCI: add a helper to convert _PRT INTx pin number to name
In reply to Bjorn HelgaasThis adds a helper function to convert INTx pin numbers from the _PRT (0, 1, 2, 3) to the pin name ('A', 'B', 'C', 'D').
--- drivers/acpi/pci_irq.c | 25 +++++++++++++++---------- 1 files changed, 15 insertions(+), 10 deletions(-)
drivers/acpi/pci_irq.c +15 -10
@@ -62,6 +62,11 @@ struct acpi_prt_list {static struct acpi_prt_list acpi_prt;static DEFINE_SPINLOCK (acpi_prt_lock); +static inline char pin_name (int pin) +{ +return 'A' + pin; +} +/* -------------------------------------------------------------------------- PCI IRQ Routing Table (PRT) Support -------------------------------------------------------------------------- */
@@ -176,14 +181,14 @@ do_prt_fixups(struct acpi_prt_entry *entry, struct acpi_pci_routing_table *prt) entry->id.segment == quirk->segment && entry->id.bus == quirk->bus && entry->id.device == quirk->device && - entry->pin + 'A' == quirk->pin && + pin_name(entry->pin) == quirk->pin && !strcmp(prt->source, quirk->source) && strlen(prt->source) >= strlen(quirk->actual_source)) { printk(KERN_WARNING PREFIX "firmware reports ""%04x:%02x:%02x PCI INT %c connected to %s; " "changing to %s\n" , entry->id.segment, entry->id.bus, - entry->id.device,'A' + entry->pin, + entry->id.device,pin_name (entry->pin), prt->source, quirk->actual_source);strcpy (prt->source, quirk->actual_source); }
@@ -237,8 +242,8 @@ acpi_pci_irq_add_entry(acpi_handle handle,ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO ," %04x:%02x:%02x[%c] -> %s[%d]\n" , entry->id.segment, entry->id.bus, - entry->id.device, ('A' + entry->pin), prt->source, - entry->link.index)); + entry->id.device,pin_name (entry->pin), + prt->source, entry->link.index));spin_lock (&acpi_prt_lock);list_add_tail (&entry->node, &acpi_prt.entries);
@@ -389,7 +394,7 @@ acpi_pci_irq_lookup(struct pci_bus *bus,ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Searching for _PRT entry for %04x:%02x:%02x[%c]\n" , - segment, bus_nr, device, ('A' + pin))); + segment, bus_nr, device,pin_name (pin))); entry =acpi_pci_irq_find_prt_entry (segment, bus_nr, device, pin);if (!entry) {
@@ -446,7 +451,7 @@ acpi_pci_irq_derive(struct pci_dev *dev,if (irq <0 ) {dev_warn (&dev->dev,"can't derive routing for PCI INT %c\n" , -'A' + orig_pin); +pin_name (orig_pin));return -1 ; }
@@ -513,7 +518,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)* driver reported one, then use it. Exit in any case. */ if (gsi <0 ) { -dev_warn (&dev->dev,"PCI INT %c: no GSI" ,'A' + pin); +dev_warn (&dev->dev,"PCI INT %c: no GSI" ,pin_name (pin));/* Interrupt Line values above 0xF are forbidden */ if (dev->irq >0 && (dev->irq <=0xF )) {printk (" - using IRQ %d\n" , dev->irq);
@@ -529,7 +534,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) rc =acpi_register_gsi (gsi, triggering, polarity);if (rc <0 ) {dev_warn (&dev->dev,"PCI INT %c: failed to register GSI\n" , -'A' + pin); +pin_name (pin));return rc; } dev->irq = rc;
@@ -540,7 +545,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) link_desc[0 ] ='\0' ;dev_info (&dev->dev,"PCI INT %c%s -> GSI %u (%s, %s) -> IRQ %d\n" , -'A' + pin, link_desc, gsi, +pin_name (pin), link_desc, gsi, (triggering ==ACPI_LEVEL_SENSITIVE ) ?"level" :"edge" , (polarity ==ACPI_ACTIVE_LOW ) ?"low" :"high" , dev->irq);
@@ -587,6 +592,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev)* (e.g. PCI_UNDEFINED_IRQ). */ -dev_info (&dev->dev,"PCI INT %c disabled\n" ,'A' + pin); +dev_info (&dev->dev,"PCI INT %c disabled\n" ,pin_name (pin));acpi_unregister_gsi (gsi); }
PATCH 8/20 ACPI: PCI: always use the PCI INTx pin values, not the _PRT ones
In reply to Bjorn HelgaasThis patch changes pci_irq.c to always use PCI INTx pin encodings instead of a mix of PCI and _PRT encodings.
The PCI INTx pin numbers from the PCI_INTERRUPT_PIN config register are 0=device doesn't use interrupts, 1=INTA, ..., 4=INTD. But the _PRT table uses 0=INTA, ..., 3=INTD.
This patch converts the _PRT encoding to the PCI encoding immediately when we add a _PRT entry to the global list. All the rest of the code can then use the PCI encoding consistently.
The point of this is to make the interrupt swizzling look the same as on other architectures, so someday we can unify them.
--- drivers/acpi/pci_irq.c | 15 ++++++++------- 1 files changed, 8 insertions(+), 7 deletions(-)
drivers/acpi/pci_irq.c +8 -7
@@ -64,7 +64,7 @@ static DEFINE_SPINLOCK(acpi_prt_lock);static inline char pin_name (int pin) { -return 'A' + pin; +return 'A' + pin -1 ; }/* --------------------------------------------------------------------------
@@ -205,10 +205,15 @@ acpi_pci_irq_add_entry(acpi_handle handle,if (!entry)return -ENOMEM ; +/* +* Note that the _PRT uses 0=INTA, 1=INTB, etc, while PCI uses +* 1=INTA, 2=INTB. We use the PCI encoding throughout, so convert +* it here. +*/ entry->id.segment = segment; entry->id.bus = bus; entry->id.device = (prt->address >>16 ) &0xFFFF ; - entry->pin = prt->pin; + entry->pin = prt->pin +1 ;do_prt_fixups (entry, prt);
@@ -427,7 +432,7 @@ acpi_pci_irq_derive(struct pci_dev *dev,* PCI interrupt routing entry (eg. yenta bridge and add-in card bridge). */ while (irq <0 && bridge->bus->self) { - pin = (pin +PCI_SLOT (bridge->devfn)) %4 ; + pin = (((pin -1 ) +PCI_SLOT (bridge->devfn)) %4 ) +1 ; bridge = bridge->bus->self;if ((bridge->class >>8 ) ==PCI_CLASS_BRIDGE_CARDBUS ) {
@@ -439,8 +444,6 @@ acpi_pci_irq_derive(struct pci_dev *dev, pci_name(bridge)));return -1 ; } -/* Pin is from 0 to 3 */ - bridge_pin--; pin = bridge_pin; }
@@ -485,7 +488,6 @@ int acpi_pci_irq_enable(struct pci_dev *dev) pci_name(dev)));return 0 ; } - pin--;/* * First we check the PCI IRQ routing table (PRT) for an IRQ. PRT
@@ -568,7 +570,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev) pin = dev->pin;if (!pin)return ; - pin--;/* * First we check the PCI IRQ routing table (PRT) for an IRQ.
PATCH 9/20 ACPI: PCI: use 1-based encoding for _PRT quirks
In reply to Bjorn HelgaasUse the PCI INTx pin encoding (1=INTA, 2=INTB, etc) for _PRT quirks. Then we can simply compare "entry->pin == quirk->pin".
--- drivers/acpi/pci_irq.c | 10 ++++++---- 1 files changed, 6 insertions(+), 4 deletions(-)
drivers/acpi/pci_irq.c +6 -4
@@ -147,19 +147,21 @@ struct prt_quirk {char *actual_source; }; +#define PCI_INTX_PIN (c) (c - 'A' + 1) +/* * These systems have incorrect _PRT entries. The BIOS claims the PCI * interrupt at the listed segment/bus/device/pin is connected to the first * link device, but it is actually connected to the second. */ static struct prt_quirk prt_quirks[] = { - { medion_md9580,0 ,0 ,9 ,'A' , + { medion_md9580,0 ,0 ,9 ,PCI_INTX_PIN ('A' ),"\\_SB_.PCI0.ISA_.LNKA" ,"\\_SB_.PCI0.ISA_.LNKB" }, - { dell_optiplex,0 ,0 ,0xd ,'A' , + { dell_optiplex,0 ,0 ,0xd ,PCI_INTX_PIN ('A' ),"\\_SB_.LNKB" ,"\\_SB_.LNKA" }, - { hp_t5710,0 ,0 ,1 ,'A' , + { hp_t5710,0 ,0 ,1 ,PCI_INTX_PIN ('A' ),"\\_SB_.PCI0.LNK1" ,"\\_SB_.PCI0.LNK3" }, };
@@ -181,7 +183,7 @@ do_prt_fixups(struct acpi_prt_entry *entry, struct acpi_pci_routing_table *prt) entry->id.segment == quirk->segment && entry->id.bus == quirk->bus && entry->id.device == quirk->device && - pin_name(entry->pin) == quirk->pin && + entry->pin == quirk->pin && !strcmp(prt->source, quirk->source) && strlen(prt->source) >= strlen(quirk->actual_source)) { printk(KERN_WARNING PREFIX "firmware reports "
PATCH 10/20 ACPI: PCI: lookup _PRT entry by PCI dev and pin, not segment/bus/dev/pin
In reply to Bjorn HelgaasThere's no reason to pass around segment, bus, and device independently when we can just pass the pci_dev pointer, which carries all those already.
The pci_dev contains an interrupt pin, too, but we still have to pass both the pci_dev and the pin because when we use a bridge to derive an IRQ, we need the pin from the downstream device, not the bridge.
--- drivers/acpi/pci_irq.c | 27 ++++++++++++--------------- 1 files changed, 12 insertions(+), 15 deletions(-)
drivers/acpi/pci_irq.c +12 -15
@@ -71,11 +71,13 @@ static inline char pin_name(int pin)PCI IRQ Routing Table (PRT) Support -------------------------------------------------------------------------- */ -static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry (int segment, -int bus, -int device,int pin) +static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry (struct pci_dev *dev, +int pin) {struct acpi_prt_entry *entry =NULL ; +int segment =pci_domain_nr (dev->bus); +int bus = dev->bus->number; +int device =PCI_SLOT (dev->devfn);if (!acpi_prt.count)return NULL ;
@@ -387,23 +389,18 @@ acpi_pci_free_irq(struct acpi_prt_entry *entry,* failure: return -1 */ static int -acpi_pci_irq_lookup (struct pci_bus *bus, -int device, -int pin, +acpi_pci_irq_lookup (struct pci_dev *dev,int pin,int *triggering,int *polarity,char **link,irq_lookup_func func) {struct acpi_prt_entry *entry =NULL ; -int segment =pci_domain_nr (bus); -int bus_nr = bus->number;int ret; -ACPI_DEBUG_PRINT ((ACPI_DB_INFO , -"Searching for _PRT entry for %04x:%02x:%02x[%c]\n" , - segment, bus_nr, device,pin_name (pin))); +ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Searching for _PRT entry for %s[%c]\n" , +pci_name (dev),pin_name (pin))); - entry =acpi_pci_irq_find_prt_entry (segment, bus_nr, device, pin); + entry =acpi_pci_irq_find_prt_entry (dev, pin);if (!entry) {ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"_PRT entry not found\n" ));return -1 ;
@@ -449,7 +446,7 @@ acpi_pci_irq_derive(struct pci_dev *dev, pin = bridge_pin; } - irq =acpi_pci_irq_lookup (bridge->bus,PCI_SLOT (bridge->devfn), + irq =acpi_pci_irq_lookup (bridge, pin, triggering, polarity, link, func); }
@@ -495,7 +492,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)* First we check the PCI IRQ routing table (PRT) for an IRQ. PRT * values override any BIOS-assigned IRQs set during boot. */ - gsi =acpi_pci_irq_lookup (dev->bus,PCI_SLOT (dev->devfn), pin, + gsi =acpi_pci_irq_lookup (dev, pin, &triggering, &polarity, &link, acpi_pci_allocate_irq);
@@ -576,7 +573,7 @@ void acpi_pci_irq_disable(struct pci_dev *dev)/* * First we check the PCI IRQ routing table (PRT) for an IRQ. */ - gsi =acpi_pci_irq_lookup (dev->bus,PCI_SLOT (dev->devfn), pin, + gsi =acpi_pci_irq_lookup (dev, pin, &triggering, &polarity,NULL , acpi_pci_free_irq);/*
PATCH 11/20 ACPI: PCI: tweak _PRT lookup debug
In reply to Bjorn HelgaasPrint one message (either "found" or "not found") for every _PRT search. And add pin information to the INTx swizzling debug.
--- drivers/acpi/pci_irq.c | 13 +++++++------ 1 files changed, 7 insertions(+), 6 deletions(-)
drivers/acpi/pci_irq.c +7 -6
@@ -397,15 +397,16 @@ acpi_pci_irq_lookup(struct pci_dev *dev, int pin,int ret; -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Searching for _PRT entry for %s[%c]\n" , -pci_name (dev),pin_name (pin))); - entry =acpi_pci_irq_find_prt_entry (dev, pin);if (!entry) { -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"_PRT entry not found\n" )); +ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"No %s[%c] _PRT entry\n" , +pci_name (dev),pin_name (pin)));return -1 ; } +ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Found %s[%c] _PRT entry\n" , +pci_name (dev),pin_name (pin))); + ret =func (entry, triggering, polarity, link);return ret; }
@@ -457,8 +458,8 @@ acpi_pci_irq_derive(struct pci_dev *dev,return -1 ; } -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Derive GSI %d for device %s from %s\n" , - irq,pci_name (dev),pci_name (bridge))); +ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Derived GSI %d for %s INT %c from %s\n" , + irq,pci_name (dev),pin_name (orig_pin),pci_name (bridge)));return irq; }
PATCH 12/20 ACPI: PCI: remove callback from acpi_pci_irq_lookup & acpi_pci_irq_derive
In reply to Bjorn HelgaasWe currently pass a callback function (either acpi_pci_allocate_irq() or acpi_pci_free_irq()) to acpi_pci_irq_lookup() and acpi_pci_irq_derive().
I think it's simpler to remove the callback and just have the enable/ disable functions make the calls directly.
--- drivers/acpi/pci_irq.c | 93 +++++++++++++++++++----------------------------- 1 files changed, 36 insertions(+), 57 deletions(-)
drivers/acpi/pci_irq.c +36 -57
@@ -341,8 +341,6 @@ void acpi_pci_irq_del_prt(int segment, int bus)/* -------------------------------------------------------------------------- PCI Interrupt Routing Support -------------------------------------------------------------------------- */ -typedef int (*irq_lookup_func ) (struct acpi_prt_entry *,int *,int *,char **); -static int acpi_pci_allocate_irq (struct acpi_prt_entry *entry,int *triggering,int *polarity,char **link)
@@ -370,8 +368,7 @@ acpi_pci_allocate_irq(struct acpi_prt_entry *entry, }static int -acpi_pci_free_irq (struct acpi_prt_entry *entry, -int *triggering,int *polarity,char **link) +acpi_pci_free_irq (struct acpi_prt_entry *entry) {int irq;
@@ -383,47 +380,29 @@ acpi_pci_free_irq(struct acpi_prt_entry *entry,return irq; } -/* -* acpi_pci_irq_lookup -* success: return IRQ >= 0 -* failure: return -1 -*/ -static int -acpi_pci_irq_lookup (struct pci_dev *dev,int pin, -int *triggering, -int *polarity,char **link,irq_lookup_func func) +static struct acpi_prt_entry * +acpi_pci_irq_lookup (struct pci_dev *dev,int pin) { -struct acpi_prt_entry *entry =NULL ; -int ret; - +struct acpi_prt_entry *entry; entry =acpi_pci_irq_find_prt_entry (dev, pin);if (!entry) {ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"No %s[%c] _PRT entry\n" ,pci_name (dev),pin_name (pin))); -return -1 ; +return NULL ; }ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Found %s[%c] _PRT entry\n" ,pci_name (dev),pin_name (pin))); - ret =func (entry, triggering, polarity, link); -return ret; +return entry; } -/* -* acpi_pci_irq_derive -* success: return IRQ >= 0 -* failure: return < 0 -*/ -static int -acpi_pci_irq_derive (struct pci_dev *dev, -int pin, -int *triggering, -int *polarity,char **link,irq_lookup_func func) +static struct acpi_prt_entry * +acpi_pci_irq_derive (struct pci_dev *dev,int pin) { +struct acpi_prt_entry *entry =NULL ;struct pci_dev *bridge = dev; -int irq =-1 ;u8 bridge_pin =0 , orig_pin = pin;
@@ -431,7 +410,7 @@ acpi_pci_irq_derive(struct pci_dev *dev,* 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). */ -while (irq <0 && bridge->bus->self) { +while (!entry && bridge->bus->self) { pin = (((pin -1 ) +PCI_SLOT (bridge->devfn)) %4 ) +1 ; bridge = bridge->bus->self;
@@ -442,26 +421,24 @@ acpi_pci_irq_derive(struct pci_dev *dev,ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"No interrupt pin configured for device %s\n" ,pci_name (bridge))); -return -1 ; +return NULL ; } pin = bridge_pin; } - irq =acpi_pci_irq_lookup (bridge, - pin, triggering, polarity, - link, func); + entry =acpi_pci_irq_lookup (bridge, pin); } -if (irq <0 ) { +if (!entry) {dev_warn (&dev->dev,"can't derive routing for PCI INT %c\n" ,pin_name (orig_pin)); -return -1 ; +return NULL ; } -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Derived GSI %d for %s INT %c from %s\n" , - irq,pci_name (dev),pin_name (orig_pin),pci_name (bridge))); +ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Derived GSI for %s INT %c from %s\n" , +pci_name (dev),pin_name (orig_pin),pci_name (bridge))); -return irq; +return entry; }/*
@@ -472,6 +449,7 @@ acpi_pci_irq_derive(struct pci_dev *dev,int acpi_pci_irq_enable (struct pci_dev *dev) { +struct acpi_prt_entry *entry;int gsi =0 ;u8 pin =0 ;int triggering =ACPI_LEVEL_SENSITIVE ;
@@ -493,18 +471,20 @@ int acpi_pci_irq_enable(struct pci_dev *dev)* First we check the PCI IRQ routing table (PRT) for an IRQ. PRT * values override any BIOS-assigned IRQs set during boot. */ - gsi =acpi_pci_irq_lookup (dev, pin, - &triggering, &polarity, &link, - acpi_pci_allocate_irq); + entry =acpi_pci_irq_lookup (dev, pin);/* * If no PRT entry was found, we'll try to derive an IRQ from the * device's parent bridge. */ -if (gsi <0 ) - gsi =acpi_pci_irq_derive (dev, pin, &triggering, - &polarity, &link, - acpi_pci_allocate_irq); +if (!entry) + entry =acpi_pci_irq_derive (dev, pin); + +if (entry) + gsi =acpi_pci_allocate_irq (entry, &triggering, &polarity, + &link); +else + gsi =-1 ;if (gsi <0 ) {/*
@@ -561,10 +541,9 @@ void __attribute__ ((weak)) acpi_unregister_gsi(u32 i)void acpi_pci_irq_disable (struct pci_dev *dev) { +struct acpi_prt_entry *entry;int gsi =0 ;u8 pin =0 ; -int triggering =ACPI_LEVEL_SENSITIVE ; -int polarity =ACPI_ACTIVE_LOW ; pin = dev->pin;
@@ -574,20 +553,20 @@ void acpi_pci_irq_disable(struct pci_dev *dev)/* * First we check the PCI IRQ routing table (PRT) for an IRQ. */ - gsi =acpi_pci_irq_lookup (dev, pin, - &triggering, &polarity,NULL , - acpi_pci_free_irq); + entry =acpi_pci_irq_lookup (dev, pin); +/* * If no PRT entry was found, we'll try to derive an IRQ from the * device's parent bridge. */ -if (gsi <0 ) - gsi =acpi_pci_irq_derive (dev, pin, - &triggering, &polarity,NULL , - acpi_pci_free_irq); -if (gsi <0 ) +if (!entry) + entry =acpi_pci_irq_derive (dev, pin); + +if (!entry)return ; + gsi =acpi_pci_free_irq (entry); +/* * TBD: It might be worth clearing dev->irq by magic constant * (e.g. PCI_UNDEFINED_IRQ).
PATCH 13/20 ACPI: PCI: use positive logic to simplify code
In reply to Bjorn HelgaasThis doesn't change anything functionally; it just changes tests so we test for success instead of failure. This makes the code read more easily and allows us to remove the "!entry" in the while loop condition.
--- drivers/acpi/pci_irq.c | 33 ++++++++++++++++----------------- 1 files changed, 16 insertions(+), 17 deletions(-)
drivers/acpi/pci_irq.c +16 -17
@@ -386,16 +386,15 @@ acpi_pci_irq_lookup(struct pci_dev *dev, int pin)struct acpi_prt_entry *entry; entry =acpi_pci_irq_find_prt_entry (dev, pin); -if (!entry) { -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"No %s[%c] _PRT entry\n" , +if (entry) { +ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Found %s[%c] _PRT entry\n" ,pci_name (dev),pin_name (pin))); -return NULL ; +return entry; } -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Found %s[%c] _PRT entry\n" , +ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"No %s[%c] _PRT entry\n" ,pci_name (dev),pin_name (pin))); - -return entry; +return NULL ; } static struct acpi_prt_entry *
@@ -410,7 +409,7 @@ acpi_pci_irq_derive(struct pci_dev *dev, int pin)* 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). */ -while (!entry && bridge->bus->self) { +while (bridge->bus->self) { pin = (((pin -1 ) +PCI_SLOT (bridge->devfn)) %4 ) +1 ; bridge = bridge->bus->self;
@@ -427,18 +426,18 @@ acpi_pci_irq_derive(struct pci_dev *dev, int pin) } entry =acpi_pci_irq_lookup (bridge, pin); +if (entry) { +ACPI_DEBUG_PRINT ((ACPI_DB_INFO , +"Derived GSI for %s INT %c from %s\n" , +pci_name (dev),pin_name (orig_pin), +pci_name (bridge))); +return entry; + } } -if (!entry) { -dev_warn (&dev->dev,"can't derive routing for PCI INT %c\n" , -pin_name (orig_pin)); -return NULL ; - } - -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Derived GSI for %s INT %c from %s\n" , -pci_name (dev),pin_name (orig_pin),pci_name (bridge))); - -return entry; +dev_warn (&dev->dev,"can't derive routing for PCI INT %c\n" , +pin_name (orig_pin)); +return NULL ; }/*
PATCH 14/20 ACPI: PCI: follow typical PCI INTx swizzling pattern
In reply to Bjorn HelgaasNo functional change; this just uses the typical pattern of PCI INTx swizzling done on other architectures.
--- drivers/acpi/pci_irq.c | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-)
drivers/acpi/pci_irq.c +7 -4
@@ -401,7 +401,7 @@ static struct acpi_prt_entry * acpi_pci_irq_derive(struct pci_dev *dev, int pin) {struct acpi_prt_entry *entry =NULL ; -struct pci_dev *bridge = dev; +struct pci_dev *bridge;u8 bridge_pin =0 , orig_pin = pin;
@@ -409,9 +409,9 @@ acpi_pci_irq_derive(struct pci_dev *dev, int pin)* 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). */ -while (bridge->bus->self) { - pin = (((pin -1 ) +PCI_SLOT (bridge->devfn)) %4 ) +1 ; - bridge = bridge->bus->self; + bridge = dev->bus->self; +while (bridge) { + pin = (((pin -1 ) +PCI_SLOT (dev->devfn)) %4 ) +1 ;if ((bridge->class >>8 ) ==PCI_CLASS_BRIDGE_CARDBUS ) {/* PC card has the same IRQ as its cardbridge */
@@ -433,6 +433,9 @@ acpi_pci_irq_derive(struct pci_dev *dev, int pin) pci_name(bridge)));return entry; } + + dev = bridge; + bridge = dev->bus->self; } dev_warn(&dev->dev, "can't derive routing for PCI INT %c\n",
PATCH 15/20 ACPI: PCI: combine lookup and derive
In reply to Bjorn HelgaasThis folds acpi_pci_irq_derive() into acpi_pci_irq_lookup() so it can be easily used by both acpi_pci_irq_enable() and acpi_pci_irq_disable().
--- drivers/acpi/pci_irq.c | 55 ++++++++++-------------------------------------- 1 files changed, 11 insertions(+), 44 deletions(-)
drivers/acpi/pci_irq.c +11 -44
@@ -384,6 +384,8 @@ static struct acpi_prt_entry * acpi_pci_irq_lookup(struct pci_dev *dev, int pin) {struct acpi_prt_entry *entry; +struct pci_dev *bridge; +u8 bridge_pin, orig_pin = pin; entry =acpi_pci_irq_find_prt_entry (dev, pin);if (entry) {
@@ -392,19 +394,6 @@ acpi_pci_irq_lookup(struct pci_dev *dev, int pin)return entry; } -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"No %s[%c] _PRT entry\n" , -pci_name (dev),pin_name (pin))); -return NULL ; -} - -static struct acpi_prt_entry * -acpi_pci_irq_derive (struct pci_dev *dev,int pin) -{ -struct acpi_prt_entry *entry =NULL ; -struct pci_dev *bridge; -u8 bridge_pin =0 , orig_pin = pin; - -/* * 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).
@@ -425,7 +414,7 @@ acpi_pci_irq_derive(struct pci_dev *dev, int pin) pin = bridge_pin; } - entry =acpi_pci_irq_lookup (bridge, pin); + entry =acpi_pci_irq_find_prt_entry (bridge, pin);if (entry) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Derived GSI for %s INT %c from %s\n",
@@ -469,26 +458,8 @@ int acpi_pci_irq_enable(struct pci_dev *dev)return 0 ; } -/* -* First we check the PCI IRQ routing table (PRT) for an IRQ. PRT -* values override any BIOS-assigned IRQs set during boot. -*/ entry =acpi_pci_irq_lookup (dev, pin); - -/* -* If no PRT entry was found, we'll try to derive an IRQ from the -* device's parent bridge. -*/ -if (!entry) - entry =acpi_pci_irq_derive (dev, pin); - -if (entry) - gsi =acpi_pci_allocate_irq (entry, &triggering, &polarity, - &link); -else - gsi =-1 ; - -if (gsi <0 ) { +if (!entry) {/* * IDE legacy mode controller IRQs are magic. Why do compat * extensions always make such a nasty mess.
@@ -497,6 +468,13 @@ int acpi_pci_irq_enable(struct pci_dev *dev) (dev->class & 0x05) == 0)return 0 ; } + +if (entry) + gsi =acpi_pci_allocate_irq (entry, &triggering, &polarity, + &link); +else + gsi =-1 ; +/* * No IRQ known to the ACPI subsystem - maybe the BIOS / * driver reported one, then use it. Exit in any case.
@@ -552,18 +530,7 @@ void acpi_pci_irq_disable(struct pci_dev *dev)if (!pin)return ; -/* -* First we check the PCI IRQ routing table (PRT) for an IRQ. -*/ entry =acpi_pci_irq_lookup (dev, pin); - -/* -* If no PRT entry was found, we'll try to derive an IRQ from the -* device's parent bridge. -*/ -if (!entry) - entry =acpi_pci_irq_derive (dev, pin); -if (!entry)return ;
PATCH 16/20 ACPI: PCI: simplify list of _PRT entries
In reply to Bjorn HelgaasWe don't need a struct containing a count and a list_head; a simple list_head is sufficient. The list iterators handle empty lists fine.
--- drivers/acpi/pci_irq.c | 60 ++++++++++-------------------------------------- 1 files changed, 12 insertions(+), 48 deletions(-)
drivers/acpi/pci_irq.c +12 -48
@@ -44,7 +44,7 @@ACPI_MODULE_NAME ("pci_irq" );struct acpi_prt_entry { -struct list_head node; +struct list_head list;struct acpi_pci_id id;u8 pin;struct {
@@ -54,12 +54,7 @@ struct acpi_prt_entry {u32 irq; }; -struct acpi_prt_list { -int count; -struct list_head entries; -}; - -static struct acpi_prt_list acpi_prt; +static LIST_HEAD (acpi_prt_list);static DEFINE_SPINLOCK (acpi_prt_lock);static inline char pin_name (int pin)
@@ -74,21 +69,13 @@ static inline char pin_name(int pin)static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry (struct pci_dev *dev,int pin) { -struct acpi_prt_entry *entry =NULL ; +struct acpi_prt_entry *entry;int segment =pci_domain_nr (dev->bus);int bus = dev->bus->number;int device =PCI_SLOT (dev->devfn); -if (!acpi_prt.count) -return NULL ; - -/* -* Parse through all PRT entries looking for a match on the specified -* PCI device's segment, bus, device, and pin (don't care about func). -* -*/ spin_lock (&acpi_prt_lock); -list_for_each_entry (entry, &acpi_prt.entries, node) { +list_for_each_entry (entry, &acpi_prt_list, list) {if ((segment == entry->id.segment) && (bus == entry->id.bus) && (device == entry->id.device)
@@ -97,7 +84,6 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(struct pci_dev *dev,return entry; } } -spin_unlock (&acpi_prt_lock);return NULL ; }
@@ -203,7 +189,7 @@ static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus, struct acpi_pci_routing_table *prt) { - struct acpi_prt_entry *entry = NULL; + struct acpi_prt_entry *entry; entry =kzalloc (sizeof (struct acpi_prt_entry ),GFP_KERNEL );if (!entry)
@@ -255,35 +241,17 @@ acpi_pci_irq_add_entry(acpi_handle handle, prt->source, entry->link.index));spin_lock (&acpi_prt_lock); -list_add_tail (&entry->node, &acpi_prt.entries); - acpi_prt.count++; +list_add_tail (&entry->list, &acpi_prt_list);spin_unlock (&acpi_prt_lock);return 0 ; } -static void -acpi_pci_irq_del_entry (int segment,int bus,struct acpi_prt_entry *entry) -{ -if (segment == entry->id.segment && bus == entry->id.bus) { - acpi_prt.count--; -list_del (&entry->node); -kfree (entry); - } -} -int acpi_pci_irq_add_prt (acpi_handle handle,int segment,int bus) {acpi_status status;struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER ,NULL };struct acpi_pci_routing_table *entry; -static int first_time =1 ; - -if (first_time) { - acpi_prt.count =0 ; -INIT_LIST_HEAD (&acpi_prt.entries); - first_time =0 ; - }/* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */ status =acpi_get_name (handle,ACPI_FULL_PATHNAME , &buffer);
@@ -319,21 +287,17 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)void acpi_pci_irq_del_prt (int segment,int bus) { -struct list_head *node =NULL , *n =NULL ; -struct acpi_prt_entry *entry =NULL ; - -if (!acpi_prt.count) { -return ; - } +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_safe (node, n, &acpi_prt.entries) { - entry = list_entry(node, struct acpi_prt_entry, node); - -acpi_pci_irq_del_entry (segment, bus, entry); +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); }
PATCH 17/20 ACPI: PCI: simplify struct acpi_prt_entry
In reply to Bjorn HelgaasRemove unused "irq" field, remove unnecessary struct, rename "handle" to "link".
--- drivers/acpi/pci_irq.c | 35 +++++++++++++++-------------------- 1 files changed, 15 insertions(+), 20 deletions(-)
drivers/acpi/pci_irq.c +15 -20
@@ -47,11 +47,8 @@ struct acpi_prt_entry {struct list_head list;struct acpi_pci_id id;u8 pin; -struct { -acpi_handle handle; -u32 index; - } link; -u32 irq; +acpi_handle link; +u32 index;/* GSI, or link _CRS index */ };static LIST_HEAD (acpi_prt_list);
@@ -207,6 +204,8 @@ acpi_pci_irq_add_entry(acpi_handle handle,do_prt_fixups (entry, prt); + entry->index = prt->source_index; +/* * Type 1: Dynamic * ---------------
@@ -220,10 +219,9 @@ acpi_pci_irq_add_entry(acpi_handle handle,* (e.g. exists somewhere 'below' this _PRT entry in the ACPI * namespace). */ -if (prt->source[0 ]) { -acpi_get_handle (handle, prt->source, &entry->link.handle); - entry->link.index = prt->source_index; - } +if (prt->source[0 ]) +acpi_get_handle (handle, prt->source, &entry->link); +/* * Type 2: Static * --------------
@@ -231,14 +229,12 @@ acpi_pci_irq_add_entry(acpi_handle handle,* the IRQ value, which is hardwired to specific interrupt inputs on * the interrupt controller. */ - else - entry->link.index = prt->source_index;ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO ," %04x:%02x:%02x[%c] -> %s[%d]\n" , entry->id.segment, entry->id.bus, entry->id.device,pin_name (entry->pin), - prt->source, entry->link.index)); + prt->source, entry->index));spin_lock (&acpi_prt_lock);list_add_tail (&entry->list, &acpi_prt_list);
@@ -312,17 +308,16 @@ acpi_pci_allocate_irq(struct acpi_prt_entry *entry,int irq; -if (entry->link.handle) { - irq =acpi_pci_link_allocate_irq (entry->link.handle, - entry->link.index, triggering, - polarity, link); +if (entry->link) { + irq =acpi_pci_link_allocate_irq (entry->link, entry->index, + triggering, polarity, link);if (irq <0 ) { printk(KERN_WARNING PREFIX "Invalid IRQ link routing entry\n");return -1 ; } }else { - irq = entry->link.index; + irq = entry->index; *triggering =ACPI_LEVEL_SENSITIVE ; *polarity =ACPI_ACTIVE_LOW ; }
@@ -336,10 +331,10 @@ acpi_pci_free_irq(struct acpi_prt_entry *entry) {int irq; -if (entry->link.handle) { - irq =acpi_pci_link_free_irq (entry->link.handle); +if (entry->link) { + irq =acpi_pci_link_free_irq (entry->link); }else { - irq = entry->link.index; + irq = entry->index; }return irq; }
PATCH 18/20 ACPI: PCI: expand acpi_pci_allocate_irq() and acpi_pci_free_irq() inline
In reply to Bjorn Helgaasacpi_pci_allocate_irq() and acpi_pci_free_irq() are trivial and only used once, so just open-code them.
--- drivers/acpi/pci_irq.c | 56 +++++++++++------------------------------------- 1 files changed, 13 insertions(+), 43 deletions(-)
drivers/acpi/pci_irq.c +13 -43
@@ -301,44 +301,6 @@ void acpi_pci_irq_del_prt(int segment, int bus)/* -------------------------------------------------------------------------- PCI Interrupt Routing Support -------------------------------------------------------------------------- */ -static int -acpi_pci_allocate_irq (struct acpi_prt_entry *entry, -int *triggering,int *polarity,char **link) -{ -int irq; - - -if (entry->link) { - irq =acpi_pci_link_allocate_irq (entry->link, entry->index, - triggering, polarity, link); -if (irq <0 ) { - printk(KERN_WARNING PREFIX - "Invalid IRQ link routing entry\n"); -return -1 ; - } - }else { - irq = entry->index; - *triggering =ACPI_LEVEL_SENSITIVE ; - *polarity =ACPI_ACTIVE_LOW ; - } - -ACPI_DEBUG_PRINT ((ACPI_DB_INFO ,"Found GSI %d\n" , irq)); -return irq; -} - -static int -acpi_pci_free_irq (struct acpi_prt_entry *entry) -{ -int irq; - -if (entry->link) { - irq =acpi_pci_link_free_irq (entry->link); - }else { - irq = entry->index; - } -return irq; -} -static struct acpi_prt_entry *acpi_pci_irq_lookup (struct pci_dev *dev,int pin) {
@@ -428,10 +390,15 @@ int acpi_pci_irq_enable(struct pci_dev *dev)return 0 ; } -if (entry) - gsi =acpi_pci_allocate_irq (entry, &triggering, &polarity, - &link); -else +if (entry) { +if (entry->link) + gsi =acpi_pci_link_allocate_irq (entry->link, + entry->index, + &triggering, &polarity, + &link); +else + gsi = entry->index; + }else gsi =-1 ;/*
@@ -493,7 +460,10 @@ void acpi_pci_irq_disable(struct pci_dev *dev)if (!entry)return ; - gsi =acpi_pci_free_irq (entry); +if (entry->link) + gsi =acpi_pci_link_free_irq (entry->link); +else + gsi = entry->index;/* * TBD: It might be worth clearing dev->irq by magic constant
PATCH 19/20 ACPI: PCI: whitespace and useless initialization cleanup
In reply to Bjorn HelgaasThis patch makes function declarations consistent throughout the file and removes some unnecessary initializations.
--- drivers/acpi/pci_irq.c | 28 +++++++++------------------- 1 files changed, 9 insertions(+), 19 deletions(-)
drivers/acpi/pci_irq.c +9 -19
@@ -151,8 +151,8 @@ static struct prt_quirk prt_quirks[] = { "\\_SB_.PCI0.LNK3"}, }; -static void -do_prt_fixups (struct acpi_prt_entry *entry,struct acpi_pci_routing_table *prt) +static void do_prt_fixups (struct acpi_prt_entry *entry, +struct acpi_pci_routing_table *prt) {int i;struct prt_quirk *quirk;
@@ -182,9 +182,8 @@ do_prt_fixups(struct acpi_prt_entry *entry, struct acpi_pci_routing_table *prt) } } -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_add_entry (acpi_handle handle,int segment,int bus, +struct acpi_pci_routing_table *prt) {struct acpi_prt_entry *entry;
@@ -301,8 +300,7 @@ void acpi_pci_irq_del_prt(int segment, int bus)/* -------------------------------------------------------------------------- PCI Interrupt Routing Support -------------------------------------------------------------------------- */ -static struct acpi_prt_entry * -acpi_pci_irq_lookup (struct pci_dev *dev,int pin) +static struct acpi_prt_entry *acpi_pci_irq_lookup (struct pci_dev *dev,int pin) {struct acpi_prt_entry *entry;struct pci_dev *bridge;
@@ -353,24 +351,17 @@ acpi_pci_irq_lookup(struct pci_dev *dev, int pin)return NULL ; } -/* -* acpi_pci_irq_enable -* success: return 0 -* failure: return < 0 -*/ -int acpi_pci_irq_enable (struct pci_dev *dev) {struct acpi_prt_entry *entry; -int gsi =0 ; -u8 pin =0 ; +int gsi; +u8 pin;int triggering =ACPI_LEVEL_SENSITIVE ;int polarity =ACPI_ACTIVE_LOW ;char *link =NULL ;char link_desc[16 ];int rc; - pin = dev->pin;if (!pin) { ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -448,9 +439,8 @@ void __attribute__ ((weak)) acpi_unregister_gsi(u32 i)void acpi_pci_irq_disable (struct pci_dev *dev) {struct acpi_prt_entry *entry; -int gsi =0 ; -u8 pin =0 ; - +int gsi; +u8 pin; pin = dev->pin;if (!pin)
PATCH 20/20 ACPI: PCI: add HP copyright
In reply to Bjorn HelgaasAdd HP copyright to pci_irq.c.
--- drivers/acpi/pci_irq.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
drivers/acpi/pci_irq.c +2 -0
@@ -4,6 +4,8 @@* Copyright (C) 2001, 2002 Andy Grover <[email protected]> * Copyright (C) 2001, 2002 Paul Diefenbaugh <[email protected]> * Copyright (C) 2002 Dominik Brodowski <[email protected]> +* (c) Copyright 2008 Hewlett-Packard Development Company, L.P. +* Bjorn Helgaas <[email protected]> * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *
Len Brown
reviewerseries looks good -- applied all 20.
thanks,
-- Len Brown, Intel Open Source Technology Center
Quoted 42 lines · Bjorn Helgaas
This series simplifies the code that handles ACPI
_PRTs(PCI routing tables). My goal is to make this look more like the corresponding code in other architectures, especially in terms of swizzling, e.g., the various implementations ofcommon_swizzle()andsimple_swizzle(), and the x86 non-ACPI code inpirq_enable_irq().There should be no functional changes in this series.
Comments welcome.
Bjorn
---
Bjorn Helgaas (20):
ACPI: PCI: add HP copyright
ACPI: PCI: whitespace and useless initialization cleanup
ACPI: PCI: expandacpi_pci_allocate_irq()andacpi_pci_free_irq()inline
ACPI: PCI: simplify structacpi_prt_entry
ACPI: PCI: simplify list of_PRTentries
ACPI: PCI: combine lookup and derive
ACPI: PCI: follow typical PCI INTx swizzling pattern
ACPI: PCI: use positive logic to simplify code
ACPI: PCI: remove callback fromacpi_pci_irq_lookup&acpi_pci_irq_derive
ACPI: PCI: tweak_PRTlookup debug
ACPI: PCI: lookup_PRTentry by PCI dev and pin, not segment/bus/dev/pin
ACPI: PCI: use 1-based encoding for_PRTquirks
ACPI: PCI: always use the PCI INTx pin values, not the_PRTones
ACPI: PCI: add a helper to convert_PRTINTx pin number to name
ACPI: PCI: move structacpi_prt_entrydeclaration out of public header file
ACPI: PCI: fix GSI/IRQ naming confusion
ACPI: PCI: ignore_PRTfunction information
ACPI: PCI: simplify buffer management for evaluating_PRT
ACPI: PCI: remove unnecessary null pointer checks
ACPI: PCI: use conventional PCI address formatdrivers/acpi/pci_bind.c | 12 + drivers/acpi/pci_irq.c | 416 +++++++++++++++-------------------------------- include/linux/acpi.h | 16 -- 3 files changed, 136 insertions(+), 308 deletions(-)