Commit 47a650f2 authored by Matthew Minter's avatar Matthew Minter Committed by Bjorn Helgaas

PCI: Add pci_assign_irq() function and have pci_fixup_irqs() use it

Here we delete the static pdev_fixup_irq() function which is currently what
pci_fixup_irqs() uses to actually assign the IRQs and replace it with the
pci_assign_irq() function which changes the interface and uses the new
function pointers stored in the host bridge structure.

Eventually this will allow pci_fixup_irqs() to be removed entirely and the
new deferred assignment code path will call pci_assign_irq() directly.
However to ensure current users continue to work, a new implementation of
pci_fixup_irqs() is introduced which simply wraps the functionality of
pci_assign_irq().
Signed-off-by: default avatarMatthew Minter <matt@masarand.com>
[lorenzo.pieralisi@arm.com: reworked comments/log]
Signed-off-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
parent 3aa8a41e
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/cache.h> #include <linux/cache.h>
#include "pci.h"
void __weak pcibios_update_irq(struct pci_dev *dev, int irq) void __weak pcibios_update_irq(struct pci_dev *dev, int irq)
{ {
...@@ -22,12 +23,17 @@ void __weak pcibios_update_irq(struct pci_dev *dev, int irq) ...@@ -22,12 +23,17 @@ void __weak pcibios_update_irq(struct pci_dev *dev, int irq)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
} }
static void pdev_fixup_irq(struct pci_dev *dev, void pci_assign_irq(struct pci_dev *dev)
u8 (*swizzle)(struct pci_dev *, u8 *),
int (*map_irq)(const struct pci_dev *, u8, u8))
{ {
u8 pin, slot; u8 pin;
u8 slot = -1;
int irq = 0; int irq = 0;
struct pci_host_bridge *hbrg = pci_find_host_bridge(dev->bus);
if (!(hbrg->map_irq)) {
dev_dbg(&dev->dev, "runtime IRQ mapping not provided by arch\n");
return;
}
/* If this device is not on the primary bus, we need to figure out /* If this device is not on the primary bus, we need to figure out
which interrupt pin it will come in on. We know which slot it which interrupt pin it will come in on. We know which slot it
...@@ -40,17 +46,22 @@ static void pdev_fixup_irq(struct pci_dev *dev, ...@@ -40,17 +46,22 @@ static void pdev_fixup_irq(struct pci_dev *dev,
if (pin > 4) if (pin > 4)
pin = 1; pin = 1;
if (pin != 0) { if (pin) {
/* Follow the chain of bridges, swizzling as we go. */ /* Follow the chain of bridges, swizzling as we go. */
slot = (*swizzle)(dev, &pin); if (hbrg->swizzle_irq)
slot = (*(hbrg->swizzle_irq))(dev, &pin);
irq = (*map_irq)(dev, slot, pin); /*
* If a swizzling function is not used map_irq must
* ignore slot
*/
irq = (*(hbrg->map_irq))(dev, slot, pin);
if (irq == -1) if (irq == -1)
irq = 0; irq = 0;
} }
dev->irq = irq; dev->irq = irq;
dev_dbg(&dev->dev, "fixup irq: got %d\n", dev->irq); dev_dbg(&dev->dev, "assign IRQ: got %d\n", dev->irq);
/* Always tell the device, so the driver knows what is /* Always tell the device, so the driver knows what is
the real IRQ to use; the device does not use it. */ the real IRQ to use; the device does not use it. */
...@@ -60,9 +71,23 @@ static void pdev_fixup_irq(struct pci_dev *dev, ...@@ -60,9 +71,23 @@ static void pdev_fixup_irq(struct pci_dev *dev,
void pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *), void pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
int (*map_irq)(const struct pci_dev *, u8, u8)) int (*map_irq)(const struct pci_dev *, u8, u8))
{ {
/*
* Implement pci_fixup_irqs() through pci_assign_irq().
* This code should be remove eventually, it is a wrapper
* around pci_assign_irq() interface to keep current
* pci_fixup_irqs() behaviour unchanged on architecture
* code still relying on its interface.
*/
struct pci_dev *dev = NULL; struct pci_dev *dev = NULL;
struct pci_host_bridge *hbrg = NULL;
for_each_pci_dev(dev) for_each_pci_dev(dev) {
pdev_fixup_irq(dev, swizzle, map_irq); hbrg = pci_find_host_bridge(dev->bus);
hbrg->swizzle_irq = swizzle;
hbrg->map_irq = map_irq;
pci_assign_irq(dev);
hbrg->swizzle_irq = NULL;
hbrg->map_irq = NULL;
}
} }
EXPORT_SYMBOL_GPL(pci_fixup_irqs); EXPORT_SYMBOL_GPL(pci_fixup_irqs);
...@@ -1147,6 +1147,7 @@ void pdev_enable_device(struct pci_dev *); ...@@ -1147,6 +1147,7 @@ void pdev_enable_device(struct pci_dev *);
int pci_enable_resources(struct pci_dev *, int mask); int pci_enable_resources(struct pci_dev *, int mask);
void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *), void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
int (*)(const struct pci_dev *, u8, u8)); int (*)(const struct pci_dev *, u8, u8));
void pci_assign_irq(struct pci_dev *dev);
struct resource *pci_find_resource(struct pci_dev *dev, struct resource *res); struct resource *pci_find_resource(struct pci_dev *dev, struct resource *res);
#define HAVE_PCI_REQ_REGIONS 2 #define HAVE_PCI_REQ_REGIONS 2
int __must_check pci_request_regions(struct pci_dev *, const char *); int __must_check pci_request_regions(struct pci_dev *, const char *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment