On Mon, Jan 29, 2024 at 01:36:54PM +0200, Ilpo Järvinen wrote: > Interrupt related code is spread into irq.c, pci.c, and setup-irq.c. > Group them into pre-existing irq.c. > > Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@xxxxxxxxxxxxxxx> Applied to pci/enumeration for v6.9, thanks. > --- > drivers/pci/Makefile | 2 +- > drivers/pci/irq.c | 204 +++++++++++++++++++++++++++++++++++++++ > drivers/pci/pci-driver.c | 9 -- > drivers/pci/pci.c | 144 --------------------------- > drivers/pci/setup-irq.c | 64 ------------ > 5 files changed, 205 insertions(+), 218 deletions(-) > delete mode 100644 drivers/pci/setup-irq.c > > diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile > index cc8b4e01e29d..54a7adf0bb88 100644 > --- a/drivers/pci/Makefile > +++ b/drivers/pci/Makefile > @@ -5,7 +5,7 @@ > obj-$(CONFIG_PCI) += 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 mmap.o setup-irq.o > + setup-bus.o vc.o mmap.o > > obj-$(CONFIG_PCI) += msi/ > obj-$(CONFIG_PCI) += pcie/ > diff --git a/drivers/pci/irq.c b/drivers/pci/irq.c > index 0050e8f6814e..4555630be9ec 100644 > --- a/drivers/pci/irq.c > +++ b/drivers/pci/irq.c > @@ -8,9 +8,13 @@ > > #include <linux/device.h> > #include <linux/kernel.h> > +#include <linux/errno.h> > #include <linux/export.h> > +#include <linux/interrupt.h> > #include <linux/pci.h> > > +#include "pci.h" > + > /** > * pci_request_irq - allocate an interrupt line for a PCI device > * @dev: PCI device to operate on > @@ -74,3 +78,203 @@ void pci_free_irq(struct pci_dev *dev, unsigned int nr, void *dev_id) > kfree(free_irq(pci_irq_vector(dev, nr), dev_id)); > } > EXPORT_SYMBOL(pci_free_irq); > + > +/** > + * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge > + * @dev: the PCI device > + * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD) > + * > + * Perform INTx swizzling for a device behind one level of bridge. This is > + * required by section 9.1 of the PCI-to-PCI bridge specification for devices > + * behind bridges on add-in cards. For devices with ARI enabled, the slot > + * number is always 0 (see the Implementation Note in section 2.2.8.1 of > + * the PCI Express Base Specification, Revision 2.1) > + */ > +u8 pci_swizzle_interrupt_pin(const struct pci_dev *dev, u8 pin) > +{ > + int slot; > + > + if (pci_ari_enabled(dev->bus)) > + slot = 0; > + else > + slot = PCI_SLOT(dev->devfn); > + > + return (((pin - 1) + slot) % 4) + 1; > +} > + > +int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge) > +{ > + u8 pin; > + > + pin = dev->pin; > + if (!pin) > + return -1; > + > + while (!pci_is_root_bus(dev->bus)) { > + pin = pci_swizzle_interrupt_pin(dev, pin); > + dev = dev->bus->self; > + } > + *bridge = dev; > + return pin; > +} > + > +/** > + * pci_common_swizzle - swizzle INTx all the way to root bridge > + * @dev: the PCI device > + * @pinp: pointer to the INTx pin value (1=INTA, 2=INTB, 3=INTD, 4=INTD) > + * > + * Perform INTx swizzling for a device. This traverses through all PCI-to-PCI > + * bridges all the way up to a PCI root bus. > + */ > +u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp) > +{ > + u8 pin = *pinp; > + > + while (!pci_is_root_bus(dev->bus)) { > + pin = pci_swizzle_interrupt_pin(dev, pin); > + dev = dev->bus->self; > + } > + *pinp = pin; > + return PCI_SLOT(dev->devfn); > +} > +EXPORT_SYMBOL_GPL(pci_common_swizzle); > + > +void pci_assign_irq(struct pci_dev *dev) > +{ > + u8 pin; > + u8 slot = -1; > + int irq = 0; > + struct pci_host_bridge *hbrg = pci_find_host_bridge(dev->bus); > + > + if (!(hbrg->map_irq)) { > + pci_dbg(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 because that slot is where the bridge is. Each > + * time the interrupt line passes through a PCI-PCI bridge we must > + * apply the swizzle function. > + */ > + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); > + /* Cope with illegal. */ > + if (pin > 4) > + pin = 1; > + > + if (pin) { > + /* Follow the chain of bridges, swizzling as we go. */ > + if (hbrg->swizzle_irq) > + slot = (*(hbrg->swizzle_irq))(dev, &pin); > + > + /* > + * If a swizzling function is not used, map_irq() must > + * ignore slot. > + */ > + irq = (*(hbrg->map_irq))(dev, slot, pin); > + if (irq == -1) > + irq = 0; > + } > + dev->irq = irq; > + > + pci_dbg(dev, "assign IRQ: got %d\n", dev->irq); > + > + /* > + * Always tell the device, so the driver knows what is the real IRQ > + * to use; the device does not use it. > + */ > + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); > +} > + > +static bool pci_check_and_set_intx_mask(struct pci_dev *dev, bool mask) > +{ > + struct pci_bus *bus = dev->bus; > + bool mask_updated = true; > + u32 cmd_status_dword; > + u16 origcmd, newcmd; > + unsigned long flags; > + bool irq_pending; > + > + /* > + * We do a single dword read to retrieve both command and status. > + * Document assumptions that make this possible. > + */ > + BUILD_BUG_ON(PCI_COMMAND % 4); > + BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS); > + > + raw_spin_lock_irqsave(&pci_lock, flags); > + > + bus->ops->read(bus, dev->devfn, PCI_COMMAND, 4, &cmd_status_dword); > + > + irq_pending = (cmd_status_dword >> 16) & PCI_STATUS_INTERRUPT; > + > + /* > + * Check interrupt status register to see whether our device > + * triggered the interrupt (when masking) or the next IRQ is > + * already pending (when unmasking). > + */ > + if (mask != irq_pending) { > + mask_updated = false; > + goto done; > + } > + > + origcmd = cmd_status_dword; > + newcmd = origcmd & ~PCI_COMMAND_INTX_DISABLE; > + if (mask) > + newcmd |= PCI_COMMAND_INTX_DISABLE; > + if (newcmd != origcmd) > + bus->ops->write(bus, dev->devfn, PCI_COMMAND, 2, newcmd); > + > +done: > + raw_spin_unlock_irqrestore(&pci_lock, flags); > + > + return mask_updated; > +} > + > +/** > + * pci_check_and_mask_intx - mask INTx on pending interrupt > + * @dev: the PCI device to operate on > + * > + * Check if the device dev has its INTx line asserted, mask it and return > + * true in that case. False is returned if no interrupt was pending. > + */ > +bool pci_check_and_mask_intx(struct pci_dev *dev) > +{ > + return pci_check_and_set_intx_mask(dev, true); > +} > +EXPORT_SYMBOL_GPL(pci_check_and_mask_intx); > + > +/** > + * pci_check_and_unmask_intx - unmask INTx if no interrupt is pending > + * @dev: the PCI device to operate on > + * > + * Check if the device dev has its INTx line asserted, unmask it if not and > + * return true. False is returned and the mask remains active if there was > + * still an interrupt pending. > + */ > +bool pci_check_and_unmask_intx(struct pci_dev *dev) > +{ > + return pci_check_and_set_intx_mask(dev, false); > +} > +EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx); > + > +/** > + * pcibios_penalize_isa_irq - penalize an ISA IRQ > + * @irq: ISA IRQ to penalize > + * @active: IRQ active or not > + * > + * Permits the platform to provide architecture-specific functionality when > + * penalizing ISA IRQs. This is the default implementation. Architecture > + * implementations can override this. > + */ > +void __weak pcibios_penalize_isa_irq(int irq, int active) {} > + > +int __weak pcibios_alloc_irq(struct pci_dev *dev) > +{ > + return 0; > +} > + > +void __weak pcibios_free_irq(struct pci_dev *dev) > +{ > +} > diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c > index 51ec9e7e784f..ec838f2e892e 100644 > --- a/drivers/pci/pci-driver.c > +++ b/drivers/pci/pci-driver.c > @@ -419,15 +419,6 @@ static int __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev) > return error; > } > > -int __weak pcibios_alloc_irq(struct pci_dev *dev) > -{ > - return 0; > -} > - > -void __weak pcibios_free_irq(struct pci_dev *dev) > -{ > -} > - > #ifdef CONFIG_PCI_IOV > static inline bool pci_device_can_probe(struct pci_dev *pdev) > { > diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c > index d8f11a078924..75388584e60d 100644 > --- a/drivers/pci/pci.c > +++ b/drivers/pci/pci.c > @@ -24,7 +24,6 @@ > #include <linux/log2.h> > #include <linux/logic_pio.h> > #include <linux/pm_wakeup.h> > -#include <linux/interrupt.h> > #include <linux/device.h> > #include <linux/pm_runtime.h> > #include <linux/pci_hotplug.h> > @@ -2292,17 +2291,6 @@ void __weak pcibios_release_device(struct pci_dev *dev) {} > */ > void __weak pcibios_disable_device(struct pci_dev *dev) {} > > -/** > - * pcibios_penalize_isa_irq - penalize an ISA IRQ > - * @irq: ISA IRQ to penalize > - * @active: IRQ active or not > - * > - * Permits the platform to provide architecture-specific functionality when > - * penalizing ISA IRQs. This is the default implementation. Architecture > - * implementations can override this. > - */ > -void __weak pcibios_penalize_isa_irq(int irq, int active) {} > - > static void do_pci_disable_device(struct pci_dev *dev) > { > u16 pci_command; > @@ -3964,66 +3952,6 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) > } > EXPORT_SYMBOL(pci_enable_atomic_ops_to_root); > > -/** > - * pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge > - * @dev: the PCI device > - * @pin: the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD) > - * > - * Perform INTx swizzling for a device behind one level of bridge. This is > - * required by section 9.1 of the PCI-to-PCI bridge specification for devices > - * behind bridges on add-in cards. For devices with ARI enabled, the slot > - * number is always 0 (see the Implementation Note in section 2.2.8.1 of > - * the PCI Express Base Specification, Revision 2.1) > - */ > -u8 pci_swizzle_interrupt_pin(const struct pci_dev *dev, u8 pin) > -{ > - int slot; > - > - if (pci_ari_enabled(dev->bus)) > - slot = 0; > - else > - slot = PCI_SLOT(dev->devfn); > - > - return (((pin - 1) + slot) % 4) + 1; > -} > - > -int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge) > -{ > - u8 pin; > - > - pin = dev->pin; > - if (!pin) > - return -1; > - > - while (!pci_is_root_bus(dev->bus)) { > - pin = pci_swizzle_interrupt_pin(dev, pin); > - dev = dev->bus->self; > - } > - *bridge = dev; > - return pin; > -} > - > -/** > - * pci_common_swizzle - swizzle INTx all the way to root bridge > - * @dev: the PCI device > - * @pinp: pointer to the INTx pin value (1=INTA, 2=INTB, 3=INTD, 4=INTD) > - * > - * Perform INTx swizzling for a device. This traverses through all PCI-to-PCI > - * bridges all the way up to a PCI root bus. > - */ > -u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp) > -{ > - u8 pin = *pinp; > - > - while (!pci_is_root_bus(dev->bus)) { > - pin = pci_swizzle_interrupt_pin(dev, pin); > - dev = dev->bus->self; > - } > - *pinp = pin; > - return PCI_SLOT(dev->devfn); > -} > -EXPORT_SYMBOL_GPL(pci_common_swizzle); > - > /** > * pci_release_region - Release a PCI bar > * @pdev: PCI device whose resources were previously reserved by > @@ -4737,78 +4665,6 @@ void pci_intx(struct pci_dev *pdev, int enable) > } > EXPORT_SYMBOL_GPL(pci_intx); > > -static bool pci_check_and_set_intx_mask(struct pci_dev *dev, bool mask) > -{ > - struct pci_bus *bus = dev->bus; > - bool mask_updated = true; > - u32 cmd_status_dword; > - u16 origcmd, newcmd; > - unsigned long flags; > - bool irq_pending; > - > - /* > - * We do a single dword read to retrieve both command and status. > - * Document assumptions that make this possible. > - */ > - BUILD_BUG_ON(PCI_COMMAND % 4); > - BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS); > - > - raw_spin_lock_irqsave(&pci_lock, flags); > - > - bus->ops->read(bus, dev->devfn, PCI_COMMAND, 4, &cmd_status_dword); > - > - irq_pending = (cmd_status_dword >> 16) & PCI_STATUS_INTERRUPT; > - > - /* > - * Check interrupt status register to see whether our device > - * triggered the interrupt (when masking) or the next IRQ is > - * already pending (when unmasking). > - */ > - if (mask != irq_pending) { > - mask_updated = false; > - goto done; > - } > - > - origcmd = cmd_status_dword; > - newcmd = origcmd & ~PCI_COMMAND_INTX_DISABLE; > - if (mask) > - newcmd |= PCI_COMMAND_INTX_DISABLE; > - if (newcmd != origcmd) > - bus->ops->write(bus, dev->devfn, PCI_COMMAND, 2, newcmd); > - > -done: > - raw_spin_unlock_irqrestore(&pci_lock, flags); > - > - return mask_updated; > -} > - > -/** > - * pci_check_and_mask_intx - mask INTx on pending interrupt > - * @dev: the PCI device to operate on > - * > - * Check if the device dev has its INTx line asserted, mask it and return > - * true in that case. False is returned if no interrupt was pending. > - */ > -bool pci_check_and_mask_intx(struct pci_dev *dev) > -{ > - return pci_check_and_set_intx_mask(dev, true); > -} > -EXPORT_SYMBOL_GPL(pci_check_and_mask_intx); > - > -/** > - * pci_check_and_unmask_intx - unmask INTx if no interrupt is pending > - * @dev: the PCI device to operate on > - * > - * Check if the device dev has its INTx line asserted, unmask it if not and > - * return true. False is returned and the mask remains active if there was > - * still an interrupt pending. > - */ > -bool pci_check_and_unmask_intx(struct pci_dev *dev) > -{ > - return pci_check_and_set_intx_mask(dev, false); > -} > -EXPORT_SYMBOL_GPL(pci_check_and_unmask_intx); > - > /** > * pci_wait_for_pending_transaction - wait for pending transaction > * @dev: the PCI device to operate on > diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c > deleted file mode 100644 > index cc7d26b015f3..000000000000 > --- a/drivers/pci/setup-irq.c > +++ /dev/null > @@ -1,64 +0,0 @@ > -// SPDX-License-Identifier: GPL-2.0 > -/* > - * Support routines for initializing a PCI subsystem > - * > - * Extruded from code written by > - * Dave Rusling (david.rusling@xxxxxxxxxxxxxxx) > - * David Mosberger (davidm@xxxxxxxxxxxxxx) > - * David Miller (davem@xxxxxxxxxx) > - */ > - > -#include <linux/kernel.h> > -#include <linux/pci.h> > -#include <linux/errno.h> > -#include <linux/ioport.h> > -#include <linux/cache.h> > -#include "pci.h" > - > -void pci_assign_irq(struct pci_dev *dev) > -{ > - u8 pin; > - u8 slot = -1; > - int irq = 0; > - struct pci_host_bridge *hbrg = pci_find_host_bridge(dev->bus); > - > - if (!(hbrg->map_irq)) { > - pci_dbg(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 because that slot is where the bridge is. Each > - * time the interrupt line passes through a PCI-PCI bridge we must > - * apply the swizzle function. > - */ > - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); > - /* Cope with illegal. */ > - if (pin > 4) > - pin = 1; > - > - if (pin) { > - /* Follow the chain of bridges, swizzling as we go. */ > - if (hbrg->swizzle_irq) > - slot = (*(hbrg->swizzle_irq))(dev, &pin); > - > - /* > - * If a swizzling function is not used, map_irq() must > - * ignore slot. > - */ > - irq = (*(hbrg->map_irq))(dev, slot, pin); > - if (irq == -1) > - irq = 0; > - } > - dev->irq = irq; > - > - pci_dbg(dev, "assign IRQ: got %d\n", dev->irq); > - > - /* > - * Always tell the device, so the driver knows what is the real IRQ > - * to use; the device does not use it. > - */ > - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); > -} > -- > 2.39.2 >