Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  1// SPDX-License-Identifier: GPL-2.0-only
  2// Copyright (C) 2013-2015 ARM Limited, All Rights Reserved.
  3// Author: Marc Zyngier <marc.zyngier@arm.com>
  4// Copyright (C) 2022 Linutronix GmbH
  5// Copyright (C) 2022 Intel
  6
  7#include <linux/acpi_iort.h>
  8#include <linux/pci.h>
  9
 10#include "irq-gic-common.h"
 11#include "irq-msi-lib.h"
 12
 13#define ITS_MSI_FLAGS_REQUIRED  (MSI_FLAG_USE_DEF_DOM_OPS |	\
 14				 MSI_FLAG_USE_DEF_CHIP_OPS |	\
 15				 MSI_FLAG_PCI_MSI_MASK_PARENT)
 16
 17#define ITS_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK |	\
 18				 MSI_FLAG_PCI_MSIX      |	\
 19				 MSI_FLAG_MULTI_PCI_MSI)
 20
 21#ifdef CONFIG_PCI_MSI
 22static int its_pci_msi_vec_count(struct pci_dev *pdev, void *data)
 23{
 24	int msi, msix, *count = data;
 25
 26	msi = max(pci_msi_vec_count(pdev), 0);
 27	msix = max(pci_msix_vec_count(pdev), 0);
 28	*count += max(msi, msix);
 29
 30	return 0;
 31}
 32
 33static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data)
 34{
 35	struct pci_dev **alias_dev = data;
 36
 37	*alias_dev = pdev;
 38
 39	return 0;
 40}
 41
 42static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
 43			       int nvec, msi_alloc_info_t *info)
 44{
 45	struct pci_dev *pdev, *alias_dev;
 46	struct msi_domain_info *msi_info;
 47	int alias_count = 0, minnvec = 1;
 48
 49	if (!dev_is_pci(dev))
 50		return -EINVAL;
 51
 52	pdev = to_pci_dev(dev);
 53	/*
 54	 * If pdev is downstream of any aliasing bridges, take an upper
 55	 * bound of how many other vectors could map to the same DevID.
 56	 * Also tell the ITS that the signalling will come from a proxy
 57	 * device, and that special allocation rules apply.
 58	 */
 59	pci_for_each_dma_alias(pdev, its_get_pci_alias, &alias_dev);
 60	if (alias_dev != pdev) {
 61		if (alias_dev->subordinate)
 62			pci_walk_bus(alias_dev->subordinate,
 63				     its_pci_msi_vec_count, &alias_count);
 64		info->flags |= MSI_ALLOC_FLAGS_PROXY_DEVICE;
 65	}
 66
 67	/* ITS specific DeviceID, as the core ITS ignores dev. */
 68	info->scratchpad[0].ul = pci_msi_domain_get_msi_rid(domain->parent, pdev);
 69
 70	/*
 71	 * @domain->msi_domain_info->hwsize contains the size of the
 72	 * MSI[-X] domain, but vector allocation happens one by one. This
 73	 * needs some thought when MSI comes into play as the size of MSI
 74	 * might be unknown at domain creation time and therefore set to
 75	 * MSI_MAX_INDEX.
 76	 */
 77	msi_info = msi_get_domain_info(domain);
 78	if (msi_info->hwsize > nvec)
 79		nvec = msi_info->hwsize;
 80
 81	/*
 82	 * Always allocate a power of 2, and special case device 0 for
 83	 * broken systems where the DevID is not wired (and all devices
 84	 * appear as DevID 0). For that reason, we generously allocate a
 85	 * minimum of 32 MSIs for DevID 0. If you want more because all
 86	 * your devices are aliasing to DevID 0, consider fixing your HW.
 87	 */
 88	nvec = max(nvec, alias_count);
 89	if (!info->scratchpad[0].ul)
 90		minnvec = 32;
 91	nvec = max_t(int, minnvec, roundup_pow_of_two(nvec));
 92
 93	msi_info = msi_get_domain_info(domain->parent);
 94	return msi_info->ops->msi_prepare(domain->parent, dev, nvec, info);
 95}
 96#else /* CONFIG_PCI_MSI */
 97#define its_pci_msi_prepare	NULL
 98#endif /* !CONFIG_PCI_MSI */
 99
100static int of_pmsi_get_dev_id(struct irq_domain *domain, struct device *dev,
101				  u32 *dev_id)
102{
103	int ret, index = 0;
104
105	/* Suck the DeviceID out of the msi-parent property */
106	do {
107		struct of_phandle_args args;
108
109		ret = of_parse_phandle_with_args(dev->of_node,
110						 "msi-parent", "#msi-cells",
111						 index, &args);
112		if (args.np == irq_domain_get_of_node(domain)) {
113			if (WARN_ON(args.args_count != 1))
114				return -EINVAL;
115			*dev_id = args.args[0];
116			break;
117		}
118		index++;
119	} while (!ret);
120
121	return ret;
122}
123
124int __weak iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
125{
126	return -1;
127}
128
129static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
130			    int nvec, msi_alloc_info_t *info)
131{
132	struct msi_domain_info *msi_info;
133	u32 dev_id;
134	int ret;
135
136	if (dev->of_node)
137		ret = of_pmsi_get_dev_id(domain->parent, dev, &dev_id);
138	else
139		ret = iort_pmsi_get_dev_id(dev, &dev_id);
140	if (ret)
141		return ret;
142
143	/* ITS specific DeviceID, as the core ITS ignores dev. */
144	info->scratchpad[0].ul = dev_id;
145
146	/*
147	 * @domain->msi_domain_info->hwsize contains the size of the device
148	 * domain, but vector allocation happens one by one.
149	 */
150	msi_info = msi_get_domain_info(domain);
151	if (msi_info->hwsize > nvec)
152		nvec = msi_info->hwsize;
153
154	/* Allocate at least 32 MSIs, and always as a power of 2 */
155	nvec = max_t(int, 32, roundup_pow_of_two(nvec));
156
157	msi_info = msi_get_domain_info(domain->parent);
158	return msi_info->ops->msi_prepare(domain->parent,
159					  dev, nvec, info);
160}
161
162static bool its_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
163				  struct irq_domain *real_parent, struct msi_domain_info *info)
164{
165	if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info))
166		return false;
167
168	switch(info->bus_token) {
169	case DOMAIN_BUS_PCI_DEVICE_MSI:
170	case DOMAIN_BUS_PCI_DEVICE_MSIX:
171		/*
172		 * FIXME: This probably should be done after a (not yet
173		 * existing) post domain creation callback once to make
174		 * support for dynamic post-enable MSI-X allocations
175		 * work without having to reevaluate the domain size
176		 * over and over. It is known already at allocation
177		 * time via info->hwsize.
178		 *
179		 * That should work perfectly fine for MSI/MSI-X but needs
180		 * some thoughts for purely software managed MSI domains
181		 * where the index space is only limited artificially via
182		 * %MSI_MAX_INDEX.
183		 */
184		info->ops->msi_prepare = its_pci_msi_prepare;
185		break;
186	case DOMAIN_BUS_DEVICE_MSI:
187	case DOMAIN_BUS_WIRED_TO_MSI:
188		/*
189		 * FIXME: See the above PCI prepare comment. The domain
190		 * size is also known at domain creation time.
191		 */
192		info->ops->msi_prepare = its_pmsi_prepare;
193		break;
194	default:
195		/* Confused. How did the lib return true? */
196		WARN_ON_ONCE(1);
197		return false;
198	}
199
200	return true;
201}
202
203const struct msi_parent_ops gic_v3_its_msi_parent_ops = {
204	.supported_flags	= ITS_MSI_FLAGS_SUPPORTED,
205	.required_flags		= ITS_MSI_FLAGS_REQUIRED,
206	.bus_select_token	= DOMAIN_BUS_NEXUS,
207	.bus_select_mask	= MATCH_PCI_MSI | MATCH_PLATFORM_MSI,
208	.prefix			= "ITS-",
209	.init_dev_msi_info	= its_init_dev_msi_info,
210};