blob: 0d63541c4052aa600e7e26620ef8152c2f0870e2 [file] [log] [blame]
Thomas Gleixneraa423ac2021-12-06 23:27:52 +01001// SPDX-License-Identifier: GPL-2.0
2/*
3 * PCI Message Signaled Interrupt (MSI) - irqdomain support
4 */
5#include <linux/acpi_iort.h>
6#include <linux/irqdomain.h>
7#include <linux/of_irq.h>
8
9#include "msi.h"
10
11int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
12{
13 struct irq_domain *domain;
14
15 domain = dev_get_msi_domain(&dev->dev);
16 if (domain && irq_domain_is_hierarchy(domain))
Thomas Gleixner5512c5e2021-12-06 23:51:13 +010017 return msi_domain_alloc_irqs_descs_locked(domain, &dev->dev, nvec);
Thomas Gleixneraa423ac2021-12-06 23:27:52 +010018
19 return pci_msi_legacy_setup_msi_irqs(dev, nvec, type);
20}
21
22void pci_msi_teardown_msi_irqs(struct pci_dev *dev)
23{
24 struct irq_domain *domain;
25
26 domain = dev_get_msi_domain(&dev->dev);
27 if (domain && irq_domain_is_hierarchy(domain))
Thomas Gleixner5512c5e2021-12-06 23:51:13 +010028 msi_domain_free_irqs_descs_locked(domain, &dev->dev);
Thomas Gleixneraa423ac2021-12-06 23:27:52 +010029 else
30 pci_msi_legacy_teardown_msi_irqs(dev);
31}
32
33/**
34 * pci_msi_domain_write_msg - Helper to write MSI message to PCI config space
35 * @irq_data: Pointer to interrupt data of the MSI interrupt
36 * @msg: Pointer to the message
37 */
38static void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
39{
40 struct msi_desc *desc = irq_data_get_msi_desc(irq_data);
41
42 /*
43 * For MSI-X desc->irq is always equal to irq_data->irq. For
44 * MSI only the first interrupt of MULTI MSI passes the test.
45 */
46 if (desc->irq == irq_data->irq)
47 __pci_write_msi_msg(desc, msg);
48}
49
50/**
51 * pci_msi_domain_calc_hwirq - Generate a unique ID for an MSI source
52 * @desc: Pointer to the MSI descriptor
53 *
54 * The ID number is only used within the irqdomain.
55 */
56static irq_hw_number_t pci_msi_domain_calc_hwirq(struct msi_desc *desc)
57{
58 struct pci_dev *dev = msi_desc_to_pci_dev(desc);
59
Thomas Gleixner173ffad2021-12-10 23:19:18 +010060 return (irq_hw_number_t)desc->msi_index |
Thomas Gleixneraa423ac2021-12-06 23:27:52 +010061 pci_dev_id(dev) << 11 |
62 (pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 27;
63}
64
65static inline bool pci_msi_desc_is_multi_msi(struct msi_desc *desc)
66{
67 return !desc->pci.msi_attrib.is_msix && desc->nvec_used > 1;
68}
69
70/**
71 * pci_msi_domain_check_cap - Verify that @domain supports the capabilities
72 * for @dev
73 * @domain: The interrupt domain to check
74 * @info: The domain info for verification
75 * @dev: The device to check
76 *
77 * Returns:
78 * 0 if the functionality is supported
79 * 1 if Multi MSI is requested, but the domain does not support it
80 * -ENOTSUPP otherwise
81 */
Thomas Gleixner57ce3a32021-12-06 23:27:57 +010082static int pci_msi_domain_check_cap(struct irq_domain *domain,
83 struct msi_domain_info *info,
84 struct device *dev)
Thomas Gleixneraa423ac2021-12-06 23:27:52 +010085{
Thomas Gleixnerae24e282021-12-06 23:51:18 +010086 struct msi_desc *desc = msi_first_desc(dev, MSI_DESC_ALL);
Thomas Gleixneraa423ac2021-12-06 23:27:52 +010087
88 /* Special handling to support __pci_enable_msi_range() */
89 if (pci_msi_desc_is_multi_msi(desc) &&
90 !(info->flags & MSI_FLAG_MULTI_PCI_MSI))
91 return 1;
Thomas Gleixneraa423ac2021-12-06 23:27:52 +010092
Thomas Gleixner7a823442021-12-10 23:19:20 +010093 if (desc->pci.msi_attrib.is_msix) {
94 if (!(info->flags & MSI_FLAG_PCI_MSIX))
95 return -ENOTSUPP;
96
97 if (info->flags & MSI_FLAG_MSIX_CONTIGUOUS) {
98 unsigned int idx = 0;
99
100 /* Check for gaps in the entry indices */
Thomas Gleixnerae24e282021-12-06 23:51:18 +0100101 msi_for_each_desc(desc, dev, MSI_DESC_ALL) {
Thomas Gleixner7a823442021-12-10 23:19:20 +0100102 if (desc->msi_index != idx++)
103 return -ENOTSUPP;
104 }
105 }
106 }
Thomas Gleixneraa423ac2021-12-06 23:27:52 +0100107 return 0;
108}
109
Thomas Gleixneraa423ac2021-12-06 23:27:52 +0100110static void pci_msi_domain_set_desc(msi_alloc_info_t *arg,
111 struct msi_desc *desc)
112{
113 arg->desc = desc;
114 arg->hwirq = pci_msi_domain_calc_hwirq(desc);
115}
116
117static struct msi_domain_ops pci_msi_domain_ops_default = {
118 .set_desc = pci_msi_domain_set_desc,
119 .msi_check = pci_msi_domain_check_cap,
Thomas Gleixneraa423ac2021-12-06 23:27:52 +0100120};
121
122static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info)
123{
124 struct msi_domain_ops *ops = info->ops;
125
126 if (ops == NULL) {
127 info->ops = &pci_msi_domain_ops_default;
128 } else {
129 if (ops->set_desc == NULL)
130 ops->set_desc = pci_msi_domain_set_desc;
131 if (ops->msi_check == NULL)
132 ops->msi_check = pci_msi_domain_check_cap;
Thomas Gleixneraa423ac2021-12-06 23:27:52 +0100133 }
134}
135
136static void pci_msi_domain_update_chip_ops(struct msi_domain_info *info)
137{
138 struct irq_chip *chip = info->chip;
139
140 BUG_ON(!chip);
141 if (!chip->irq_write_msi_msg)
142 chip->irq_write_msi_msg = pci_msi_domain_write_msg;
143 if (!chip->irq_mask)
144 chip->irq_mask = pci_msi_mask_irq;
145 if (!chip->irq_unmask)
146 chip->irq_unmask = pci_msi_unmask_irq;
147}
148
149/**
150 * pci_msi_create_irq_domain - Create a MSI interrupt domain
151 * @fwnode: Optional fwnode of the interrupt controller
152 * @info: MSI domain info
153 * @parent: Parent irq domain
154 *
155 * Updates the domain and chip ops and creates a MSI interrupt domain.
156 *
157 * Returns:
158 * A domain pointer or NULL in case of failure.
159 */
160struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode,
161 struct msi_domain_info *info,
162 struct irq_domain *parent)
163{
164 struct irq_domain *domain;
165
166 if (WARN_ON(info->flags & MSI_FLAG_LEVEL_CAPABLE))
167 info->flags &= ~MSI_FLAG_LEVEL_CAPABLE;
168
169 if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS)
170 pci_msi_domain_update_dom_ops(info);
171 if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
172 pci_msi_domain_update_chip_ops(info);
173
Thomas Gleixner9fb9eb42021-12-06 23:51:16 +0100174 info->flags |= MSI_FLAG_ACTIVATE_EARLY | MSI_FLAG_DEV_SYSFS |
175 MSI_FLAG_FREE_MSI_DESCS;
Thomas Gleixneraa423ac2021-12-06 23:27:52 +0100176 if (IS_ENABLED(CONFIG_GENERIC_IRQ_RESERVATION_MODE))
177 info->flags |= MSI_FLAG_MUST_REACTIVATE;
178
179 /* PCI-MSI is oneshot-safe */
180 info->chip->flags |= IRQCHIP_ONESHOT_SAFE;
181
182 domain = msi_create_irq_domain(fwnode, info, parent);
183 if (!domain)
184 return NULL;
185
186 irq_domain_update_bus_token(domain, DOMAIN_BUS_PCI_MSI);
187 return domain;
188}
189EXPORT_SYMBOL_GPL(pci_msi_create_irq_domain);
190
191/*
192 * Users of the generic MSI infrastructure expect a device to have a single ID,
193 * so with DMA aliases we have to pick the least-worst compromise. Devices with
194 * DMA phantom functions tend to still emit MSIs from the real function number,
195 * so we ignore those and only consider topological aliases where either the
196 * alias device or RID appears on a different bus number. We also make the
197 * reasonable assumption that bridges are walked in an upstream direction (so
198 * the last one seen wins), and the much braver assumption that the most likely
199 * case is that of PCI->PCIe so we should always use the alias RID. This echoes
200 * the logic from intel_irq_remapping's set_msi_sid(), which presumably works
201 * well enough in practice; in the face of the horrible PCIe<->PCI-X conditions
202 * for taking ownership all we can really do is close our eyes and hope...
203 */
204static int get_msi_id_cb(struct pci_dev *pdev, u16 alias, void *data)
205{
206 u32 *pa = data;
207 u8 bus = PCI_BUS_NUM(*pa);
208
209 if (pdev->bus->number != bus || PCI_BUS_NUM(alias) != bus)
210 *pa = alias;
211
212 return 0;
213}
214
215/**
216 * pci_msi_domain_get_msi_rid - Get the MSI requester id (RID)
217 * @domain: The interrupt domain
218 * @pdev: The PCI device.
219 *
220 * The RID for a device is formed from the alias, with a firmware
221 * supplied mapping applied
222 *
223 * Returns: The RID.
224 */
225u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev)
226{
227 struct device_node *of_node;
228 u32 rid = pci_dev_id(pdev);
229
230 pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
231
232 of_node = irq_domain_get_of_node(domain);
233 rid = of_node ? of_msi_map_id(&pdev->dev, of_node, rid) :
234 iort_msi_map_id(&pdev->dev, rid);
235
236 return rid;
237}
238
239/**
240 * pci_msi_get_device_domain - Get the MSI domain for a given PCI device
241 * @pdev: The PCI device
242 *
243 * Use the firmware data to find a device-specific MSI domain
244 * (i.e. not one that is set as a default).
245 *
246 * Returns: The corresponding MSI domain or NULL if none has been found.
247 */
248struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev)
249{
250 struct irq_domain *dom;
251 u32 rid = pci_dev_id(pdev);
252
253 pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
254 dom = of_msi_map_get_device_domain(&pdev->dev, rid, DOMAIN_BUS_PCI_MSI);
255 if (!dom)
256 dom = iort_get_device_domain(&pdev->dev, rid,
257 DOMAIN_BUS_PCI_MSI);
258 return dom;
259}
260
261/**
262 * pci_dev_has_special_msi_domain - Check whether the device is handled by
263 * a non-standard PCI-MSI domain
264 * @pdev: The PCI device to check.
265 *
266 * Returns: True if the device irqdomain or the bus irqdomain is
267 * non-standard PCI/MSI.
268 */
269bool pci_dev_has_special_msi_domain(struct pci_dev *pdev)
270{
271 struct irq_domain *dom = dev_get_msi_domain(&pdev->dev);
272
273 if (!dom)
274 dom = dev_get_msi_domain(&pdev->bus->dev);
275
276 if (!dom)
277 return true;
278
279 return dom->bus_token != DOMAIN_BUS_PCI_MSI;
280}