xref: /linux/drivers/pci/msi/msi.h (revision 2e2f69fc8ae2b280e1c5e01d876c17bc06dbe23f)
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, 0, mask);
17 }
18 
19 static inline void pci_msi_unmask(struct msi_desc *desc, u32 mask)
20 {
21 	pci_msi_update_mask(desc, mask, 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 	/* The Table is unreachable while the Link is down */
40 	if (pci_channel_offline(msi_desc_to_pci_dev(desc)))
41 		return;
42 
43 	if (desc->pci.msi_attrib.can_mask)
44 		writel(ctrl, desc_addr + PCI_MSIX_ENTRY_VECTOR_CTRL);
45 }
46 
47 static inline void pci_msix_mask(struct msi_desc *desc)
48 {
49 	desc->pci.msix_ctrl |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
50 
51 	if (pci_channel_offline(msi_desc_to_pci_dev(desc)))
52 		return;
53 
54 	pci_msix_write_vector_ctrl(desc, desc->pci.msix_ctrl);
55 	/* Flush write to device */
56 	readl(desc->pci.mask_base);
57 }
58 
59 static inline void pci_msix_unmask(struct msi_desc *desc)
60 {
61 	desc->pci.msix_ctrl &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
62 	pci_msix_write_vector_ctrl(desc, desc->pci.msix_ctrl);
63 }
64 
65 static inline void __pci_msi_mask_desc(struct msi_desc *desc, u32 mask)
66 {
67 	if (desc->pci.msi_attrib.is_msix)
68 		pci_msix_mask(desc);
69 	else
70 		pci_msi_mask(desc, mask);
71 }
72 
73 static inline void __pci_msi_unmask_desc(struct msi_desc *desc, u32 mask)
74 {
75 	if (desc->pci.msi_attrib.is_msix)
76 		pci_msix_unmask(desc);
77 	else
78 		pci_msi_unmask(desc, mask);
79 }
80 
81 /*
82  * PCI 2.3 does not specify mask bits for each MSI interrupt.  Attempting to
83  * mask all MSI interrupts by clearing the MSI enable bit does not work
84  * reliably as devices without an INTx disable bit will then generate a
85  * level IRQ which will never be cleared.
86  */
87 static inline __attribute_const__ u32 msi_multi_mask(struct msi_desc *desc)
88 {
89 	/* Don't shift by >= width of type */
90 	if (desc->pci.msi_attrib.multi_cap >= 5)
91 		return 0xffffffff;
92 	return (1 << (1 << desc->pci.msi_attrib.multi_cap)) - 1;
93 }
94 
95 void msix_prepare_msi_desc(struct pci_dev *dev, struct msi_desc *desc);
96 
97 /* Subsystem variables */
98 extern bool pci_msi_enable;
99 
100 /* MSI internal functions invoked from the public APIs */
101 void pci_msi_shutdown(struct pci_dev *dev);
102 void pci_msix_shutdown(struct pci_dev *dev);
103 void pci_free_msi_irqs(struct pci_dev *dev);
104 int __pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec, struct irq_affinity *affd);
105 int __pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, int minvec,
106 			    int maxvec,  struct irq_affinity *affd, int flags);
107 void __pci_restore_msi_state(struct pci_dev *dev);
108 void __pci_restore_msix_state(struct pci_dev *dev);
109 
110 /* irq_domain related functionality */
111 
112 enum support_mode {
113 	ALLOW_LEGACY,
114 	DENY_LEGACY,
115 };
116 
117 bool pci_msi_domain_supports(struct pci_dev *dev, unsigned int feature_mask, enum support_mode mode);
118 bool pci_setup_msi_device_domain(struct pci_dev *pdev, unsigned int hwsize);
119 bool pci_setup_msix_device_domain(struct pci_dev *pdev, unsigned int hwsize);
120 
121 /* Legacy (!IRQDOMAIN) fallbacks */
122 
123 #ifdef CONFIG_PCI_MSI_ARCH_FALLBACKS
124 int pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
125 void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev);
126 #else
127 static inline int pci_msi_legacy_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
128 {
129 	WARN_ON_ONCE(1);
130 	return -ENODEV;
131 }
132 
133 static inline void pci_msi_legacy_teardown_msi_irqs(struct pci_dev *dev)
134 {
135 	WARN_ON_ONCE(1);
136 }
137 #endif
138