1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | |
3 | #include <linux/pci.h> |
4 | #include <linux/msi.h> |
5 | |
6 | #define msix_table_size(flags) ((flags & PCI_MSIX_FLAGS_QSIZE) + 1) |
7 | |
8 | int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); |
9 | void pci_msi_teardown_msi_irqs(struct pci_dev *dev); |
10 | |
11 | /* Mask/unmask helpers */ |
12 | void pci_msi_update_mask(struct msi_desc *desc, u32 clear, u32 set); |
13 | |
14 | static inline void pci_msi_mask(struct msi_desc *desc, u32 mask) |
15 | { |
16 | pci_msi_update_mask(desc, clear: 0, set: mask); |
17 | } |
18 | |
19 | static inline void pci_msi_unmask(struct msi_desc *desc, u32 mask) |
20 | { |
21 | pci_msi_update_mask(desc, clear: mask, set: 0); |
22 | } |
23 | |
24 | static inline void __iomem *pci_msix_desc_addr(struct msi_desc *desc) |
25 | { |
26 | return desc->pci.mask_base + desc->msi_index * PCI_MSIX_ENTRY_SIZE; |
27 | } |
28 | |
29 | /* |
30 | * This internal function does not flush PCI writes to the device. All |
31 | * users must ensure that they read from the device before either assuming |
32 | * that the device state is up to date, or returning out of this file. |
33 | * It does not affect the msi_desc::msix_ctrl cache either. Use with care! |
34 | */ |
35 | static inline void pci_msix_write_vector_ctrl(struct msi_desc *desc, u32 ctrl) |
36 | { |
37 | void __iomem *desc_addr = pci_msix_desc_addr(desc); |
38 | |
39 | if (desc->pci.msi_attrib.can_mask) |
40 | writel(val: ctrl, addr: desc_addr + PCI_MSIX_ENTRY_VECTOR_CTRL); |
41 | } |
42 | |
43 | static inline void pci_msix_mask(struct msi_desc *desc) |
44 | { |
45 | desc->pci.msix_ctrl |= PCI_MSIX_ENTRY_CTRL_MASKBIT; |
46 | pci_msix_write_vector_ctrl(desc, ctrl: desc->pci.msix_ctrl); |
47 | /* Flush write to device */ |
48 | readl(addr: desc->pci.mask_base); |
49 | } |
50 | |
51 | static inline void pci_msix_unmask(struct msi_desc *desc) |
52 | { |
53 | desc->pci.msix_ctrl &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT; |
54 | pci_msix_write_vector_ctrl(desc, ctrl: desc->pci.msix_ctrl); |
55 | } |
56 | |
57 | static inline void __pci_msi_mask_desc(struct msi_desc *desc, u32 mask) |
58 | { |
59 | if (desc->pci.msi_attrib.is_msix) |
60 | pci_msix_mask(desc); |
61 | else |
62 | pci_msi_mask(desc, mask); |
63 | } |
64 | |
65 | static inline void __pci_msi_unmask_desc(struct msi_desc *desc, u32 mask) |
66 | { |
67 | if (desc->pci.msi_attrib.is_msix) |
68 | pci_msix_unmask(desc); |
69 | else |
70 | pci_msi_unmask(desc, mask); |
71 | } |
72 | |
73 | /* |
74 | * PCI 2.3 does not specify mask bits for each MSI interrupt. Attempting to |
75 | * mask all MSI interrupts by clearing the MSI enable bit does not work |
76 | * reliably as devices without an INTx disable bit will then generate a |
77 | * level IRQ which will never be cleared. |
78 | */ |
79 | static inline __attribute_const__ u32 msi_multi_mask(struct msi_desc *desc) |
80 | { |
81 | /* Don't shift by >= width of type */ |
82 | if (desc->pci.msi_attrib.multi_cap >= 5) |
83 | return 0xffffffff; |
84 | return (1 << (1 << desc->pci.msi_attrib.multi_cap)) - 1; |
85 | } |
86 | |
87 | void msix_prepare_msi_desc(struct pci_dev *dev, struct msi_desc *desc); |
88 | |
89 | /* Subsystem variables */ |
90 | extern int pci_msi_enable; |
91 | |
92 | /* MSI internal functions invoked from the public APIs */ |
93 | void pci_msi_shutdown(struct pci_dev *dev); |
94 | void pci_msix_shutdown(struct pci_dev *dev); |
95 | void pci_free_msi_irqs(struct pci_dev *dev); |
96 | int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec, struct irq_affinity *affd); |
97 | int __pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, int minvec, |
98 | int maxvec, struct irq_affinity *affd, int flags); |
99 | void __pci_restore_msi_state(struct pci_dev *dev); |
100 | void __pci_restore_msix_state(struct pci_dev *dev); |
101 | |
102 | /* irq_domain related functionality */ |
103 | |
104 | enum support_mode { |
105 | ALLOW_LEGACY, |
106 | DENY_LEGACY, |
107 | }; |
108 | |
109 | bool pci_msi_domain_supports(struct pci_dev *dev, unsigned int feature_mask, enum support_mode mode); |
110 | bool pci_setup_msi_device_domain(struct pci_dev *pdev); |
111 | bool pci_setup_msix_device_domain(struct pci_dev *pdev, unsigned int hwsize); |
112 | |
113 | /* Legacy (!IRQDOMAIN) fallbacks */ |
114 | |
115 | #ifdef CONFIG_PCI_MSI_ARCH_FALLBACKS |
116 | int pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); |
117 | void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev); |
118 | #else |
119 | static inline int pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) |
120 | { |
121 | WARN_ON_ONCE(1); |
122 | return -ENODEV; |
123 | } |
124 | |
125 | static inline void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev) |
126 | { |
127 | WARN_ON_ONCE(1); |
128 | } |
129 | #endif |
130 | |