diff options
author | Lucas Stach <l.stach@pengutronix.de> | 2015-09-18 14:58:35 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2015-09-18 14:58:35 -0400 |
commit | 79707374090411c5fa9dbcde862e59306bf8f765 (patch) | |
tree | 27fa887d0045afa25b0e4d4ae6fb3f3d4936a923 | |
parent | ea643e1a33576216de589cf525dbb40267fde5a9 (diff) |
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>
-rw-r--r-- | drivers/pci/host/pcie-designware.c | 31 |
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) | |||
286 | } | 286 | } |
287 | 287 | ||
288 | *pos = pos0; | 288 | *pos = pos0; |
289 | desc->nvec_used = no_irqs; | ||
290 | desc->msi_attrib.multiple = order_base_2(no_irqs); | ||
291 | |||
289 | return irq; | 292 | return irq; |
290 | 293 | ||
291 | no_valid_irq: | 294 | no_valid_irq: |
@@ -329,6 +332,33 @@ static int dw_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev, | |||
329 | return 0; | 332 | return 0; |
330 | } | 333 | } |
331 | 334 | ||
335 | static int dw_msi_setup_irqs(struct msi_controller *chip, struct pci_dev *pdev, | ||
336 | int nvec, int type) | ||
337 | { | ||
338 | #ifdef CONFIG_PCI_MSI | ||
339 | int irq, pos; | ||
340 | struct msi_desc *desc; | ||
341 | struct pcie_port *pp = sys_to_pcie(pdev->bus->sysdata); | ||
342 | |||
343 | /* MSI-X interrupts are not supported */ | ||
344 | if (type == PCI_CAP_ID_MSIX) | ||
345 | return -EINVAL; | ||
346 | |||
347 | WARN_ON(!list_is_singular(&pdev->dev.msi_list)); | ||
348 | desc = list_entry(pdev->dev.msi_list.next, struct msi_desc, list); | ||
349 | |||
350 | irq = assign_irq(nvec, desc, &pos); | ||
351 | if (irq < 0) | ||
352 | return irq; | ||
353 | |||
354 | dw_msi_setup_msg(pp, irq, pos); | ||
355 | |||
356 | return 0; | ||
357 | #else | ||
358 | return -EINVAL; | ||
359 | #endif | ||
360 | } | ||
361 | |||
332 | static void dw_msi_teardown_irq(struct msi_controller *chip, unsigned int irq) | 362 | static void dw_msi_teardown_irq(struct msi_controller *chip, unsigned int irq) |
333 | { | 363 | { |
334 | struct irq_data *data = irq_get_irq_data(irq); | 364 | 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) | |||
340 | 370 | ||
341 | static struct msi_controller dw_pcie_msi_chip = { | 371 | static struct msi_controller dw_pcie_msi_chip = { |
342 | .setup_irq = dw_msi_setup_irq, | 372 | .setup_irq = dw_msi_setup_irq, |
373 | .setup_irqs = dw_msi_setup_irqs, | ||
343 | .teardown_irq = dw_msi_teardown_irq, | 374 | .teardown_irq = dw_msi_teardown_irq, |
344 | }; | 375 | }; |
345 | 376 | ||