summaryrefslogtreecommitdiffstats
path: root/drivers/pci/host/pcie-designware.c
diff options
context:
space:
mode:
authorLucas Stach2015-09-18 20:58:35 +0200
committerBjorn Helgaas2015-09-18 20:58:35 +0200
commit79707374090411c5fa9dbcde862e59306bf8f765 (patch)
tree27fa887d0045afa25b0e4d4ae6fb3f3d4936a923 /drivers/pci/host/pcie-designware.c
parentPCI: designware: Factor out MSI msg setup (diff)
downloadkernel-qcow2-linux-79707374090411c5fa9dbcde862e59306bf8f765.tar.gz
kernel-qcow2-linux-79707374090411c5fa9dbcde862e59306bf8f765.tar.xz
kernel-qcow2-linux-79707374090411c5fa9dbcde862e59306bf8f765.zip
PCI: designware: Implement multivector MSI IRQ setup
Implement multivector MSI IRQ setup. This allows to set up and use multiple MSI IRQs per device. [bhelgaas: changelog, use -EINVAL instead of -ENOSYS] Signed-off-by: Lucas Stach <l.stach@pengutronix.de> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Acked-by: Pratyush Anand <pratyush.anand@gmail.com>
Diffstat (limited to 'drivers/pci/host/pcie-designware.c')
-rw-r--r--drivers/pci/host/pcie-designware.c31
1 files changed, 31 insertions, 0 deletions
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index ea5b285baea6..66d789aefa0d 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -286,6 +286,9 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
}
*pos = pos0;
+ desc->nvec_used = no_irqs;
+ desc->msi_attrib.multiple = order_base_2(no_irqs);
+
return irq;
no_valid_irq:
@@ -329,6 +332,33 @@ static int dw_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev,
return 0;
}
+static int dw_msi_setup_irqs(struct msi_controller *chip, struct pci_dev *pdev,
+ int nvec, int type)
+{
+#ifdef CONFIG_PCI_MSI
+ int irq, pos;
+ struct msi_desc *desc;
+ struct pcie_port *pp = sys_to_pcie(pdev->bus->sysdata);
+
+ /* MSI-X interrupts are not supported */
+ if (type == PCI_CAP_ID_MSIX)
+ return -EINVAL;
+
+ WARN_ON(!list_is_singular(&pdev->dev.msi_list));
+ desc = list_entry(pdev->dev.msi_list.next, struct msi_desc, list);
+
+ irq = assign_irq(nvec, desc, &pos);
+ if (irq < 0)
+ return irq;
+
+ dw_msi_setup_msg(pp, irq, pos);
+
+ return 0;
+#else
+ return -EINVAL;
+#endif
+}
+
static void dw_msi_teardown_irq(struct msi_controller *chip, unsigned int irq)
{
struct irq_data *data = irq_get_irq_data(irq);
@@ -340,6 +370,7 @@ static void dw_msi_teardown_irq(struct msi_controller *chip, unsigned int irq)
static struct msi_controller dw_pcie_msi_chip = {
.setup_irq = dw_msi_setup_irq,
+ .setup_irqs = dw_msi_setup_irqs,
.teardown_irq = dw_msi_teardown_irq,
};