Discussion:
[PATCH 11/18] Delayed mips setup of PCI IRQs to bus scan time
m***@masarand.com
2014-10-02 03:50:30 UTC
Permalink
From: Matthew Minter <***@masarand.com>

Currently mips PCI IRQs are assigned at boot, this creates an extra
pass over the PCI bus and causes hot-plugged devices which are not
present at boot to not be given IRQs, this patch set fixes this by
registering assignment functions which are then run later during the
device enable code path.

---
arch/mips/pci/pci.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index 1bf60b1..dc660a0 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -242,13 +242,18 @@ static int __init pcibios_init(void)
for (hose = hose_head; hose; hose = hose->next)
pcibios_scanbus(hose);

- pci_fixup_irqs(pci_common_swizzle, pcibios_map_irq);
-
pci_initialized = 1;

return 0;
}

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pci_common_swizzle;
+ bridge->map_irq = pcibios_map_irq;
+ return 0;
+}
+
subsys_initcall(pcibios_init);

static int pcibios_enable_resources(struct pci_dev *dev, int mask)
--
2.1.0
m***@masarand.com
2014-10-02 03:50:27 UTC
Permalink
From: Matthew Minter <***@masarand.com>

PCI IRQs are being assigned during the frv pcibios phase. This causes
devices which are not connected at boot but are later hot-plugged
to not receive an IRQ. This patch set causes the pcibios to instead
register an IRQ assignment function which is called during the enable
device path to apply to all devices.

---
arch/frv/mb93090-mb00/pci-frv.h | 1 -
arch/frv/mb93090-mb00/pci-irq.c | 28 +++++++++++++++++-----------
arch/frv/mb93090-mb00/pci-vdk.c | 1 -
3 files changed, 17 insertions(+), 13 deletions(-)

diff --git a/arch/frv/mb93090-mb00/pci-frv.h b/arch/frv/mb93090-mb00/pci-frv.h
index a7e487fe..492b56d 100644
--- a/arch/frv/mb93090-mb00/pci-frv.h
+++ b/arch/frv/mb93090-mb00/pci-frv.h
@@ -36,5 +36,4 @@ extern struct pci_ops *__nongpreldata pci_root_ops;
extern unsigned int pcibios_irq_mask;

void pcibios_irq_init(void);
-void pcibios_fixup_irqs(void);
void pcibios_enable_irq(struct pci_dev *dev);
diff --git a/arch/frv/mb93090-mb00/pci-irq.c b/arch/frv/mb93090-mb00/pci-irq.c
index 1c35c93..3463e30 100644
--- a/arch/frv/mb93090-mb00/pci-irq.c
+++ b/arch/frv/mb93090-mb00/pci-irq.c
@@ -40,19 +40,25 @@ void __init pcibios_irq_init(void)
{
}

-void __init pcibios_fixup_irqs(void)
+int pcibios_map_irq(struct pci_dev *dev, uint8_t slot, uint8_t pin)
{
- struct pci_dev *dev = NULL;
- uint8_t line, pin;
-
- for_each_pci_dev(dev) {
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
- if (pin) {
- dev->irq = pci_bus0_irq_routing[PCI_SLOT(dev->devfn)][pin - 1];
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
- }
- pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line);
+ uint8_t line;
+ int irq;
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ if (pin) {
+ irq = pci_bus0_irq_routing[PCI_SLOT(dev->devfn)][pin - 1];
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
+ pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line);
+ return irq;
+}
+
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pcibios_map_irq;
+ return 0;
}

void pcibios_enable_irq(struct pci_dev *dev)
diff --git a/arch/frv/mb93090-mb00/pci-vdk.c b/arch/frv/mb93090-mb00/pci-vdk.c
index efa5d65..86657a7 100644
--- a/arch/frv/mb93090-mb00/pci-vdk.c
+++ b/arch/frv/mb93090-mb00/pci-vdk.c
@@ -386,7 +386,6 @@ int __init pcibios_init(void)
pci_scan_root_bus(NULL, 0, pci_root_ops, NULL, &resources);

pcibios_irq_init();
- pcibios_fixup_irqs();
pcibios_resource_survey();

return 0;
--
2.1.0
m***@masarand.com
2014-10-02 03:50:36 UTC
Permalink
From: Vality <***@masarand.com>

Most of the architectures are switched to allocating IRQs at device_enable
time instead of boot time, however parisc does not provide an easy way of
making that transition so the new code is disabled here on parisc.

---
arch/parisc/kernel/pci.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c
index 64f2764..9654c69 100644
--- a/arch/parisc/kernel/pci.c
+++ b/arch/parisc/kernel/pci.c
@@ -105,7 +105,13 @@ PCI_PORT_OUT(b, 8)
PCI_PORT_OUT(w, 16)
PCI_PORT_OUT(l, 32)

-
+/* We do not support hot-add irq assignment */
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = NULL;
+ return 0;
+}

/*
* BIOS32 replacement.
--
2.1.0
m***@masarand.com
2014-10-02 03:50:25 UTC
Permalink
From: Vality <***@masarand.com>

PCI IRQ initialisation is currently run during the boot code on alpha,
this has the issue that firstly an extra pass over the PCI bus is
required and second hot-plugged devices which are added after boot have
no way to be assigned an IRQ. This patch set fixes this by defering the
assignment of PCI IRQs untill device enable time which should solve
both of these issues.

---
arch/alpha/kernel/pci.c | 16 ++++++++++------
arch/alpha/kernel/sys_nautilus.c | 1 -
2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index 076c35c..338537c 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -28,7 +28,7 @@


/*
- * Some string constants used by the various core logics.
+ * Some string constants used by the various core logics.
*/

const char *const pci_io_names[] = {
@@ -247,7 +247,7 @@ void pcibios_fixup_bus(struct pci_bus *bus)
if (pci_has_flag(PCI_PROBE_ONLY) && dev &&
(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
pci_read_bridge_bases(bus);
- }
+ }

list_for_each_entry(dev, &bus->devices, bus_list) {
pdev_save_srm_config(dev);
@@ -338,7 +338,7 @@ common_init_pci(void)
hose->need_domain_info = need_domain_info;
next_busno = bus->busn_res.end + 1;
/* Don't allow 8-bit bus number overflow inside the hose -
- reserve some space for bridges. */
+ reserve some space for bridges. */
if (next_busno > 224) {
next_busno = 0;
need_domain_info = 1;
@@ -346,11 +346,15 @@ common_init_pci(void)
}

pcibios_claim_console_setup();
-
pci_assign_unassigned_resources();
- pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
}

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = alpha_mv.pci_swizzle;
+ bridge->map_irq = alpha_mv.pci_map_irq;
+ return 0;
+}

struct pci_controller * __init
alloc_pci_controller(void)
@@ -387,7 +391,7 @@ sys_pciconfig_iobase(long which, unsigned long bus, unsigned long dfn)

/* from hose or from bus.devfn */
if (which & IOBASE_FROM_HOSE) {
- for(hose = hose_head; hose; hose = hose->next)
+ for(hose = hose_head; hose; hose = hose->next)
if (hose->index == bus) break;
if (!hose) return -ENODEV;
} else {
diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c
index 837c0fa..7fb4d51 100644
--- a/arch/alpha/kernel/sys_nautilus.c
+++ b/arch/alpha/kernel/sys_nautilus.c
@@ -252,7 +252,6 @@ nautilus_init_pci(void)
/* pci_common_swizzle() relies on bus->self being NULL
for the root bus, so just clear it. */
bus->self = NULL;
- pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
}

/*
--
2.1.0
m***@masarand.com
2014-10-02 03:50:22 UTC
Permalink
From: Vality <***@masarand.com>

Currently PCI device IRQs under arm are initialised during the
pci_common_init_dev code path, this results in an extra sweep of the
PCI bus as well as causing PCI devices hot-plugged after boot to not
receive an IRQ.

This patch set defers this assignment untill the device enable phase
which prevents both these issues.

---
arch/arm/kernel/bios32.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 17a26c1..4dcf3f7 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -389,7 +389,7 @@ void pcibios_remove_bus(struct pci_bus *bus)
* PCI standard swizzle is implemented on plug-in cards and Cardbus based
* PCI extenders, so it can not be ignored.
*/
-static u8 pcibios_swizzle(struct pci_dev *dev, u8 *pin)
+u8 pcibios_swizzle(struct pci_dev *dev, u8 *pin)
{
struct pci_sys_data *sys = dev->sysdata;
int slot, oldpin = *pin;
@@ -409,7 +409,7 @@ static u8 pcibios_swizzle(struct pci_dev *dev, u8 *pin)
/*
* Map a slot/pin to an IRQ.
*/
-static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+int pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
struct pci_sys_data *sys = dev->sysdata;
int irq = -1;
@@ -424,6 +424,13 @@ static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
return irq;
}

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pcibios_swizzle;
+ bridge->map_irq = pcibios_map_irq;
+ return 0;
+}
+
static int pcibios_init_resources(int busnr, struct pci_sys_data *sys)
{
int ret;
@@ -523,8 +530,6 @@ void pci_common_init_dev(struct device *parent, struct hw_pci *hw)
if (hw->postinit)
hw->postinit();

- pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq);
-
list_for_each_entry(sys, &head, node) {
struct pci_bus *bus = sys->bus;
--
2.1.0
m***@masarand.com
2014-10-02 03:50:20 UTC
Permalink
From: Vality <***@masarand.com>

These are the main infrastructure changes to allow the registration of
PCI IRQ assignment functions which can then be called during the device
enabling stage. This replaces the pre-initialisation of PCI IRQs at boot
time which caused limitations such as failing for devices which are
hot-plugged after the machine has booted and resulted in highly
fragmented PCI initialisation paths.

The pdev_assign_irq function becomes a centralised method of assigning
IRQs to PCI devices in a non platform specific way. The pci_host_bridge
structure has had some function pointers added to it where the boot code
can register the platform specific ways of assigning PCI IRQs to be used
to allow them to be used by pdev_assign_irq.

Some small adjustements have also been made to makefiles in order to
accomodate these changes.

Note this code completely obsolites the pci_fixup_irqs code path which
has thus been removed.

---
drivers/of/of_pci_irq.c | 2 +-
drivers/pci/Makefile | 15 ++-------------
drivers/pci/host-bridge.c | 2 +-
drivers/pci/pci.c | 5 ++++-
drivers/pci/pci.h | 1 +
drivers/pci/probe.c | 12 ------------
drivers/pci/setup-irq.c | 34 ++++++++++++++++------------------
include/linux/pci.h | 6 ++++--
8 files changed, 29 insertions(+), 48 deletions(-)

diff --git a/drivers/of/of_pci_irq.c b/drivers/of/of_pci_irq.c
index 1710d9d..205eb7a 100644
--- a/drivers/of/of_pci_irq.c
+++ b/drivers/of/of_pci_irq.c
@@ -97,7 +97,7 @@ EXPORT_SYMBOL_GPL(of_irq_parse_pci);
* @pin: PCI irq pin number; passed when used as map_irq callback. Unused
*
* @slot and @pin are unused, but included in the function so that this
- * function can be used directly as the map_irq callback to pci_fixup_irqs().
+ * function can be used directly as the map_irq callback to pdev_assign_irq().
*/
int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin)
{
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index e04fe2d..38c4cb0 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -4,7 +4,8 @@

obj-y += access.o bus.o probe.o host-bridge.o remove.o pci.o \
pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \
- irq.o vpd.o setup-bus.o vc.o
+ irq.o vpd.o setup-bus.o vc.o setup-irq.o
+
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSFS) += slot.o

@@ -31,18 +32,6 @@ obj-$(CONFIG_PCI_ATS) += ats.o
obj-$(CONFIG_PCI_IOV) += iov.o

#
-# Some architectures use the generic PCI setup functions
-#
-obj-$(CONFIG_ALPHA) += setup-irq.o
-obj-$(CONFIG_ARM) += setup-irq.o
-obj-$(CONFIG_UNICORE32) += setup-irq.o
-obj-$(CONFIG_SUPERH) += setup-irq.o
-obj-$(CONFIG_MIPS) += setup-irq.o
-obj-$(CONFIG_TILE) += setup-irq.o
-obj-$(CONFIG_SPARC_LEON) += setup-irq.o
-obj-$(CONFIG_M68K) += setup-irq.o
-
-#
# ACPI Related PCI FW Functions
# ACPI _DSM provided firmware instance and string name
#
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
index 0e5f3c9..8ed186f 100644
--- a/drivers/pci/host-bridge.c
+++ b/drivers/pci/host-bridge.c
@@ -16,7 +16,7 @@ static struct pci_bus *find_pci_root_bus(struct pci_bus *bus)
return bus;
}

-static struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus)
+struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus)
{
struct pci_bus *root_bus = find_pci_root_bus(bus);

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 2c9ac70..2dd28d9 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1192,11 +1192,15 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
struct pci_dev *bridge;
u16 cmd;
u8 pin;
+ struct pci_host_bridge *hbrg = find_pci_host_bridge(dev->bus);

err = pci_set_power_state(dev, PCI_D0);
if (err < 0 && err != -EIO)
return err;

+ pdev_assign_irq(dev, hbrg->swizzle_irq, hbrg->map_irq);
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+
bridge = pci_upstream_bridge(dev);
if (bridge)
pcie_aspm_powersave_config_link(bridge);
@@ -1209,7 +1213,6 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
if (dev->msi_enabled || dev->msix_enabled)
return 0;

- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (pin) {
pci_read_config_word(dev, PCI_COMMAND, &cmd);
if (cmd & PCI_COMMAND_INTX_DISABLE)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 0601890..a6cf445 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -70,6 +70,7 @@ void pci_config_pm_runtime_put(struct pci_dev *dev);
void pci_pm_init(struct pci_dev *dev);
void pci_allocate_cap_save_buffers(struct pci_dev *dev);
void pci_free_cap_save_buffers(struct pci_dev *dev);
+struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus);

static inline void pci_wakeup_event(struct pci_dev *dev)
{
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 4170113..314e9e3 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1719,18 +1719,6 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
}
EXPORT_SYMBOL_GPL(pci_scan_child_bus);

-/**
- * pcibios_root_bridge_prepare - Platform-specific host bridge setup.
- * @bridge: Host bridge to set up.
- *
- * Default empty implementation. Replace with an architecture-specific setup
- * routine, if necessary.
- */
-int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
-{
- return 0;
-}
-
void __weak pcibios_add_bus(struct pci_bus *bus)
{
}
diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c
index 4e2d595..203bf7e 100644
--- a/drivers/pci/setup-irq.c
+++ b/drivers/pci/setup-irq.c
@@ -22,13 +22,19 @@ void __weak pcibios_update_irq(struct pci_dev *dev, int irq)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}

-static void pdev_fixup_irq(struct pci_dev *dev,
+void pdev_assign_irq(struct pci_dev *dev,
u8 (*swizzle)(struct pci_dev *, u8 *),
- int (*map_irq)(const struct pci_dev *, u8, u8))
+ int (*map_irq)(struct pci_dev *, u8, u8))
{
- u8 pin, slot;
+ u8 pin;
+ u8 slot = -1;
int irq = 0;

+ if (!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
which interrupt pin it will come in on. We know which slot it
will come in on 'cos that slot is where the bridge is. Each
@@ -40,28 +46,20 @@ static void pdev_fixup_irq(struct pci_dev *dev,
if (pin > 4)
pin = 1;

- if (pin != 0) {
- /* Follow the chain of bridges, swizzling as we go. */
- slot = (*swizzle)(dev, &pin);
+ if (pin) {
+ /* Follow the chain of bridges, swizzling as we go. */
+ if(swizzle)
+ slot = (*swizzle)(dev, &pin);

+ /* If a swizzling function is not used map_irq must ignore slot */
irq = (*map_irq)(dev, slot, pin);
if (irq == -1)
irq = 0;
}
- 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);
+ dev->irq = irq;
/* Always tell the device, so the driver knows what is
the real IRQ to use; the device does not use it. */
pcibios_update_irq(dev, irq);
}
-
-void pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
- int (*map_irq)(const struct pci_dev *, u8, u8))
-{
- struct pci_dev *dev = NULL;
-
- for_each_pci_dev(dev)
- pdev_fixup_irq(dev, swizzle, map_irq);
-}
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 96453f9..5426d11 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -403,6 +403,8 @@ struct pci_host_bridge {
struct device dev;
struct pci_bus *bus; /* root bus */
struct list_head windows; /* pci_host_bridge_windows */
+ u8 (*swizzle_irq)(struct pci_dev *, u8 *); /* platform irq swizzler */
+ int (*map_irq)(struct pci_dev *, u8, u8);
void (*release_fn)(struct pci_host_bridge *);
void *release_data;
};
@@ -1064,8 +1066,8 @@ void pci_assign_unassigned_bus_resources(struct pci_bus *bus);
void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus);
void pdev_enable_device(struct pci_dev *);
int pci_enable_resources(struct pci_dev *, int mask);
-void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
- int (*)(const struct pci_dev *, u8, u8));
+void pdev_assign_irq(struct pci_dev *dev, u8 (*swizzle)(struct pci_dev *, u8 *),
+ int (*map_irq)(struct pci_dev *, u8, u8));
#define HAVE_PCI_REQ_REGIONS 2
int __must_check pci_request_regions(struct pci_dev *, const char *);
int __must_check pci_request_regions_exclusive(struct pci_dev *, const char *);
--
2.1.0
m***@masarand.com
2014-10-02 03:50:26 UTC
Permalink
From: Matthew Minter <***@masarand.com>

PCI IRQs are currently configured to be enabled once at boot in a
dedicated pass. This means that PCI devices which are hot-plugged after
boot time will not be given an IRQ, this patch-set fixes this by
registering the assignment function to be called later in the device
enable path.

---
arch/cris/arch-v32/drivers/pci/bios.c | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/arch/cris/arch-v32/drivers/pci/bios.c b/arch/cris/arch-v32/drivers/pci/bios.c
index 64a5fb9..d04ecc8 100644
--- a/arch/cris/arch-v32/drivers/pci/bios.c
+++ b/arch/cris/arch-v32/drivers/pci/bios.c
@@ -80,20 +80,16 @@ int pcibios_enable_resources(struct pci_dev *dev, int mask)
return 0;
}

-int pcibios_enable_irq(struct pci_dev *dev)
+int pcibios_enable_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
dev->irq = EXT_INTR_VECT;
return 0;
}

-int pcibios_enable_device(struct pci_dev *dev, int mask)
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{
- int err;
-
- if ((err = pcibios_enable_resources(dev, mask)) < 0)
- return err;
-
- if (!dev->msi_enabled)
- pcibios_enable_irq(dev);
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pcibios_enable_irq;
return 0;
}
+
--
2.1.0
m***@masarand.com
2014-10-02 03:50:37 UTC
Permalink
From: Matthew Minter <***@masarand.com>

Most of the architectures are switched to allocating IRQs at device_enable
time instead of boot time, however s390 does not provide an easy way of
making that transition so the new code is disabled here on s390.

---
arch/s390/pci/pci.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 2fa7b14..720592f 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -434,6 +434,13 @@ out:
return rc;
}

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = NULL;
+ return 0;
+}
+
void arch_teardown_msi_irqs(struct pci_dev *pdev)
{
struct zpci_dev *zdev = get_zdev(pdev);
--
2.1.0
m***@masarand.com
2014-10-02 03:50:32 UTC
Permalink
From: Vality <***@masarand.com>

Currently sparc allocates PCI IRQs through several different methods
based on device. This is done during the boot stage and faces a draw-back
by which hot-plugged devices will not be allocated an IRQ, this is fixed
by registering IRQ allocation functions for later use during the device
enable path.

---
arch/sparc/kernel/leon_pci.c | 12 +++++++++++-
arch/sparc/kernel/pci.c | 21 +++++++++++++++++----
2 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c
index 899b720..1079eb7 100644
--- a/arch/sparc/kernel/leon_pci.c
+++ b/arch/sparc/kernel/leon_pci.c
@@ -13,6 +13,8 @@
#include <asm/leon.h>
#include <asm/leon_pci.h>

+int (*leon_pci_map_irq)(const struct pci_dev *dev, u8 slot, u8 pin);
+
/* The LEON architecture does not rely on a BIOS or bootloader to setup
* PCI for us. The Linux generic routines are used to setup resources,
* reset values of configuration-space register settings are preserved.
@@ -36,7 +38,7 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
&resources);
if (root_bus) {
/* Setup IRQs of all devices using custom routines */
- pci_fixup_irqs(pci_common_swizzle, info->map_irq);
+ leon_pci_map_irq = info->map_irq;

/* Assign devices with resources */
pci_assign_unassigned_resources();
@@ -45,6 +47,14 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
}
}

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pci_common_swizzle;
+ bridge->map_irq = leon_pci_map_irq;
+ return 0;
+}
+
+
void pcibios_fixup_bus(struct pci_bus *pbus)
{
struct pci_dev *dev;
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index b36365f..7361c52 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -340,10 +340,6 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
} else {
dev->hdr_type = PCI_HEADER_TYPE_NORMAL;
dev->rom_base_reg = PCI_ROM_ADDRESS;
-
- dev->irq = sd->op->archdata.irqs[0];
- if (dev->irq == 0xffffffff)
- dev->irq = PCI_IRQ_NONE;
}

