PCI: Add pci_irqd_intx_xlate()

Legacy PCI INTx interrupts are represented in the PCI_INTERRUPT_PIN
register using the range 1-4, which matches our enum pci_interrupt_pin.
This is however not ideal for an IRQ domain, where with 4 interrupts we
would ideally have a domain of size 4 & hwirq numbers in the range 0-3.

Different PCI host controller drivers have handled this in different ways.
Of those under drivers/pci/ which register an INTx IRQ domain, we have:

  - pcie-altera uses the range 1-4 in device trees and an IRQ domain of
    size 5 to cover that range, with entry 0 wasted.

  - pcie-xilinx & pcie-xilinx-nwl use the range 1-4 in device trees but
    register an IRQ domain of size 4, which doesn't cover the hwirq=4/INTD
    case leading to that interrupt being broken.

  - pci-ftpci100 & pci-aardvark use the range 0-3 in both device trees & as
    hwirq numbering in the driver & IRQ domain.

In order to introduce some level of consistency in at least the hwirq
numbering used by the drivers & IRQ domains, this patch introduces a new
pci_irqd_intx_xlate() helper function which drivers using the 1-4 range in
device trees can assign as the xlate callback for their INTx IRQ domain.
This translates the 1-4 range into a 0-3 range, allowing us to use an IRQ
domain of size 4 & avoid a wasted entry. Further patches will make use of
this in drivers to allow them to use an IRQ domain of size 4 for legacy
INTx interrupts without breaking INTD.

Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
This commit is contained in:
Paul Burton 2017-08-15 12:02:17 -07:00 committed by Bjorn Helgaas
parent b352baf15b
commit 0d58e6c1b1
1 changed files with 32 additions and 0 deletions

View File

@ -1416,6 +1416,38 @@ pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
NULL); NULL);
} }
/**
* pci_irqd_intx_xlate() - Translate PCI INTx value to an IRQ domain hwirq
* @d: the INTx IRQ domain
* @node: the DT node for the device whose interrupt we're translating
* @intspec: the interrupt specifier data from the DT
* @intsize: the number of entries in @intspec
* @out_hwirq: pointer at which to write the hwirq number
* @out_type: pointer at which to write the interrupt type
*
* Translate a PCI INTx interrupt number from device tree in the range 1-4, as
* stored in the standard PCI_INTERRUPT_PIN register, to a value in the range
* 0-3 suitable for use in a 4 entry IRQ domain. That is, subtract one from the
* INTx value to obtain the hwirq number.
*
* Returns 0 on success, or -EINVAL if the interrupt specifier is out of range.
*/
static inline int pci_irqd_intx_xlate(struct irq_domain *d,
struct device_node *node,
const u32 *intspec,
unsigned int intsize,
unsigned long *out_hwirq,
unsigned int *out_type)
{
const u32 intx = intspec[0];
if (intx < PCI_INTERRUPT_INTA || intx > PCI_INTERRUPT_INTD)
return -EINVAL;
*out_hwirq = intx - PCI_INTERRUPT_INTA;
return 0;
}
#ifdef CONFIG_PCIEPORTBUS #ifdef CONFIG_PCIEPORTBUS
extern bool pcie_ports_disabled; extern bool pcie_ports_disabled;
extern bool pcie_ports_auto; extern bool pcie_ports_auto;