mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-17 01:04:19 +08:00
ae24e28fef
Use the new iterator functions which pave the way for dynamically extending MSI-X vectors. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Michael Kelley <mikelley@microsoft.com> Tested-by: Nishanth Menon <nm@ti.com> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Acked-by: Bjorn Helgaas <bhelgaas@google.com> Link: https://lore.kernel.org/r/20211206210748.142603657@linutronix.de
82 lines
1.7 KiB
C
82 lines
1.7 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* PCI Message Signaled Interrupt (MSI).
|
|
*
|
|
* Legacy architecture specific setup and teardown mechanism.
|
|
*/
|
|
#include "msi.h"
|
|
|
|
/* Arch hooks */
|
|
int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
|
|
void __weak arch_teardown_msi_irq(unsigned int irq)
|
|
{
|
|
}
|
|
|
|
int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
|
|
{
|
|
struct msi_desc *desc;
|
|
int ret;
|
|
|
|
/*
|
|
* If an architecture wants to support multiple MSI, it needs to
|
|
* override arch_setup_msi_irqs()
|
|
*/
|
|
if (type == PCI_CAP_ID_MSI && nvec > 1)
|
|
return 1;
|
|
|
|
msi_for_each_desc(desc, &dev->dev, MSI_DESC_NOTASSOCIATED) {
|
|
ret = arch_setup_msi_irq(dev, desc);
|
|
if (ret)
|
|
return ret < 0 ? ret : -ENOSPC;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void __weak arch_teardown_msi_irqs(struct pci_dev *dev)
|
|
{
|
|
struct msi_desc *desc;
|
|
int i;
|
|
|
|
msi_for_each_desc(desc, &dev->dev, MSI_DESC_ASSOCIATED) {
|
|
for (i = 0; i < desc->nvec_used; i++)
|
|
arch_teardown_msi_irq(desc->irq + i);
|
|
}
|
|
}
|
|
|
|
static int pci_msi_setup_check_result(struct pci_dev *dev, int type, int ret)
|
|
{
|
|
struct msi_desc *desc;
|
|
int avail = 0;
|
|
|
|
if (type != PCI_CAP_ID_MSIX || ret >= 0)
|
|
return ret;
|
|
|
|
/* Scan the MSI descriptors for successfully allocated ones. */
|
|
msi_for_each_desc(desc, &dev->dev, MSI_DESC_ASSOCIATED)
|
|
avail++;
|
|
|
|
return avail ? avail : ret;
|
|
}
|
|
|
|
int pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
|
|
{
|
|
int ret = arch_setup_msi_irqs(dev, nvec, type);
|
|
|
|
ret = pci_msi_setup_check_result(dev, type, ret);
|
|
if (!ret)
|
|
ret = msi_device_populate_sysfs(&dev->dev);
|
|
return ret;
|
|
}
|
|
|
|
void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev)
|
|
{
|
|
msi_device_destroy_sysfs(&dev->dev);
|
|
arch_teardown_msi_irqs(dev);
|
|
msi_free_msi_descs(&dev->dev);
|
|
}
|