pci_parse_of_addrs(sd->op, node, dev);
@@ -356,6 +352,23 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
return dev;
}

+int pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int irq;
+ struct platform_device *op = of_find_device_by_node(dev->sysdata);
+ irq = op->archdata.irqs[0];
+ if (irq == 0xffffffff)
+ irq = PCI_IRQ_NONE;
+ return irq;
+}
+
+int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pci_map_irq;
+ return 0;
+}
+
static void apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p)
{
u32 idx, first, last;
--
2.1.0
m***@masarand.com
2014-10-02 03:50:24 UTC
Permalink
From: Vality <***@masarand.com>

Currently platform specific PCI device IRQ assignment is run during
the boot code, this results in a wide array of differing code paths
and causes hot-plugged PCI devices to not be assigned IRQs, this
patch removes the boot time initialisation of such IRQs and instead
registers assignment functions to be run during the PCI device enable
plase.

---
arch/sh/drivers/pci/fixups-cayman.c | 2 +-
arch/sh/drivers/pci/fixups-dreamcast.c | 2 +-
arch/sh/drivers/pci/fixups-r7780rp.c | 2 +-
arch/sh/drivers/pci/fixups-rts7751r2d.c | 6 +++---
arch/sh/drivers/pci/fixups-sdk7780.c | 4 ++--
arch/sh/drivers/pci/fixups-se7751.c | 2 +-
arch/sh/drivers/pci/fixups-sh03.c | 2 +-
arch/sh/drivers/pci/fixups-snapgear.c | 2 +-
arch/sh/drivers/pci/fixups-titan.c | 4 ++--
arch/sh/drivers/pci/pci.c | 10 +++++++---
arch/sh/drivers/pci/pcie-sh7786.c | 2 +-
11 files changed, 21 insertions(+), 17 deletions(-)

diff --git a/arch/sh/drivers/pci/fixups-cayman.c b/arch/sh/drivers/pci/fixups-cayman.c
index edc2fb7..3246788 100644
--- a/arch/sh/drivers/pci/fixups-cayman.c
+++ b/arch/sh/drivers/pci/fixups-cayman.c
@@ -5,7 +5,7 @@
#include <cpu/irq.h>
#include "pci-sh5.h"

-int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
int result = -1;

diff --git a/arch/sh/drivers/pci/fixups-dreamcast.c b/arch/sh/drivers/pci/fixups-dreamcast.c
index 1d1c5a2..9d597f7 100644
--- a/arch/sh/drivers/pci/fixups-dreamcast.c
+++ b/arch/sh/drivers/pci/fixups-dreamcast.c
@@ -76,7 +76,7 @@ static void gapspci_fixup_resources(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, gapspci_fixup_resources);

-int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
/*
* The interrupt routing semantics here are quite trivial.
diff --git a/arch/sh/drivers/pci/fixups-r7780rp.c b/arch/sh/drivers/pci/fixups-r7780rp.c
index 57ed3f0..2c9b58f 100644
--- a/arch/sh/drivers/pci/fixups-r7780rp.c
+++ b/arch/sh/drivers/pci/fixups-r7780rp.c
@@ -15,7 +15,7 @@
#include <linux/sh_intc.h>
#include "pci-sh4.h"

-int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
return evt2irq(0xa20) + slot;
}
diff --git a/arch/sh/drivers/pci/fixups-rts7751r2d.c b/arch/sh/drivers/pci/fixups-rts7751r2d.c
index eaddb56..358ac10 100644
--- a/arch/sh/drivers/pci/fixups-rts7751r2d.c
+++ b/arch/sh/drivers/pci/fixups-rts7751r2d.c
@@ -20,18 +20,18 @@
#define PCIMCR_MRSET_OFF 0xBFFFFFFF
#define PCIMCR_RFSH_OFF 0xFFFFFFFB

-static u8 rts7751r2d_irq_tab[] __initdata = {
+static u8 rts7751r2d_irq_tab[] = {
IRQ_PCI_INTA,
IRQ_PCI_INTB,
IRQ_PCI_INTC,
IRQ_PCI_INTD,
};

-static char lboxre2_irq_tab[] __initdata = {
+static char lboxre2_irq_tab[] = {
IRQ_ETH0, IRQ_ETH1, IRQ_INTA, IRQ_INTD,
};

-int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
if (mach_is_lboxre2())
return lboxre2_irq_tab[slot];
diff --git a/arch/sh/drivers/pci/fixups-sdk7780.c b/arch/sh/drivers/pci/fixups-sdk7780.c
index c0a015a..24e96df 100644
--- a/arch/sh/drivers/pci/fixups-sdk7780.c
+++ b/arch/sh/drivers/pci/fixups-sdk7780.c
@@ -22,7 +22,7 @@
#define IRQ_INTD evt2irq(0xa80)

/* IDSEL [16][17][18][19][20][21][22][23][24][25][26][27][28][29][30][31] */
-static char sdk7780_irq_tab[4][16] __initdata = {
+static char sdk7780_irq_tab[4][16] = {
/* INTA */
{ IRQ_INTA, IRQ_INTD, IRQ_INTC, IRQ_INTD, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1 },
@@ -37,7 +37,7 @@ static char sdk7780_irq_tab[4][16] __initdata = {
-1, -1, -1 },
};

-int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
return sdk7780_irq_tab[pin-1][slot];
}
diff --git a/arch/sh/drivers/pci/fixups-se7751.c b/arch/sh/drivers/pci/fixups-se7751.c
index 84a88ca..1cb8d0a 100644
--- a/arch/sh/drivers/pci/fixups-se7751.c
+++ b/arch/sh/drivers/pci/fixups-se7751.c
@@ -7,7 +7,7 @@
#include <linux/sh_intc.h>
#include "pci-sh4.h"

-int __init pcibios_map_platform_irq(const struct pci_dev *, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *, u8 slot, u8 pin)
{
switch (slot) {
case 0: return evt2irq(0x3a0);
diff --git a/arch/sh/drivers/pci/fixups-sh03.c b/arch/sh/drivers/pci/fixups-sh03.c
index 16207be..55ac1ba 100644
--- a/arch/sh/drivers/pci/fixups-sh03.c
+++ b/arch/sh/drivers/pci/fixups-sh03.c
@@ -4,7 +4,7 @@
#include <linux/pci.h>
#include <linux/sh_intc.h>

-int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
int irq;

diff --git a/arch/sh/drivers/pci/fixups-snapgear.c b/arch/sh/drivers/pci/fixups-snapgear.c
index 6e33ba4..a931e59 100644
--- a/arch/sh/drivers/pci/fixups-snapgear.c
+++ b/arch/sh/drivers/pci/fixups-snapgear.c
@@ -19,7 +19,7 @@
#include <linux/sh_intc.h>
#include "pci-sh4.h"

-int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
int irq = -1;

diff --git a/arch/sh/drivers/pci/fixups-titan.c b/arch/sh/drivers/pci/fixups-titan.c
index bd1addb..a9d563e 100644
--- a/arch/sh/drivers/pci/fixups-titan.c
+++ b/arch/sh/drivers/pci/fixups-titan.c
@@ -19,7 +19,7 @@
#include <mach/titan.h>
#include "pci-sh4.h"

-static char titan_irq_tab[] __initdata = {
+static char titan_irq_tab[] = {
TITAN_IRQ_WAN,
TITAN_IRQ_LAN,
TITAN_IRQ_MPCIA,
@@ -27,7 +27,7 @@ static char titan_irq_tab[] __initdata = {
TITAN_IRQ_USB,
};

-int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
int irq = titan_irq_tab[slot];

diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index 1bc09ee..718fae3 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -141,16 +141,20 @@ static int __init pcibios_init(void)
for (hose = hose_head; hose; hose = hose->next)
pcibios_scanbus(hose);

- pci_fixup_irqs(pci_common_swizzle, pcibios_map_platform_irq);
-
dma_debug_add_bus(&pci_bus_type);
-
pci_initialized = 1;

return 0;
}
subsys_initcall(pcibios_init);

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pci_common_swizzle;
+ bridge->map_irq = pcibios_map_platform_irq;
+ return 0;
+}
+
/*
* Called after each bus is probed, but before its children
* are examined.
diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c
index a162a7f..0167a73 100644
--- a/arch/sh/drivers/pci/pcie-sh7786.c
+++ b/arch/sh/drivers/pci/pcie-sh7786.c
@@ -467,7 +467,7 @@ static int __init pcie_init(struct sh7786_pcie_port *port)
return 0;
}

-int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
return evt2irq(0xae0);
}
--
2.1.0
m***@masarand.com
2014-10-02 03:50:23 UTC
Permalink
From: Vality <***@masarand.com>

The powerpc PCI init code is currently initialising PCI device IRQ during
the boot time pcibios phase. This results in devices which are connected
after boot time not being asigned IRQs which can cause various problems.

This patch as part of its set fixes this be moving the IRQ initialisation
into the PCI device enable code path so that it is run for boot time and
hot-plugged devices alike.

---
arch/powerpc/kernel/pci-common.c | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index b2814e2..a8be5a5 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -217,7 +217,7 @@ struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
* If the interrupt is used, then gets the interrupt line from the
* openfirmware and sets it in the pci_dev and pci_config line.
*/
-static int pci_read_irq_line(struct pci_dev *pci_dev)
+static int pci_read_irq_line(struct pci_dev *pci_dev, u8 pin)
{
struct of_phandle_args oirq;
unsigned int virq;
@@ -229,7 +229,7 @@ static int pci_read_irq_line(struct pci_dev *pci_dev)
#endif
/* Try to get a mapping from the device-tree */
if (of_irq_parse_pci(pci_dev, &oirq)) {
- u8 line, pin;
+ u8 line;

/* If that fails, lets fallback to what is in the config
* space and map that through the default controller. We
@@ -238,10 +238,6 @@ static int pci_read_irq_line(struct pci_dev *pci_dev)
* either provide a proper interrupt tree or don't use this
* function.
*/
- if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &pin))
- return -1;
- if (pin == 0)
- return -1;
if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_LINE, &line) ||
line == 0xff || line == 0) {
return -1;
@@ -266,9 +262,16 @@ static int pci_read_irq_line(struct pci_dev *pci_dev)

pr_debug(" Mapped to linux irq %d\n", virq);

- pci_dev->irq = virq;
+ return virq;
+}

- return 0;
+int pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ /* Read default IRQs and fixup if necessary */
+ int irq = pci_read_irq_line(dev, pin);
+ if (ppc_md.pci_irq_fixup)
+ ppc_md.pci_irq_fixup(dev);
+ return irq;
}

/*
@@ -766,6 +769,8 @@ int pci_proc_domain(struct pci_bus *bus)

int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pci_map_irq;
if (ppc_md.pcibios_root_bridge_prepare)
return ppc_md.pcibios_root_bridge_prepare(bridge);

@@ -968,11 +973,6 @@ static void pcibios_setup_device(struct pci_dev *dev)
/* Additional platform DMA/iommu setup */
if (ppc_md.pci_dma_dev_setup)
ppc_md.pci_dma_dev_setup(dev);
-
- /* Read default IRQs and fixup if necessary */
- pci_read_irq_line(dev);
- if (ppc_md.pci_irq_fixup)
- ppc_md.pci_irq_fixup(dev);
}

int pcibios_add_device(struct pci_dev *dev)
--
2.1.0
m***@masarand.com
2014-10-02 03:50:31 UTC
Permalink
From: Matthew Minter <***@masarand.com>

PCI IRQs are being asigned during pcibios_irq_init currently, this causes
a problem by which hot-plug devices connected after boot will not recieve
an IRQ, this patch-set fixes this by registering the IRQ assignment
functions at boot, to then be called later by the device enable code.

---
arch/mn10300/unit-asb2305/pci-asb2305.h | 5 +----
arch/mn10300/unit-asb2305/pci-irq.c | 25 +++++--------------------
arch/mn10300/unit-asb2305/pci.c | 21 ++++++++-------------
3 files changed, 14 insertions(+), 37 deletions(-)

diff --git a/arch/mn10300/unit-asb2305/pci-asb2305.h b/arch/mn10300/unit-asb2305/pci-asb2305.h
index 9e17aca..fb520cf 100644
--- a/arch/mn10300/unit-asb2305/pci-asb2305.h
+++ b/arch/mn10300/unit-asb2305/pci-asb2305.h
@@ -67,9 +67,6 @@ struct irq_routing_table {
} __attribute__((packed));

extern unsigned int pcibios_irq_mask;
-
-extern void pcibios_irq_init(void);
-extern void pcibios_fixup_irqs(void);
-extern void pcibios_enable_irq(struct pci_dev *dev);
+extern int pci_map_irq(struct pci_dev *, u8 slot, u8 pin);

#endif /* PCI_ASB2305_H */
diff --git a/arch/mn10300/unit-asb2305/pci-irq.c b/arch/mn10300/unit-asb2305/pci-irq.c
index fcb28ce..5be6fea 100644
--- a/arch/mn10300/unit-asb2305/pci-irq.c
+++ b/arch/mn10300/unit-asb2305/pci-irq.c
@@ -20,27 +20,12 @@
#include <asm/smp.h>
#include "pci-asb2305.h"

-void __init pcibios_irq_init(void)
+int pci_map_irq(struct pci_dev *, u8 slot, u8 pin)
{
-}
-
-void __init pcibios_fixup_irqs(void)
-{
- struct pci_dev *dev = NULL;
- u8 line, pin;
+ u8 line;

- for_each_pci_dev(dev) {
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
- if (pin) {
- dev->irq = XIRQ1;
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
- dev->irq);
- }
- pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line);
- }
-}
-
-void pcibios_enable_irq(struct pci_dev *dev)
-{
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ dev->irq = XIRQ1;
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+ pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line);
}
diff --git a/arch/mn10300/unit-asb2305/pci.c b/arch/mn10300/unit-asb2305/pci.c
index 6b4339f..22f8786 100644
--- a/arch/mn10300/unit-asb2305/pci.c
+++ b/arch/mn10300/unit-asb2305/pci.c
@@ -377,13 +377,18 @@ static int __init pcibios_init(void)
pci_add_resource_offset(&resources, &pci_ioport_resource, io_offset);
pci_add_resource_offset(&resources, &pci_iomem_resource, mem_offset);
pci_scan_root_bus(NULL, 0, &pci_direct_ampci, NULL, &resources);
-
- pcibios_irq_init();
- pcibios_fixup_irqs();
pcibios_resource_survey();
return 0;
}

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pci_map_irq;
+ return 0;
+}
+
+
arch_initcall(pcibios_init);

char *__init pcibios_setup(char *str)
@@ -396,16 +401,6 @@ char *__init pcibios_setup(char *str)
return str;
}

-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
- int err;
-
- err = pci_enable_resources(dev, mask);
- if (err == 0)
- pcibios_enable_irq(dev);
- return err;
-}
-
/*
* disable the ethernet chipset
*/
--
2.1.0
m***@masarand.com
2014-10-02 03:50:21 UTC
Permalink
From: Vality <***@masarand.com>

The x86 architecture boot code currently traverses the PCI buses with
an extra pass in order to initialise the PCI device IRQs at boot, this
patch avoids this pass and defers the IRQ assignment untill device
enable time which also has the benefit that hot-plugged devices are
assigned IRQs without additional code.

---
arch/x86/include/asm/pci_x86.h | 7 ++--
arch/x86/kernel/x86_init.c | 1 -
arch/x86/pci/acpi.c | 5 ++-
arch/x86/pci/common.c | 2 -
arch/x86/pci/irq.c | 94 +++++++++++++++++++++++-------------------
5 files changed, 59 insertions(+), 50 deletions(-)

diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
index fa1195d..16fd8e9 100644
--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -90,6 +90,7 @@ extern unsigned int pcibios_irq_mask;

extern raw_spinlock_t pci_config_lock;

+extern int pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin);
extern int (*pcibios_enable_irq)(struct pci_dev *dev);
extern void (*pcibios_disable_irq)(struct pci_dev *dev);

@@ -119,7 +120,7 @@ extern int __init pci_acpi_init(void);
extern void __init pcibios_irq_init(void);
extern int __init pcibios_init(void);
extern int pci_legacy_init(void);
-extern void pcibios_fixup_irqs(void);
+extern int pcibios_fixup_irq(struct pci_dev *dev, u8 pin);

/* pci-mmconfig.c */

@@ -200,9 +201,9 @@ static inline void mmio_config_writel(void __iomem *pos, u32 val)
# define x86_default_pci_init pci_legacy_init
# endif
# define x86_default_pci_init_irq pcibios_irq_init
-# define x86_default_pci_fixup_irqs pcibios_fixup_irqs
+# define x86_default_pci_fixup_irq pcibios_fixup_irq
#else
# define x86_default_pci_init NULL
# define x86_default_pci_init_irq NULL
-# define x86_default_pci_fixup_irqs NULL
+# define x86_default_pci_fixup_irq NULL
#endif
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index e48b674..064457f 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -81,7 +81,6 @@ struct x86_init_ops x86_init __initdata = {
.pci = {
.init = x86_default_pci_init,
.init_irq = x86_default_pci_init_irq,
- .fixup_irqs = x86_default_pci_fixup_irqs,
},
};

diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index cfd1b13..2c433f4 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -311,7 +311,7 @@ static acpi_status setup_resource(struct acpi_resource *acpi_res, void *data)
} else if (orig_end != end) {
dev_info(&info->bridge->dev,
"host bridge window [%#llx-%#llx] "
- "([%#llx-%#llx] ignored, not CPU addressable)\n",
+ "([%#llx-%#llx] ignored, not CPU addressable)\n",
start, orig_end, end + 1, orig_end);
}

@@ -571,6 +571,9 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
struct pci_sysdata *sd = bridge->bus->sysdata;

ACPI_COMPANION_SET(&bridge->dev, sd->companion);
+
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pci_map_irq;
return 0;
}

diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 059a76c..d4ed0b0 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -662,8 +662,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
if ((err = pci_enable_resources(dev, mask)) < 0)
return err;

- if (!pci_dev_msi_enabled(dev))
- return pcibios_enable_irq(dev);
return 0;
}

diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index eb500c2..33d323d 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -594,9 +594,9 @@ static __init int intel_router_probe(struct irq_router *r, struct pci_dev *route
return 1;
}

- if ((device >= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN &&
- device <= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX)
- || (device >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN &&
+ if ((device >= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN &&
+ device <= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX)
+ || (device >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN &&
device <= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX)
|| (device >= PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MIN &&
device <= PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MAX)
@@ -875,9 +875,8 @@ static struct irq_info *pirq_get_info(struct pci_dev *dev)
return NULL;
}

-static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
+static int pcibios_lookup_irq(struct pci_dev *dev, u8 pin, int assign)
{
- u8 pin;
struct irq_info *info;
int i, pirq, newirq;
int irq = 0;
@@ -887,7 +886,6 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
char *msg = NULL;

/* Find IRQ pin */
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (!pin) {
dev_dbg(&dev->dev, "no interrupt pin\n");
return 0;
@@ -1017,50 +1015,45 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
irq, pci_name(dev2));
}
}
- return 1;
+ /*
+ * Due to the complicated platform specific behvaiour we cannot defer
+ * assigning dev->irq to the caller but will return it anyway
+ */
+ return dev->irq;
}

