109 lines
3.3 KiB
Diff
109 lines
3.3 KiB
Diff
From 9c6ddccbbfaf789beccc6a1d87abe9bc60dc570f Mon Sep 17 00:00:00 2001
|
|
From: Thierry Reding <thierry.reding@avionic-design.de>
|
|
Date: Thu, 6 Jun 2013 18:20:29 +0200
|
|
Subject: [PATCH 072/203] PCI: Introduce new MSI chip infrastructure
|
|
|
|
The new struct msi_chip is used to associated an MSI controller with a
|
|
PCI bus. It is automatically handed down from the root to its children
|
|
during bus enumeration.
|
|
|
|
This patch provides default (weak) implementations for the architecture-
|
|
specific MSI functions (arch_setup_msi_irq(), arch_teardown_msi_irq()
|
|
and arch_msi_check_device()) which check if a PCI device's bus has an
|
|
attached MSI chip and forward the call appropriately.
|
|
|
|
Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de>
|
|
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
|
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
|
|
Tested-by: Daniel Price <daniel.price@gmail.com>
|
|
Tested-by: Thierry Reding <thierry.reding@gmail.com>
|
|
---
|
|
drivers/pci/msi.c | 27 +++++++++++++++++++++++++--
|
|
drivers/pci/probe.c | 1 +
|
|
include/linux/msi.h | 11 +++++++++++
|
|
include/linux/pci.h | 1 +
|
|
4 files changed, 38 insertions(+), 2 deletions(-)
|
|
|
|
--- a/drivers/pci/msi.c
|
|
+++ b/drivers/pci/msi.c
|
|
@@ -32,16 +32,39 @@ static int pci_msi_enable = 1;
|
|
|
|
int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
|
|
{
|
|
- return -EINVAL;
|
|
+ struct msi_chip *chip = dev->bus->msi;
|
|
+ int err;
|
|
+
|
|
+ if (!chip || !chip->setup_irq)
|
|
+ return -EINVAL;
|
|
+
|
|
+ err = chip->setup_irq(chip, dev, desc);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
+
|
|
+ irq_set_chip_data(desc->irq, chip);
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
void __weak arch_teardown_msi_irq(unsigned int irq)
|
|
{
|
|
+ struct msi_chip *chip = irq_get_chip_data(irq);
|
|
+
|
|
+ if (!chip || !chip->teardown_irq)
|
|
+ return;
|
|
+
|
|
+ chip->teardown_irq(chip, irq);
|
|
}
|
|
|
|
int __weak arch_msi_check_device(struct pci_dev *dev, int nvec, int type)
|
|
{
|
|
- return 0;
|
|
+ struct msi_chip *chip = dev->bus->msi;
|
|
+
|
|
+ if (!chip || !chip->check_device)
|
|
+ return 0;
|
|
+
|
|
+ return chip->check_device(chip, dev, nvec, type);
|
|
}
|
|
|
|
int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
|
|
--- a/drivers/pci/probe.c
|
|
+++ b/drivers/pci/probe.c
|
|
@@ -634,6 +634,7 @@ static struct pci_bus *pci_alloc_child_b
|
|
|
|
child->parent = parent;
|
|
child->ops = parent->ops;
|
|
+ child->msi = parent->msi;
|
|
child->sysdata = parent->sysdata;
|
|
child->bus_flags = parent->bus_flags;
|
|
|
|
--- a/include/linux/msi.h
|
|
+++ b/include/linux/msi.h
|
|
@@ -64,4 +64,15 @@ void arch_restore_msi_irqs(struct pci_de
|
|
void default_teardown_msi_irqs(struct pci_dev *dev);
|
|
void default_restore_msi_irqs(struct pci_dev *dev, int irq);
|
|
|
|
+struct msi_chip {
|
|
+ struct module *owner;
|
|
+ struct device *dev;
|
|
+
|
|
+ int (*setup_irq)(struct msi_chip *chip, struct pci_dev *dev,
|
|
+ struct msi_desc *desc);
|
|
+ void (*teardown_irq)(struct msi_chip *chip, unsigned int irq);
|
|
+ int (*check_device)(struct msi_chip *chip, struct pci_dev *dev,
|
|
+ int nvec, int type);
|
|
+};
|
|
+
|
|
#endif /* LINUX_MSI_H */
|
|
--- a/include/linux/pci.h
|
|
+++ b/include/linux/pci.h
|
|
@@ -432,6 +432,7 @@ struct pci_bus {
|
|
struct resource busn_res; /* bus numbers routed to this bus */
|
|
|
|
struct pci_ops *ops; /* configuration access functions */
|
|
+ struct msi_chip *msi; /* MSI controller */
|
|
void *sysdata; /* hook for sys-specific extension */
|
|
struct proc_dir_entry *procdir; /* directory entry in /proc/bus/pci */
|
|
|