Skip to contentSkip to conversation

PCI: use common INTx swizzling loop

PATCH In review Bjorn Helgaas 2 participants 8 messages Dec 17, 2008 – Jan 5, 2009

Subsystems (7)
Arm (32-bit) x86 PCI MIPS +3 more subsystems
lore
Share & tools
lore
#0 lore raw

cover PCI: use common INTx swizzling loop

This series adds a pci_common_swizzle() function in the PCI core and changes several architectures to use it instead of architecture-specific code.

Comments welcome.

Bjorn
---

Bjorn Helgaas (6):
PCI: x86/visws: use generic INTx swizzle from PCI core
PCI: sh: use generic INTx swizzle from PCI core
PCI: mips: use generic INTx swizzle from PCI core
PCI: arm: use generic INTx swizzle from PCI core
PCI: alpha: use generic INTx swizzle from PCI core
PCI: add pci_common_swizzle() for INTx swizzling

 arch/alpha/kernel/pci.c         |   18 ------------------
 arch/alpha/kernel/pci_impl.h    |    4 ++--
 arch/arm/include/asm/mach/pci.h |    2 +-
 arch/arm/kernel/bios32.c        |   27 ---------------------------
 arch/mips/pci/pci.c             |   17 +----------------
 arch/sh/drivers/pci/pci.c       |   17 +----------------
 arch/x86/pci/visws.c            |   15 +--------------
 drivers/pci/pci.c               |   20 ++++++++++++++++++++
 include/linux/pci.h             |    1 +
 9 files changed, 27 insertions(+), 94 deletions(-)
#1 lore raw

PATCH 1/6 PCI: add pci_common_swizzle() for INTx swizzling

This patch adds pci_common_swizzle(), which swizzles INTx values all the way up to a root bridge.

This common implementation can replace several architecture-specific ones. This should someday be combined with pci_get_interrupt_pin(), but I left it separate for now to make reviewing easier.

---
 drivers/pci/pci.c   |   20 ++++++++++++++++++++
 include/linux/pci.h |    1 +
 2 files changed, 21 insertions(+), 0 deletions(-)
drivers/pci/pci.c +20 -0
index 388a32a..6988089 100644
@@ -1369,6 +1369,26 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
 }
 
 /**
+ * pci_common_swizzle - swizzle INTx all the way to root bridge
+ * @dev: the PCI device
+ * @pinp: pointer to the INTx pin value (1=INTA, 2=INTB, 3=INTD, 4=INTD)
+ *
+ * Perform INTx swizzling for a device.  This traverses through all PCI-to-PCI
+ * bridges all the way up to a PCI root bus.
+ */
+u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp)
+{
+	u8 pin = *pinp;
+
+	while (dev->bus->self) {
+		pin = pci_swizzle_interrupt_pin(dev, pin);
+		dev = dev->bus->self;
+	}
+	*pinp = pin;
+	return PCI_SLOT(dev->devfn);
+}
+
+/**
  *	pci_release_region - Release a PCI bar
  *	@pdev: PCI device whose resources were previously reserved by pci_request_region
  *	@bar: BAR to release
include/linux/pci.h +1 -0
index 4be596f..e89d0b7 100644
@@ -529,6 +529,7 @@ 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);
+u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp);
 extern struct pci_dev *pci_dev_get(struct pci_dev *dev);
 extern void pci_dev_put(struct pci_dev *dev);
 extern void pci_remove_bus(struct pci_bus *b);
#2 lore raw

Re: [PATCH 1/6] PCI: add pci_common_swizzle() for INTx swizzling

Quoted 8 lines · Bjorn Helgaas

This patch adds pci_common_swizzle(), which swizzles INTx values all the way up to a root bridge.

This common implementation can replace several architecture-specific ones. This should someday be combined with pci_get_interrupt_pin(), but I left it separate for now to make reviewing easier.

We got acks from the arch maintainers on the previous series, so I'm assuming these ones are ok too (please pipe up if not, they're in my linux-next queue).

Thanks,

Signature · 1 line
Jesse Barnes, Intel Open Source Technology Center
#3 lore raw

PATCH 2/6 PCI: alpha: use generic INTx swizzle from PCI core

In reply to Bjorn Helgaas

Use the generic pci_common_swizzle() instead of arch-specific code.

Note that pci_common_swizzle() loops based on dev->bus->self, not dev->bus->parent as the alpha common_swizzle() did. I think they are equivalent for this purpose.

---
 arch/alpha/kernel/pci.c      |   18 ------------------
 arch/alpha/kernel/pci_impl.h |    4 ++--
 2 files changed, 2 insertions(+), 20 deletions(-)
arch/alpha/kernel/pci.c +0 -18
index b03d9f4..a3b9388 100644
@@ -320,24 +320,6 @@ pcibios_update_irq(struct pci_dev *dev, int irq)
 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
 
-/* Most Alphas have straight-forward swizzling needs.  */
-
-u8 __init
-common_swizzle(struct pci_dev *dev, u8 *pinp)
-{
-	u8 pin = *pinp;
-
-	while (dev->bus->parent) {
-		pin = pci_swizzle_interrupt_pin(dev, pin);
-		/* Move up the chain of bridges. */
-		dev = dev->bus->self;
-        }
-	*pinp = pin;
-
-	/* The slot is the slot of the last bridge. */
-	return PCI_SLOT(dev->devfn);
-}
-
 void
 pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
 			 struct resource *res)