-void __init pcibios_fixup_irqs(void)
+int pcibios_fixup_irq(struct pci_dev *dev, u8 pin)
{
- struct pci_dev *dev = NULL;
- u8 pin;
-
+ int irq = dev->irq;
DBG(KERN_DEBUG "PCI: IRQ fixup\n");
- for_each_pci_dev(dev) {
- /*
- * If the BIOS has set an out of range IRQ number, just
- * ignore it. Also keep track of which IRQ's are
- * already in use.
- */
- if (dev->irq >= 16) {
- dev_dbg(&dev->dev, "ignoring bogus IRQ %d\n", dev->irq);
- dev->irq = 0;
- }
- /*
- * If the IRQ is already assigned to a PCI device,
- * ignore its ISA use penalty
- */
- if (pirq_penalty[dev->irq] >= 100 &&
- pirq_penalty[dev->irq] < 100000)
- pirq_penalty[dev->irq] = 0;
- pirq_penalty[dev->irq]++;
+ /*
+ * If the BIOS has set an out of range IRQ number, just
+ * ignore it. Also keep track of which IRQ's are
+ * already in use.
+ */
+ if (irq >= 16) {
+ dev_dbg(&dev->dev, "ignoring bogus IRQ %d\n", irq);
+ irq = 0;
}
+ /*
+ * If the IRQ is already assigned to a PCI device,
+ * ignore its ISA use penalty
+ */
+ if (pirq_penalty[irq] >= 100 &&
+ pirq_penalty[irq] < 100000)
+ pirq_penalty[irq] = 0;
+ pirq_penalty[irq]++;

- if (io_apic_assign_pci_irqs)
- return;
+ if (io_apic_assign_pci_irqs || !pin)
+ return irq;

- dev = NULL;
- for_each_pci_dev(dev) {
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
- if (!pin)
- continue;
+ /*
+ * Still no IRQ? Try to lookup one...
+ */
+ if (!irq)
+ irq = pcibios_lookup_irq(dev, pin, 0);

- /*
- * Still no IRQ? Try to lookup one...
- */
- if (!dev->irq)
- pcibios_lookup_irq(dev, 0);
- }
+ return irq;
}

/*
@@ -1161,6 +1154,13 @@ void __init pcibios_irq_init(void)
}
}

+int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pci_map_irq;
+ return 0;
+}
+
static void pirq_penalize_isa_irq(int irq, int active)
{
/*
@@ -1185,12 +1185,20 @@ void pcibios_penalize_isa_irq(int irq, int active)
pirq_penalize_isa_irq(irq, active);
}

+int pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ dev->irq = pcibios_fixup_irq(dev, pin);
+ if (pcibios_enable_irq(dev))
+ return -1;
+ return dev->irq;
+}
+
static int pirq_enable_irq(struct pci_dev *dev)
{
u8 pin = 0;

pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
- if (pin && !pcibios_lookup_irq(dev, 1)) {
+ if (pin && !pcibios_lookup_irq(dev, pin, 1)) {
char *msg = "";

if (!io_apic_assign_pci_irqs && dev->irq)
--
2.1.0
m***@masarand.com
2014-10-02 03:50:34 UTC
Permalink
From: Matthew Minter <***@masarand.com>

PCI IRQs are currently assigned during pci_common_init, this is only run
at boot time so devices hot-plugged after boot will not be allocated an IRQ.
this is fixed here by defering the assignment untill the device enable code,
instead registering the function pointer at boot time.

---
arch/unicore32/kernel/pci.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/arch/unicore32/kernel/pci.c b/arch/unicore32/kernel/pci.c
index 374a055..6a9da80 100644
--- a/arch/unicore32/kernel/pci.c
+++ b/arch/unicore32/kernel/pci.c
@@ -101,7 +101,7 @@ void pci_puv3_preinit(void)
writel(readl(PCIBRI_CMD) | PCIBRI_CMD_IO | PCIBRI_CMD_MEM, PCIBRI_CMD);
}

-static int __init pci_puv3_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+static int pci_puv3_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
if (dev->bus->number == 0) {
#ifdef CONFIG_ARCH_FPGA /* 4 pci slots */
@@ -263,8 +263,6 @@ static int __init pci_common_init(void)
if (!puv3_bus)
panic("PCI: unable to scan bus!");

- pci_fixup_irqs(pci_common_swizzle, pci_puv3_map_irq);
-
if (!pci_has_flag(PCI_PROBE_ONLY)) {
/*
* Size the bridge windows.
@@ -281,6 +279,13 @@ static int __init pci_common_init(void)
}
subsys_initcall(pci_common_init);

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pci_common_swizzle;
+ bridge->map_irq = pci_puv3_map_irq;
+ return 0;
+}
+
char * __init pcibios_setup(char *str)
{
if (!strcmp(str, "debug")) {
--
2.1.0
m***@masarand.com
2014-10-02 03:50:29 UTC
Permalink
From: Matthew Minter <***@masarand.com>

Currently microblaze assigns PCI IRQs during the pcibios phase, this means
that devices connected after boot will not be assigned an IRQ, instead the
boot code now registers IRQ assignment functions to be called later by the
device enable code paths.

---
arch/microblaze/pci/pci-common.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index 9037914..6843b34 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -850,12 +850,16 @@ void pcibios_setup_bus_devices(struct pci_bus *bus)
* code and is needed by the DMA init
*/
set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
-
- /* Read default IRQs and fixup if necessary */
- dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
}
}

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = of_irq_parse_and_map_pci;
+ return 0;
+}
+
void pcibios_fixup_bus(struct pci_bus *bus)
{
/* When called from the generic PCI probe, read PCI<->PCI bridge
--
2.1.0
m***@masarand.com
2014-10-02 03:50:28 UTC
Permalink
From: Vality <***@masarand.com>

Currently PCI IRQs are assigned during mcf_pci_init which is only run
at boot time, this causes devices which are connected after boot time
to not receive an IRQ, this patch set fixes this by registering an IRQ
assignment function to be run later at device enable time.

---
arch/m68k/platform/coldfire/pci.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/m68k/platform/coldfire/pci.c b/arch/m68k/platform/coldfire/pci.c
index df96792..058ca86 100644
--- a/arch/m68k/platform/coldfire/pci.c
+++ b/arch/m68k/platform/coldfire/pci.c
@@ -316,10 +316,16 @@ static int __init mcf_pci_init(void)
rootbus->resource[0] = &mcf_pci_io;
rootbus->resource[1] = &mcf_pci_mem;

- pci_fixup_irqs(pci_common_swizzle, mcf_pci_map_irq);
pci_bus_size_bridges(rootbus);
pci_bus_assign_resources(rootbus);
return 0;
}

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pci_common_swizzle;
+ bridge->map_irq = mcf_pci_map_irq;
+ return 0;
+}
+
subsys_initcall(mcf_pci_init);
--
2.1.0
m***@masarand.com
2014-10-02 03:50:35 UTC
Permalink
From: Vality <***@masarand.com>

Most of the architectures are switched to allocating IRQs at device_enable
time instead of boot time, however ia64 does not provide an easy way of
making that transition so the new code is disabled here on ia64.

---
arch/ia64/pci/pci.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 291a582..398d5d4 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -483,6 +483,9 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{
struct pci_controller *controller = bridge->bus->sysdata;

+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = NULL;
+
ACPI_COMPANION_SET(&bridge->dev, controller->companion);
return 0;
}
--
2.1.0
m***@masarand.com
2014-10-02 03:50:33 UTC
Permalink
From: Vality <***@masarand.com>

Currently pcibios_init is running pci_fixup_irqs in order to assign
IRQs to PCI devices, this is only done once at boot-time and causes
devices hot-plugged after boot time to not be allocated an IRQ.
This is fixed in this patch-set by delaying the allocation untill
device enable time by registering the function to be called later.

---
arch/tile/kernel/pci.c | 10 +++++++---
arch/tile/kernel/pci_gx.c | 10 +++++++---
2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/arch/tile/kernel/pci.c b/arch/tile/kernel/pci.c
index 1f80a88..6dc0bd8 100644
--- a/arch/tile/kernel/pci.c
+++ b/arch/tile/kernel/pci.c
@@ -313,9 +313,6 @@ int __init pcibios_init(void)
}
}

- /* Do machine dependent PCI interrupt routing */
- pci_fixup_irqs(pci_common_swizzle, tile_map_irq);
-
/*
* This comes from the generic Linux PCI driver.
*
@@ -367,6 +364,13 @@ int __init pcibios_init(void)
}
subsys_initcall(pcibios_init);

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pci_common_swizzle;
+ bridge->map_irq = tile_map_irq;
+ return 0;
+}
+
/*
* No bus fixups needed.
*/
diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c
index e39f9c5..7d1b5bf 100644
--- a/arch/tile/kernel/pci_gx.c
+++ b/arch/tile/kernel/pci_gx.c
@@ -893,9 +893,6 @@ int __init pcibios_init(void)
next_busno = bus->busn_res.end + 1;
}

- /* Do machine dependent PCI interrupt routing */
- pci_fixup_irqs(pci_common_swizzle, tile_map_irq);
-
/*
* This comes from the generic Linux PCI driver.
*
@@ -1048,6 +1045,13 @@ alloc_mem_map_failed:
}
subsys_initcall(pcibios_init);

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pci_common_swizzle;
+ bridge->map_irq = tile_map_irq;
+ return 0;
+}
+
/* No bus fixups needed. */
void pcibios_fixup_bus(struct pci_bus *bus)
{
--
2.1.0
m***@masarand.com
2014-10-02 04:07:30 UTC
Permalink
From: Matthew Minter <***@masarand.com>

The x86 architecture boot code currently traverses the PCI buses with
an extra pass in order to initialise the PCI device IRQs at boot, this
patch avoids this pass and defers the IRQ assignment untill device
enable time which also has the benefit that hot-plugged devices are
assigned IRQs without additional code.

Signed-off-by: Matthew Minter <***@masarand.com>

---
arch/x86/include/asm/pci_x86.h | 7 ++--
arch/x86/kernel/x86_init.c | 1 -
arch/x86/pci/acpi.c | 5 ++-
arch/x86/pci/common.c | 2 -
arch/x86/pci/irq.c | 94 +++++++++++++++++++++++-------------------
5 files changed, 59 insertions(+), 50 deletions(-)

diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
index fa1195d..16fd8e9 100644
--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -90,6 +90,7 @@ extern unsigned int pcibios_irq_mask;

extern raw_spinlock_t pci_config_lock;

+extern int pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin);
extern int (*pcibios_enable_irq)(struct pci_dev *dev);
extern void (*pcibios_disable_irq)(struct pci_dev *dev);

@@ -119,7 +120,7 @@ extern int __init pci_acpi_init(void);
extern void __init pcibios_irq_init(void);
extern int __init pcibios_init(void);
extern int pci_legacy_init(void);
-extern void pcibios_fixup_irqs(void);
+extern int pcibios_fixup_irq(struct pci_dev *dev, u8 pin);

/* pci-mmconfig.c */

@@ -200,9 +201,9 @@ static inline void mmio_config_writel(void __iomem *pos, u32 val)
# define x86_default_pci_init pci_legacy_init
# endif
# define x86_default_pci_init_irq pcibios_irq_init
-# define x86_default_pci_fixup_irqs pcibios_fixup_irqs
+# define x86_default_pci_fixup_irq pcibios_fixup_irq
#else
# define x86_default_pci_init NULL
# define x86_default_pci_init_irq NULL
-# define x86_default_pci_fixup_irqs NULL
+# define x86_default_pci_fixup_irq NULL
#endif
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index e48b674..064457f 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -81,7 +81,6 @@ struct x86_init_ops x86_init __initdata = {
.pci = {
.init = x86_default_pci_init,
.init_irq = x86_default_pci_init_irq,
- .fixup_irqs = x86_default_pci_fixup_irqs,
},
};

diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index cfd1b13..2c433f4 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -311,7 +311,7 @@ static acpi_status setup_resource(struct acpi_resource *acpi_res, void *data)
} else if (orig_end != end) {
dev_info(&info->bridge->dev,
"host bridge window [%#llx-%#llx] "
- "([%#llx-%#llx] ignored, not CPU addressable)\n",
+ "([%#llx-%#llx] ignored, not CPU addressable)\n",
start, orig_end, end + 1, orig_end);
}

@@ -571,6 +571,9 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
struct pci_sysdata *sd = bridge->bus->sysdata;

ACPI_COMPANION_SET(&bridge->dev, sd->companion);
+
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pci_map_irq;
return 0;
}

diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 059a76c..d4ed0b0 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -662,8 +662,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
if ((err = pci_enable_resources(dev, mask)) < 0)
return err;

- if (!pci_dev_msi_enabled(dev))
- return pcibios_enable_irq(dev);
return 0;
}

diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index eb500c2..33d323d 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -594,9 +594,9 @@ static __init int intel_router_probe(struct irq_router *r, struct pci_dev *route
return 1;
}

- if ((device >= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN &&
- device <= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX)
- || (device >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN &&
+ if ((device >= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN &&
+ device <= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX)
+ || (device >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN &&
device <= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX)
|| (device >= PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MIN &&
device <= PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MAX)
@@ -875,9 +875,8 @@ static struct irq_info *pirq_get_info(struct pci_dev *dev)
return NULL;
}

-static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
+static int pcibios_lookup_irq(struct pci_dev *dev, u8 pin, int assign)
{
- u8 pin;
struct irq_info *info;
int i, pirq, newirq;
int irq = 0;
@@ -887,7 +886,6 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
char *msg = NULL;

/* Find IRQ pin */
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (!pin) {
dev_dbg(&dev->dev, "no interrupt pin\n");
return 0;
@@ -1017,50 +1015,45 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
irq, pci_name(dev2));
}
}
- return 1;
+ /*
+ * Due to the complicated platform specific behvaiour we cannot defer
+ * assigning dev->irq to the caller but will return it anyway
+ */
+ return dev->irq;
}

-void __init pcibios_fixup_irqs(void)
+int pcibios_fixup_irq(struct pci_dev *dev, u8 pin)
{
- struct pci_dev *dev = NULL;
- u8 pin;
-
+ int irq = dev->irq;
DBG(KERN_DEBUG "PCI: IRQ fixup\n");
- for_each_pci_dev(dev) {
- /*
- * If the BIOS has set an out of range IRQ number, just
- * ignore it. Also keep track of which IRQ's are
- * already in use.
- */
- if (dev->irq >= 16) {
- dev_dbg(&dev->dev, "ignoring bogus IRQ %d\n", dev->irq);
- dev->irq = 0;
- }
- /*
- * If the IRQ is already assigned to a PCI device,
- * ignore its ISA use penalty
- */
- if (pirq_penalty[dev->irq] >= 100 &&
- pirq_penalty[dev->irq] < 100000)
- pirq_penalty[dev->irq] = 0;
- pirq_penalty[dev->irq]++;
+ /*
+ * If the BIOS has set an out of range IRQ number, just
+ * ignore it. Also keep track of which IRQ's are
+ * already in use.
+ */
+ if (irq >= 16) {
+ dev_dbg(&dev->dev, "ignoring bogus IRQ %d\n", irq);
+ irq = 0;
}
+ /*
+ * If the IRQ is already assigned to a PCI device,
+ * ignore its ISA use penalty
+ */
+ if (pirq_penalty[irq] >= 100 &&
+ pirq_penalty[irq] < 100000)
+ pirq_penalty[irq] = 0;
+ pirq_penalty[irq]++;

- if (io_apic_assign_pci_irqs)
- return;
+ if (io_apic_assign_pci_irqs || !pin)
+ return irq;

- dev = NULL;
- for_each_pci_dev(dev) {
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
- if (!pin)
- continue;
+ /*
+ * Still no IRQ? Try to lookup one...
+ */
+ if (!irq)
+ irq = pcibios_lookup_irq(dev, pin, 0);

- /*
- * Still no IRQ? Try to lookup one...
- */
- if (!dev->irq)
- pcibios_lookup_irq(dev, 0);
- }
+ return irq;
}

/*
@@ -1161,6 +1154,13 @@ void __init pcibios_irq_init(void)
}
}

+int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pci_map_irq;
+ return 0;
+}
+
static void pirq_penalize_isa_irq(int irq, int active)
{
/*
@@ -1185,12 +1185,20 @@ void pcibios_penalize_isa_irq(int irq, int active)
pirq_penalize_isa_irq(irq, active);
}

+int pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ dev->irq = pcibios_fixup_irq(dev, pin);
+ if (pcibios_enable_irq(dev))
+ return -1;
+ return dev->irq;
+}
+
static int pirq_enable_irq(struct pci_dev *dev)
{
u8 pin = 0;

pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
- if (pin && !pcibios_lookup_irq(dev, 1)) {
+ if (pin && !pcibios_lookup_irq(dev, pin, 1)) {
char *msg = "";

if (!io_apic_assign_pci_irqs && dev->irq)
--
2.1.0
Liviu Dudau
2014-10-02 10:51:12 UTC
Permalink
Post by m***@masarand.com
=20
The x86 architecture boot code currently traverses the PCI buses with
an extra pass in order to initialise the PCI device IRQs at boot, thi=
s
Post by m***@masarand.com
patch avoids this pass and defers the IRQ assignment untill device
enable time which also has the benefit that hot-plugged devices are
assigned IRQs without additional code.
=20
=20
---
arch/x86/include/asm/pci_x86.h | 7 ++--
arch/x86/kernel/x86_init.c | 1 -
arch/x86/pci/acpi.c | 5 ++-
arch/x86/pci/common.c | 2 -
arch/x86/pci/irq.c | 94 +++++++++++++++++++++++---------=
----------
Post by m***@masarand.com
5 files changed, 59 insertions(+), 50 deletions(-)
=20
diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pc=
i_x86.h
Post by m***@masarand.com
index fa1195d..16fd8e9 100644
--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -90,6 +90,7 @@ extern unsigned int pcibios_irq_mask;
=20
extern raw_spinlock_t pci_config_lock;
=20
+extern int pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin);
extern int (*pcibios_enable_irq)(struct pci_dev *dev);
extern void (*pcibios_disable_irq)(struct pci_dev *dev);
=20
@@ -119,7 +120,7 @@ extern int __init pci_acpi_init(void);
extern void __init pcibios_irq_init(void);
extern int __init pcibios_init(void);
extern int pci_legacy_init(void);
-extern void pcibios_fixup_irqs(void);
+extern int pcibios_fixup_irq(struct pci_dev *dev, u8 pin);
=20
/* pci-mmconfig.c */
=20
@@ -200,9 +201,9 @@ static inline void mmio_config_writel(void __iome=
m *pos, u32 val)
Post by m***@masarand.com
# define x86_default_pci_init pci_legacy_init
# endif
# define x86_default_pci_init_irq pcibios_irq_init
-# define x86_default_pci_fixup_irqs pcibios_fixup_irqs
+# define x86_default_pci_fixup_irq pcibios_fixup_irq
#else
# define x86_default_pci_init NULL
# define x86_default_pci_init_irq NULL
-# define x86_default_pci_fixup_irqs NULL
+# define x86_default_pci_fixup_irq NULL
#endif
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index e48b674..064457f 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -81,7 +81,6 @@ struct x86_init_ops x86_init __initdata =3D {
.pci =3D {
.init =3D x86_default_pci_init,
.init_irq =3D x86_default_pci_init_irq,
- .fixup_irqs =3D x86_default_pci_fixup_irqs,
},
};
=20
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index cfd1b13..2c433f4 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -311,7 +311,7 @@ static acpi_status setup_resource(struct acpi_res=
ource *acpi_res, void *data)
Post by m***@masarand.com
} else if (orig_end !=3D end) {
dev_info(&info->bridge->dev,
"host bridge window [%#llx-%#llx] "
- "([%#llx-%#llx] ignored, not CPU addressable)\n",=20
+ "([%#llx-%#llx] ignored, not CPU addressable)\n",
start, orig_end, end + 1, orig_end);
}
=20
@@ -571,6 +571,9 @@ int pcibios_root_bridge_prepare(struct pci_host_b=
ridge *bridge)

Your previous patch removed the weak implementation of pcibios_root_bri=
dge_prepare yet
you are adding it here in the arch specific code. Again, confused on wh=
at you
were trying to achieve by removing the __weak version. Should that not =
have by default
setup bridge->swizzle_irq and bridge->map_irq to some sane defaults and=
kept into drivers/pci?
Post by m***@masarand.com
struct pci_sysdata *sd =3D bridge->bus->sysdata;
=20
ACPI_COMPANION_SET(&bridge->dev, sd->companion);
+
+ bridge->swizzle_irq =3D NULL;
+ bridge->map_irq =3D pci_map_irq;
return 0;
}
=20
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 059a76c..d4ed0b0 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -662,8 +662,6 @@ int pcibios_enable_device(struct pci_dev *dev, in=
t mask)
Post by m***@masarand.com
if ((err =3D pci_enable_resources(dev, mask)) < 0)
return err;
=20
- if (!pci_dev_msi_enabled(dev))
- return pcibios_enable_irq(dev);
return 0;
}
=20
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index eb500c2..33d323d 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -594,9 +594,9 @@ static __init int intel_router_probe(struct irq_r=
outer *r, struct pci_dev *route
Post by m***@masarand.com
return 1;
}
=20
- if ((device >=3D PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN &&=20
- device <=3D PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX)=20
- || (device >=3D PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN &&=20
+ if ((device >=3D PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN &&
+ device <=3D PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX)
+ || (device >=3D PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN &&
More indentation fixes?
Post by m***@masarand.com
device <=3D PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX)
|| (device >=3D PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MIN &&
device <=3D PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MAX)
@@ -875,9 +875,8 @@ static struct irq_info *pirq_get_info(struct pci_=
dev *dev)
Post by m***@masarand.com
return NULL;
}
=20
-static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
+static int pcibios_lookup_irq(struct pci_dev *dev, u8 pin, int assig=
n)
Post by m***@masarand.com
{
- u8 pin;
struct irq_info *info;
int i, pirq, newirq;
int irq =3D 0;
@@ -887,7 +886,6 @@ static int pcibios_lookup_irq(struct pci_dev *dev=
, int assign)
Post by m***@masarand.com
char *msg =3D NULL;
=20
/* Find IRQ pin */
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (!pin) {
dev_dbg(&dev->dev, "no interrupt pin\n");
return 0;
@@ -1017,50 +1015,45 @@ static int pcibios_lookup_irq(struct pci_dev =
*dev, int assign)
Post by m***@masarand.com
irq, pci_name(dev2));
}
}
- return 1;
+ /*
+ * Due to the complicated platform specific behvaiour we cannot def=
er

behaviour
Post by m***@masarand.com
+ * assigning dev->irq to the caller but will return it anyway
+ */
What? How is that sane?
Post by m***@masarand.com
+ return dev->irq;
Beside the above comment, you are changing the behaviour of the functio=
n from previously
returning 0/1 depending on whether an irq has been found into returning=
0/dev->irq. That
is unnecessary as you can extract the information anyway from dev, acco=
rding to your
comment.
Post by m***@masarand.com
}
=20
-void __init pcibios_fixup_irqs(void)
+int pcibios_fixup_irq(struct pci_dev *dev, u8 pin)
{
- struct pci_dev *dev =3D NULL;
- u8 pin;
-
+ int irq =3D dev->irq;
DBG(KERN_DEBUG "PCI: IRQ fixup\n");
- for_each_pci_dev(dev) {
- /*
- * If the BIOS has set an out of range IRQ number, just
- * ignore it. Also keep track of which IRQ's are
- * already in use.
- */
- if (dev->irq >=3D 16) {
- dev_dbg(&dev->dev, "ignoring bogus IRQ %d\n", dev->irq);
- dev->irq =3D 0;
- }
- /*
- * If the IRQ is already assigned to a PCI device,
- * ignore its ISA use penalty
- */
- if (pirq_penalty[dev->irq] >=3D 100 &&
- pirq_penalty[dev->irq] < 100000)
- pirq_penalty[dev->irq] =3D 0;
- pirq_penalty[dev->irq]++;
+ /*
+ * If the BIOS has set an out of range IRQ number, just
+ * ignore it. Also keep track of which IRQ's are
+ * already in use.
+ */
+ if (irq >=3D 16) {
+ dev_dbg(&dev->dev, "ignoring bogus IRQ %d\n", irq);
+ irq =3D 0;
}
+ /*
+ * If the IRQ is already assigned to a PCI device,
+ * ignore its ISA use penalty
+ */
+ if (pirq_penalty[irq] >=3D 100 &&
+ pirq_penalty[irq] < 100000)
+ pirq_penalty[irq] =3D 0;
+ pirq_penalty[irq]++;
=20
- if (io_apic_assign_pci_irqs)
- return;
+ if (io_apic_assign_pci_irqs || !pin)
+ return irq;
=20
- dev =3D NULL;
- for_each_pci_dev(dev) {
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
- if (!pin)
- continue;
+ /*
+ * Still no IRQ? Try to lookup one...
+ */
+ if (!irq)
+ irq =3D pcibios_lookup_irq(dev, pin, 0);
=20
- /*
- * Still no IRQ? Try to lookup one...
- */
- if (!dev->irq)
- pcibios_lookup_irq(dev, 0);
- }
+ return irq;
}
=20
/*
@@ -1161,6 +1154,13 @@ void __init pcibios_irq_init(void)
}
}
=20
+int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridg=
e)
Post by m***@masarand.com
+{
+ bridge->swizzle_irq =3D NULL;
+ bridge->map_irq =3D pci_map_irq;
+ return 0;
+}
Like I've mentioned above, you already have a non-weak version in arch/=
x86/pci/acpi.c,
why do you provide a week one here?

Best regards,
Liviu
Post by m***@masarand.com
+
static void pirq_penalize_isa_irq(int irq, int active)
{
/*
@@ -1185,12 +1185,20 @@ void pcibios_penalize_isa_irq(int irq, int ac=
tive)
Post by m***@masarand.com
pirq_penalize_isa_irq(irq, active);
}
=20
+int pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ dev->irq =3D pcibios_fixup_irq(dev, pin);
+ if (pcibios_enable_irq(dev))
+ return -1;
+ return dev->irq;
+}
+
static int pirq_enable_irq(struct pci_dev *dev)
{
u8 pin =3D 0;
=20
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
- if (pin && !pcibios_lookup_irq(dev, 1)) {
+ if (pin && !pcibios_lookup_irq(dev, pin, 1)) {
char *msg =3D "";
=20
if (!io_apic_assign_pci_irqs && dev->irq)
--=20
2.1.0
=20
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" =
in
Post by m***@masarand.com
More majordomo info at http://vger.kernel.org/majordomo-info.html
=20
--=20
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
=C2=AF\_(=E3=83=84)_/=C2=AF
Bjorn Helgaas
2014-10-14 18:11:36 UTC
Permalink
Post by m***@masarand.com
The x86 architecture boot code currently traverses the PCI buses with
an extra pass in order to initialise the PCI device IRQs at boot, this
patch avoids this pass and defers the IRQ assignment untill device
enable time which also has the benefit that hot-plugged devices are
assigned IRQs without additional code.
---
arch/x86/include/asm/pci_x86.h | 7 ++--
arch/x86/kernel/x86_init.c | 1 -
arch/x86/pci/acpi.c | 5 ++-
arch/x86/pci/common.c | 2 -
arch/x86/pci/irq.c | 94 +++++++++++++++++++++++-------------------
5 files changed, 59 insertions(+), 50 deletions(-)
diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
index fa1195d..16fd8e9 100644
--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -90,6 +90,7 @@ extern unsigned int pcibios_irq_mask;
extern raw_spinlock_t pci_config_lock;
+extern int pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin);
extern int (*pcibios_enable_irq)(struct pci_dev *dev);
extern void (*pcibios_disable_irq)(struct pci_dev *dev);
@@ -119,7 +120,7 @@ extern int __init pci_acpi_init(void);
extern void __init pcibios_irq_init(void);
extern int __init pcibios_init(void);
extern int pci_legacy_init(void);
-extern void pcibios_fixup_irqs(void);
+extern int pcibios_fixup_irq(struct pci_dev *dev, u8 pin);
/* pci-mmconfig.c */
@@ -200,9 +201,9 @@ static inline void mmio_config_writel(void __iomem *pos, u32 val)
# define x86_default_pci_init pci_legacy_init
# endif
# define x86_default_pci_init_irq pcibios_irq_init
-# define x86_default_pci_fixup_irqs pcibios_fixup_irqs
+# define x86_default_pci_fixup_irq pcibios_fixup_irq
#else
# define x86_default_pci_init NULL
# define x86_default_pci_init_irq NULL
-# define x86_default_pci_fixup_irqs NULL
+# define x86_default_pci_fixup_irq NULL
#endif
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index e48b674..064457f 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -81,7 +81,6 @@ struct x86_init_ops x86_init __initdata = {
.pci = {
.init = x86_default_pci_init,
.init_irq = x86_default_pci_init_irq,
- .fixup_irqs = x86_default_pci_fixup_irqs,
},
};
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index cfd1b13..2c433f4 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -311,7 +311,7 @@ static acpi_status setup_resource(struct acpi_resource *acpi_res, void *data)
} else if (orig_end != end) {
dev_info(&info->bridge->dev,
"host bridge window [%#llx-%#llx] "
- "([%#llx-%#llx] ignored, not CPU addressable)\n",
+ "([%#llx-%#llx] ignored, not CPU addressable)\n",
This and the similar whitespace fixes below are out of scope for this
patch. This patch series should have the minimal set of IRQ changes you
need, and whitespace changes can be done later. This makes the series
easier to review and to backport.
Post by m***@masarand.com
start, orig_end, end + 1, orig_end);
}
@@ -571,6 +571,9 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
struct pci_sysdata *sd = bridge->bus->sysdata;
ACPI_COMPANION_SET(&bridge->dev, sd->companion);
+
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pci_map_irq;
return 0;
}
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 059a76c..d4ed0b0 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -662,8 +662,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
if ((err = pci_enable_resources(dev, mask)) < 0)
return err;
- if (!pci_dev_msi_enabled(dev))
- return pcibios_enable_irq(dev);
return 0;
}
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index eb500c2..33d323d 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -594,9 +594,9 @@ static __init int intel_router_probe(struct irq_router *r, struct pci_dev *route
return 1;
}
- if ((device >= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN &&
- device <= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX)
- || (device >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN &&
+ if ((device >= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN &&
+ device <= PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX)
+ || (device >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN &&
device <= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX)
|| (device >= PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MIN &&
device <= PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MAX)
@@ -875,9 +875,8 @@ static struct irq_info *pirq_get_info(struct pci_dev *dev)
return NULL;
}
-static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
+static int pcibios_lookup_irq(struct pci_dev *dev, u8 pin, int assign)
{
- u8 pin;
struct irq_info *info;
int i, pirq, newirq;
int irq = 0;
@@ -887,7 +886,6 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
char *msg = NULL;
/* Find IRQ pin */
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (!pin) {
dev_dbg(&dev->dev, "no interrupt pin\n");
return 0;
@@ -1017,50 +1015,45 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
irq, pci_name(dev2));
}
}
- return 1;
+ /*
+ * Due to the complicated platform specific behvaiour we cannot defer
+ * assigning dev->irq to the caller but will return it anyway
+ */
+ return dev->irq;
}
-void __init pcibios_fixup_irqs(void)
+int pcibios_fixup_irq(struct pci_dev *dev, u8 pin)
{
- struct pci_dev *dev = NULL;
- u8 pin;
-
+ int irq = dev->irq;
DBG(KERN_DEBUG "PCI: IRQ fixup\n");
- for_each_pci_dev(dev) {
- /*
- * If the BIOS has set an out of range IRQ number, just
- * ignore it. Also keep track of which IRQ's are
- * already in use.
- */
- if (dev->irq >= 16) {
- dev_dbg(&dev->dev, "ignoring bogus IRQ %d\n", dev->irq);
- dev->irq = 0;
- }
- /*
- * If the IRQ is already assigned to a PCI device,
- * ignore its ISA use penalty
- */
- if (pirq_penalty[dev->irq] >= 100 &&
- pirq_penalty[dev->irq] < 100000)
- pirq_penalty[dev->irq] = 0;
- pirq_penalty[dev->irq]++;
+ /*
+ * If the BIOS has set an out of range IRQ number, just
+ * ignore it. Also keep track of which IRQ's are
+ * already in use.
+ */
+ if (irq >= 16) {
+ dev_dbg(&dev->dev, "ignoring bogus IRQ %d\n", irq);
+ irq = 0;
}
+ /*
+ * If the IRQ is already assigned to a PCI device,
+ * ignore its ISA use penalty
+ */
+ if (pirq_penalty[irq] >= 100 &&
+ pirq_penalty[irq] < 100000)
+ pirq_penalty[irq] = 0;
+ pirq_penalty[irq]++;
- if (io_apic_assign_pci_irqs)
- return;
+ if (io_apic_assign_pci_irqs || !pin)
+ return irq;
- dev = NULL;
- for_each_pci_dev(dev) {
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
- if (!pin)
- continue;
+ /*
+ * Still no IRQ? Try to lookup one...
+ */
+ if (!irq)
+ irq = pcibios_lookup_irq(dev, pin, 0);
- /*
- * Still no IRQ? Try to lookup one...
- */
- if (!dev->irq)
- pcibios_lookup_irq(dev, 0);
- }
+ return irq;
}
/*
@@ -1161,6 +1154,13 @@ void __init pcibios_irq_init(void)
}
}
+int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pci_map_irq;
+ return 0;
+}
It's confusing to have two pcibios_root_bridge_prepare() definitions for
one architecture, especially since one is weak and the other is not, and
they contain duplicated code. I think the only practical way to use __weak
is to have a single default weak version in the entire kernel. If we have
more than one, e.g., this one and the one in drivers/pci/probe.c, we can't
really tell which version will be used because it depends on link order.

I think it'd be better to just move the arch/x86/pci/acpi.c implementation
to here so it's always compiled. It can still use ACPI_COMPANION_SET(),
since there's a stub for that even when CONFIG_ACPI is not set.

Moving pcibios_root_bridge_prepare() can be its own separate patch since
it's trivial and can be done independently. Then you can add the setting
of ->map_irq in this patch. Setting ->swizzle_irq is optional since it
defaults to NULL anyway.
Post by m***@masarand.com
+
static void pirq_penalize_isa_irq(int irq, int active)
{
/*
@@ -1185,12 +1185,20 @@ void pcibios_penalize_isa_irq(int irq, int active)
pirq_penalize_isa_irq(irq, active);
}
+int pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ dev->irq = pcibios_fixup_irq(dev, pin);
+ if (pcibios_enable_irq(dev))
+ return -1;
+ return dev->irq;
+}
+
static int pirq_enable_irq(struct pci_dev *dev)
{
u8 pin = 0;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
- if (pin && !pcibios_lookup_irq(dev, 1)) {
+ if (pin && !pcibios_lookup_irq(dev, pin, 1)) {
This change (passing in "pin" instead of reading it again inside
pcibios_lookup_irq()) can also be done separately in a small,
obviously-correct patch. Splitting it out will make the essential
parts of *this* patch more obvious.
Post by m***@masarand.com
char *msg = "";
if (!io_apic_assign_pci_irqs && dev->irq)
--
2.1.0
m***@masarand.com
2014-10-02 04:07:29 UTC
Permalink
From: Matthew Minter <***@masarand.com>


These are the main infrastructure changes to allow the registration of
PCI IRQ assignment functions which can then be called during the device
enabling stage. This replaces the pre-initialisation of PCI IRQs at boot
time which caused limitations such as failing for devices which are
hot-plugged after the machine has booted and resulted in highly
fragmented PCI initialisation paths.

The pdev_assign_irq function becomes a centralised method of assigning
IRQs to PCI devices in a non platform specific way. The pci_host_bridge
structure has had some function pointers added to it where the boot code
can register the platform specific ways of assigning PCI IRQs to be used
to allow them to be used by pdev_assign_irq.

Some small adjustements have also been made to makefiles in order to
accomodate these changes.

Note this code completely obsolites the pci_fixup_irqs code path which
has thus been removed.

Signed-off-by: Matthew Minter <***@masarand.com>

---
drivers/of/of_pci_irq.c | 2 +-
drivers/pci/Makefile | 15 ++-------------
drivers/pci/host-bridge.c | 2 +-
drivers/pci/pci.c | 5 ++++-
drivers/pci/pci.h | 1 +
drivers/pci/probe.c | 12 ------------
drivers/pci/setup-irq.c | 34 ++++++++++++++++------------------
include/linux/pci.h | 6 ++++--
8 files changed, 29 insertions(+), 48 deletions(-)

diff --git a/drivers/of/of_pci_irq.c b/drivers/of/of_pci_irq.c
index 1710d9d..205eb7a 100644
--- a/drivers/of/of_pci_irq.c
+++ b/drivers/of/of_pci_irq.c
@@ -97,7 +97,7 @@ EXPORT_SYMBOL_GPL(of_irq_parse_pci);
* @pin: PCI irq pin number; passed when used as map_irq callback. Unused
*
* @slot and @pin are unused, but included in the function so that this
- * function can be used directly as the map_irq callback to pci_fixup_irqs().
+ * function can be used directly as the map_irq callback to pdev_assign_irq().
*/
int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin)
{
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index e04fe2d..38c4cb0 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -4,7 +4,8 @@

obj-y += access.o bus.o probe.o host-bridge.o remove.o pci.o \
pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \
- irq.o vpd.o setup-bus.o vc.o
+ irq.o vpd.o setup-bus.o vc.o setup-irq.o
+
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSFS) += slot.o

@@ -31,18 +32,6 @@ obj-$(CONFIG_PCI_ATS) += ats.o
obj-$(CONFIG_PCI_IOV) += iov.o

#
-# Some architectures use the generic PCI setup functions
-#
-obj-$(CONFIG_ALPHA) += setup-irq.o
-obj-$(CONFIG_ARM) += setup-irq.o
-obj-$(CONFIG_UNICORE32) += setup-irq.o
-obj-$(CONFIG_SUPERH) += setup-irq.o
-obj-$(CONFIG_MIPS) += setup-irq.o
-obj-$(CONFIG_TILE) += setup-irq.o
-obj-$(CONFIG_SPARC_LEON) += setup-irq.o
-obj-$(CONFIG_M68K) += setup-irq.o
-
-#
# ACPI Related PCI FW Functions
# ACPI _DSM provided firmware instance and string name
#
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
index 0e5f3c9..8ed186f 100644
--- a/drivers/pci/host-bridge.c
+++ b/drivers/pci/host-bridge.c
@@ -16,7 +16,7 @@ static struct pci_bus *find_pci_root_bus(struct pci_bus *bus)
return bus;
}

-static struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus)
+struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus)
{
struct pci_bus *root_bus = find_pci_root_bus(bus);

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 2c9ac70..2dd28d9 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1192,11 +1192,15 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
struct pci_dev *bridge;
u16 cmd;
u8 pin;
+ struct pci_host_bridge *hbrg = find_pci_host_bridge(dev->bus);

err = pci_set_power_state(dev, PCI_D0);
if (err < 0 && err != -EIO)
return err;

+ pdev_assign_irq(dev, hbrg->swizzle_irq, hbrg->map_irq);
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+
bridge = pci_upstream_bridge(dev);
if (bridge)
pcie_aspm_powersave_config_link(bridge);
@@ -1209,7 +1213,6 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
if (dev->msi_enabled || dev->msix_enabled)
return 0;

- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (pin) {
pci_read_config_word(dev, PCI_COMMAND, &cmd);
if (cmd & PCI_COMMAND_INTX_DISABLE)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 0601890..a6cf445 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -70,6 +70,7 @@ void pci_config_pm_runtime_put(struct pci_dev *dev);
void pci_pm_init(struct pci_dev *dev);
void pci_allocate_cap_save_buffers(struct pci_dev *dev);
void pci_free_cap_save_buffers(struct pci_dev *dev);
+struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus);

static inline void pci_wakeup_event(struct pci_dev *dev)
{
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 4170113..314e9e3 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1719,18 +1719,6 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
}
EXPORT_SYMBOL_GPL(pci_scan_child_bus);

-/**
- * pcibios_root_bridge_prepare - Platform-specific host bridge setup.
- * @bridge: Host bridge to set up.
- *
- * Default empty implementation. Replace with an architecture-specific setup
- * routine, if necessary.
- */
-int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
-{
- return 0;
-}
-
void __weak pcibios_add_bus(struct pci_bus *bus)
{
}
diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c
index 4e2d595..203bf7e 100644
--- a/drivers/pci/setup-irq.c
+++ b/drivers/pci/setup-irq.c
@@ -22,13 +22,19 @@ void __weak pcibios_update_irq(struct pci_dev *dev, int irq)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}

-static void pdev_fixup_irq(struct pci_dev *dev,
+void pdev_assign_irq(struct pci_dev *dev,
u8 (*swizzle)(struct pci_dev *, u8 *),
- int (*map_irq)(const struct pci_dev *, u8, u8))
+ int (*map_irq)(struct pci_dev *, u8, u8))
{
- u8 pin, slot;
+ u8 pin;
+ u8 slot = -1;
int irq = 0;

+ if (!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
which interrupt pin it will come in on. We know which slot it
will come in on 'cos that slot is where the bridge is. Each
@@ -40,28 +46,20 @@ static void pdev_fixup_irq(struct pci_dev *dev,
if (pin > 4)
pin = 1;

- if (pin != 0) {
- /* Follow the chain of bridges, swizzling as we go. */
- slot = (*swizzle)(dev, &pin);
+ if (pin) {
+ /* Follow the chain of bridges, swizzling as we go. */
+ if(swizzle)
+ slot = (*swizzle)(dev, &pin);

+ /* If a swizzling function is not used map_irq must ignore slot */
irq = (*map_irq)(dev, slot, pin);
if (irq == -1)
irq = 0;
}
- 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);
+ dev->irq = irq;
/* Always tell the device, so the driver knows what is
the real IRQ to use; the device does not use it. */
pcibios_update_irq(dev, irq);
}
-
-void pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
- int (*map_irq)(const struct pci_dev *, u8, u8))
-{
- struct pci_dev *dev = NULL;
-
- for_each_pci_dev(dev)
- pdev_fixup_irq(dev, swizzle, map_irq);
-}
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 96453f9..5426d11 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -403,6 +403,8 @@ struct pci_host_bridge {
struct device dev;
struct pci_bus *bus; /* root bus */
struct list_head windows; /* pci_host_bridge_windows */
+ u8 (*swizzle_irq)(struct pci_dev *, u8 *); /* platform irq swizzler */
+ int (*map_irq)(struct pci_dev *, u8, u8);
void (*release_fn)(struct pci_host_bridge *);
void *release_data;
};
@@ -1064,8 +1066,8 @@ void pci_assign_unassigned_bus_resources(struct pci_bus *bus);
void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus);
void pdev_enable_device(struct pci_dev *);
int pci_enable_resources(struct pci_dev *, int mask);
-void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
- int (*)(const struct pci_dev *, u8, u8));
+void pdev_assign_irq(struct pci_dev *dev, u8 (*swizzle)(struct pci_dev *, u8 *),
+ int (*map_irq)(struct pci_dev *, u8, u8));
#define HAVE_PCI_REQ_REGIONS 2
int __must_check pci_request_regions(struct pci_dev *, const char *);
int __must_check pci_request_regions_exclusive(struct pci_dev *, const char *);
--
2.1.0
Liviu Dudau
2014-10-02 10:33:15 UTC
Permalink
=20
Hi Matthew,
=20
These are the main infrastructure changes to allow the registration o=
f
PCI IRQ assignment functions which can then be called during the devi=
ce
enabling stage. This replaces the pre-initialisation of PCI IRQs at b=
oot
time which caused limitations such as failing for devices which are
hot-plugged after the machine has booted and resulted in highly
fragmented PCI initialisation paths.
=20
The pdev_assign_irq function becomes a centralised method of assignin=
g
IRQs to PCI devices in a non platform specific way. The pci_host_brid=
ge
structure has had some function pointers added to it where the boot c=
ode
can register the platform specific ways of assigning PCI IRQs to be u=
sed
to allow them to be used by pdev_assign_irq.
=20
Some small adjustements have also been made to makefiles in order to
accomodate these changes.
=20
Note this code completely obsolites the pci_fixup_irqs code path whic=
h

