Commit c9953a73 authored by Michael Ellerman's avatar Michael Ellerman Committed by Greg Kroah-Hartman

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: default avatarMichael Ellerman <michael@ellerman.id.au>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 17bbc12a
...@@ -459,15 +459,17 @@ static int msix_capability_init(struct pci_dev *dev, ...@@ -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 * 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 * @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 ? * @type: are we checking for MSI or MSI-X ?
* *
* Look at global flags, the device itself, and its parent busses * 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 * to determine if MSI/-X are supported for the device. If MSI/-X is
* supported return 0, else return an error code. * 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; struct pci_bus *bus;
int ret;
/* MSI must be globally enabled and supported by the device */ /* MSI must be globally enabled and supported by the device */
if (!pci_msi_enable || !dev || dev->no_msi) if (!pci_msi_enable || !dev || dev->no_msi)
...@@ -483,6 +485,10 @@ static int pci_msi_check_device(struct pci_dev * dev, int type) ...@@ -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) if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
return -EINVAL; return -EINVAL;
ret = arch_msi_check_device(dev, nvec, type);
if (ret)
return ret;
if (!pci_find_capability(dev, type)) if (!pci_find_capability(dev, type))
return -EINVAL; return -EINVAL;
...@@ -503,8 +509,9 @@ int pci_enable_msi(struct pci_dev* dev) ...@@ -503,8 +509,9 @@ int pci_enable_msi(struct pci_dev* dev)
{ {
int status; int status;
if (pci_msi_check_device(dev, PCI_CAP_ID_MSI)) status = pci_msi_check_device(dev, 1, PCI_CAP_ID_MSI);
return -EINVAL; if (status)
return status;
WARN_ON(!!dev->msi_enabled); WARN_ON(!!dev->msi_enabled);
...@@ -601,9 +608,13 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) ...@@ -601,9 +608,13 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
int i, j; int i, j;
u16 control; u16 control;
if (!entries || pci_msi_check_device(dev, PCI_CAP_ID_MSIX)) if (!entries)
return -EINVAL; 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); pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
pci_read_config_word(dev, msi_control_reg(pos), &control); pci_read_config_word(dev, msi_control_reg(pos), &control);
nr_entries = multi_msix_capable(control); nr_entries = multi_msix_capable(control);
...@@ -687,3 +698,13 @@ void pci_no_msi(void) ...@@ -687,3 +698,13 @@ void pci_no_msi(void)
{ {
pci_msi_enable = 0; pci_msi_enable = 0;
} }
/* Arch hooks */
int __attribute__ ((weak))
arch_msi_check_device(struct pci_dev* dev, int nvec, int type)
{
return 0;
}
...@@ -41,6 +41,7 @@ struct msi_desc { ...@@ -41,6 +41,7 @@ struct msi_desc {
*/ */
int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc); int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc);
void arch_teardown_msi_irq(unsigned int irq); 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 */ #endif /* LINUX_MSI_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment