summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Ellerman <michael@ellerman.id.au>2007-04-05 17:19:08 +1000
committerGreg Kroah-Hartman <gregkh@suse.de>2007-05-02 19:02:37 -0700
commitc9953a73e92df11edd812d863ff741877ea9e58c (patch)
tree27262efa28f6c05e26bfd87ef03af4a81fda3d22
parent17bbc12acdb23ffb9613e12ca974fafd31bfcb56 (diff)
MSI: Add an arch_msi_check_device()
Add an arch_check_device(), which gives archs a chance to check the input to pci_enable_msi/x. The arch might be interested in the value of nvec so pass it in. Propagate the error value returned from the arch routine out to the caller. Signed-off-by: Michael Ellerman <michael@ellerman.id.au> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/pci/msi.c29
-rw-r--r--include/linux/msi.h1
2 files changed, 26 insertions, 4 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 34087af68833..5902c00f4fce 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -459,15 +459,17 @@ static int msix_capability_init(struct pci_dev *dev,
/**
* pci_msi_check_device - check whether MSI may be enabled on a device
* @dev: pointer to the pci_dev data structure of MSI device function
+ * @nvec: how many MSIs have been requested ?
* @type: are we checking for MSI or MSI-X ?
*
* Look at global flags, the device itself, and its parent busses
* to determine if MSI/-X are supported for the device. If MSI/-X is
* supported return 0, else return an error code.
**/
-static int pci_msi_check_device(struct pci_dev * dev, int type)
+static int pci_msi_check_device(struct pci_dev* dev, int nvec, int type)
{
struct pci_bus *bus;
+ int ret;
/* MSI must be globally enabled and supported by the device */
if (!pci_msi_enable || !dev || dev->no_msi)
@@ -483,6 +485,10 @@ static int pci_msi_check_device(struct pci_dev * dev, int type)
if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
return -EINVAL;
+ ret = arch_msi_check_device(dev, nvec, type);
+ if (ret)
+ return ret;
+
if (!pci_find_capability(dev, type))
return -EINVAL;
@@ -503,8 +509,9 @@ int pci_enable_msi(struct pci_dev* dev)
{
int status;
- if (pci_msi_check_device(dev, PCI_CAP_ID_MSI))
- return -EINVAL;
+ status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI);
+ if (status)
+ return status;
WARN_ON(!!dev->msi_enabled);
@@ -601,9 +608,13 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
int i, j;
u16 control;
- if (!entries || pci_msi_check_device(dev, PCI_CAP_ID_MSIX))
+ if (!entries)
return -EINVAL;
+ status = pci_msi_check_device(dev, nvec, PCI_CAP_ID_MSIX);
+ if (status)
+ return status;
+
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
pci_read_config_word(dev, msi_control_reg(pos), &control);
nr_entries = multi_msix_capable(control);
@@ -687,3 +698,13 @@ void pci_no_msi(void)
{
pci_msi_enable = 0;
}
+
+
+/* Arch hooks */
+
+int __attribute__ ((weak))
+arch_msi_check_device(struct pci_dev* dev, int nvec, int type)
+{
+ return 0;
+}
+
diff --git a/include/linux/msi.h b/include/linux/msi.h
index e38fe6822cb4..d2a200048b22 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -41,6 +41,7 @@ struct msi_desc {
*/
int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc);
void arch_teardown_msi_irq(unsigned int irq);
+extern int arch_msi_check_device(struct pci_dev* dev, int nvec, int type);
#endif /* LINUX_MSI_H */