162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * PCI Message Signaled Interrupt (MSI). 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Legacy architecture specific setup and teardown mechanism. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include "msi.h" 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci/* Arch hooks */ 1062306a36Sopenharmony_ciint __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) 1162306a36Sopenharmony_ci{ 1262306a36Sopenharmony_ci return -EINVAL; 1362306a36Sopenharmony_ci} 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_civoid __weak arch_teardown_msi_irq(unsigned int irq) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci} 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ciint __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci struct msi_desc *desc; 2262306a36Sopenharmony_ci int ret; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci /* 2562306a36Sopenharmony_ci * If an architecture wants to support multiple MSI, it needs to 2662306a36Sopenharmony_ci * override arch_setup_msi_irqs() 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci if (type == PCI_CAP_ID_MSI && nvec > 1) 2962306a36Sopenharmony_ci return 1; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci msi_for_each_desc(desc, &dev->dev, MSI_DESC_NOTASSOCIATED) { 3262306a36Sopenharmony_ci ret = arch_setup_msi_irq(dev, desc); 3362306a36Sopenharmony_ci if (ret) 3462306a36Sopenharmony_ci return ret < 0 ? ret : -ENOSPC; 3562306a36Sopenharmony_ci } 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci return 0; 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_civoid __weak arch_teardown_msi_irqs(struct pci_dev *dev) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct msi_desc *desc; 4362306a36Sopenharmony_ci int i; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci msi_for_each_desc(desc, &dev->dev, MSI_DESC_ASSOCIATED) { 4662306a36Sopenharmony_ci for (i = 0; i < desc->nvec_used; i++) 4762306a36Sopenharmony_ci arch_teardown_msi_irq(desc->irq + i); 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic int pci_msi_setup_check_result(struct pci_dev *dev, int type, int ret) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci struct msi_desc *desc; 5462306a36Sopenharmony_ci int avail = 0; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci if (type != PCI_CAP_ID_MSIX || ret >= 0) 5762306a36Sopenharmony_ci return ret; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci /* Scan the MSI descriptors for successfully allocated ones. */ 6062306a36Sopenharmony_ci msi_for_each_desc(desc, &dev->dev, MSI_DESC_ASSOCIATED) 6162306a36Sopenharmony_ci avail++; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci return avail ? avail : ret; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ciint pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci int ret = arch_setup_msi_irqs(dev, nvec, type); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci ret = pci_msi_setup_check_result(dev, type, ret); 7162306a36Sopenharmony_ci if (!ret) 7262306a36Sopenharmony_ci ret = msi_device_populate_sysfs(&dev->dev); 7362306a36Sopenharmony_ci return ret; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_civoid pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci msi_device_destroy_sysfs(&dev->dev); 7962306a36Sopenharmony_ci arch_teardown_msi_irqs(dev); 8062306a36Sopenharmony_ci} 81