File Index
Files and directories
Sign in
FILE

irqdomain.c

File preview with syntax highlighting.

linux-6.19.14/drivers/pci/msi/irqdomain.c C
  1// 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))
 17		return msi_domain_alloc_irqs_all_locked(&dev->dev, MSI_DEFAULT_DOMAIN, nvec);
 18
 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)) {
 28		msi_domain_free_irqs_all_locked(&dev->dev, MSI_DEFAULT_DOMAIN);
 29	} else {
 30		pci_msi_legacy_teardown_msi_irqs(dev);
 31		msi_free_msi_descs(&dev->dev);
 32	}
 33}
 34
 35/**
 36 * pci_msi_domain_write_msg - Helper to write MSI message to PCI config space
 37 * @irq_data:	Pointer to interrupt data of the MSI interrupt
 38 * @msg:	Pointer to the message
 39 */
 40static void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
 41{
 42	struct msi_desc *desc = irq_data_get_msi_desc(irq_data);
 43
 44	/*
 45	 * For MSI-X desc->irq is always equal to irq_data->irq. For
 46	 * MSI only the first interrupt of MULTI MSI passes the test.
 47	 */
 48	if (desc->irq == irq_data->irq)
 49		__pci_write_msi_msg(desc, msg);
 50}
 51
 52/*
 53 * Per device MSI[-X] domain functionality
 54 */
 55static void pci_device_domain_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
 56{
 57	arg->desc = desc;
 58	arg->hwirq = desc->msi_index;
 59}
 60
 61static void cond_shutdown_parent(struct irq_data *data)
 62{
 63	struct msi_domain_info *info = data->domain->host_data;
 64
 65	if (unlikely(info->flags & MSI_FLAG_PCI_MSI_STARTUP_PARENT))
 66		irq_chip_shutdown_parent(data);
 67	else if (unlikely(info->flags & MSI_FLAG_PCI_MSI_MASK_PARENT))
 68		irq_chip_mask_parent(data);
 69}
 70
 71static unsigned int cond_startup_parent(struct irq_data *data)
 72{
 73	struct msi_domain_info *info = data->domain->host_data;
 74
 75	if (unlikely(info->flags & MSI_FLAG_PCI_MSI_STARTUP_PARENT))
 76		return irq_chip_startup_parent(data);
 77	else if (unlikely(info->flags & MSI_FLAG_PCI_MSI_MASK_PARENT))
 78		irq_chip_unmask_parent(data);
 79
 80	return 0;
 81}
 82
 83static void pci_irq_shutdown_msi(struct irq_data *data)
 84{
 85	struct msi_desc *desc = irq_data_get_msi_desc(data);
 86
 87	pci_msi_mask(desc, BIT(data->irq - desc->irq));
 88	cond_shutdown_parent(data);
 89}
 90
 91static unsigned int pci_irq_startup_msi(struct irq_data *data)
 92{
 93	struct msi_desc *desc = irq_data_get_msi_desc(data);
 94	unsigned int ret = cond_startup_parent(data);
 95
 96	pci_msi_unmask(desc, BIT(data->irq - desc->irq));
 97	return ret;
 98}
 99
