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