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(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->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->dev); |
79 | arch_teardown_msi_irqs(dev); |
80 | } |
81 | |