100static void pci_irq_mask_msi(struct irq_data *data)
101{
102	struct msi_desc *desc = irq_data_get_msi_desc(data);
103
104	pci_msi_mask(desc, BIT(data->irq - desc->irq));
105}
106
107static void pci_irq_unmask_msi(struct irq_data *data)
108{
109	struct msi_desc *desc = irq_data_get_msi_desc(data);
110
111	pci_msi_unmask(desc, BIT(data->irq - desc->irq));
112}
113
114#ifdef CONFIG_GENERIC_IRQ_RESERVATION_MODE
115# define MSI_REACTIVATE		MSI_FLAG_MUST_REACTIVATE
116#else
117# define MSI_REACTIVATE		0
118#endif
119
120#define MSI_COMMON_FLAGS	(MSI_FLAG_FREE_MSI_DESCS |	\
121				 MSI_FLAG_ACTIVATE_EARLY |	\
122				 MSI_FLAG_DEV_SYSFS |		\
123				 MSI_REACTIVATE)
124
125static const struct msi_domain_template pci_msi_template = {
126	.chip = {
127		.name			= "PCI-MSI",
128		.irq_startup		= pci_irq_startup_msi,
129		.irq_shutdown		= pci_irq_shutdown_msi,
130		.irq_mask		= pci_irq_mask_msi,
131		.irq_unmask		= pci_irq_unmask_msi,
132		.irq_write_msi_msg	= pci_msi_domain_write_msg,
133		.flags			= IRQCHIP_ONESHOT_SAFE,
134	},
135
136	.ops = {
137		.set_desc		= pci_device_domain_set_desc,
138	},
139
140	.info = {
141		.flags			= MSI_COMMON_FLAGS | MSI_FLAG_MULTI_PCI_MSI,
142		.bus_token		= DOMAIN_BUS_PCI_DEVICE_MSI,
143	},
144};
145
146static void pci_irq_shutdown_msix(struct irq_data *data)
147{
148	pci_msix_mask(irq_data_get_msi_desc(data));
149	cond_shutdown_parent(data);
150}
151
152static unsigned int pci_irq_startup_msix(struct irq_data *data)
153{
154	unsigned int ret = cond_startup_parent(data);
155
156	pci_msix_unmask(irq_data_get_msi_desc(data));
157	return ret;
158}
159
160static void pci_irq_mask_msix(struct irq_data *data)
161{
162	pci_msix_mask(irq_data_get_msi_desc(data));
163}
164
165static void pci_irq_unmask_msix(struct irq_data *data)
166{
167	pci_msix_unmask(irq_data_get_msi_desc(data));
168}
169
170void pci_msix_prepare_desc(struct irq_domain *domain, msi_alloc_info_t *arg,
171			   struct msi_desc *desc)
172{
173	/* Don't fiddle with preallocated MSI descriptors */
174	if (!desc->pci.mask_base)
175		msix_prepare_msi_desc(to_pci_dev(desc->dev), desc);
176}
177EXPORT_SYMBOL_GPL(pci_msix_prepare_desc);
178
179static const struct msi_domain_template pci_msix_template = {
180	.chip = {
181		.name			= "PCI-MSIX",
182		.irq_startup		= pci_irq_startup_msix,
183		.irq_shutdown		= pci_irq_shutdown_msix,
184		.irq_mask		= pci_irq_mask_msix,
185		.irq_unmask		= pci_irq_unmask_msix,
186		.irq_write_msi_msg	= pci_msi_domain_write_msg,
187		.flags			= IRQCHIP_ONESHOT_SAFE,
188	},
189
190	.ops = {
191		.prepare_desc		= pci_msix_prepare_desc,
192		.set_desc		= pci_device_domain_set_desc,
193	},
194
195	.info = {
196		.flags			= MSI_COMMON_FLAGS | MSI_FLAG_PCI_MSIX |
197					  MSI_FLAG_PCI_MSIX_ALLOC_DYN,
198		.bus_token		= DOMAIN_BUS_PCI_DEVICE_MSIX,
199	},
200};
201
202static bool pci_match_device_domain(struct pci_dev *pdev, enum irq_domain_bus_token bus_token)
203{
204	return msi_match_device_irq_domain(&pdev->dev, MSI_DEFAULT_DOMAIN, bus_token);
205}
206
207static bool pci_create_device_domain(struct pci_dev *pdev, const struct msi_domain_template *tmpl,
208				     unsigned int hwsize)
209{
210	struct irq_domain *domain = dev_get_msi_domain(&pdev->dev);
211
212	if (!domain || !irq_domain_is_msi_parent(domain))
213		return true;
214
215	return msi_create_device_irq_domain(&pdev->dev, MSI_DEFAULT_DOMAIN, tmpl,
216					    hwsize, NULL, NULL);
217}
218
219/**
220 * pci_setup_msi_device_domain - Setup a device MSI interrupt domain
221 * @pdev:	The PCI device to create the domain on
222 * @hwsize:	The maximum number of MSI vectors
223 *
224 * Return:
225 *  True when:
226 *	- The device does not have a MSI parent irq domain associated,
227 *	  which keeps the legacy architecture specific and the global
228 *	  PCI/MSI domain models working
229 *	- The MSI domain exists already
230 *	- The MSI domain was successfully allocated
231 *  False when:
232 *	- MSI-X is enabled
233 *	- The domain creation fails.
234 *
235 * The created MSI domain is preserved until:
236 *	- The device is removed
237 *	- MSI is disabled and a MSI-X domain is created
238 */
239bool pci_setup_msi_device_domain(struct pci_dev *pdev, unsigned int hwsize)
240{
241	if (WARN_ON_ONCE(pdev->msix_enabled))
242		return false;
243
244	if (pci_match_device_domain(pdev, DOMAIN_BUS_PCI_DEVICE_MSI))
245		return true;
246	if (pci_match_device_domain(pdev, DOMAIN_BUS_PCI_DEVICE_MSIX))
247		msi_remove_device_irq_domain(&pdev->dev, MSI_DEFAULT_DOMAIN);
248
249	return pci_create_device_domain(pdev, &pci_msi_template, hwsize);
250}
251
252/**
253 * pci_setup_msix_device_domain - Setup a device MSI-X interrupt domain
254 * @pdev:	The PCI device to create the domain on
255 * @hwsize:	The size of the MSI-X vector table
256 *
257 * Return:
258 *  True when:
259 *	- The device does not have a MSI parent irq domain associated,
260 *	  which keeps the legacy architecture specific and the global
261 *	  PCI/MSI domain models working
262 *	- The MSI-X domain exists already
263 *	- The MSI-X domain was successfully allocated
264 *  False when:
265 *	- MSI is enabled
266 *	- The domain creation fails.
267 *
268 * The created MSI-X domain is preserved until:
269 *	- The device is removed
270 *	- MSI-X is disabled and a MSI domain is created
271 */
272bool pci_setup_msix_device_domain(struct pci_dev *pdev, unsigned int hwsize)
273{
274	if (WARN_ON_ONCE(pdev->msi_enabled))
275		return false;
276
277	if (pci_match_device_domain(pdev, DOMAIN_BUS_PCI_DEVICE_MSIX))
278		return true;
279	if (pci_match_device_domain(pdev, DOMAIN_BUS_PCI_DEVICE_MSI))
280		msi_remove_device_irq_domain(&pdev->dev, MSI_DEFAULT_DOMAIN);
281
282	return pci_create_device_domain(pdev, &pci_msix_template, hwsize);
283}
284
285/**
286 * pci_msi_domain_supports - Check for support of a particular feature flag
287 * @pdev:		The PCI device to operate on
288 * @feature_mask:	The feature mask to check for (full match)
289 * @mode:		If ALLOW_LEGACY this grants the feature when there is no irq domain
290 *			associated to the device. If DENY_LEGACY the lack of an irq domain
291 *			makes the feature unsupported
292 */
293bool pci_msi_domain_supports(struct pci_dev *pdev, unsigned int feature_mask,
294			     enum support_mode mode)
295{
296	struct msi_domain_info *info;
297	struct irq_domain *domain;
298	unsigned int supported;
299
300	domain = dev_get_msi_domain(&pdev->dev);
301
302	if (!domain || !irq_domain_is_hierarchy(domain)) {
303		if (IS_ENABLED(CONFIG_PCI_MSI_ARCH_FALLBACKS))
304			return mode == ALLOW_LEGACY;
305		return false;
306	}
307
308	if (!irq_domain_is_msi_parent(domain)) {
309		/*
310		 * For "global" PCI/MSI interrupt domains the associated
311		 * msi_domain_info::flags is the authoritative source of
312		 * information.
313		 */
314		info = domain->host_data;
315		supported = info->flags;
316	} else {
317		/*
318		 * For MSI parent domains the supported feature set
319		 * is available in the parent ops. This makes checks
320		 * possible before actually instantiating the
321		 * per device domain because the parent is never
322		 * expanding the PCI/MSI functionality.
323		 */
324		supported = domain->msi_parent_ops->supported_flags;
325	}
326
327	return (supported & feature_mask) == feature_mask;
328}
329
330/*
331 * Users of the generic MSI infrastructure expect a device to have a single ID,
332 * so with DMA aliases we have to pick the least-worst compromise. Devices with
333 * DMA phantom functions tend to still emit MSIs from the real function number,
334 * so we ignore those and only consider topological aliases where either the
335 * alias device or RID appears on a different bus number. We also make the
336 * reasonable assumption that bridges are walked in an upstream direction (so
337 * the last one seen wins), and the much braver assumption that the most likely
338 * case is that of PCI->PCIe so we should always use the alias RID. This echoes
339 * the logic from intel_irq_remapping's set_msi_sid(), which presumably works
340 * well enough in practice; in the face of the horrible PCIe<->PCI-X conditions
341 * for taking ownership all we can really do is close our eyes and hope...
342 */
343static int get_msi_id_cb(struct pci_dev *pdev, u16 alias, void *data)
344{
345	u32 *pa = data;
346	u8 bus = PCI_BUS_NUM(*pa);
347
348	if (pdev->bus->number != bus || PCI_BUS_NUM(alias) != bus)
349		*pa = alias;
350
351	return 0;
352}
353
354/**
355 * pci_msi_domain_get_msi_rid - Get the MSI requester id (RID)
356 * @domain:	The interrupt domain
357 * @pdev:	The PCI device.
358 *
359 * The RID for a device is formed from the alias, with a firmware
360 * supplied mapping applied
361 *
362 * Returns: The RID.
363 */
364u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev)
365{
366	struct device_node *of_node;
367	u32 rid = pci_dev_id(pdev);
368
369	pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
370
371	of_node = irq_domain_get_of_node(domain);
372	rid = of_node ? of_msi_xlate(&pdev->dev, &of_node, rid) :
373			iort_msi_map_id(&pdev->dev, rid);
374
375	return rid;
376}
377
378/**
379 * pci_msi_map_rid_ctlr_node - Get the MSI controller node and MSI requester id (RID)
380 * @pdev:	The PCI device
381 * @node:	Pointer to store the MSI controller device node
382 *
383 * Use the firmware data to find the MSI controller node for @pdev.
384 * If found map the RID and initialize @node with it. @node value must
385 * be set to NULL on entry.
386 *
387 * Returns: The RID.
388 */
389u32 pci_msi_map_rid_ctlr_node(struct pci_dev *pdev, struct device_node **node)
390{
391	u32 rid = pci_dev_id(pdev);
392
393	pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
394
395	return of_msi_xlate(&pdev->dev, node, rid);
396}
397
398/**
399 * pci_msi_get_device_domain - Get the MSI domain for a given PCI device
400 * @pdev:	The PCI device
401 *
402 * Use the firmware data to find a device-specific MSI domain
403 * (i.e. not one that is set as a default).
404 *
405 * Returns: The corresponding MSI domain or NULL if none has been found.
406 */
407struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev)
408{
409	struct irq_domain *dom;
410	u32 rid = pci_dev_id(pdev);
411
412	pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid);
413	dom = of_msi_map_get_device_domain(&pdev->dev, rid, DOMAIN_BUS_PCI_MSI);
414	if (!dom)
415		dom = iort_get_device_domain(&pdev->dev, rid,
416					     DOMAIN_BUS_PCI_MSI);
417	return dom;
418}
~/ Read-only file preview.