Re: [PATCH 1/1] PCI: Place interrupt related code into irq.c

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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
> 




[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux