linux/drivers/pci/msi/legacy.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * PCI Message Signaled Interrupt (MSI).
   4 *
   5 * Legacy architecture specific setup and teardown mechanism.
   6 */
   7#include "msi.h"
   8
   9/* Arch hooks */
  10int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
  11{
  12        return -EINVAL;
  13}
  14
  15void __weak arch_teardown_msi_irq(unsigned int irq)
  16{
  17}
  18
  19int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
  20{
  21        struct msi_desc *desc;
  22        int ret;
  23
  24        /*
  25         * If an architecture wants to support multiple MSI, it needs to
  26         * override arch_setup_msi_irqs()
  27         */
  28        if (type == PCI_CAP_ID_MSI && nvec > 1)
  29                return 1;
  30
  31        msi_for_each_desc(desc, &dev->dev, MSI_DESC_NOTASSOCIATED) {
  32                ret = arch_setup_msi_irq(dev, desc);
  33                if (ret)
  34                        return ret < 0 ? ret : -ENOSPC;
  35        }
  36
  37        return 0;
  38}
  39
  40void __weak arch_teardown_msi_irqs(struct pci_dev *dev)
  41{
  42        struct msi_desc *desc;
  43        int i;
  44
  45        msi_for_each_desc(desc, &dev->dev, MSI_DESC_ASSOCIATED) {
  46                for (i = 0; i < desc->nvec_used; i++)
  47                        arch_teardown_msi_irq(desc->irq + i);
  48        }
  49}
  50
  51static int pci_msi_setup_check_result(struct pci_dev *dev, int type, int ret)
  52{
  53        struct msi_desc *desc;
  54        int avail = 0;
  55
  56        if (type != PCI_CAP_ID_MSIX || ret >= 0)
  57                return ret;
  58
  59        /* Scan the MSI descriptors for successfully allocated ones. */
  60        msi_for_each_desc(desc, &dev->dev, MSI_DESC_ASSOCIATED)
  61                avail++;
  62
  63        return avail ? avail : ret;
  64}
  65
  66int pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
  67{
  68        int ret = arch_setup_msi_irqs(dev, nvec, type);
  69
  70        ret = pci_msi_setup_check_result(dev, type, ret);
  71        if (!ret)
  72                ret = msi_device_populate_sysfs(&dev->dev);
  73        return ret;
  74}
  75
  76void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev)
  77{
  78        msi_device_destroy_sysfs(&dev->dev);
  79        arch_teardown_msi_irqs(dev);
  80}
  81