arch/alpha/kernel/pci_impl.h +2 -2
index 7336651..00edd04 100644
@@ -107,7 +107,7 @@ struct pci_iommu_arena;
  *   Thus, each swizzle is ((pin-1) + (device#-4)) % 4
  *
  *   pci_swizzle_interrupt_pin() swizzles for exactly one bridge.  The routine
- *   common_swizzle below handles multiple bridges.  But there are a
+ *   pci_common_swizzle() handles multiple bridges.  But there are a
  *   couple boards that do strange things.
  */
 
@@ -179,7 +179,7 @@ extern int pci_probe_only;
 extern unsigned long alpha_agpgart_size;
 
 extern void common_init_pci(void);
-extern u8 common_swizzle(struct pci_dev *, u8 *);
+#define common_swizzle pci_common_swizzle
 extern struct pci_controller *alloc_pci_controller(void);
 extern struct resource *alloc_resource(void);
 
#4 lore raw

PATCH 3/6 PCI: arm: use generic INTx swizzle from PCI core

In reply to Bjorn Helgaas

Use the generic pci_common_swizzle() instead of arch-specific code.

---
 arch/arm/include/asm/mach/pci.h |    2 +-
 arch/arm/kernel/bios32.c        |   27 ---------------------------
 2 files changed, 1 insertions(+), 28 deletions(-)
arch/arm/include/asm/mach/pci.h +1 -1
index 32da1ae..a38bdc7 100644
@@ -42,7 +42,7 @@ struct pci_sys_data {
 /*
  * This is the standard PCI-PCI bridge swizzling algorithm.
  */
-u8 pci_std_swizzle(struct pci_dev *dev, u8 *pinp);
+#define pci_std_swizzle pci_common_swizzle
 
 /*
  * Call this with your hw_pci struct to initialise the PCI system.
arch/arm/kernel/bios32.c +0 -27
index 5c5a0bc..8096819 100644
@@ -480,33 +480,6 @@ EXPORT_SYMBOL(pcibios_bus_to_resource);
 #endif
 
 /*
- * This is the standard PCI-PCI bridge swizzling algorithm:
- *
- *   Dev: 0  1  2  3
- *    A   A  B  C  D
- *    B   B  C  D  A
- *    C   C  D  A  B
- *    D   D  A  B  C
- *        ^^^^^^^^^^ irq pin on bridge
- */
-u8 __devinit pci_std_swizzle(struct pci_dev *dev, u8 *pinp)
-{
-	int pin = *pinp;
-
-	while (dev->bus->self) {
-		pin = pci_swizzle_interrupt_pin(dev, pin);
-		/*
-		 * move up the chain of bridges,
-		 * swizzling as we go.
-		 */
-		dev = dev->bus->self;
-	}
-	*pinp = pin;
-
-	return PCI_SLOT(dev->devfn);
-}
-
-/*
  * Swizzle the device pin each time we cross a bridge.
  * This might update pin and returns the slot number.
  */
#5 lore raw

PATCH 4/6 PCI: mips: use generic INTx swizzle from PCI core

In reply to Bjorn Helgaas

Use the generic pci_common_swizzle() instead of arch-specific code.

Note that pci_common_swizzle() loops based on dev->bus->self, not dev->bus->parent as the mips common_swizzle() did. I think they are equivalent for this purpose.

---
 arch/mips/pci/pci.c |   17 +----------------
 1 files changed, 1 insertions(+), 16 deletions(-)
arch/mips/pci/pci.c +1 -16
index fa63dc2..b0eb9e7 100644
@@ -149,21 +149,6 @@ out:
 	       "Skipping PCI bus scan due to resource conflict\n");
 }
 
-static u8 __init common_swizzle(struct pci_dev *dev, u8 *pinp)
-{
-	u8 pin = *pinp;
-
-	while (dev->bus->parent) {
-		pin = pci_swizzle_interrupt_pin(dev, pin);
-		/* Move up the chain of bridges. */
-		dev = dev->bus->self;
-        }
-	*pinp = pin;
-
-	/* The slot is the slot of the last bridge. */
-	return PCI_SLOT(dev->devfn);
-}
-
 static int __init pcibios_init(void)
 {
 	struct pci_controller *hose;
@@ -172,7 +157,7 @@ static int __init pcibios_init(void)
 	for (hose = hose_head; hose; hose = hose->next)
 		pcibios_scanbus(hose);
 
-	pci_fixup_irqs(common_swizzle, pcibios_map_irq);
+	pci_fixup_irqs(pci_common_swizzle, pcibios_map_irq);
 
 	pci_initialized = 1;
 
#6 lore raw

PATCH 5/6 PCI: sh: use generic INTx swizzle from PCI core

In reply to Bjorn Helgaas

Use the generic pci_common_swizzle() instead of arch-specific code.

Note that pci_common_swizzle() loops based on dev->bus->self, not dev->bus->parent as the sh simple_swizzle() did. I think they are equivalent for this purpose.

---
 arch/sh/drivers/pci/pci.c |   17 +----------------
 1 files changed, 1 insertions(+), 16 deletions(-)
arch/sh/drivers/pci/pci.c +1 -16
index aea3b6b..e36c7b8 100644
@@ -21,21 +21,6 @@
 #include <linux/init.h>
 #include <asm/io.h>
 
-static u8 __init simple_swizzle(struct pci_dev *dev, u8 *pinp)
-{
-	u8 pin = *pinp;
-
-	while (dev->bus->parent) {
-		pin = pci_swizzle_interrupt_pin(dev, pin);
-		/* Move up the chain of bridges. */
-		dev = dev->bus->self;
-	}
-	*pinp = pin;
-
-	/* The slot is the slot of the last bridge. */
-	return PCI_SLOT(dev->devfn);
-}
-
 static int __init pcibios_init(void)
 {
 	struct pci_channel *p;
@@ -56,7 +41,7 @@ static int __init pcibios_init(void)
 		busno = bus->subordinate + 1;
 	}
 
-	pci_fixup_irqs(simple_swizzle, pcibios_map_platform_irq);
+	pci_fixup_irqs(pci_common_swizzle, pcibios_map_platform_irq);
 
 	return 0;
 }
#7 lore raw

PATCH 6/6 PCI: x86/visws: use generic INTx swizzle from PCI core

In reply to Bjorn Helgaas

Use the generic pci_common_swizzle() instead of arch-specific code.

---
 arch/x86/pci/visws.c |   15 +--------------
 1 files changed, 1 insertions(+), 14 deletions(-)
arch/x86/pci/visws.c +1 -14
index 6b5ed3d..fd7b76f 100644
@@ -25,19 +25,6 @@ static void pci_visws_disable_irq(struct pci_dev *dev) { }
 
 unsigned int pci_bus0, pci_bus1;
 
-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 = pci_swizzle_interrupt_pin(dev, pin);
-		dev = dev->bus->self;
-	}
-	*pinp = pin;
-
-	return PCI_SLOT(dev->devfn);
-}
-
 static int __init visws_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 {
 	int irq, bus = dev->bus->number;
@@ -102,7 +89,7 @@ int __init pci_visws_init(void)
 	raw_pci_ops = &pci_direct_conf1;
 	pci_scan_bus_with_sysdata(pci_bus0);
 	pci_scan_bus_with_sysdata(pci_bus1);
-	pci_fixup_irqs(visws_swizzle, visws_map_irq);
+	pci_fixup_irqs(pci_common_swizzle, visws_map_irq);
 	pcibios_resource_survey();
 	return 0;
 }