s/obsolites/obsoletes/
has thus been removed.
=20
=20
---
drivers/of/of_pci_irq.c | 2 +-
drivers/pci/Makefile | 15 ++-------------
drivers/pci/host-bridge.c | 2 +-
drivers/pci/pci.c | 5 ++++-
drivers/pci/pci.h | 1 +
drivers/pci/probe.c | 12 ------------
drivers/pci/setup-irq.c | 34 ++++++++++++++++------------------
include/linux/pci.h | 6 ++++--
8 files changed, 29 insertions(+), 48 deletions(-)
=20
diff --git a/drivers/of/of_pci_irq.c b/drivers/of/of_pci_irq.c
index 1710d9d..205eb7a 100644
--- a/drivers/of/of_pci_irq.c
+++ b/drivers/of/of_pci_irq.c
@@ -97,7 +97,7 @@ EXPORT_SYMBOL_GPL(of_irq_parse_pci);
nused
*
his
- * function can be used directly as the map_irq callback to pci_fixu=
p_irqs().
+ * function can be used directly as the map_irq callback to pdev_ass=
ign_irq().
*/
int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 =
pin)
{
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index e04fe2d..38c4cb0 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -4,7 +4,8 @@
=20
obj-y +=3D access.o bus.o probe.o host-bridge.o remove.o pci.o \
pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \
- irq.o vpd.o setup-bus.o vc.o
+ irq.o vpd.o setup-bus.o vc.o setup-irq.o
+
obj-$(CONFIG_PROC_FS) +=3D proc.o
obj-$(CONFIG_SYSFS) +=3D slot.o
=20
@@ -31,18 +32,6 @@ obj-$(CONFIG_PCI_ATS) +=3D ats.o
obj-$(CONFIG_PCI_IOV) +=3D iov.o
=20
#
-# Some architectures use the generic PCI setup functions
-#
-obj-$(CONFIG_ALPHA) +=3D setup-irq.o
-obj-$(CONFIG_ARM) +=3D setup-irq.o
-obj-$(CONFIG_UNICORE32) +=3D setup-irq.o
-obj-$(CONFIG_SUPERH) +=3D setup-irq.o
-obj-$(CONFIG_MIPS) +=3D setup-irq.o
-obj-$(CONFIG_TILE) +=3D setup-irq.o
-obj-$(CONFIG_SPARC_LEON) +=3D setup-irq.o
-obj-$(CONFIG_M68K) +=3D setup-irq.o
-
-#
# ACPI Related PCI FW Functions
# ACPI _DSM provided firmware instance and string name
#
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
index 0e5f3c9..8ed186f 100644
--- a/drivers/pci/host-bridge.c
+++ b/drivers/pci/host-bridge.c
@@ -16,7 +16,7 @@ static struct pci_bus *find_pci_root_bus(struct pci=
_bus *bus)
return bus;
}
=20
-static struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *=
bus)
+struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus)
When I did the same thing in one of the versions of my generic host bri=
dge series,
Bjorn has mentioned that he would like the name to be changed to pci_xx=
xxx to
make clear that the function is now public.
{
struct pci_bus *root_bus =3D find_pci_root_bus(bus);
=20
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 2c9ac70..2dd28d9 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1192,11 +1192,15 @@ static int do_pci_enable_device(struct pci_de=
v *dev, int bars)
struct pci_dev *bridge;
u16 cmd;
u8 pin;
+ struct pci_host_bridge *hbrg =3D find_pci_host_bridge(dev->bus);
=20
err =3D pci_set_power_state(dev, PCI_D0);
if (err < 0 && err !=3D -EIO)
return err;
=20
+ pdev_assign_irq(dev, hbrg->swizzle_irq, hbrg->map_irq);
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+
bridge =3D pci_upstream_bridge(dev);
if (bridge)
pcie_aspm_powersave_config_link(bridge);
@@ -1209,7 +1213,6 @@ static int do_pci_enable_device(struct pci_dev =
*dev, int bars)
if (dev->msi_enabled || dev->msix_enabled)
return 0;
=20
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (pin) {
pci_read_config_word(dev, PCI_COMMAND, &cmd);
if (cmd & PCI_COMMAND_INTX_DISABLE)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 0601890..a6cf445 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -70,6 +70,7 @@ void pci_config_pm_runtime_put(struct pci_dev *dev)=
;
void pci_pm_init(struct pci_dev *dev);
void pci_allocate_cap_save_buffers(struct pci_dev *dev);
void pci_free_cap_save_buffers(struct pci_dev *dev);
+struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus);
=20
static inline void pci_wakeup_event(struct pci_dev *dev)
{
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 4170113..314e9e3 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1719,18 +1719,6 @@ unsigned int pci_scan_child_bus(struct pci_bus=
*bus)
}
EXPORT_SYMBOL_GPL(pci_scan_child_bus);
=20
-/**
- * pcibios_root_bridge_prepare - Platform-specific host bridge setup=
=2E
- *
- * Default empty implementation. Replace with an architecture-speci=
fic setup
- * routine, if necessary.
- */
-int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridg=
e)
-{
- return 0;
-}
-
Any reason for removing this? It is meant for host bridge setup, I don'=
t see how
it relates to your patchset.
void __weak pcibios_add_bus(struct pci_bus *bus)
{
}
diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c
index 4e2d595..203bf7e 100644
--- a/drivers/pci/setup-irq.c
+++ b/drivers/pci/setup-irq.c
@@ -22,13 +22,19 @@ void __weak pcibios_update_irq(struct pci_dev *de=
v, int irq)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
=20
-static void pdev_fixup_irq(struct pci_dev *dev,
+void pdev_assign_irq(struct pci_dev *dev,
u8 (*swizzle)(struct pci_dev *, u8 *),
- int (*map_irq)(const struct pci_dev *, u8, u8))
+ int (*map_irq)(struct pci_dev *, u8, u8))
{
- u8 pin, slot;
+ u8 pin;
+ u8 slot =3D -1;
int irq =3D 0;
=20
+ if (!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
which interrupt pin it will come in on. We know which slot it
will come in on 'cos that slot is where the bridge is. Each
@@ -40,28 +46,20 @@ static void pdev_fixup_irq(struct pci_dev *dev,
if (pin > 4)
pin =3D 1;
=20
- if (pin !=3D 0) {
- /* Follow the chain of bridges, swizzling as we go. */
- slot =3D (*swizzle)(dev, &pin);
+ if (pin) {
+ /* Follow the chain of bridges, swizzling as we go. */
Space adjustments in comments should be a separate patch. And if you ca=
re so much about
spaces ....
+ if(swizzle)
how about adding one here?
+ slot =3D (*swizzle)(dev, &pin);
=20
+ /* If a swizzling function is not used map_irq must ignore slot */
irq =3D (*map_irq)(dev, slot, pin);
if (irq =3D=3D -1)
irq =3D 0;
}
- dev->irq =3D irq;
-
- dev_dbg(&dev->dev, "fixup irq: got %d\n", dev->irq);
=20
+ dev_dbg(&dev->dev, "assign irq: got %d\n", dev->irq);
+ dev->irq =3D irq;
/* Always tell the device, so the driver knows what is
the real IRQ to use; the device does not use it. */
pcibios_update_irq(dev, irq);
}
-
-void pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
- int (*map_irq)(const struct pci_dev *, u8, u8))
-{
- struct pci_dev *dev =3D NULL;
-
- for_each_pci_dev(dev)
- pdev_fixup_irq(dev, swizzle, map_irq);
-}
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 96453f9..5426d11 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -403,6 +403,8 @@ struct pci_host_bridge {
struct device dev;
struct pci_bus *bus; /* root bus */
struct list_head windows; /* pci_host_bridge_windows */
+ u8 (*swizzle_irq)(struct pci_dev *, u8 *); /* platform irq swizzler=
*/
+ int (*map_irq)(struct pci_dev *, u8, u8);
I think you should split this patch so that you first introduce the hoo=
ks and the
way to set them and after that you make the change from pdev_fixup_irq =
to pdev_assign_irq.

Best regards,
Liviu
void (*release_fn)(struct pci_host_bridge *);
void *release_data;
};
@@ -1064,8 +1066,8 @@ void pci_assign_unassigned_bus_resources(struct=
pci_bus *bus);
void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus);
void pdev_enable_device(struct pci_dev *);
int pci_enable_resources(struct pci_dev *, int mask);
-void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
- int (*)(const struct pci_dev *, u8, u8));
+void pdev_assign_irq(struct pci_dev *dev, u8 (*swizzle)(struct pci_d=
ev *, u8 *),
+ int (*map_irq)(struct pci_dev *, u8, u8));
#define HAVE_PCI_REQ_REGIONS 2
int __must_check pci_request_regions(struct pci_dev *, const char *)=
;
int __must_check pci_request_regions_exclusive(struct pci_dev *, con=
st char *);
--=20
2.1.0
=20
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" =
in
More majordomo info at http://vger.kernel.org/majordomo-info.html
=20
--=20
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
| I would like to |
| fix the world, |
| but they're not |
| giving me the |
\ source code! /
---------------
=C2=AF\_(=E3=83=84)_/=C2=AF
Bjorn Helgaas
2014-10-14 23:25:18 UTC
Permalink
Post by Liviu Dudau
Hi Matthew,
Hi Liviu,

Thank you very much for reviewing this! Sorry that I didn't notice your
comments until later (mutt email-reading snafu on my end), so I duplicated
some of your thoughts. This was just out of my ignorance, not because I'm
taking issue with your comments.
Post by Liviu Dudau
Post by m***@masarand.com
-static struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus)
+struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus)
When I did the same thing in one of the versions of my generic host bridge series,
Bjorn has mentioned that he would like the name to be changed to pci_xxxxx to
make clear that the function is now public.
This particular one is not a big deal to me because it's in
drivers/pci/pci.h, which is really only for use inside the PCI core. It's
when we expose things in include/linux/pci.h, and especially when we export
things for use by modules, that I think we should be careful to use a
consistent namespace.

Bjorn

Bjorn Helgaas
2014-10-14 17:15:19 UTC
Permalink
I like the overall idea here and I think this will be a major improvement.
But we need to tweak a few procedural things to integrate it cleanly.
Please run "git log --oneline --no-merges drivers/pci" and follow the
style there for subject lines, i.e.,

PCI: Add ...

For the patches that touch things outside drivers/pci, e.g., the
architecture patches, run git log on those as well and try to do something
consistent with previous patch descriptions.
Post by m***@masarand.com
These are the main infrastructure changes to allow the registration of
PCI IRQ assignment functions which can then be called during the device
enabling stage. This replaces the pre-initialisation of PCI IRQs at boot
time which caused limitations such as failing for devices which are
hot-plugged after the machine has booted and resulted in highly
fragmented PCI initialisation paths.
The pdev_assign_irq function becomes a centralised method of assigning
IRQs to PCI devices in a non platform specific way. The pci_host_bridge
structure has had some function pointers added to it where the boot code
can register the platform specific ways of assigning PCI IRQs to be used
to allow them to be used by pdev_assign_irq.
Some small adjustements have also been made to makefiles in order to
accomodate these changes.
Note this code completely obsolites the pci_fixup_irqs code path which
has thus been removed.
---
drivers/of/of_pci_irq.c | 2 +-
drivers/pci/Makefile | 15 ++-------------
drivers/pci/host-bridge.c | 2 +-
drivers/pci/pci.c | 5 ++++-
drivers/pci/pci.h | 1 +
drivers/pci/probe.c | 12 ------------
drivers/pci/setup-irq.c | 34 ++++++++++++++++------------------
include/linux/pci.h | 6 ++++--
8 files changed, 29 insertions(+), 48 deletions(-)
There's a lot going on in this first patch. I'd like to split it up so
it's easier to see where the critical changes are. For example, I think it
is safe to build setup-irq.o for all arches, even if they don't actually
use it, so the makefile changes could be split out. Similarly for the
change to make find_pci_host_bridge() non-static.
Post by m***@masarand.com
diff --git a/drivers/of/of_pci_irq.c b/drivers/of/of_pci_irq.c
index 1710d9d..205eb7a 100644
--- a/drivers/of/of_pci_irq.c
+++ b/drivers/of/of_pci_irq.c
@@ -97,7 +97,7 @@ EXPORT_SYMBOL_GPL(of_irq_parse_pci);
*
- * function can be used directly as the map_irq callback to pci_fixup_irqs().
+ * function can be used directly as the map_irq callback to pdev_assign_irq().
*/
int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin)
{
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index e04fe2d..38c4cb0 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -4,7 +4,8 @@
obj-y += access.o bus.o probe.o host-bridge.o remove.o pci.o \
pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \
- irq.o vpd.o setup-bus.o vc.o
+ irq.o vpd.o setup-bus.o vc.o setup-irq.o
+
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSFS) += slot.o
@@ -31,18 +32,6 @@ obj-$(CONFIG_PCI_ATS) += ats.o
obj-$(CONFIG_PCI_IOV) += iov.o
#
-# Some architectures use the generic PCI setup functions
-#
-obj-$(CONFIG_ALPHA) += setup-irq.o
-obj-$(CONFIG_ARM) += setup-irq.o
-obj-$(CONFIG_UNICORE32) += setup-irq.o
-obj-$(CONFIG_SUPERH) += setup-irq.o
-obj-$(CONFIG_MIPS) += setup-irq.o
-obj-$(CONFIG_TILE) += setup-irq.o
-obj-$(CONFIG_SPARC_LEON) += setup-irq.o
-obj-$(CONFIG_M68K) += setup-irq.o
-
-#
# ACPI Related PCI FW Functions
# ACPI _DSM provided firmware instance and string name
#
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
index 0e5f3c9..8ed186f 100644
--- a/drivers/pci/host-bridge.c
+++ b/drivers/pci/host-bridge.c
@@ -16,7 +16,7 @@ static struct pci_bus *find_pci_root_bus(struct pci_bus *bus)
return bus;
}
-static struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus)
+struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus)
{
struct pci_bus *root_bus = find_pci_root_bus(bus);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 2c9ac70..2dd28d9 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1192,11 +1192,15 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
struct pci_dev *bridge;
u16 cmd;
u8 pin;
+ struct pci_host_bridge *hbrg = find_pci_host_bridge(dev->bus);
err = pci_set_power_state(dev, PCI_D0);
if (err < 0 && err != -EIO)
return err;
+ pdev_assign_irq(dev, hbrg->swizzle_irq, hbrg->map_irq);
We don't need the host bridge for anything else here, so why not just look
it up inside pdev_assign_irq()?
Post by m***@masarand.com
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+
bridge = pci_upstream_bridge(dev);
if (bridge)
pcie_aspm_powersave_config_link(bridge);
@@ -1209,7 +1213,6 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars)
if (dev->msi_enabled || dev->msix_enabled)
return 0;
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (pin) {
pci_read_config_word(dev, PCI_COMMAND, &cmd);
if (cmd & PCI_COMMAND_INTX_DISABLE)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 0601890..a6cf445 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -70,6 +70,7 @@ void pci_config_pm_runtime_put(struct pci_dev *dev);
void pci_pm_init(struct pci_dev *dev);
void pci_allocate_cap_save_buffers(struct pci_dev *dev);
void pci_free_cap_save_buffers(struct pci_dev *dev);
+struct pci_host_bridge *find_pci_host_bridge(struct pci_bus *bus);
static inline void pci_wakeup_event(struct pci_dev *dev)
{
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 4170113..314e9e3 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1719,18 +1719,6 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
}
EXPORT_SYMBOL_GPL(pci_scan_child_bus);
-/**
- * pcibios_root_bridge_prepare - Platform-specific host bridge setup.
- *
- * Default empty implementation. Replace with an architecture-specific setup
- * routine, if necessary.
- */
-int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
-{
- return 0;
-}
We can't just remove this, because it will cause link failures for any arch
that doesn't supply its own implementation of
pcibios_root_bridge_prepare(). Future patches add such implementations,
but the tree should build and work correctly after every patch. That is
required for bisectability.

If your intent is that every arch must supply its own
pcibios_root_bridge_prepare(), you should

- keep the __weak version here,
- add a non-weak version for every arch,
- then finally remove this __weak default version at the end.
Post by m***@masarand.com
-
void __weak pcibios_add_bus(struct pci_bus *bus)
{
}
diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c
index 4e2d595..203bf7e 100644
--- a/drivers/pci/setup-irq.c
+++ b/drivers/pci/setup-irq.c
@@ -22,13 +22,19 @@ void __weak pcibios_update_irq(struct pci_dev *dev, int irq)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
-static void pdev_fixup_irq(struct pci_dev *dev,
+void pdev_assign_irq(struct pci_dev *dev,
u8 (*swizzle)(struct pci_dev *, u8 *),
- int (*map_irq)(const struct pci_dev *, u8, u8))
+ int (*map_irq)(struct pci_dev *, u8, u8))
{
- u8 pin, slot;
+ u8 pin;
+ u8 slot = -1;
int irq = 0;
+ if (!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
which interrupt pin it will come in on. We know which slot it
will come in on 'cos that slot is where the bridge is. Each
@@ -40,28 +46,20 @@ static void pdev_fixup_irq(struct pci_dev *dev,
if (pin > 4)
pin = 1;
- if (pin != 0) {
- /* Follow the chain of bridges, swizzling as we go. */
- slot = (*swizzle)(dev, &pin);
+ if (pin) {
+ /* Follow the chain of bridges, swizzling as we go. */
+ if(swizzle)
+ slot = (*swizzle)(dev, &pin);
+ /* If a swizzling function is not used map_irq must ignore slot */
irq = (*map_irq)(dev, slot, pin);
if (irq == -1)
irq = 0;
}
- 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);
+ dev->irq = irq;
/* Always tell the device, so the driver knows what is
the real IRQ to use; the device does not use it. */
pcibios_update_irq(dev, irq);
}
-
-void pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
- int (*map_irq)(const struct pci_dev *, u8, u8))
-{
- struct pci_dev *dev = NULL;
-
- for_each_pci_dev(dev)
- pdev_fixup_irq(dev, swizzle, map_irq);
-}
This removes pci_fixup_irqs(), which is still used (at this point) by many
architectures. I see that you remove those uses in later patches, but that
means the tree is broken in the interim, so it's not bisectable.

I think you're going to have to build up the new assign-IRQ-at-enable-time
path while leaving the old path intact, in such a way that the new path
does nothing until an arch is converted to use it. Then when you convert
each arch to the new strategy, you can remove its use of the old path.
After all arches are converted and there are no users of the old path, you
can remove it completely.
Post by m***@masarand.com
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 96453f9..5426d11 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -403,6 +403,8 @@ struct pci_host_bridge {
struct device dev;
struct pci_bus *bus; /* root bus */
struct list_head windows; /* pci_host_bridge_windows */
+ u8 (*swizzle_irq)(struct pci_dev *, u8 *); /* platform irq swizzler */
+ int (*map_irq)(struct pci_dev *, u8, u8);
void (*release_fn)(struct pci_host_bridge *);
void *release_data;
};
@@ -1064,8 +1066,8 @@ void pci_assign_unassigned_bus_resources(struct pci_bus *bus);
void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus);
void pdev_enable_device(struct pci_dev *);
int pci_enable_resources(struct pci_dev *, int mask);
-void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
- int (*)(const struct pci_dev *, u8, u8));
+void pdev_assign_irq(struct pci_dev *dev, u8 (*swizzle)(struct pci_dev *, u8 *),
For things exported via include/linux/pci.h, I think we should use names
prefixed by "pci_", not "pdev_".
Post by m***@masarand.com
+ int (*map_irq)(struct pci_dev *, u8, u8));
#define HAVE_PCI_REQ_REGIONS 2
int __must_check pci_request_regions(struct pci_dev *, const char *);
int __must_check pci_request_regions_exclusive(struct pci_dev *, const char *);
Bjorn
m***@masarand.com
2014-10-02 04:07:32 UTC
Permalink
From: Matthew Minter <***@masarand.com>

The powerpc PCI init code is currently initialising PCI device IRQ during
the boot time pcibios phase. This results in devices which are connected
after boot time not being asigned IRQs which can cause various problems.

This patch as part of its set fixes this be moving the IRQ initialisation
into the PCI device enable code path so that it is run for boot time and
hot-plugged devices alike.

Signed-off-by: Matthew Minter <***@masarand.com>

---
arch/powerpc/kernel/pci-common.c | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index b2814e2..a8be5a5 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -217,7 +217,7 @@ struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
* If the interrupt is used, then gets the interrupt line from the
* openfirmware and sets it in the pci_dev and pci_config line.
*/
-static int pci_read_irq_line(struct pci_dev *pci_dev)
+static int pci_read_irq_line(struct pci_dev *pci_dev, u8 pin)
{
struct of_phandle_args oirq;
unsigned int virq;
@@ -229,7 +229,7 @@ static int pci_read_irq_line(struct pci_dev *pci_dev)
#endif
/* Try to get a mapping from the device-tree */
if (of_irq_parse_pci(pci_dev, &oirq)) {
- u8 line, pin;
+ u8 line;

/* If that fails, lets fallback to what is in the config
* space and map that through the default controller. We
@@ -238,10 +238,6 @@ static int pci_read_irq_line(struct pci_dev *pci_dev)
* either provide a proper interrupt tree or don't use this
* function.
*/
- if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &pin))
- return -1;
- if (pin == 0)
- return -1;
if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_LINE, &line) ||
line == 0xff || line == 0) {
return -1;
@@ -266,9 +262,16 @@ static int pci_read_irq_line(struct pci_dev *pci_dev)

pr_debug(" Mapped to linux irq %d\n", virq);

- pci_dev->irq = virq;
+ return virq;
+}

- return 0;
+int pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ /* Read default IRQs and fixup if necessary */
+ int irq = pci_read_irq_line(dev, pin);
+ if (ppc_md.pci_irq_fixup)
+ ppc_md.pci_irq_fixup(dev);
+ return irq;
}

/*
@@ -766,6 +769,8 @@ int pci_proc_domain(struct pci_bus *bus)

int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pci_map_irq;
if (ppc_md.pcibios_root_bridge_prepare)
return ppc_md.pcibios_root_bridge_prepare(bridge);

@@ -968,11 +973,6 @@ static void pcibios_setup_device(struct pci_dev *dev)
/* Additional platform DMA/iommu setup */
if (ppc_md.pci_dma_dev_setup)
ppc_md.pci_dma_dev_setup(dev);
-
- /* Read default IRQs and fixup if necessary */
- pci_read_irq_line(dev);
- if (ppc_md.pci_irq_fixup)
- ppc_md.pci_irq_fixup(dev);
}

int pcibios_add_device(struct pci_dev *dev)
--
2.1.0
Bjorn Helgaas
2014-10-14 18:20:48 UTC
Permalink
Post by m***@masarand.com
The powerpc PCI init code is currently initialising PCI device IRQ during
the boot time pcibios phase. This results in devices which are connected
after boot time not being asigned IRQs which can cause various problems.
This patch as part of its set fixes this be moving the IRQ initialisation
into the PCI device enable code path so that it is run for boot time and
hot-plugged devices alike.
---
arch/powerpc/kernel/pci-common.c | 26 +++++++++++++-------------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index b2814e2..a8be5a5 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -217,7 +217,7 @@ struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
* If the interrupt is used, then gets the interrupt line from the
* openfirmware and sets it in the pci_dev and pci_config line.
*/
-static int pci_read_irq_line(struct pci_dev *pci_dev)
+static int pci_read_irq_line(struct pci_dev *pci_dev, u8 pin)
{
struct of_phandle_args oirq;
unsigned int virq;
@@ -229,7 +229,7 @@ static int pci_read_irq_line(struct pci_dev *pci_dev)
#endif
/* Try to get a mapping from the device-tree */
if (of_irq_parse_pci(pci_dev, &oirq)) {
- u8 line, pin;
+ u8 line;
/* If that fails, lets fallback to what is in the config
* space and map that through the default controller. We
@@ -238,10 +238,6 @@ static int pci_read_irq_line(struct pci_dev *pci_dev)
* either provide a proper interrupt tree or don't use this
* function.
*/
- if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &pin))
- return -1;
- if (pin == 0)
- return -1;
if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_LINE, &line) ||
line == 0xff || line == 0) {
return -1;
@@ -266,9 +262,16 @@ static int pci_read_irq_line(struct pci_dev *pci_dev)
pr_debug(" Mapped to linux irq %d\n", virq);
- pci_dev->irq = virq;
+ return virq;
+}
- return 0;
+int pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
Should be static.
Post by m***@masarand.com
+{
+ /* Read default IRQs and fixup if necessary */
+ int irq = pci_read_irq_line(dev, pin);
+ if (ppc_md.pci_irq_fixup)
+ ppc_md.pci_irq_fixup(dev);
+ return irq;
The .pci_irq_fixup() can change dev->irq, so wouldn't you want to return
dev->irq, not irq, here? Otherwise, pdev_assign_irq() (the caller of
pci_map_irq()) will overwrite the dev->irq value set by the fixup.
Post by m***@masarand.com
}
/*
@@ -766,6 +769,8 @@ int pci_proc_domain(struct pci_bus *bus)
int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pci_map_irq;
if (ppc_md.pcibios_root_bridge_prepare)
return ppc_md.pcibios_root_bridge_prepare(bridge);
@@ -968,11 +973,6 @@ static void pcibios_setup_device(struct pci_dev *dev)
/* Additional platform DMA/iommu setup */
if (ppc_md.pci_dma_dev_setup)
ppc_md.pci_dma_dev_setup(dev);
-
- /* Read default IRQs and fixup if necessary */
- pci_read_irq_line(dev);
- if (ppc_md.pci_irq_fixup)
- ppc_md.pci_irq_fixup(dev);
}
int pcibios_add_device(struct pci_dev *dev)
--
2.1.0
m***@masarand.com
2014-10-02 04:07:31 UTC
Permalink
From: Matthew Minter <***@masarand.com>

Currently PCI device IRQs under arm are initialised during the
pci_common_init_dev code path, this results in an extra sweep of the
PCI bus as well as causing PCI devices hot-plugged after boot to not
receive an IRQ.

This patch set defers this assignment untill the device enable phase
which prevents both these issues.

Signed-off-by: Matthew Minter <***@masarand.com>

---
arch/arm/kernel/bios32.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 17a26c1..4dcf3f7 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -389,7 +389,7 @@ void pcibios_remove_bus(struct pci_bus *bus)
* PCI standard swizzle is implemented on plug-in cards and Cardbus based
* PCI extenders, so it can not be ignored.
*/
-static u8 pcibios_swizzle(struct pci_dev *dev, u8 *pin)
+u8 pcibios_swizzle(struct pci_dev *dev, u8 *pin)
{
struct pci_sys_data *sys = dev->sysdata;
int slot, oldpin = *pin;
@@ -409,7 +409,7 @@ static u8 pcibios_swizzle(struct pci_dev *dev, u8 *pin)
/*
* Map a slot/pin to an IRQ.
*/
-static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+int pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
struct pci_sys_data *sys = dev->sysdata;
int irq = -1;
@@ -424,6 +424,13 @@ static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
return irq;
}

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pcibios_swizzle;
+ bridge->map_irq = pcibios_map_irq;
+ return 0;
+}
+
static int pcibios_init_resources(int busnr, struct pci_sys_data *sys)
{
int ret;
@@ -523,8 +530,6 @@ void pci_common_init_dev(struct device *parent, struct hw_pci *hw)
if (hw->postinit)
hw->postinit();

- pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq);
-
list_for_each_entry(sys, &head, node) {
struct pci_bus *bus = sys->bus;
--
2.1.0
Bjorn Helgaas
2014-10-14 18:14:29 UTC
Permalink
Post by m***@masarand.com
Currently PCI device IRQs under arm are initialised during the
pci_common_init_dev code path, this results in an extra sweep of the
PCI bus as well as causing PCI devices hot-plugged after boot to not
receive an IRQ.
This patch set defers this assignment untill the device enable phase
which prevents both these issues.
---
arch/arm/kernel/bios32.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 17a26c1..4dcf3f7 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -389,7 +389,7 @@ void pcibios_remove_bus(struct pci_bus *bus)
* PCI standard swizzle is implemented on plug-in cards and Cardbus based
* PCI extenders, so it can not be ignored.
*/
-static u8 pcibios_swizzle(struct pci_dev *dev, u8 *pin)
+u8 pcibios_swizzle(struct pci_dev *dev, u8 *pin)
I don't think there's anything in this patch that requires
pcibios_swizzle() or pcibios_map_irq() to be non-static.
Post by m***@masarand.com
{
struct pci_sys_data *sys = dev->sysdata;
int slot, oldpin = *pin;
@@ -409,7 +409,7 @@ static u8 pcibios_swizzle(struct pci_dev *dev, u8 *pin)
/*
* Map a slot/pin to an IRQ.
*/
-static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+int pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
struct pci_sys_data *sys = dev->sysdata;
int irq = -1;
@@ -424,6 +424,13 @@ static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
return irq;
}
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pcibios_swizzle;
+ bridge->map_irq = pcibios_map_irq;
+ return 0;
+}
+
static int pcibios_init_resources(int busnr, struct pci_sys_data *sys)
{
int ret;
@@ -523,8 +530,6 @@ void pci_common_init_dev(struct device *parent, struct hw_pci *hw)
if (hw->postinit)
hw->postinit();
- pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq);
-
list_for_each_entry(sys, &head, node) {
struct pci_bus *bus = sys->bus;
--
2.1.0
m***@masarand.com
2014-10-02 04:07:36 UTC
Permalink
From: Matthew Minter <***@masarand.com>

PCI IRQs are being assigned during the frv pcibios phase. This causes
devices which are not connected at boot but are later hot-plugged
to not receive an IRQ. This patch set causes the pcibios to instead
register an IRQ assignment function which is called during the enable
device path to apply to all devices.

Signed-off-by: Matthew Minter <***@masarand.com>

---
arch/frv/mb93090-mb00/pci-frv.h | 1 -
arch/frv/mb93090-mb00/pci-irq.c | 28 +++++++++++++++++-----------
arch/frv/mb93090-mb00/pci-vdk.c | 1 -
3 files changed, 17 insertions(+), 13 deletions(-)

diff --git a/arch/frv/mb93090-mb00/pci-frv.h b/arch/frv/mb93090-mb00/pci-frv.h
index a7e487fe..492b56d 100644
--- a/arch/frv/mb93090-mb00/pci-frv.h
+++ b/arch/frv/mb93090-mb00/pci-frv.h
@@ -36,5 +36,4 @@ extern struct pci_ops *__nongpreldata pci_root_ops;
extern unsigned int pcibios_irq_mask;

void pcibios_irq_init(void);
-void pcibios_fixup_irqs(void);
void pcibios_enable_irq(struct pci_dev *dev);
diff --git a/arch/frv/mb93090-mb00/pci-irq.c b/arch/frv/mb93090-mb00/pci-irq.c
index 1c35c93..3463e30 100644
--- a/arch/frv/mb93090-mb00/pci-irq.c
+++ b/arch/frv/mb93090-mb00/pci-irq.c
@@ -40,19 +40,25 @@ void __init pcibios_irq_init(void)
{
}

-void __init pcibios_fixup_irqs(void)
+int pcibios_map_irq(struct pci_dev *dev, uint8_t slot, uint8_t pin)
{
- struct pci_dev *dev = NULL;
- uint8_t line, pin;
-
- for_each_pci_dev(dev) {
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
- if (pin) {
- dev->irq = pci_bus0_irq_routing[PCI_SLOT(dev->devfn)][pin - 1];
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
- }
- pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line);
+ uint8_t line;
+ int irq;
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ if (pin) {
+ irq = pci_bus0_irq_routing[PCI_SLOT(dev->devfn)][pin - 1];
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
+ pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line);
+ return irq;
+}
+
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pcibios_map_irq;
+ return 0;
}

void pcibios_enable_irq(struct pci_dev *dev)
diff --git a/arch/frv/mb93090-mb00/pci-vdk.c b/arch/frv/mb93090-mb00/pci-vdk.c
index efa5d65..86657a7 100644
--- a/arch/frv/mb93090-mb00/pci-vdk.c
+++ b/arch/frv/mb93090-mb00/pci-vdk.c
@@ -386,7 +386,6 @@ int __init pcibios_init(void)
pci_scan_root_bus(NULL, 0, pci_root_ops, NULL, &resources);

pcibios_irq_init();
- pcibios_fixup_irqs();
pcibios_resource_survey();

return 0;
--
2.1.0
Bjorn Helgaas
2014-10-14 18:37:26 UTC
Permalink
Post by m***@masarand.com
PCI IRQs are being assigned during the frv pcibios phase. This causes
devices which are not connected at boot but are later hot-plugged
to not receive an IRQ. This patch set causes the pcibios to instead
register an IRQ assignment function which is called during the enable
device path to apply to all devices.
---
arch/frv/mb93090-mb00/pci-frv.h | 1 -
arch/frv/mb93090-mb00/pci-irq.c | 28 +++++++++++++++++-----------
arch/frv/mb93090-mb00/pci-vdk.c | 1 -
3 files changed, 17 insertions(+), 13 deletions(-)
diff --git a/arch/frv/mb93090-mb00/pci-frv.h b/arch/frv/mb93090-mb00/pci-frv.h
index a7e487fe..492b56d 100644
--- a/arch/frv/mb93090-mb00/pci-frv.h
+++ b/arch/frv/mb93090-mb00/pci-frv.h
@@ -36,5 +36,4 @@ extern struct pci_ops *__nongpreldata pci_root_ops;
extern unsigned int pcibios_irq_mask;
void pcibios_irq_init(void);
-void pcibios_fixup_irqs(void);
void pcibios_enable_irq(struct pci_dev *dev);
diff --git a/arch/frv/mb93090-mb00/pci-irq.c b/arch/frv/mb93090-mb00/pci-irq.c
index 1c35c93..3463e30 100644
--- a/arch/frv/mb93090-mb00/pci-irq.c
+++ b/arch/frv/mb93090-mb00/pci-irq.c
@@ -40,19 +40,25 @@ void __init pcibios_irq_init(void)
{
}
-void __init pcibios_fixup_irqs(void)
+int pcibios_map_irq(struct pci_dev *dev, uint8_t slot, uint8_t pin)
{
- struct pci_dev *dev = NULL;
- uint8_t line, pin;
-
- for_each_pci_dev(dev) {
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
- if (pin) {
- dev->irq = pci_bus0_irq_routing[PCI_SLOT(dev->devfn)][pin - 1];
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
- }
- pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line);
+ uint8_t line;
+ int irq;
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
Doesn't your common code always read PCI_INTERRUPT_PIN and pass it in, so
you wouldn't need to read it again here?
Post by m***@masarand.com
+ if (pin) {
+ irq = pci_bus0_irq_routing[PCI_SLOT(dev->devfn)][pin - 1];
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
+ pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line);
+ return irq;
+}
+
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pcibios_map_irq;
+ return 0;
}
void pcibios_enable_irq(struct pci_dev *dev)
diff --git a/arch/frv/mb93090-mb00/pci-vdk.c b/arch/frv/mb93090-mb00/pci-vdk.c
index efa5d65..86657a7 100644
--- a/arch/frv/mb93090-mb00/pci-vdk.c
+++ b/arch/frv/mb93090-mb00/pci-vdk.c
@@ -386,7 +386,6 @@ int __init pcibios_init(void)
pci_scan_root_bus(NULL, 0, pci_root_ops, NULL, &resources);
pcibios_irq_init();
- pcibios_fixup_irqs();
pcibios_resource_survey();
return 0;
--
2.1.0
m***@masarand.com
2014-10-02 04:07:38 UTC
Permalink
From: Matthew Minter <***@masarand.com>

Currently microblaze assigns PCI IRQs during the pcibios phase, this means
that devices connected after boot will not be assigned an IRQ, instead the
boot code now registers IRQ assignment functions to be called later by the
device enable code paths.

Signed-off-by: Matthew Minter <***@masarand.com>

