legacy.c 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  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. /* Arch hooks */
  9. int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
  10. {
  11. return -EINVAL;
  12. }
  13. void __weak arch_teardown_msi_irq(unsigned int irq)
  14. {
  15. }
  16. int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
  17. {
  18. struct msi_desc *desc;
  19. int ret;
  20. /*
  21. * If an architecture wants to support multiple MSI, it needs to
  22. * override arch_setup_msi_irqs()
  23. */
  24. if (type == PCI_CAP_ID_MSI && nvec > 1)
  25. return 1;
  26. msi_for_each_desc(desc, &dev->dev, MSI_DESC_NOTASSOCIATED) {
  27. ret = arch_setup_msi_irq(dev, desc);
  28. if (ret)
  29. return ret < 0 ? ret : -ENOSPC;
  30. }
  31. return 0;
  32. }
  33. void __weak arch_teardown_msi_irqs(struct pci_dev *dev)
  34. {
  35. struct msi_desc *desc;
  36. int i;
  37. msi_for_each_desc(desc, &dev->dev, MSI_DESC_ASSOCIATED) {
  38. for (i = 0; i < desc->nvec_used; i++)
  39. arch_teardown_msi_irq(desc->irq + i);
  40. }
  41. }
  42. static int pci_msi_setup_check_result(struct pci_dev *dev, int type, int ret)
  43. {
  44. struct msi_desc *desc;
  45. int avail = 0;
  46. if (type != PCI_CAP_ID_MSIX || ret >= 0)
  47. return ret;
  48. /* Scan the MSI descriptors for successfully allocated ones. */
  49. msi_for_each_desc(desc, &dev->dev, MSI_DESC_ASSOCIATED)
  50. avail++;
  51. return avail ? avail : ret;
  52. }
  53. int pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
  54. {
  55. int ret = arch_setup_msi_irqs(dev, nvec, type);
  56. ret = pci_msi_setup_check_result(dev, type, ret);
  57. if (!ret)
  58. ret = msi_device_populate_sysfs(&dev->dev);
  59. return ret;
  60. }
  61. void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev)
  62. {
  63. msi_device_destroy_sysfs(&dev->dev);
  64. arch_teardown_msi_irqs(dev);
  65. }