mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-18 00:50:45 +07:00
PCI/portdrv: Factor out Interrupt Message Number lookup
Factor out Interrupt Message Number lookup from the MSI/MSI-X interrupt setup. One side effect is that we only have to check once to see if we have enough vectors for all the services. No functional change intended. Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
parent
b8acfd7c0f
commit
3321eafd2a
@ -43,6 +43,53 @@ static void release_pcie_device(struct device *dev)
|
||||
kfree(to_pcie_device(dev));
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in *pme, *aer, *dpc with the relevant Interrupt Message Numbers if
|
||||
* services are enabled in "mask". Return the number of MSI/MSI-X vectors
|
||||
* required to accommodate the largest Message Number.
|
||||
*/
|
||||
static int pcie_message_numbers(struct pci_dev *dev, int mask,
|
||||
u32 *pme, u32 *aer, u32 *dpc)
|
||||
{
|
||||
u32 nvec = 0, pos, reg32;
|
||||
u16 reg16;
|
||||
|
||||
/*
|
||||
* The Interrupt Message Number indicates which vector is used, i.e.,
|
||||
* the MSI-X table entry or the MSI offset between the base Message
|
||||
* Data and the generated interrupt message. See PCIe r3.1, sec
|
||||
* 7.8.2, 7.10.10, 7.31.2.
|
||||
*/
|
||||
|
||||
if (mask & (PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP)) {
|
||||
pcie_capability_read_word(dev, PCI_EXP_FLAGS, ®16);
|
||||
*pme = (reg16 & PCI_EXP_FLAGS_IRQ) >> 9;
|
||||
nvec = *pme + 1;
|
||||
}
|
||||
|
||||
if (mask & PCIE_PORT_SERVICE_AER) {
|
||||
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
|
||||
if (pos) {
|
||||
pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS,
|
||||
®32);
|
||||
*aer = (reg32 & PCI_ERR_ROOT_AER_IRQ) >> 27;
|
||||
nvec = max(nvec, *aer + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & PCIE_PORT_SERVICE_DPC) {
|
||||
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DPC);
|
||||
if (pos) {
|
||||
pci_read_config_word(dev, pos + PCI_EXP_DPC_CAP,
|
||||
®16);
|
||||
*dpc = reg16 & PCI_EXP_DPC_IRQ;
|
||||
nvec = max(nvec, *dpc + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return nvec;
|
||||
}
|
||||
|
||||
/**
|
||||
* pcie_port_enable_irq_vec - try to set up MSI-X or MSI as interrupt mode
|
||||
* for given port
|
||||
@ -54,7 +101,8 @@ static void release_pcie_device(struct device *dev)
|
||||
*/
|
||||
static int pcie_port_enable_irq_vec(struct pci_dev *dev, int *irqs, int mask)
|
||||
{
|
||||
int nr_entries, entry, nvec = 0;
|
||||
int nr_entries, nvec;
|
||||
u32 pme = 0, aer = 0, dpc = 0;
|
||||
|
||||
/* Allocate the maximum possible number of MSI/MSI-X vectors */
|
||||
nr_entries = pci_alloc_irq_vectors(dev, 1, PCIE_PORT_MAX_MSI_ENTRIES,
|
||||
@ -62,54 +110,24 @@ static int pcie_port_enable_irq_vec(struct pci_dev *dev, int *irqs, int mask)
|
||||
if (nr_entries < 0)
|
||||
return nr_entries;
|
||||
|
||||
/*
|
||||
* The Interrupt Message Number indicates which vector is used, i.e.,
|
||||
* the MSI-X table entry or the MSI offset between the base Message
|
||||
* Data and the generated interrupt message. See PCIe r3.1, sec
|
||||
* 7.8.2, 7.10.10, 7.31.2.
|
||||
*/
|
||||
/* See how many and which Interrupt Message Numbers we actually use */
|
||||
nvec = pcie_message_numbers(dev, mask, &pme, &aer, &dpc);
|
||||
if (nvec > nr_entries) {
|
||||
pci_free_irq_vectors(dev);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* PME and hotplug share an MSI/MSI-X vector */
|
||||
if (mask & (PCIE_PORT_SERVICE_PME | PCIE_PORT_SERVICE_HP)) {
|
||||
u16 reg16;
|
||||
|
||||
pcie_capability_read_word(dev, PCI_EXP_FLAGS, ®16);
|
||||
entry = (reg16 & PCI_EXP_FLAGS_IRQ) >> 9;
|
||||
if (entry >= nr_entries)
|
||||
goto out_free_irqs;
|
||||
|
||||
/* PME and hotplug share an MSI/MSI-X vector */
|
||||
irqs[PCIE_PORT_SERVICE_PME_SHIFT] = pci_irq_vector(dev, entry);
|
||||
irqs[PCIE_PORT_SERVICE_HP_SHIFT] = pci_irq_vector(dev, entry);
|
||||
|
||||
nvec = max(nvec, entry + 1);
|
||||
irqs[PCIE_PORT_SERVICE_PME_SHIFT] = pci_irq_vector(dev, pme);
|
||||
irqs[PCIE_PORT_SERVICE_HP_SHIFT] = pci_irq_vector(dev, pme);
|
||||
}
|
||||
|
||||
if (mask & PCIE_PORT_SERVICE_AER) {
|
||||
u32 reg32, pos;
|
||||
if (mask & PCIE_PORT_SERVICE_AER)
|
||||
irqs[PCIE_PORT_SERVICE_AER_SHIFT] = pci_irq_vector(dev, aer);
|
||||
|
||||
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
|
||||
pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, ®32);
|
||||
entry = (reg32 & PCI_ERR_ROOT_AER_IRQ) >> 27;
|
||||
if (entry >= nr_entries)
|
||||
goto out_free_irqs;
|
||||
|
||||
irqs[PCIE_PORT_SERVICE_AER_SHIFT] = pci_irq_vector(dev, entry);
|
||||
|
||||
nvec = max(nvec, entry + 1);
|
||||
}
|
||||
|
||||
if (mask & PCIE_PORT_SERVICE_DPC) {
|
||||
u16 reg16, pos;
|
||||
|
||||
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_DPC);
|
||||
pci_read_config_word(dev, pos + PCI_EXP_DPC_CAP, ®16);
|
||||
entry = reg16 & PCI_EXP_DPC_IRQ;
|
||||
if (entry >= nr_entries)
|
||||
goto out_free_irqs;
|
||||
|
||||
irqs[PCIE_PORT_SERVICE_DPC_SHIFT] = pci_irq_vector(dev, entry);
|
||||
|
||||
nvec = max(nvec, entry + 1);
|
||||
}
|
||||
if (mask & PCIE_PORT_SERVICE_DPC)
|
||||
irqs[PCIE_PORT_SERVICE_DPC_SHIFT] = pci_irq_vector(dev, dpc);
|
||||
|
||||
/* If we allocated more than we need, free them and allocate fewer */
|
||||
if (nvec != nr_entries) {
|
||||
@ -122,10 +140,6 @@ static int pcie_port_enable_irq_vec(struct pci_dev *dev, int *irqs, int mask)
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_irqs:
|
||||
pci_free_irq_vectors(dev);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user