---
arch/microblaze/pci/pci-common.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index 9037914..6843b34 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
@@ -850,12 +850,16 @@ void pcibios_setup_bus_devices(struct pci_bus *bus)
* code and is needed by the DMA init
*/
set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
-
- /* Read default IRQs and fixup if necessary */
- dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
}
}

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = of_irq_parse_and_map_pci;
+ return 0;
+}
+
void pcibios_fixup_bus(struct pci_bus *bus)
{
/* When called from the generic PCI probe, read PCI<->PCI bridge
--
2.1.0
m***@masarand.com
2014-10-02 04:07:33 UTC
Permalink
From: Matthew Minter <***@masarand.com>

Currently platform specific PCI device IRQ assignment is run during
the boot code, this results in a wide array of differing code paths
and causes hot-plugged PCI devices to not be assigned IRQs, this
patch removes the boot time initialisation of such IRQs and instead
registers assignment functions to be run during the PCI device enable
plase.

Signed-off-by: Matthew Minter <***@masarand.com>

---
arch/sh/drivers/pci/fixups-cayman.c | 2 +-
arch/sh/drivers/pci/fixups-dreamcast.c | 2 +-
arch/sh/drivers/pci/fixups-r7780rp.c | 2 +-
arch/sh/drivers/pci/fixups-rts7751r2d.c | 6 +++---
arch/sh/drivers/pci/fixups-sdk7780.c | 4 ++--
arch/sh/drivers/pci/fixups-se7751.c | 2 +-
arch/sh/drivers/pci/fixups-sh03.c | 2 +-
arch/sh/drivers/pci/fixups-snapgear.c | 2 +-
arch/sh/drivers/pci/fixups-titan.c | 4 ++--
arch/sh/drivers/pci/pci.c | 10 +++++++---
arch/sh/drivers/pci/pcie-sh7786.c | 2 +-
11 files changed, 21 insertions(+), 17 deletions(-)

diff --git a/arch/sh/drivers/pci/fixups-cayman.c b/arch/sh/drivers/pci/fixups-cayman.c
index edc2fb7..3246788 100644
--- a/arch/sh/drivers/pci/fixups-cayman.c
+++ b/arch/sh/drivers/pci/fixups-cayman.c
@@ -5,7 +5,7 @@
#include <cpu/irq.h>
#include "pci-sh5.h"

-int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
int result = -1;

diff --git a/arch/sh/drivers/pci/fixups-dreamcast.c b/arch/sh/drivers/pci/fixups-dreamcast.c
index 1d1c5a2..9d597f7 100644
--- a/arch/sh/drivers/pci/fixups-dreamcast.c
+++ b/arch/sh/drivers/pci/fixups-dreamcast.c
@@ -76,7 +76,7 @@ static void gapspci_fixup_resources(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, gapspci_fixup_resources);

-int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
/*
* The interrupt routing semantics here are quite trivial.
diff --git a/arch/sh/drivers/pci/fixups-r7780rp.c b/arch/sh/drivers/pci/fixups-r7780rp.c
index 57ed3f0..2c9b58f 100644
--- a/arch/sh/drivers/pci/fixups-r7780rp.c
+++ b/arch/sh/drivers/pci/fixups-r7780rp.c
@@ -15,7 +15,7 @@
#include <linux/sh_intc.h>
#include "pci-sh4.h"

-int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
return evt2irq(0xa20) + slot;
}
diff --git a/arch/sh/drivers/pci/fixups-rts7751r2d.c b/arch/sh/drivers/pci/fixups-rts7751r2d.c
index eaddb56..358ac10 100644
--- a/arch/sh/drivers/pci/fixups-rts7751r2d.c
+++ b/arch/sh/drivers/pci/fixups-rts7751r2d.c
@@ -20,18 +20,18 @@
#define PCIMCR_MRSET_OFF 0xBFFFFFFF
#define PCIMCR_RFSH_OFF 0xFFFFFFFB

-static u8 rts7751r2d_irq_tab[] __initdata = {
+static u8 rts7751r2d_irq_tab[] = {
IRQ_PCI_INTA,
IRQ_PCI_INTB,
IRQ_PCI_INTC,
IRQ_PCI_INTD,
};

-static char lboxre2_irq_tab[] __initdata = {
+static char lboxre2_irq_tab[] = {
IRQ_ETH0, IRQ_ETH1, IRQ_INTA, IRQ_INTD,
};

-int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
if (mach_is_lboxre2())
return lboxre2_irq_tab[slot];
diff --git a/arch/sh/drivers/pci/fixups-sdk7780.c b/arch/sh/drivers/pci/fixups-sdk7780.c
index c0a015a..24e96df 100644
--- a/arch/sh/drivers/pci/fixups-sdk7780.c
+++ b/arch/sh/drivers/pci/fixups-sdk7780.c
@@ -22,7 +22,7 @@
#define IRQ_INTD evt2irq(0xa80)

/* IDSEL [16][17][18][19][20][21][22][23][24][25][26][27][28][29][30][31] */
-static char sdk7780_irq_tab[4][16] __initdata = {
+static char sdk7780_irq_tab[4][16] = {
/* INTA */
{ IRQ_INTA, IRQ_INTD, IRQ_INTC, IRQ_INTD, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1 },
@@ -37,7 +37,7 @@ static char sdk7780_irq_tab[4][16] __initdata = {
-1, -1, -1 },
};

-int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
return sdk7780_irq_tab[pin-1][slot];
}
diff --git a/arch/sh/drivers/pci/fixups-se7751.c b/arch/sh/drivers/pci/fixups-se7751.c
index 84a88ca..1cb8d0a 100644
--- a/arch/sh/drivers/pci/fixups-se7751.c
+++ b/arch/sh/drivers/pci/fixups-se7751.c
@@ -7,7 +7,7 @@
#include <linux/sh_intc.h>
#include "pci-sh4.h"

-int __init pcibios_map_platform_irq(const struct pci_dev *, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *, u8 slot, u8 pin)
{
switch (slot) {
case 0: return evt2irq(0x3a0);
diff --git a/arch/sh/drivers/pci/fixups-sh03.c b/arch/sh/drivers/pci/fixups-sh03.c
index 16207be..55ac1ba 100644
--- a/arch/sh/drivers/pci/fixups-sh03.c
+++ b/arch/sh/drivers/pci/fixups-sh03.c
@@ -4,7 +4,7 @@
#include <linux/pci.h>
#include <linux/sh_intc.h>

-int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
int irq;

diff --git a/arch/sh/drivers/pci/fixups-snapgear.c b/arch/sh/drivers/pci/fixups-snapgear.c
index 6e33ba4..a931e59 100644
--- a/arch/sh/drivers/pci/fixups-snapgear.c
+++ b/arch/sh/drivers/pci/fixups-snapgear.c
@@ -19,7 +19,7 @@
#include <linux/sh_intc.h>
#include "pci-sh4.h"

-int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
int irq = -1;

diff --git a/arch/sh/drivers/pci/fixups-titan.c b/arch/sh/drivers/pci/fixups-titan.c
index bd1addb..a9d563e 100644
--- a/arch/sh/drivers/pci/fixups-titan.c
+++ b/arch/sh/drivers/pci/fixups-titan.c
@@ -19,7 +19,7 @@
#include <mach/titan.h>
#include "pci-sh4.h"

-static char titan_irq_tab[] __initdata = {
+static char titan_irq_tab[] = {
TITAN_IRQ_WAN,
TITAN_IRQ_LAN,
TITAN_IRQ_MPCIA,
@@ -27,7 +27,7 @@ static char titan_irq_tab[] __initdata = {
TITAN_IRQ_USB,
};

-int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
int irq = titan_irq_tab[slot];

diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index 1bc09ee..718fae3 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -141,16 +141,20 @@ static int __init pcibios_init(void)
for (hose = hose_head; hose; hose = hose->next)
pcibios_scanbus(hose);

- pci_fixup_irqs(pci_common_swizzle, pcibios_map_platform_irq);
-
dma_debug_add_bus(&pci_bus_type);
-
pci_initialized = 1;

return 0;
}
subsys_initcall(pcibios_init);

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pci_common_swizzle;
+ bridge->map_irq = pcibios_map_platform_irq;
+ return 0;
+}
+
/*
* Called after each bus is probed, but before its children
* are examined.
diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c
index a162a7f..0167a73 100644
--- a/arch/sh/drivers/pci/pcie-sh7786.c
+++ b/arch/sh/drivers/pci/pcie-sh7786.c
@@ -467,7 +467,7 @@ static int __init pcie_init(struct sh7786_pcie_port *port)
return 0;
}

-int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
return evt2irq(0xae0);
}
--
2.1.0
Bjorn Helgaas
2014-10-14 18:25:45 UTC
Permalink
Post by m***@masarand.com
Currently platform specific PCI device IRQ assignment is run during
the boot code, this results in a wide array of differing code paths
and causes hot-plugged PCI devices to not be assigned IRQs, this
patch removes the boot time initialisation of such IRQs and instead
registers assignment functions to be run during the PCI device enable
plase.
---
arch/sh/drivers/pci/fixups-cayman.c | 2 +-
arch/sh/drivers/pci/fixups-dreamcast.c | 2 +-
arch/sh/drivers/pci/fixups-r7780rp.c | 2 +-
arch/sh/drivers/pci/fixups-rts7751r2d.c | 6 +++---
arch/sh/drivers/pci/fixups-sdk7780.c | 4 ++--
arch/sh/drivers/pci/fixups-se7751.c | 2 +-
arch/sh/drivers/pci/fixups-sh03.c | 2 +-
arch/sh/drivers/pci/fixups-snapgear.c | 2 +-
arch/sh/drivers/pci/fixups-titan.c | 4 ++--
arch/sh/drivers/pci/pci.c | 10 +++++++---
arch/sh/drivers/pci/pcie-sh7786.c | 2 +-
11 files changed, 21 insertions(+), 17 deletions(-)
diff --git a/arch/sh/drivers/pci/fixups-cayman.c b/arch/sh/drivers/pci/fixups-cayman.c
index edc2fb7..3246788 100644
--- a/arch/sh/drivers/pci/fixups-cayman.c
+++ b/arch/sh/drivers/pci/fixups-cayman.c
@@ -5,7 +5,7 @@
#include <cpu/irq.h>
#include "pci-sh5.h"
-int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
Most of this patch is just removing "__init". Can you split it into two:
one that removes the __init annotations, and another that adds the
pcibios_root_bridge_prepare() definition? Then the first will be obviously
correct (it should always be safe to remove the __init optimization), and
the second will be smaller and contain only the interesting part.
Post by m***@masarand.com
{
int result = -1;
diff --git a/arch/sh/drivers/pci/fixups-dreamcast.c b/arch/sh/drivers/pci/fixups-dreamcast.c
index 1d1c5a2..9d597f7 100644
--- a/arch/sh/drivers/pci/fixups-dreamcast.c
+++ b/arch/sh/drivers/pci/fixups-dreamcast.c
@@ -76,7 +76,7 @@ static void gapspci_fixup_resources(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, gapspci_fixup_resources);
-int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
/*
* The interrupt routing semantics here are quite trivial.
diff --git a/arch/sh/drivers/pci/fixups-r7780rp.c b/arch/sh/drivers/pci/fixups-r7780rp.c
index 57ed3f0..2c9b58f 100644
--- a/arch/sh/drivers/pci/fixups-r7780rp.c
+++ b/arch/sh/drivers/pci/fixups-r7780rp.c
@@ -15,7 +15,7 @@
#include <linux/sh_intc.h>
#include "pci-sh4.h"
-int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
return evt2irq(0xa20) + slot;
}
diff --git a/arch/sh/drivers/pci/fixups-rts7751r2d.c b/arch/sh/drivers/pci/fixups-rts7751r2d.c
index eaddb56..358ac10 100644
--- a/arch/sh/drivers/pci/fixups-rts7751r2d.c
+++ b/arch/sh/drivers/pci/fixups-rts7751r2d.c
@@ -20,18 +20,18 @@
#define PCIMCR_MRSET_OFF 0xBFFFFFFF
#define PCIMCR_RFSH_OFF 0xFFFFFFFB
-static u8 rts7751r2d_irq_tab[] __initdata = {
+static u8 rts7751r2d_irq_tab[] = {
IRQ_PCI_INTA,
IRQ_PCI_INTB,
IRQ_PCI_INTC,
IRQ_PCI_INTD,
};
-static char lboxre2_irq_tab[] __initdata = {
+static char lboxre2_irq_tab[] = {
IRQ_ETH0, IRQ_ETH1, IRQ_INTA, IRQ_INTD,
};
-int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
if (mach_is_lboxre2())
return lboxre2_irq_tab[slot];
diff --git a/arch/sh/drivers/pci/fixups-sdk7780.c b/arch/sh/drivers/pci/fixups-sdk7780.c
index c0a015a..24e96df 100644
--- a/arch/sh/drivers/pci/fixups-sdk7780.c
+++ b/arch/sh/drivers/pci/fixups-sdk7780.c
@@ -22,7 +22,7 @@
#define IRQ_INTD evt2irq(0xa80)
/* IDSEL [16][17][18][19][20][21][22][23][24][25][26][27][28][29][30][31] */
-static char sdk7780_irq_tab[4][16] __initdata = {
+static char sdk7780_irq_tab[4][16] = {
/* INTA */
{ IRQ_INTA, IRQ_INTD, IRQ_INTC, IRQ_INTD, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1 },
@@ -37,7 +37,7 @@ static char sdk7780_irq_tab[4][16] __initdata = {
-1, -1, -1 },
};
-int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
return sdk7780_irq_tab[pin-1][slot];
}
diff --git a/arch/sh/drivers/pci/fixups-se7751.c b/arch/sh/drivers/pci/fixups-se7751.c
index 84a88ca..1cb8d0a 100644
--- a/arch/sh/drivers/pci/fixups-se7751.c
+++ b/arch/sh/drivers/pci/fixups-se7751.c
@@ -7,7 +7,7 @@
#include <linux/sh_intc.h>
#include "pci-sh4.h"
-int __init pcibios_map_platform_irq(const struct pci_dev *, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *, u8 slot, u8 pin)
{
switch (slot) {
case 0: return evt2irq(0x3a0);
diff --git a/arch/sh/drivers/pci/fixups-sh03.c b/arch/sh/drivers/pci/fixups-sh03.c
index 16207be..55ac1ba 100644
--- a/arch/sh/drivers/pci/fixups-sh03.c
+++ b/arch/sh/drivers/pci/fixups-sh03.c
@@ -4,7 +4,7 @@
#include <linux/pci.h>
#include <linux/sh_intc.h>
-int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
int irq;
diff --git a/arch/sh/drivers/pci/fixups-snapgear.c b/arch/sh/drivers/pci/fixups-snapgear.c
index 6e33ba4..a931e59 100644
--- a/arch/sh/drivers/pci/fixups-snapgear.c
+++ b/arch/sh/drivers/pci/fixups-snapgear.c
@@ -19,7 +19,7 @@
#include <linux/sh_intc.h>
#include "pci-sh4.h"
-int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
int irq = -1;
diff --git a/arch/sh/drivers/pci/fixups-titan.c b/arch/sh/drivers/pci/fixups-titan.c
index bd1addb..a9d563e 100644
--- a/arch/sh/drivers/pci/fixups-titan.c
+++ b/arch/sh/drivers/pci/fixups-titan.c
@@ -19,7 +19,7 @@
#include <mach/titan.h>
#include "pci-sh4.h"
-static char titan_irq_tab[] __initdata = {
+static char titan_irq_tab[] = {
TITAN_IRQ_WAN,
TITAN_IRQ_LAN,
TITAN_IRQ_MPCIA,
@@ -27,7 +27,7 @@ static char titan_irq_tab[] __initdata = {
TITAN_IRQ_USB,
};
-int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
int irq = titan_irq_tab[slot];
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index 1bc09ee..718fae3 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -141,16 +141,20 @@ static int __init pcibios_init(void)
for (hose = hose_head; hose; hose = hose->next)
pcibios_scanbus(hose);
- pci_fixup_irqs(pci_common_swizzle, pcibios_map_platform_irq);
-
dma_debug_add_bus(&pci_bus_type);
-
pci_initialized = 1;
return 0;
}
subsys_initcall(pcibios_init);
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pci_common_swizzle;
+ bridge->map_irq = pcibios_map_platform_irq;
+ return 0;
+}
+
/*
* Called after each bus is probed, but before its children
* are examined.
diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c
index a162a7f..0167a73 100644
--- a/arch/sh/drivers/pci/pcie-sh7786.c
+++ b/arch/sh/drivers/pci/pcie-sh7786.c
@@ -467,7 +467,7 @@ static int __init pcie_init(struct sh7786_pcie_port *port)
return 0;
}
-int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
+int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
return evt2irq(0xae0);
}
--
2.1.0
m***@masarand.com
2014-10-02 04:07:40 UTC
Permalink
From: Matthew Minter <***@masarand.com>


PCI IRQs are being asigned during pcibios_irq_init currently, this causes
a problem by which hot-plug devices connected after boot will not recieve
an IRQ, this patch-set fixes this by registering the IRQ assignment
functions at boot, to then be called later by the device enable code.

Signed-off-by: Matthew Minter <***@masarand.com>

---
arch/mn10300/unit-asb2305/pci-asb2305.h | 5 +----
arch/mn10300/unit-asb2305/pci-irq.c | 25 +++++--------------------
arch/mn10300/unit-asb2305/pci.c | 21 ++++++++-------------
3 files changed, 14 insertions(+), 37 deletions(-)

diff --git a/arch/mn10300/unit-asb2305/pci-asb2305.h b/arch/mn10300/unit-asb2305/pci-asb2305.h
index 9e17aca..fb520cf 100644
--- a/arch/mn10300/unit-asb2305/pci-asb2305.h
+++ b/arch/mn10300/unit-asb2305/pci-asb2305.h
@@ -67,9 +67,6 @@ struct irq_routing_table {
} __attribute__((packed));

extern unsigned int pcibios_irq_mask;
-
-extern void pcibios_irq_init(void);
-extern void pcibios_fixup_irqs(void);
-extern void pcibios_enable_irq(struct pci_dev *dev);
+extern int pci_map_irq(struct pci_dev *, u8 slot, u8 pin);

#endif /* PCI_ASB2305_H */
diff --git a/arch/mn10300/unit-asb2305/pci-irq.c b/arch/mn10300/unit-asb2305/pci-irq.c
index fcb28ce..5be6fea 100644
--- a/arch/mn10300/unit-asb2305/pci-irq.c
+++ b/arch/mn10300/unit-asb2305/pci-irq.c
@@ -20,27 +20,12 @@
#include <asm/smp.h>
#include "pci-asb2305.h"

-void __init pcibios_irq_init(void)
+int pci_map_irq(struct pci_dev *, u8 slot, u8 pin)
{
-}
-
-void __init pcibios_fixup_irqs(void)
-{
- struct pci_dev *dev = NULL;
- u8 line, pin;
+ u8 line;

- for_each_pci_dev(dev) {
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
- if (pin) {
- dev->irq = XIRQ1;
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
- dev->irq);
- }
- pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line);
- }
-}
-
-void pcibios_enable_irq(struct pci_dev *dev)
-{
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ dev->irq = XIRQ1;
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+ pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line);
}
diff --git a/arch/mn10300/unit-asb2305/pci.c b/arch/mn10300/unit-asb2305/pci.c
index 6b4339f..22f8786 100644
--- a/arch/mn10300/unit-asb2305/pci.c
+++ b/arch/mn10300/unit-asb2305/pci.c
@@ -377,13 +377,18 @@ static int __init pcibios_init(void)
pci_add_resource_offset(&resources, &pci_ioport_resource, io_offset);
pci_add_resource_offset(&resources, &pci_iomem_resource, mem_offset);
pci_scan_root_bus(NULL, 0, &pci_direct_ampci, NULL, &resources);
-
- pcibios_irq_init();
- pcibios_fixup_irqs();
pcibios_resource_survey();
return 0;
}

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pci_map_irq;
+ return 0;
+}
+
+
arch_initcall(pcibios_init);

char *__init pcibios_setup(char *str)
@@ -396,16 +401,6 @@ char *__init pcibios_setup(char *str)
return str;
}

-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
- int err;
-
- err = pci_enable_resources(dev, mask);
- if (err == 0)
- pcibios_enable_irq(dev);
- return err;
-}
-
/*
* disable the ethernet chipset
*/
--
2.1.0
Bjorn Helgaas
2014-10-14 18:46:22 UTC
Permalink
Post by m***@masarand.com
PCI IRQs are being asigned during pcibios_irq_init currently, this causes
a problem by which hot-plug devices connected after boot will not recieve
an IRQ, this patch-set fixes this by registering the IRQ assignment
functions at boot, to then be called later by the device enable code.
---
arch/mn10300/unit-asb2305/pci-asb2305.h | 5 +----
arch/mn10300/unit-asb2305/pci-irq.c | 25 +++++--------------------
arch/mn10300/unit-asb2305/pci.c | 21 ++++++++-------------
3 files changed, 14 insertions(+), 37 deletions(-)
diff --git a/arch/mn10300/unit-asb2305/pci-asb2305.h b/arch/mn10300/unit-asb2305/pci-asb2305.h
index 9e17aca..fb520cf 100644
--- a/arch/mn10300/unit-asb2305/pci-asb2305.h
+++ b/arch/mn10300/unit-asb2305/pci-asb2305.h
@@ -67,9 +67,6 @@ struct irq_routing_table {
} __attribute__((packed));
extern unsigned int pcibios_irq_mask;
-
-extern void pcibios_irq_init(void);
-extern void pcibios_fixup_irqs(void);
-extern void pcibios_enable_irq(struct pci_dev *dev);
+extern int pci_map_irq(struct pci_dev *, u8 slot, u8 pin);
#endif /* PCI_ASB2305_H */
diff --git a/arch/mn10300/unit-asb2305/pci-irq.c b/arch/mn10300/unit-asb2305/pci-irq.c
index fcb28ce..5be6fea 100644
--- a/arch/mn10300/unit-asb2305/pci-irq.c
+++ b/arch/mn10300/unit-asb2305/pci-irq.c
@@ -20,27 +20,12 @@
#include <asm/smp.h>
#include "pci-asb2305.h"
-void __init pcibios_irq_init(void)
+int pci_map_irq(struct pci_dev *, u8 slot, u8 pin)
{
-}
-
-void __init pcibios_fixup_irqs(void)
-{
- struct pci_dev *dev = NULL;
- u8 line, pin;
+ u8 line;
- for_each_pci_dev(dev) {
- pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
- if (pin) {
- dev->irq = XIRQ1;
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
- dev->irq);
- }
- pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line);
- }
-}
-
-void pcibios_enable_irq(struct pci_dev *dev)
-{
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ dev->irq = XIRQ1;
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+ pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line);
}
diff --git a/arch/mn10300/unit-asb2305/pci.c b/arch/mn10300/unit-asb2305/pci.c
index 6b4339f..22f8786 100644
--- a/arch/mn10300/unit-asb2305/pci.c
+++ b/arch/mn10300/unit-asb2305/pci.c
@@ -377,13 +377,18 @@ static int __init pcibios_init(void)
pci_add_resource_offset(&resources, &pci_ioport_resource, io_offset);
pci_add_resource_offset(&resources, &pci_iomem_resource, mem_offset);
pci_scan_root_bus(NULL, 0, &pci_direct_ampci, NULL, &resources);
-
- pcibios_irq_init();
- pcibios_fixup_irqs();
pcibios_resource_survey();
return 0;
}
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pci_map_irq;
I would lean toward omitting the "= NULL" initializations here and
elsewhere, because it will make git grep and cscope searches for
swizzle_irq more useful because they will show only the arches that
actually need it. But it's fine either way.
Post by m***@masarand.com
+ return 0;
+}
+
+
arch_initcall(pcibios_init);
char *__init pcibios_setup(char *str)
@@ -396,16 +401,6 @@ char *__init pcibios_setup(char *str)
return str;
}
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
- int err;
-
- err = pci_enable_resources(dev, mask);
- if (err == 0)
- pcibios_enable_irq(dev);
- return err;
I would personally do this as two patches -- one that does the IRQ change,
and a second that drops the pcibios_enable_device() implementation because
it is now the same as the default one in drivers/pci/pci.c. That way it's
clear that there really two logical changes happening here and reviewers
can easily verify that the two pcibios_enable_device() implementations are
identical.
Post by m***@masarand.com
-}
-
/*
* disable the ethernet chipset
*/
--
2.1.0
m***@masarand.com
2014-10-02 04:07:42 UTC
Permalink
From: Matthew Minter <***@masarand.com>

Currently pcibios_init is running pci_fixup_irqs in order to assign
IRQs to PCI devices, this is only done once at boot-time and causes
devices hot-plugged after boot time to not be allocated an IRQ.
This is fixed in this patch-set by delaying the allocation untill
device enable time by registering the function to be called later.

Signed-off-by: Matthew Minter <***@masarand.com>

---
arch/tile/kernel/pci.c | 10 +++++++---
arch/tile/kernel/pci_gx.c | 10 +++++++---
2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/arch/tile/kernel/pci.c b/arch/tile/kernel/pci.c
index 1f80a88..6dc0bd8 100644
--- a/arch/tile/kernel/pci.c
+++ b/arch/tile/kernel/pci.c
@@ -313,9 +313,6 @@ int __init pcibios_init(void)
}
}

- /* Do machine dependent PCI interrupt routing */
- pci_fixup_irqs(pci_common_swizzle, tile_map_irq);
-
/*
* This comes from the generic Linux PCI driver.
*
@@ -367,6 +364,13 @@ int __init pcibios_init(void)
}
subsys_initcall(pcibios_init);

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pci_common_swizzle;
+ bridge->map_irq = tile_map_irq;
+ return 0;
+}
+
/*
* No bus fixups needed.
*/
diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c
index e39f9c5..7d1b5bf 100644
--- a/arch/tile/kernel/pci_gx.c
+++ b/arch/tile/kernel/pci_gx.c
@@ -893,9 +893,6 @@ int __init pcibios_init(void)
next_busno = bus->busn_res.end + 1;
}

- /* Do machine dependent PCI interrupt routing */
- pci_fixup_irqs(pci_common_swizzle, tile_map_irq);
-
/*
* This comes from the generic Linux PCI driver.
*
@@ -1048,6 +1045,13 @@ alloc_mem_map_failed:
}
subsys_initcall(pcibios_init);

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pci_common_swizzle;
+ bridge->map_irq = tile_map_irq;
+ return 0;
+}
+
/* No bus fixups needed. */
void pcibios_fixup_bus(struct pci_bus *bus)
{
--
2.1.0
m***@masarand.com
2014-10-02 04:07:45 UTC
Permalink
From: Matthew Minter <***@masarand.com>

Most of the architectures are switched to allocating IRQs at device_enable
time instead of boot time, however parisc does not provide an easy way of
making that transition so the new code is disabled here on parisc.

Signed-off-by: Matthew Minter <***@masarand.com>

---
arch/parisc/kernel/pci.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c
index 64f2764..9654c69 100644
--- a/arch/parisc/kernel/pci.c
+++ b/arch/parisc/kernel/pci.c
@@ -105,7 +105,13 @@ PCI_PORT_OUT(b, 8)
PCI_PORT_OUT(w, 16)
PCI_PORT_OUT(l, 32)

-
+/* We do not support hot-add irq assignment */
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = NULL;
+ return 0;
+}

