PCI: unify P2P bridge INTx swizzling
Subsystems (10)
cover PCI: unify P2P bridge INTx swizzling
This series adds a pci_swizzle_interrupt_pin() function in the PCI core. Most architectures currently implement this independently.
After this series, many of the callers of pci_swizzle_interrupt_pin() follow a similar pattern. I'd like to consolidate those callers, too, but I haven't started that yet.
One strange thing I'd like to understand eventually is why the swizzle in acpi_pci_irq_derive() does something special for CardBus bridges, while no other architecture does.
Comments welcome.
These patches have been compile-tested on:
alpha
arm
ia64
mips
powerpc (ppc64)
sh
x86 (32-bit)
x86 (64-bit)I've boot-tested these architectures:
ia64
x86 (32-bit)I haven't compiled parisc for want of a cross-compiler.
Bjorn
---
Bjorn Helgaas (12):
PCI: x86: use generic pci_swizzle_interrupt_pin()
PCI: sh: use generic pci_swizzle_interrupt_pin()
PCI: powerpc: use generic pci_swizzle_interrupt_pin()
PCI: parisc: use generic pci_swizzle_interrupt_pin()
PCI: mips: use generic pci_swizzle_interrupt_pin()
PCI: arm: use generic pci_swizzle_interrupt_pin()
PCI: alpha: use generic pci_swizzle_interrupt_pin()
PCI: add pci_swizzle_interrupt_pin()
x86/PCI: minor logic simplications
x86/PCI: use config space encoding for interrupt pins
PCI: use config space encoding in pci_get_interrupt_pin() PCI Hotplug: cpqphp: use config space PCI interrupt pin encoding
arch/alpha/kernel/pci.c | 2 + arch/alpha/kernel/pci_impl.h | 9 +----- arch/alpha/kernel/sys_dp264.c | 2 + arch/alpha/kernel/sys_eiger.c | 2 + arch/alpha/kernel/sys_miata.c | 2 + arch/alpha/kernel/sys_noritake.c | 2 + arch/alpha/kernel/sys_ruffian.c | 2 + arch/alpha/kernel/sys_sable.c | 2 + arch/arm/kernel/bios32.c | 6 ++-- arch/arm/mach-integrator/pci.c | 11 +------- arch/mips/pci/pci-ip27.c | 6 ---- arch/mips/pci/pci.c | 9 +----- arch/powerpc/kernel/prom_parse.c | 7 +---- arch/sh/drivers/pci/ops-cayman.c | 9 +----- arch/sh/drivers/pci/pci.c | 7 +---- arch/x86/pci/irq.c | 54 +++++++++++++++++-------------------- arch/x86/pci/visws.c | 7 +---- drivers/parisc/dino.c | 4 +-- drivers/parisc/iosapic.c | 3 +- drivers/pci/hotplug/cpqphp_ctrl.c | 4 +-- drivers/pci/hotplug/cpqphp_pci.c | 2 + drivers/pci/pci.c | 10 +++++-- include/linux/pci.h | 1 + 23 files changed, 60 insertions(+), 103 deletions(-)
Signature · 1 line
Signature
PATCH 1/12 PCI Hotplug: cpqphp: use config space PCI interrupt pin encoding
This patch changes cpqphp to use interrupt pin values just as they come from PCI config space, i.e., 1=INTA, ..., 4=INTD.
pcibios_set_irq_routing() takes pin arguments in the range 0=INTA, ..., 3=INTD, so we'll adjust the pin just before calling it.
--- drivers/pci/hotplug/cpqphp_ctrl.c | 4 ++-- drivers/pci/hotplug/cpqphp_pci.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-)
drivers/pci/hotplug/cpqphp_ctrl.c +2 -2
@@ -2604,7 +2604,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *funcfor (cloop =0 ; cloop <4 ; cloop++) {if (irqs.valid_INT & (0x01 << cloop)) { rc =cpqhp_set_irq (func->bus, func->device, -0x0A + cloop, irqs.interrupt[cloop]); + cloop +1 , irqs.interrupt[cloop]);if (rc) goto free_and_out; }
@@ -2945,7 +2945,7 @@ static int configure_new_function(struct controller *ctrl, struct pci_func *func }if (!behind_bridge) { - rc =cpqhp_set_irq (func->bus, func->device, temp_byte +0x09 ,IRQ ); + rc =cpqhp_set_irq (func->bus, func->device, temp_byte,IRQ );if (rc)return 1 ; }else {
drivers/pci/hotplug/cpqphp_pci.c +1 -1
@@ -171,7 +171,7 @@ int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) fakebus->number = bus_num;dbg ("%s: dev %d, bus %d, pin %d, num %d\n" , __func__, dev_num, bus_num, int_pin, irq_num); - rc =pcibios_set_irq_routing (fakedev, int_pin -0x0a , irq_num); + rc =pcibios_set_irq_routing (fakedev, int_pin -1 , irq_num);kfree (fakedev);kfree (fakebus);dbg ("%s: rc %d\n" , __func__, rc);
PATCH 2/12 PCI: use config space encoding in pci_get_interrupt_pin()
In reply to Bjorn HelgaasThis patch makes pci_get_interrupt_pin() return values encoded the same way as the "Interrupt Pin" value in PCI config space, i.e., 1=INTA, ..., 4=INTD.
pirq_bios_set() is the only in-tree caller of pci_get_interrupt_pin() and pci_get_interrupt_pin() is not exported.
--- arch/x86/pci/irq.c | 2 +- drivers/pci/pci.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-)
arch/x86/pci/irq.c +1 -1
@@ -534,7 +534,7 @@ static int pirq_bios_set(struct pci_dev *router, struct pci_dev *dev, int pirq, {struct pci_dev *bridge;int pin =pci_get_interrupt_pin (dev, &bridge); -return pcibios_set_irq_routing (bridge, pin, irq); +return pcibios_set_irq_routing (bridge, pin -1 , irq); }#endif
drivers/pci/pci.c +2 -2
@@ -1345,9 +1345,9 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge) pin = dev->pin;if (!pin)return -1 ; - pin--; +while (dev->bus->self) { - pin = (pin +PCI_SLOT (dev->devfn)) %4 ; + pin = (((pin -1 ) +PCI_SLOT (dev->devfn)) %4 ) +1 ; dev = dev->bus->self; } *bridge = dev;
PATCH 3/12 x86/PCI: use config space encoding for interrupt pins
In reply to Bjorn HelgaasKeep "pin" encoded as it is in the "Interrupt Pin" value in PCI config space, i.e., 0=device doesn't use interrupts, 1=INTA, ..., 4=INTD.
This makes the bridge INTx swizzle match other architectures.
--- arch/x86/pci/irq.c | 44 ++++++++++++++++++++------------------------ 1 files changed, 20 insertions(+), 24 deletions(-)
arch/x86/pci/irq.c +20 -24
@@ -888,7 +888,6 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)dev_dbg (&dev->dev,"no interrupt pin\n" );return 0 ; } - pin = pin -1 ;/* Find IRQ routing entry */
@@ -898,17 +897,17 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) info =pirq_get_info (dev);if (!info) {dev_dbg (&dev->dev,"PCI INT %c not found in routing table\n" , -'A' + pin); +'A' + pin -1 );return 0 ; } - pirq = info->irq[pin].link; - mask = info->irq[pin].bitmap; + pirq = info->irq[pin -1 ].link; + mask = info->irq[pin -1 ].bitmap;if (!pirq) { -dev_dbg (&dev->dev,"PCI INT %c not routed\n" ,'A' + pin); +dev_dbg (&dev->dev,"PCI INT %c not routed\n" ,'A' + pin -1 );return 0 ; }dev_dbg (&dev->dev,"PCI INT %c -> PIRQ %02x, mask %04x, excl %04x" , -'A' + pin, pirq, mask, pirq_table->exclusive_irqs); +'A' + pin -1 , pirq, mask, pirq_table->exclusive_irqs); mask &= pcibios_irq_mask;/* Work around broken HP Pavilion Notebooks which assign USB to
@@ -950,7 +949,7 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) newirq = i; } } -dev_dbg (&dev->dev,"PCI INT %c -> newirq %d" ,'A' + pin, newirq); +dev_dbg (&dev->dev,"PCI INT %c -> newirq %d" ,'A' + pin -1 , newirq);/* Check if it is hardcoded */ if ((pirq &0xf0 ) ==0xf0 ) {
@@ -978,18 +977,18 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)return 0 ; } } -dev_info (&dev->dev,"%s PCI INT %c -> IRQ %d\n" , msg,'A' + pin, irq); +dev_info (&dev->dev,"%s PCI INT %c -> IRQ %d\n" , msg,'A' + pin -1 , irq);/* Update IRQ for all devices with the same pirq value */ while ((dev2 =pci_get_device (PCI_ANY_ID ,PCI_ANY_ID , dev2)) !=NULL ) {pci_read_config_byte (dev2,PCI_INTERRUPT_PIN , &pin);if (!pin)continue ; - pin--; + info =pirq_get_info (dev2);if (!info)continue ; -if (info->irq[pin].link == pirq) { +if (info->irq[pin -1 ].link == pirq) {/* * We refuse to override the dev->irq * information. Give a warning!
@@ -1056,9 +1055,8 @@ static void __init pcibios_fixup_irqs(void)/* * interrupt pins are numbered starting from 1 */ - pin--; irq =IO_APIC_get_PCI_irq_vector (dev->bus->number, -PCI_SLOT (dev->devfn), pin); +PCI_SLOT (dev->devfn), pin -1 );/* * Busses behind bridges are typically not listed in the * MP-table. In this case we have to look up the IRQ
@@ -1071,22 +1069,22 @@ static void __init pcibios_fixup_irqs(void)struct pci_dev *bridge = dev->bus->self;int bus; - pin = (pin +PCI_SLOT (dev->devfn)) %4 ; + pin = (((pin -1 ) +PCI_SLOT (dev->devfn)) %4 ) +1 ; bus = bridge->bus->number; irq =IO_APIC_get_PCI_irq_vector (bus, -PCI_SLOT (bridge->devfn), pin); +PCI_SLOT (bridge->devfn), pin -1 );if (irq >=0 )dev_warn (&dev->dev,"using bridge %s INT %c to " "get IRQ %d\n" ,pci_name (bridge), -'A' + pin, irq); +'A' + pin -1 , irq); }if (irq >=0 ) {dev_info (&dev->dev,"PCI->APIC IRQ transform: INT %c " "-> IRQ %d\n" , -'A' + pin, irq); +'A' + pin -1 , irq); dev->irq = irq; } }
@@ -1221,12 +1219,10 @@ static int pirq_enable_irq(struct pci_dev *dev)if (pin && !pcibios_lookup_irq (dev,1 ) && !dev->irq) {char *msg ="" ; - pin--;/* interrupt pins are numbered starting from 1 */ -if (io_apic_assign_pci_irqs) {int irq; - irq =IO_APIC_get_PCI_irq_vector (dev->bus->number,PCI_SLOT (dev->devfn), pin); + irq =IO_APIC_get_PCI_irq_vector (dev->bus->number,PCI_SLOT (dev->devfn), pin -1 );/* * Busses behind bridges are typically not listed in the MP-table. * In this case we have to look up the IRQ based on the parent bus,
@@ -1237,20 +1233,20 @@ static int pirq_enable_irq(struct pci_dev *dev)while (irq <0 && dev->bus->parent) {/* go back to the bridge */ struct pci_dev *bridge = dev->bus->self; - pin = (pin +PCI_SLOT (dev->devfn)) %4 ; + pin = (((pin -1 ) +PCI_SLOT (dev->devfn)) %4 ) +1 ; irq =IO_APIC_get_PCI_irq_vector (bridge->bus->number, -PCI_SLOT (bridge->devfn), pin); +PCI_SLOT (bridge->devfn), pin -1 );if (irq >=0 )dev_warn (&dev->dev,"using bridge %s " "INT %c to get IRQ %d\n" , -pci_name (bridge),'A' + pin, +pci_name (bridge),'A' + pin -1 , irq); dev = bridge; } dev = temp_dev;if (irq >=0 ) {dev_info (&dev->dev,"PCI->APIC IRQ transform: " -"INT %c -> IRQ %d\n" ,'A' + pin, irq); +"INT %c -> IRQ %d\n" ,'A' + pin -1 , irq); dev->irq = irq;return 0 ; }else
@@ -1269,7 +1265,7 @@ static int pirq_enable_irq(struct pci_dev *dev)return 0 ;dev_warn (&dev->dev,"can't find IRQ for PCI INT %c%s\n" , -'A' + pin, msg); +'A' + pin -1 , msg); }return 0 ; }
PATCH 4/12 x86/PCI: minor logic simplications
In reply to Bjorn HelgaasTest "pin" immediately to simplify the subsequent code.
--- arch/x86/pci/irq.c | 8 ++++---- 1 files changed, 4 insertions(+), 4 deletions(-)
arch/x86/pci/irq.c +4 -4
@@ -1042,6 +1042,9 @@ static void __init pcibios_fixup_irqs(void) dev =NULL ;while ((dev =pci_get_device (PCI_ANY_ID ,PCI_ANY_ID , dev)) !=NULL ) {pci_read_config_byte (dev,PCI_INTERRUPT_PIN , &pin); +if (!pin) +continue ; +#ifdef CONFIG_X86_IO_APIC /* * Recalculate IRQ numbers if we use the I/O APIC.
@@ -1049,9 +1052,6 @@ static void __init pcibios_fixup_irqs(void)if (io_apic_assign_pci_irqs) {int irq; -if (!pin) -continue ; -/* * interrupt pins are numbered starting from 1 */
@@ -1092,7 +1092,7 @@ static void __init pcibios_fixup_irqs(void)/* * Still no IRQ? Try to lookup one... */ -if (pin && !dev->irq) +if (!dev->irq)pcibios_lookup_irq (dev,0 ); } }
PATCH 5/12 PCI: add pci_swizzle_interrupt_pin()
In reply to Bjorn HelgaasThis patch adds pci_swizzle_interrupt_pin(), which implements the INTx swizzling algorithm specified in Table 9-1 of the "PCI-to-PCI Bridge Architecture Specification," revision 1.2.
There are many architecture-specific implementations of this swizzle that can be replaced by this common one.
--- drivers/pci/pci.c | 8 +++++++- include/linux/pci.h | 1 + 2 files changed, 8 insertions(+), 1 deletions(-)
drivers/pci/pci.c +7 -1
@@ -1337,6 +1337,12 @@ void pci_enable_ari(struct pci_dev *dev) bridge->ari_enabled =1 ; } +u8 pci_swizzle_interrupt_pin (struct pci_dev *dev,u8 pin) +{ +/* This implements Table 9-1 of the PCI-to-PCI bridge spec */ +return (((pin -1 ) +PCI_SLOT (dev->devfn)) %4 ) +1 ; +} +int pci_get_interrupt_pin (struct pci_dev *dev,struct pci_dev **bridge) {
@@ -1347,7 +1353,7 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)return -1 ;while (dev->bus->self) { - pin = (((pin -1 ) +PCI_SLOT (dev->devfn)) %4 ) +1 ; + pin =pci_swizzle_interrupt_pin (dev, pin); dev = dev->bus->self; } *bridge = dev;
include/linux/pci.h +1 -0
@@ -527,6 +527,7 @@ int __must_check pci_bus_add_device(struct pci_dev *dev);void pci_read_bridge_bases (struct pci_bus *child);struct resource *pci_find_parent_resource (const struct pci_dev *dev,struct resource *res); +u8 pci_swizzle_interrupt_pin (struct pci_dev *dev,u8 pin);int pci_get_interrupt_pin (struct pci_dev *dev,struct pci_dev **bridge);extern struct pci_dev *pci_dev_get (struct pci_dev *dev);extern void pci_dev_put (struct pci_dev *dev);
Re: [PATCH 05/12] PCI: add pci_swizzle_interrupt_pin()
drivers/pci/pci.c void pci_enable_ari(struct pci_dev *dev) · line 1345
Quoted 7 lines · Bjorn Helgaas
drivers/pci/pci.c +6
-0+u8 pci_swizzle_interrupt_pin (struct pci_dev *dev,u8 pin) +{ +/* This implements Table 9-1 of the PCI-to-PCI bridge spec */ +return (((pin -1 ) +PCI_SLOT (dev->devfn)) %4 ) +1 ; +} +
Can you please add a banner comment to this function that gives at least a quick description of what this function is meant to do? Feel free to use kerneldoc.
Saying table X of document Y isn't immediately helpful.
David
Re: [PATCH 05/12] PCI: add pci_swizzle_interrupt_pin()
Quoted 13 lines · David Howells
Review
Quoted 7 lines · Bjorn Helgaas
(quoted diff) +6
-0+u8 pci_swizzle_interrupt_pin(struct pci_dev *dev, u8 pin) +{ + /* This implements Table 9-1 of the PCI-to-PCI bridge spec */ + return (((pin - 1) + PCI_SLOT(dev->devfn)) % 4) + 1; +} +Can you please add a banner comment to this function that gives at least a quick description of what this function is meant to do? Feel free to use kerneldoc.
I'm not really a fan of comments that are bigger than the code and add little or no information, but if you like the following better, use it instead :-)
PCI: add pci_swizzle_interrupt_pin()
From: Bjorn Helgaas <[email protected]>
This patch adds pci_swizzle_interrupt_pin(), which implements the INTx swizzling algorithm specified in Table 9-1 of the "PCI-to-PCI Bridge Architecture Specification," revision 1.2.
There are many architecture-specific implementations of this swizzle that can be replaced by this common one.
--- drivers/pci/pci.c | 17 ++++++++++++++++- include/linux/pci.h | 1 + 2 files changed, 17 insertions(+), 1 deletions(-)
drivers/pci/pci.c +16 -1
@@ -1337,6 +1337,21 @@ void pci_enable_ari(struct pci_dev *dev) bridge->ari_enabled =1 ; } +/** +* pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge +* @dev: the PCI device +* @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD) +* +* The PCI-to-PCI bridge specification requires INTx swizzling for +* devices behind bridges on add-in cards. This performs the swizzle +* for one level of bridge. +*/ +u8 pci_swizzle_interrupt_pin (struct pci_dev *dev,u8 pin) +{ +/* This implements Table 9-1 of the PCI-to-PCI bridge spec */ +return (((pin -1 ) +PCI_SLOT (dev->devfn)) %4 ) +1 ; +} +int pci_get_interrupt_pin (struct pci_dev *dev,struct pci_dev **bridge) {
@@ -1347,7 +1362,7 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)return -1 ;while (dev->bus->self) { - pin = (((pin -1 ) +PCI_SLOT (dev->devfn)) %4 ) +1 ; + pin =pci_swizzle_interrupt_pin (dev, pin); dev = dev->bus->self; } *bridge = dev;
include/linux/pci.h +1 -0
@@ -527,6 +527,7 @@ int __must_check pci_bus_add_device(struct pci_dev *dev);void pci_read_bridge_bases (struct pci_bus *child);struct resource *pci_find_parent_resource (const struct pci_dev *dev,struct resource *res); +u8 pci_swizzle_interrupt_pin (struct pci_dev *dev,u8 pin);int pci_get_interrupt_pin (struct pci_dev *dev,struct pci_dev **bridge);extern struct pci_dev *pci_dev_get (struct pci_dev *dev);extern void pci_dev_put (struct pci_dev *dev);
Re: [PATCH 05/12] PCI: add pci_swizzle_interrupt_pin()
Quoted 9 lines · Bjorn Helgaas
+/**
+ *pci_swizzle_interrupt_pin- swizzle INTx for device behind bridge
+ * @dev: the PCI device
+ * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD)
+ *
+ * The PCI-to-PCI bridge specification requires INTx swizzling for
+ * devices behind bridges on add-in cards. This performs the swizzle
+ * for one level of bridge.
+ */
Better.
drivers/pci/pci.c void pci_enable_ari(struct pci_dev *dev) · line 1351
Quoted 3 lines
drivers/pci/pci.c +3
-0+u8 pci_swizzle_interrupt_pin (struct pci_dev *dev,u8 pin) +{ +/* This implements Table 9-1 of the PCI-to-PCI bridge spec */
I'd recommend merging this comment into the banner.
drivers/pci/pci.c void pci_enable_ari(struct pci_dev *dev) · line 1354
Quoted 3 lines
drivers/pci/pci.c +3
-0+return (((pin -1 ) +PCI_SLOT (dev->devfn)) %4 ) +1 ; +} +
David
Re: [PATCH 05/12] PCI: add pci_swizzle_interrupt_pin()
Quoted 12 lines · David Howells
Quoted 9 lines · Bjorn Helgaas
+/**
+ *pci_swizzle_interrupt_pin- swizzle INTx for device behind bridge
+ * @dev: the PCI device
+ * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD)
+ *
+ * The PCI-to-PCI bridge specification requires INTx swizzling for
+ * devices behind bridges on add-in cards. This performs the swizzle
+ * for one level of bridge.
+ */
Quoted 7 lines
Better.
Review
Quoted 3 lines
(quoted diff) +3
-0+u8 pci_swizzle_interrupt_pin(struct pci_dev *dev, u8 pin) +{ + /* This implements Table 9-1 of the PCI-to-PCI bridge spec */I'd recommend merging this comment into the banner.
OK. How's this? I suck at writing comments.
PCI: add pci_swizzle_interrupt_pin()
From: Bjorn Helgaas <[email protected]>
This patch adds pci_swizzle_interrupt_pin(), which implements the INTx swizzling algorithm specified in Table 9-1 of the "PCI-to-PCI Bridge Architecture Specification," revision 1.2.
There are many architecture-specific implementations of this swizzle that can be replaced by this common one.
--- drivers/pci/pci.c | 16 +++++++++++++++- include/linux/pci.h | 1 + 2 files changed, 16 insertions(+), 1 deletions(-)
drivers/pci/pci.c +15 -1
@@ -1337,6 +1337,20 @@ void pci_enable_ari(struct pci_dev *dev) bridge->ari_enabled =1 ; } +/** +* pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge +* @dev: the PCI device +* @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD) +* +* The PCI-to-PCI bridge specification, section 9.1, requires INTx swizzling +* for devices behind bridges on add-in cards. This performs the swizzle +* for one level of bridge. +*/ +u8 pci_swizzle_interrupt_pin (struct pci_dev *dev,u8 pin) +{ +return (((pin -1 ) +PCI_SLOT (dev->devfn)) %4 ) +1 ; +} +int pci_get_interrupt_pin (struct pci_dev *dev,struct pci_dev **bridge) {
@@ -1347,7 +1361,7 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)return -1 ;while (dev->bus->self) { - pin = (((pin -1 ) +PCI_SLOT (dev->devfn)) %4 ) +1 ; + pin =pci_swizzle_interrupt_pin (dev, pin); dev = dev->bus->self; } *bridge = dev;
include/linux/pci.h +1 -0
@@ -527,6 +527,7 @@ int __must_check pci_bus_add_device(struct pci_dev *dev);void pci_read_bridge_bases (struct pci_bus *child);struct resource *pci_find_parent_resource (const struct pci_dev *dev,struct resource *res); +u8 pci_swizzle_interrupt_pin (struct pci_dev *dev,u8 pin);int pci_get_interrupt_pin (struct pci_dev *dev,struct pci_dev **bridge);extern struct pci_dev *pci_dev_get (struct pci_dev *dev);extern void pci_dev_put (struct pci_dev *dev);
Re: [PATCH 05/12] PCI: add pci_swizzle_interrupt_pin()
Quoted 9 lines · Bjorn Helgaas
+/**
+ *pci_swizzle_interrupt_pin- swizzle INTx for device behind bridge
+ * @dev: the PCI device
+ * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD)
+ *
+ * The PCI-to-PCI bridge specification, section 9.1, requires INTx swizzling
+ * for devices behind bridges on add-in cards. This performs the swizzle
+ * for one level of bridge.
+ */
That's okay. It might be better to put the what before the why, though:
* Perform INTx swizzling for a device behind one level of bridge. This is
* required by section 9.1 of the PCI-to-PCI bridge specification for devices
* behind bridges on add-in cards.
David
Re: [PATCH 05/12] PCI: add pci_swizzle_interrupt_pin()
Quoted 12 lines · David Howells
Quoted 9 lines · Bjorn Helgaas
+/**
+ *pci_swizzle_interrupt_pin- swizzle INTx for device behind bridge
+ * @dev: the PCI device
+ * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD)
+ *
+ * The PCI-to-PCI bridge specification, section 9.1, requires INTx swizzling
+ * for devices behind bridges on add-in cards. This performs the swizzle
+ * for one level of bridge.
+ */
Quoted 5 lines
That's okay. It might be better to put the what before the why, though:
* Perform INTx swizzling for a device behind one level of bridge. This is
* required by section 9.1 of the PCI-to-PCI bridge specification for devices
* behind bridges on add-in cards.
That *is* much better. Thanks for the wordsmithing.
PCI: add pci_swizzle_interrupt_pin()
From: Bjorn Helgaas <[email protected]>
This patch adds pci_swizzle_interrupt_pin(), which implements the INTx swizzling algorithm specified in Table 9-1 of the "PCI-to-PCI Bridge Architecture Specification," revision 1.2.
There are many architecture-specific implementations of this swizzle that can be replaced by this common one.
--- drivers/pci/pci.c | 16 +++++++++++++++- include/linux/pci.h | 1 + 2 files changed, 16 insertions(+), 1 deletions(-)
drivers/pci/pci.c +15 -1
@@ -1337,6 +1337,20 @@ void pci_enable_ari(struct pci_dev *dev) bridge->ari_enabled =1 ; } +/** +* pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge +* @dev: the PCI device +* @pin: the INTx pin (1=INTA, 2=INTB, 3=INTD, 4=INTD) +* +* Perform INTx swizzling for a device behind one level of bridge. This is +* required by section 9.1 of the PCI-to-PCI bridge specification for devices +* behind bridges on add-in cards. +*/ +u8 pci_swizzle_interrupt_pin (struct pci_dev *dev,u8 pin) +{ +return (((pin -1 ) +PCI_SLOT (dev->devfn)) %4 ) +1 ; +} +int pci_get_interrupt_pin (struct pci_dev *dev,struct pci_dev **bridge) {
@@ -1347,7 +1361,7 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)return -1 ;while (dev->bus->self) { - pin = (((pin -1 ) +PCI_SLOT (dev->devfn)) %4 ) +1 ; + pin =pci_swizzle_interrupt_pin (dev, pin); dev = dev->bus->self; } *bridge = dev;
include/linux/pci.h +1 -0
@@ -527,6 +527,7 @@ int __must_check pci_bus_add_device(struct pci_dev *dev);void pci_read_bridge_bases (struct pci_bus *child);struct resource *pci_find_parent_resource (const struct pci_dev *dev,struct resource *res); +u8 pci_swizzle_interrupt_pin (struct pci_dev *dev,u8 pin);int pci_get_interrupt_pin (struct pci_dev *dev,struct pci_dev **bridge);extern struct pci_dev *pci_dev_get (struct pci_dev *dev);extern void pci_dev_put (struct pci_dev *dev);
PATCH 6/12 PCI: alpha: use generic pci_swizzle_interrupt_pin()
In reply to Bjorn HelgaasUse the generic pci_swizzle_interrupt_pin() instead of arch-specific code.
--- arch/alpha/kernel/pci.c | 2 +- arch/alpha/kernel/pci_impl.h | 9 ++------- arch/alpha/kernel/sys_dp264.c | 2 +- arch/alpha/kernel/sys_eiger.c | 2 +- arch/alpha/kernel/sys_miata.c | 2 +- arch/alpha/kernel/sys_noritake.c | 2 +- arch/alpha/kernel/sys_ruffian.c | 2 +- arch/alpha/kernel/sys_sable.c | 2 +- 8 files changed, 9 insertions(+), 14 deletions(-)
arch/alpha/kernel/pci.c +1 -1
@@ -328,7 +328,7 @@ common_swizzle(struct pci_dev *dev, u8 *pinp)u8 pin = *pinp;while (dev->bus->parent) { - pin =bridge_swizzle (pin,PCI_SLOT (dev->devfn)); + pin =pci_swizzle_interrupt_pin (dev, pin);/* Move up the chain of bridges. */ dev = dev->bus->self; }
arch/alpha/kernel/pci_impl.h +2 -7
@@ -106,16 +106,11 @@ struct pci_iommu_arena;* Where A = pin 1, B = pin 2 and so on and pin=0 = default = A. * Thus, each swizzle is ((pin-1) + (device#-4)) % 4 * -* The following code swizzles for exactly one bridge. The routine +* pci_swizzle_interrupt_pin() swizzles for exactly one bridge. The routine * common_swizzle below handles multiple bridges. But there are a -* couple boards that do strange things, so we define this here. +* couple boards that do strange things. */ -static inline u8 bridge_swizzle (u8 pin,u8 slot) -{ -return (((pin-1 ) + slot) %4 ) +1 ; -} -/* The following macro is used to implement the table-based irq mapping function for all single-bus Alphas. */
arch/alpha/kernel/sys_dp264.c +1 -1
@@ -481,7 +481,7 @@ monet_swizzle(struct pci_dev *dev, u8 *pinp) slot =PCI_SLOT (dev->devfn);break ; } - pin =bridge_swizzle (pin,PCI_SLOT (dev->devfn)) ; + pin =pci_swizzle_interrupt_pin (dev, pin);/* Move up the chain of bridges. */ dev = dev->bus->self;
arch/alpha/kernel/sys_eiger.c +1 -1
@@ -204,7 +204,7 @@ eiger_swizzle(struct pci_dev *dev, u8 *pinp)break ; }/* Must be a card-based bridge. */ - pin =bridge_swizzle (pin,PCI_SLOT (dev->devfn)); + pin =pci_swizzle_interrupt_pin (dev, pin);/* Move up the chain of bridges. */ dev = dev->bus->self;
arch/alpha/kernel/sys_miata.c +1 -1
@@ -219,7 +219,7 @@ miata_swizzle(struct pci_dev *dev, u8 *pinp) slot =PCI_SLOT (dev->devfn) +9 ;break ; } - pin =bridge_swizzle (pin,PCI_SLOT (dev->devfn)); + pin =pci_swizzle_interrupt_pin (dev, pin);/* Move up the chain of bridges. */ dev = dev->bus->self;
arch/alpha/kernel/sys_noritake.c +1 -1
@@ -257,7 +257,7 @@ noritake_swizzle(struct pci_dev *dev, u8 *pinp) slot =PCI_SLOT (dev->devfn) +15 ;break ; } - pin =bridge_swizzle (pin,PCI_SLOT (dev->devfn)) ; + pin =pci_swizzle_interrupt_pin (dev, pin);/* Move up the chain of bridges. */ dev = dev->bus->self;
arch/alpha/kernel/sys_ruffian.c +1 -1
@@ -160,7 +160,7 @@ ruffian_swizzle(struct pci_dev *dev, u8 *pinp) slot =PCI_SLOT (dev->devfn) +10 ;break ; } - pin =bridge_swizzle (pin,PCI_SLOT (dev->devfn)); + pin =pci_swizzle_interrupt_pin (dev, pin);/* Move up the chain of bridges. */ dev = dev->bus->self;
arch/alpha/kernel/sys_sable.c +1 -1
@@ -425,7 +425,7 @@ lynx_swizzle(struct pci_dev *dev, u8 *pinp) slot =PCI_SLOT (dev->devfn) +11 ;break ; } - pin =bridge_swizzle (pin,PCI_SLOT (dev->devfn)) ; + pin =pci_swizzle_interrupt_pin (dev, pin);/* Move up the chain of bridges. */ dev = dev->bus->self;
PATCH 7/12 PCI: arm: use generic pci_swizzle_interrupt_pin()
In reply to Bjorn HelgaasUse the generic pci_swizzle_interrupt_pin() instead of arch-specific code.
--- arch/arm/kernel/bios32.c | 6 +++--- arch/arm/mach-integrator/pci.c | 11 ++--------- 2 files changed, 5 insertions(+), 12 deletions(-)
arch/arm/kernel/bios32.c +3 -3
@@ -491,17 +491,17 @@ EXPORT_SYMBOL(pcibios_bus_to_resource);*/ u8 __devinit pci_std_swizzle (struct pci_dev *dev,u8 *pinp) { -int pin = *pinp -1 ; +int pin = *pinp;while (dev->bus->self) { - pin = (pin +PCI_SLOT (dev->devfn)) &3 ; + pin =pci_swizzle_interrupt_pin (dev, pin);/* * move up the chain of bridges, * swizzling as we go. */ dev = dev->bus->self; } - *pinp = pin +1 ; + *pinp = pin;return PCI_SLOT (dev->devfn); }
arch/arm/mach-integrator/pci.c +2 -9
@@ -63,13 +63,7 @@* * Where A = pin 1, B = pin 2 and so on and pin=0 = default = A. * Thus, each swizzle is ((pin-1) + (device#-4)) % 4 -* -* The following code swizzles for exactly one bridge. */ -static inline int bridge_swizzle (int pin,unsigned int slot) -{ -return (pin + slot) &3 ; -}/* * This routine handles multiple bridges.
@@ -81,15 +75,14 @@ static u8 __init integrator_swizzle(struct pci_dev *dev, u8 *pinp)if (pin ==0 ) pin =1 ; - pin -=1 ;while (dev->bus->self) { - pin =bridge_swizzle (pin,PCI_SLOT (dev->devfn)); + pin =pci_swizzle_interrupt_pin (dev, pin);/* * move up the chain of bridges, swizzling as we go. */ dev = dev->bus->self; } - *pinp = pin +1 ; + *pinp = pin;return PCI_SLOT (dev->devfn); }
PATCH 8/12 PCI: mips: use generic pci_swizzle_interrupt_pin()
In reply to Bjorn HelgaasUse the generic pci_swizzle_interrupt_pin() instead of arch-specific code.
--- arch/mips/pci/pci-ip27.c | 6 ------ arch/mips/pci/pci.c | 9 +-------- 2 files changed, 1 insertions(+), 14 deletions(-)
arch/mips/pci/pci-ip27.c +0 -6
@@ -146,12 +146,6 @@ int __devinit pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)return 0 ; } -/* Most MIPS systems have straight-forward swizzling needs. */ -static inline u8 bridge_swizzle (u8 pin,u8 slot) -{ -return (((pin -1 ) + slot) %4 ) +1 ; -} -static inline struct pci_dev *bridge_root_dev (struct pci_dev *dev) {while (dev->bus->parent) {
arch/mips/pci/pci.c +1 -8
@@ -149,19 +149,12 @@ out: "Skipping PCI bus scan due to resource conflict\n"); } -/* Most MIPS systems have straight-forward swizzling needs. */ - -static inline u8 bridge_swizzle (u8 pin,u8 slot) -{ -return (((pin -1 ) + slot) %4 ) +1 ; -} -static u8 __init common_swizzle (struct pci_dev *dev,u8 *pinp) {u8 pin = *pinp;while (dev->bus->parent) { - pin =bridge_swizzle (pin,PCI_SLOT (dev->devfn)); + pin =pci_swizzle_interrupt_pin (dev, pin);/* Move up the chain of bridges. */ dev = dev->bus->self; }
Re: [PATCH 08/12] PCI: mips: use generic pci_swizzle_interrupt_pin()
Quoted 3 lines · Bjorn Helgaas
Use the generic
pci_swizzle_interrupt_pin()instead of arch-specific code.Signed-off-by Bjorn Helgaas <[email protected]>
Looking good,
Ralf
PATCH 9/12 PCI: parisc: use generic pci_swizzle_interrupt_pin()
In reply to Bjorn HelgaasUse the generic pci_swizzle_interrupt_pin() instead of arch-specific code.
--- drivers/parisc/dino.c | 4 ++-- drivers/parisc/iosapic.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-)
drivers/parisc/dino.c +2 -2
@@ -547,7 +547,7 @@ dino_card_fixup(struct pci_dev *dev)** The additional "-1" adjusts for skewing the IRQ<->slot. */ dino_cfg_read (dev->bus, dev->devfn,PCI_INTERRUPT_PIN ,1 , &irq_pin); - dev->irq = (irq_pin +PCI_SLOT (dev->devfn) -1 ) %4 ; + dev->irq =pci_swizzle_interrupt_pin (dev, irq_pin) -1 ;/* Shouldn't really need to do this but it's in case someone tries ** to bypass PCI services and look at the card themselves.
@@ -672,7 +672,7 @@ dino_fixup_bus(struct pci_bus *bus)dino_cfg_read (dev->bus, dev->devfn,PCI_INTERRUPT_PIN ,1 , &irq_pin); - irq_pin = (irq_pin +PCI_SLOT (dev->devfn) -1 ) %4 ; + irq_pin =pci_swizzle_interrupt_pin (dev, irq_pin) -1 ;printk (KERN_WARNING "Device %s has undefined IRQ, " "setting to %d\n" ,pci_name (dev), irq_pin); dino_cfg_write(dev->bus, dev->devfn,
drivers/parisc/iosapic.c +1 -2
@@ -519,8 +519,7 @@ iosapic_xlate_pin(struct iosapic_info *isi, struct pci_dev *pcidev)** ** Advantage is it's really easy to implement. */ - intr_pin = ((intr_pin-1 )+PCI_SLOT (pcidev->devfn)) %4 ; - intr_pin++;/* convert back to INTA-D (1-4) */ + intr_pin =pci_swizzle_interrupt_pin (pcidev, intr_pin);#endif /* PCI_BRIDGE_FUNCS */ /*
Re: [PATCH 09/12] PCI: parisc: use generic pci_swizzle_interrupt_pin()
Quoted 3 lines · Bjorn Helgaas
Use the generic
pci_swizzle_interrupt_pin()instead of arch-specific code.Signed-off-by Bjorn Helgaas <[email protected]>
cool, ack.
PATCH 10/12 PCI: powerpc: use generic pci_swizzle_interrupt_pin()
In reply to Bjorn HelgaasUse the generic pci_swizzle_interrupt_pin() instead of arch-specific code.
--- arch/powerpc/kernel/prom_parse.c | 7 +------ 1 files changed, 1 insertions(+), 6 deletions(-)
arch/powerpc/kernel/prom_parse.c +1 -6
@@ -232,11 +232,6 @@ int of_pci_address_to_resource(struct device_node *dev, int bar, }EXPORT_SYMBOL_GPL (of_pci_address_to_resource); -static u8 of_irq_pci_swizzle (u8 slot,u8 pin) -{ -return (((pin -1 ) + slot) %4 ) +1 ; -} -int of_irq_map_pci (struct pci_dev *pdev,struct of_irq *out_irq) {struct device_node *dn, *ppnode;
@@ -306,7 +301,7 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)/* We can only get here if we hit a P2P bridge with no node, * let's do standard swizzling and try again */ - lspec =of_irq_pci_swizzle (PCI_SLOT (pdev->devfn), lspec); + lspec =pci_swizzle_interrupt_pin (pdev, lspec); pdev = ppdev; }
Re: [PATCH 10/12] PCI: powerpc: use generic pci_swizzle_interrupt_pin()
Quoted 4 lines · Bjorn Helgaas
Use the generic
pci_swizzle_interrupt_pin()instead of arch-specific code.Signed-off-by Bjorn Helgaas <[email protected]>---
Quoted 33 lines
arch/powerpc/kernel/prom_parse.c | 7 +------ 1 files changed, 1 insertions(+), 6 deletions(-)arch/powerpc/kernel/prom_parse.c +1
-7@@ -232,11 +232,6 @@ int of_pci_address_to_resource(struct device_node *dev, int bar, }EXPORT_SYMBOL_GPL (of_pci_address_to_resource); -static u8 of_irq_pci_swizzle (u8 slot,u8 pin) -{ -return (((pin -1 ) + slot) %4 ) +1 ; -} -int of_irq_map_pci (struct pci_dev *pdev,struct of_irq *out_irq) {struct device_node *dn, *ppnode;@@ -306,7 +301,7 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)/* We can only get here if we hit a P2P bridge with no node, * let's do standard swizzling and try again */ - lspec =of_irq_pci_swizzle (PCI_SLOT (pdev->devfn), lspec); + lspec =pci_swizzle_interrupt_pin (pdev, lspec); pdev = ppdev; } --To unsubscribe from this list: send the line "unsubscribe linux-arch" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 11/12 PCI: sh: use generic pci_swizzle_interrupt_pin()
In reply to Bjorn HelgaasUse the generic pci_swizzle_interrupt_pin() instead of arch-specific code.
--- arch/sh/drivers/pci/ops-cayman.c | 9 ++------- arch/sh/drivers/pci/pci.c | 7 +------ 2 files changed, 3 insertions(+), 13 deletions(-)
arch/sh/drivers/pci/ops-cayman.c +2 -7
@@ -5,11 +5,6 @@#include <cpu/irq.h> #include "pci-sh5.h" -static inline u8 bridge_swizzle (u8 pin,u8 slot) -{ -return (((pin -1 ) + slot) %4 ) +1 ; -} -int __init pcibios_map_platform_irq (struct pci_dev *dev,u8 slot,u8 pin) {int result =-1 ;
@@ -42,7 +37,7 @@ int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)while (dev->bus->number >0 ) { slot = path[i].slot =PCI_SLOT (dev->devfn); - pin = path[i].pin =bridge_swizzle (pin, slot); + pin = path[i].pin =pci_swizzle_interrupt_pin (dev, pin); dev = dev->bus->self; i++;if (i >3 )panic ("PCI path to root bus too long!\n" );
@@ -56,7 +51,7 @@ int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)if ((slot <3 ) || (i ==0 )) {/* Bus 0 (incl. PCI-PCI bridge itself) : perform the final swizzle now. */ - result =IRQ_INTA +bridge_swizzle (pin, slot) -1 ; + result =IRQ_INTA +pci_swizzle_interrupt_pin (dev, pin) -1 ; }else { i--; slot = path[i].slot;
arch/sh/drivers/pci/pci.c +1 -6
@@ -21,17 +21,12 @@#include <linux/init.h> #include <asm/io.h> -static inline u8 bridge_swizzle (u8 pin,u8 slot) -{ -return (((pin -1 ) + slot) %4 ) +1 ; -} -static u8 __init simple_swizzle (struct pci_dev *dev,u8 *pinp) {u8 pin = *pinp;while (dev->bus->parent) { - pin =bridge_swizzle (pin,PCI_SLOT (dev->devfn)); + pin =pci_swizzle_interrupt_pin (dev, pin);/* Move up the chain of bridges. */ dev = dev->bus->self; }
Re: [PATCH 11/12] PCI: sh: use generic pci_swizzle_interrupt_pin()
Quoted 3 lines · Bjorn Helgaas
Use the generic
pci_swizzle_interrupt_pin()instead of arch-specific code.Signed-off-by Bjorn Helgaas <[email protected]>
Looks good, thanks.
PATCH 12/12 PCI: x86: use generic pci_swizzle_interrupt_pin()
In reply to Bjorn HelgaasUse the generic pci_swizzle_interrupt_pin() instead of arch-specific code.
--- arch/x86/pci/irq.c | 4 ++-- arch/x86/pci/visws.c | 7 +------ 2 files changed, 3 insertions(+), 8 deletions(-)
arch/x86/pci/irq.c +2 -2
@@ -1069,7 +1069,7 @@ static void __init pcibios_fixup_irqs(void)struct pci_dev *bridge = dev->bus->self;int bus; - pin = (((pin -1 ) +PCI_SLOT (dev->devfn)) %4 ) +1 ; + pin =pci_swizzle_interrupt_pin (dev, pin); bus = bridge->bus->number; irq =IO_APIC_get_PCI_irq_vector (bus,PCI_SLOT (bridge->devfn), pin -1 );
@@ -1233,7 +1233,7 @@ static int pirq_enable_irq(struct pci_dev *dev)while (irq <0 && dev->bus->parent) {/* go back to the bridge */ struct pci_dev *bridge = dev->bus->self; - pin = (((pin -1 ) +PCI_SLOT (dev->devfn)) %4 ) +1 ; + pin =pci_swizzle_interrupt_pin (dev, pin); irq =IO_APIC_get_PCI_irq_vector (bridge->bus->number,PCI_SLOT (bridge->devfn), pin -1 );if (irq >=0 )
arch/x86/pci/visws.c +1 -6
@@ -25,17 +25,12 @@ static void pci_visws_disable_irq(struct pci_dev *dev) { }unsigned int pci_bus0, pci_bus1; -static inline u8 bridge_swizzle (u8 pin,u8 slot) -{ -return (((pin -1 ) + slot) %4 ) +1 ; -} -static u8 __init visws_swizzle (struct pci_dev *dev,u8 *pinp) {u8 pin = *pinp;while (dev->bus->self) {/* Move up the chain of bridges. */ - pin =bridge_swizzle (pin,PCI_SLOT (dev->devfn)); + pin =pci_swizzle_interrupt_pin (dev, pin); dev = dev->bus->self; } *pinp = pin;
Jesse Barnes
AppliedQuoted 7 lines · Bjorn Helgaas
This series adds a
pci_swizzle_interrupt_pin()function in the PCI core. Most architectures currently implement this independently.After this series, many of the callers of
pci_swizzle_interrupt_pin()follow a similar pattern. I'd like to consolidate those callers, too, but I haven't started that yet.
Quoted 5 lines
One strange thing I'd like to understand eventually is why the swizzle in
acpi_pci_irq_derive()does something special for CardBus bridges, while no other architecture does.Comments welcome.
Applied the series to my linux-next branch, thanks a lot for unifying this.
Jesse