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 */ 10 int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) 11 { 12 return -EINVAL; 13 } 14 15 void __weak arch_teardown_msi_irq(unsigned int irq) 16 { 17 } 18 19 int __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 40 void __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 51 static 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 66 int 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 76 void 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 msi_free_msi_descs(&dev->dev); 81 } 82