/*
* BIOS32 replacement.
--
2.1.0
m***@masarand.com
2014-10-02 04:07:37 UTC
Permalink
From: Matthew Minter <***@masarand.com>

Currently PCI IRQs are assigned during mcf_pci_init which is only run
at boot time, this causes devices which are connected after boot time
to not receive an IRQ, this patch set fixes this by registering an IRQ
assignment function to be run later at device enable time.

Signed-off-by: Matthew Minter <***@masarand.com>

---
arch/m68k/platform/coldfire/pci.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/m68k/platform/coldfire/pci.c b/arch/m68k/platform/coldfire/pci.c
index df96792..058ca86 100644
--- a/arch/m68k/platform/coldfire/pci.c
+++ b/arch/m68k/platform/coldfire/pci.c
@@ -316,10 +316,16 @@ static int __init mcf_pci_init(void)
rootbus->resource[0] = &mcf_pci_io;
rootbus->resource[1] = &mcf_pci_mem;

- pci_fixup_irqs(pci_common_swizzle, mcf_pci_map_irq);
pci_bus_size_bridges(rootbus);
pci_bus_assign_resources(rootbus);
return 0;
}

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pci_common_swizzle;
+ bridge->map_irq = mcf_pci_map_irq;
+ return 0;
+}
+
subsys_initcall(mcf_pci_init);
--
2.1.0
Bjorn Helgaas
2014-10-14 18:38:51 UTC
Permalink
Post by m***@masarand.com
Currently PCI IRQs are assigned during mcf_pci_init which is only run
at boot time, this causes devices which are connected after boot time
to not receive an IRQ, this patch set fixes this by registering an IRQ
assignment function to be run later at device enable time.
---
arch/m68k/platform/coldfire/pci.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/m68k/platform/coldfire/pci.c b/arch/m68k/platform/coldfire/pci.c
index df96792..058ca86 100644
--- a/arch/m68k/platform/coldfire/pci.c
+++ b/arch/m68k/platform/coldfire/pci.c
@@ -316,10 +316,16 @@ static int __init mcf_pci_init(void)
rootbus->resource[0] = &mcf_pci_io;
rootbus->resource[1] = &mcf_pci_mem;
- pci_fixup_irqs(pci_common_swizzle, mcf_pci_map_irq);
pci_bus_size_bridges(rootbus);
pci_bus_assign_resources(rootbus);
return 0;
}
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pci_common_swizzle;
+ bridge->map_irq = mcf_pci_map_irq;
+ return 0;
+}
+
subsys_initcall(mcf_pci_init);
--
2.1.0
Awesome, very nice and simple!
m***@masarand.com
2014-10-02 04:07:39 UTC
Permalink
From: Matthew Minter <***@masarand.com>

Currently mips PCI IRQs are assigned at boot, this creates an extra
pass over the PCI bus and causes hot-plugged devices which are not
present at boot to not be given IRQs, this patch set fixes this by
registering assignment functions which are then run later during the
device enable code path.

Signed-off-by: Matthew Minter <***@masarand.com>

---
arch/mips/pci/pci.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index 1bf60b1..dc660a0 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -242,13 +242,18 @@ static int __init pcibios_init(void)
for (hose = hose_head; hose; hose = hose->next)
pcibios_scanbus(hose);

- pci_fixup_irqs(pci_common_swizzle, pcibios_map_irq);
-
pci_initialized = 1;

return 0;
}

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pci_common_swizzle;
+ bridge->map_irq = pcibios_map_irq;
+ return 0;
+}
+
subsys_initcall(pcibios_init);

static int pcibios_enable_resources(struct pci_dev *dev, int mask)
--
2.1.0
m***@masarand.com
2014-10-02 04:07:44 UTC
Permalink
From: Matthew Minter <***@masarand.com>

Most of the architectures are switched to allocating IRQs at device_enable
time instead of boot time, however ia64 does not provide an easy way of
making that transition so the new code is disabled here on ia64.

Signed-off-by: Matthew Minter <***@masarand.com>

---
arch/ia64/pci/pci.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 291a582..398d5d4 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -483,6 +483,9 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{
struct pci_controller *controller = bridge->bus->sysdata;

+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = NULL;
+
ACPI_COMPANION_SET(&bridge->dev, controller->companion);
return 0;
}
--
2.1.0
Bjorn Helgaas
2014-10-14 18:53:44 UTC
Permalink
Post by m***@masarand.com
Most of the architectures are switched to allocating IRQs at device_enable
time instead of boot time, however ia64 does not provide an easy way of
making that transition so the new code is disabled here on ia64.
---
arch/ia64/pci/pci.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 291a582..398d5d4 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -483,6 +483,9 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{
struct pci_controller *controller = bridge->bus->sysdata;
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = NULL;
Since ->swizzle_irq and ->map_irq default to NULL anyway, isn't this a
no-op?
Post by m***@masarand.com
ACPI_COMPANION_SET(&bridge->dev, controller->companion);
return 0;
}
--
2.1.0
m***@masarand.com
2014-10-02 04:07:43 UTC
Permalink
From: Matthew Minter <***@masarand.com>

PCI IRQs are currently assigned during pci_common_init, this is only run
at boot time so devices hot-plugged after boot will not be allocated an IRQ.
this is fixed here by defering the assignment untill the device enable code,
instead registering the function pointer at boot time.

Signed-off-by: Matthew Minter <***@masarand.com>

---
arch/unicore32/kernel/pci.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/arch/unicore32/kernel/pci.c b/arch/unicore32/kernel/pci.c
index 374a055..6a9da80 100644
--- a/arch/unicore32/kernel/pci.c
+++ b/arch/unicore32/kernel/pci.c
@@ -101,7 +101,7 @@ void pci_puv3_preinit(void)
writel(readl(PCIBRI_CMD) | PCIBRI_CMD_IO | PCIBRI_CMD_MEM, PCIBRI_CMD);
}

-static int __init pci_puv3_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+static int pci_puv3_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
if (dev->bus->number == 0) {
#ifdef CONFIG_ARCH_FPGA /* 4 pci slots */
@@ -263,8 +263,6 @@ static int __init pci_common_init(void)
if (!puv3_bus)
panic("PCI: unable to scan bus!");

- pci_fixup_irqs(pci_common_swizzle, pci_puv3_map_irq);
-
if (!pci_has_flag(PCI_PROBE_ONLY)) {
/*
* Size the bridge windows.
@@ -281,6 +279,13 @@ static int __init pci_common_init(void)
}
subsys_initcall(pci_common_init);

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pci_common_swizzle;
+ bridge->map_irq = pci_puv3_map_irq;
+ return 0;
+}
+
char * __init pcibios_setup(char *str)
{
if (!strcmp(str, "debug")) {
--
2.1.0
m***@masarand.com
2014-10-02 04:07:41 UTC
Permalink
From: Matthew Minter <***@masarand.com>

Currently sparc allocates PCI IRQs through several different methods
based on device. This is done during the boot stage and faces a draw-back
by which hot-plugged devices will not be allocated an IRQ, this is fixed
by registering IRQ allocation functions for later use during the device
enable path.

Signed-off-by: Matthew Minter <***@masarand.com>

---
arch/sparc/kernel/leon_pci.c | 12 +++++++++++-
arch/sparc/kernel/pci.c | 21 +++++++++++++++++----
2 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c
index 899b720..1079eb7 100644
--- a/arch/sparc/kernel/leon_pci.c
+++ b/arch/sparc/kernel/leon_pci.c
@@ -13,6 +13,8 @@
#include <asm/leon.h>
#include <asm/leon_pci.h>

+int (*leon_pci_map_irq)(const struct pci_dev *dev, u8 slot, u8 pin);
+
/* The LEON architecture does not rely on a BIOS or bootloader to setup
* PCI for us. The Linux generic routines are used to setup resources,
* reset values of configuration-space register settings are preserved.
@@ -36,7 +38,7 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
&resources);
if (root_bus) {
/* Setup IRQs of all devices using custom routines */
- pci_fixup_irqs(pci_common_swizzle, info->map_irq);
+ leon_pci_map_irq = info->map_irq;

/* Assign devices with resources */
pci_assign_unassigned_resources();
@@ -45,6 +47,14 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
}
}

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pci_common_swizzle;
+ bridge->map_irq = leon_pci_map_irq;
+ return 0;
+}
+
+
void pcibios_fixup_bus(struct pci_bus *pbus)
{
struct pci_dev *dev;
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index b36365f..7361c52 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -340,10 +340,6 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
} else {
dev->hdr_type = PCI_HEADER_TYPE_NORMAL;
dev->rom_base_reg = PCI_ROM_ADDRESS;
-
- dev->irq = sd->op->archdata.irqs[0];
- if (dev->irq == 0xffffffff)
- dev->irq = PCI_IRQ_NONE;
}

pci_parse_of_addrs(sd->op, node, dev);
@@ -356,6 +352,23 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
return dev;
}

+int pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int irq;
+ struct platform_device *op = of_find_device_by_node(dev->sysdata);
+ irq = op->archdata.irqs[0];
+ if (irq == 0xffffffff)
+ irq = PCI_IRQ_NONE;
+ return irq;
+}
+
+int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pci_map_irq;
+ return 0;
+}
+
static void apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p)
{
u32 idx, first, last;
--
2.1.0
Bjorn Helgaas
2014-10-14 18:51:28 UTC
Permalink
Post by m***@masarand.com
Currently sparc allocates PCI IRQs through several different methods
based on device. This is done during the boot stage and faces a draw-back
by which hot-plugged devices will not be allocated an IRQ, this is fixed
by registering IRQ allocation functions for later use during the device
enable path.
---
arch/sparc/kernel/leon_pci.c | 12 +++++++++++-
arch/sparc/kernel/pci.c | 21 +++++++++++++++++----
2 files changed, 28 insertions(+), 5 deletions(-)
diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c
index 899b720..1079eb7 100644
--- a/arch/sparc/kernel/leon_pci.c
+++ b/arch/sparc/kernel/leon_pci.c
@@ -13,6 +13,8 @@
#include <asm/leon.h>
#include <asm/leon_pci.h>
+int (*leon_pci_map_irq)(const struct pci_dev *dev, u8 slot, u8 pin);
+
/* The LEON architecture does not rely on a BIOS or bootloader to setup
* PCI for us. The Linux generic routines are used to setup resources,
* reset values of configuration-space register settings are preserved.
@@ -36,7 +38,7 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
&resources);
if (root_bus) {
/* Setup IRQs of all devices using custom routines */
- pci_fixup_irqs(pci_common_swizzle, info->map_irq);
+ leon_pci_map_irq = info->map_irq;
/* Assign devices with resources */
pci_assign_unassigned_resources();
@@ -45,6 +47,14 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info)
}
}
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = pci_common_swizzle;
+ bridge->map_irq = leon_pci_map_irq;
+ return 0;
+}
+
+
void pcibios_fixup_bus(struct pci_bus *pbus)
{
struct pci_dev *dev;
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index b36365f..7361c52 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -340,10 +340,6 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
} else {
dev->hdr_type = PCI_HEADER_TYPE_NORMAL;
dev->rom_base_reg = PCI_ROM_ADDRESS;
-
- dev->irq = sd->op->archdata.irqs[0];
- if (dev->irq == 0xffffffff)
- dev->irq = PCI_IRQ_NONE;
}
pci_parse_of_addrs(sd->op, node, dev);
@@ -356,6 +352,23 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
return dev;
}
+int pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int irq;
+ struct platform_device *op = of_find_device_by_node(dev->sysdata);
Add a blank line here.
Post by m***@masarand.com
+ irq = op->archdata.irqs[0];
+ if (irq == 0xffffffff)
+ irq = PCI_IRQ_NONE;
+ return irq;
+}
+
+int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
Shouldn't be weak. I see why you're doing it, since you added a non-weak
version in leon_pci.c, but without leon_pci.c, we'll have two weak versions
(this one and the one in drivers/pci/probe.c), and it's not clear which one
will be used. Maybe keep this implementation (non-weak), and make a global
map_irq pointer that defaults to pci_map_irq() and leon_pci.c would
override that?
Post by m***@masarand.com
+{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pci_map_irq;
+ return 0;
+}
+
static void apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p)
{
u32 idx, first, last;
--
2.1.0
m***@masarand.com
2014-10-02 04:07:35 UTC
Permalink
From: Matthew Minter <***@masarand.com>

PCI IRQs are currently configured to be enabled once at boot in a
dedicated pass. This means that PCI devices which are hot-plugged after
boot time will not be given an IRQ, this patch-set fixes this by
registering the assignment function to be called later in the device
enable path.

Signed-off-by: Matthew Minter <***@masarand.com>

---
arch/cris/arch-v32/drivers/pci/bios.c | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/arch/cris/arch-v32/drivers/pci/bios.c b/arch/cris/arch-v32/drivers/pci/bios.c
index 64a5fb9..d04ecc8 100644
--- a/arch/cris/arch-v32/drivers/pci/bios.c
+++ b/arch/cris/arch-v32/drivers/pci/bios.c
@@ -80,20 +80,16 @@ int pcibios_enable_resources(struct pci_dev *dev, int mask)
return 0;
}

-int pcibios_enable_irq(struct pci_dev *dev)
+int pcibios_enable_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
dev->irq = EXT_INTR_VECT;
return 0;
}

-int pcibios_enable_device(struct pci_dev *dev, int mask)
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{
- int err;
-
- if ((err = pcibios_enable_resources(dev, mask)) < 0)
- return err;
-
- if (!dev->msi_enabled)
- pcibios_enable_irq(dev);
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pcibios_enable_irq;
return 0;
}
+
--
2.1.0
Bjorn Helgaas
2014-10-14 18:34:19 UTC
Permalink
Post by m***@masarand.com
PCI IRQs are currently configured to be enabled once at boot in a
dedicated pass. This means that PCI devices which are hot-plugged after
boot time will not be given an IRQ, this patch-set fixes this by
registering the assignment function to be called later in the device
enable path.
---
arch/cris/arch-v32/drivers/pci/bios.c | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/arch/cris/arch-v32/drivers/pci/bios.c b/arch/cris/arch-v32/drivers/pci/bios.c
index 64a5fb9..d04ecc8 100644
--- a/arch/cris/arch-v32/drivers/pci/bios.c
+++ b/arch/cris/arch-v32/drivers/pci/bios.c
@@ -80,20 +80,16 @@ int pcibios_enable_resources(struct pci_dev *dev, int mask)
return 0;
}
-int pcibios_enable_irq(struct pci_dev *dev)
+int pcibios_enable_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
dev->irq = EXT_INTR_VECT;
return 0;
}
-int pcibios_enable_device(struct pci_dev *dev, int mask)
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
{
- int err;
-
- if ((err = pcibios_enable_resources(dev, mask)) < 0)
- return err;
If I understand correctly, this means we'd now use the default
pcibios_enable_device() from drivers/pci/pci.c, which uses
pci_enable_resources(), instead of cris's pcibios_enable_resources().

That's a good thing that we should do someday, but it's out of scope for
this series because they *are* different, and we need to evaluate whether
it's safe to use the default version instead of the cris version. Also, I
think this patch leaves the cris pcibios_enable_resources() unused.
Post by m***@masarand.com
-
- if (!dev->msi_enabled)
- pcibios_enable_irq(dev);
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = pcibios_enable_irq;
return 0;
}
+
--
2.1.0
m***@masarand.com
2014-10-02 04:07:46 UTC
Permalink
From: Matthew Minter <***@masarand.com>

Most of the architectures are switched to allocating IRQs at device_enable
time instead of boot time, however s390 does not provide an easy way of
making that transition so the new code is disabled here on s390.

Signed-off-by: Matthew Minter <***@masarand.com>

---
arch/s390/pci/pci.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 2fa7b14..720592f 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -434,6 +434,13 @@ out:
return rc;
}

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = NULL;
+ bridge->map_irq = NULL;
+ return 0;
+}
+
void arch_teardown_msi_irqs(struct pci_dev *pdev)
{
struct zpci_dev *zdev = get_zdev(pdev);
--
2.1.0
m***@masarand.com
2014-10-02 04:07:34 UTC
Permalink
From: Matthew Minter <***@masarand.com>

PCI IRQ initialisation is currently run during the boot code on alpha,
this has the issue that firstly an extra pass over the PCI bus is
required and second hot-plugged devices which are added after boot have
no way to be assigned an IRQ. This patch set fixes this by defering the
assignment of PCI IRQs untill device enable time which should solve
both of these issues.

Signed-off-by: Matthew Minter <***@masarand.com>

---
arch/alpha/kernel/pci.c | 16 ++++++++++------
arch/alpha/kernel/sys_nautilus.c | 1 -
2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index 076c35c..338537c 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -28,7 +28,7 @@


/*
- * Some string constants used by the various core logics.
+ * Some string constants used by the various core logics.
*/

const char *const pci_io_names[] = {
@@ -247,7 +247,7 @@ void pcibios_fixup_bus(struct pci_bus *bus)
if (pci_has_flag(PCI_PROBE_ONLY) && dev &&
(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
pci_read_bridge_bases(bus);
- }
+ }

list_for_each_entry(dev, &bus->devices, bus_list) {
pdev_save_srm_config(dev);
@@ -338,7 +338,7 @@ common_init_pci(void)
hose->need_domain_info = need_domain_info;
next_busno = bus->busn_res.end + 1;
/* Don't allow 8-bit bus number overflow inside the hose -
- reserve some space for bridges. */
+ reserve some space for bridges. */
if (next_busno > 224) {
next_busno = 0;
need_domain_info = 1;
@@ -346,11 +346,15 @@ common_init_pci(void)
}

pcibios_claim_console_setup();
-
pci_assign_unassigned_resources();
- pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
}

+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = alpha_mv.pci_swizzle;
+ bridge->map_irq = alpha_mv.pci_map_irq;
+ return 0;
+}

struct pci_controller * __init
alloc_pci_controller(void)
@@ -387,7 +391,7 @@ sys_pciconfig_iobase(long which, unsigned long bus, unsigned long dfn)

/* from hose or from bus.devfn */
if (which & IOBASE_FROM_HOSE) {
- for(hose = hose_head; hose; hose = hose->next)
+ for(hose = hose_head; hose; hose = hose->next)
if (hose->index == bus) break;
if (!hose) return -ENODEV;
} else {
diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c
index 837c0fa..7fb4d51 100644
--- a/arch/alpha/kernel/sys_nautilus.c
+++ b/arch/alpha/kernel/sys_nautilus.c
@@ -252,7 +252,6 @@ nautilus_init_pci(void)
/* pci_common_swizzle() relies on bus->self being NULL
for the root bus, so just clear it. */
bus->self = NULL;
- pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
}

/*
--
2.1.0
Bjorn Helgaas
2014-10-14 18:27:22 UTC
Permalink
Post by m***@masarand.com
PCI IRQ initialisation is currently run during the boot code on alpha,
this has the issue that firstly an extra pass over the PCI bus is
required and second hot-plugged devices which are added after boot have
no way to be assigned an IRQ. This patch set fixes this by defering the
assignment of PCI IRQs untill device enable time which should solve
both of these issues.
---
arch/alpha/kernel/pci.c | 16 ++++++++++------
arch/alpha/kernel/sys_nautilus.c | 1 -
2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index 076c35c..338537c 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -28,7 +28,7 @@
/*
- * Some string constants used by the various core logics.
+ * Some string constants used by the various core logics.
*/
const char *const pci_io_names[] = {
@@ -247,7 +247,7 @@ void pcibios_fixup_bus(struct pci_bus *bus)
if (pci_has_flag(PCI_PROBE_ONLY) && dev &&
(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
pci_read_bridge_bases(bus);
- }
+ }
list_for_each_entry(dev, &bus->devices, bus_list) {
pdev_save_srm_config(dev);
@@ -338,7 +338,7 @@ common_init_pci(void)
hose->need_domain_info = need_domain_info;
next_busno = bus->busn_res.end + 1;
/* Don't allow 8-bit bus number overflow inside the hose -
- reserve some space for bridges. */
+ reserve some space for bridges. */
Extraneous whitespace changes above.
Post by m***@masarand.com
if (next_busno > 224) {
next_busno = 0;
need_domain_info = 1;
@@ -346,11 +346,15 @@ common_init_pci(void)
}
pcibios_claim_console_setup();
-
pci_assign_unassigned_resources();
- pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
}
+int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+ bridge->swizzle_irq = alpha_mv.pci_swizzle;
+ bridge->map_irq = alpha_mv.pci_map_irq;
+ return 0;
+}
struct pci_controller * __init
alloc_pci_controller(void)
@@ -387,7 +391,7 @@ sys_pciconfig_iobase(long which, unsigned long bus, unsigned long dfn)
/* from hose or from bus.devfn */
if (which & IOBASE_FROM_HOSE) {
- for(hose = hose_head; hose; hose = hose->next)
+ for(hose = hose_head; hose; hose = hose->next)
Extraneous whitespace change. If you fix this in a separate patch, also
add a space after "for".
Post by m***@masarand.com
if (hose->index == bus) break;
if (!hose) return -ENODEV;
} else {
diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c
index 837c0fa..7fb4d51 100644
--- a/arch/alpha/kernel/sys_nautilus.c
+++ b/arch/alpha/kernel/sys_nautilus.c
@@ -252,7 +252,6 @@ nautilus_init_pci(void)
/* pci_common_swizzle() relies on bus->self being NULL
for the root bus, so just clear it. */
bus->self = NULL;
- pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
}
/*
--
2.1.0
Loading...