summaryrefslogtreecommitdiff
path: root/drivers/irqchip/irq-gic-v3-its-msi-parent.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/irqchip/irq-gic-v3-its-msi-parent.c')
-rw-r--r--drivers/irqchip/irq-gic-v3-its-msi-parent.c210
1 files changed, 0 insertions, 210 deletions
diff --git a/drivers/irqchip/irq-gic-v3-its-msi-parent.c b/drivers/irqchip/irq-gic-v3-its-msi-parent.c
deleted file mode 100644
index e150365fbe89..000000000000
--- a/drivers/irqchip/irq-gic-v3-its-msi-parent.c
+++ /dev/null
@@ -1,210 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-// Copyright (C) 2013-2015 ARM Limited, All Rights Reserved.
-// Author: Marc Zyngier <marc.zyngier@arm.com>
-// Copyright (C) 2022 Linutronix GmbH
-// Copyright (C) 2022 Intel
-
-#include <linux/acpi_iort.h>
-#include <linux/pci.h>
-
-#include "irq-gic-common.h"
-#include "irq-msi-lib.h"
-
-#define ITS_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
- MSI_FLAG_USE_DEF_CHIP_OPS | \
- MSI_FLAG_PCI_MSI_MASK_PARENT)
-
-#define ITS_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK | \
- MSI_FLAG_PCI_MSIX | \
- MSI_FLAG_MULTI_PCI_MSI)
-
-#ifdef CONFIG_PCI_MSI
-static int its_pci_msi_vec_count(struct pci_dev *pdev, void *data)
-{
- int msi, msix, *count = data;
-
- msi = max(pci_msi_vec_count(pdev), 0);
- msix = max(pci_msix_vec_count(pdev), 0);
- *count += max(msi, msix);
-
- return 0;
-}
-
-static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data)
-{
- struct pci_dev **alias_dev = data;
-
- *alias_dev = pdev;
-
- return 0;
-}
-
-static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
- int nvec, msi_alloc_info_t *info)
-{
- struct pci_dev *pdev, *alias_dev;
- struct msi_domain_info *msi_info;
- int alias_count = 0, minnvec = 1;
-
- if (!dev_is_pci(dev))
- return -EINVAL;
-
- pdev = to_pci_dev(dev);
- /*
- * If pdev is downstream of any aliasing bridges, take an upper
- * bound of how many other vectors could map to the same DevID.
- * Also tell the ITS that the signalling will come from a proxy
- * device, and that special allocation rules apply.
- */
- pci_for_each_dma_alias(pdev, its_get_pci_alias, &alias_dev);
- if (alias_dev != pdev) {
- if (alias_dev->subordinate)
- pci_walk_bus(alias_dev->subordinate,
- its_pci_msi_vec_count, &alias_count);
- info->flags |= MSI_ALLOC_FLAGS_PROXY_DEVICE;
- }
-
- /* ITS specific DeviceID, as the core ITS ignores dev. */
- info->scratchpad[0].ul = pci_msi_domain_get_msi_rid(domain->parent, pdev);
-
- /*
- * @domain->msi_domain_info->hwsize contains the size of the
- * MSI[-X] domain, but vector allocation happens one by one. This
- * needs some thought when MSI comes into play as the size of MSI
- * might be unknown at domain creation time and therefore set to
- * MSI_MAX_INDEX.
- */
- msi_info = msi_get_domain_info(domain);
- if (msi_info->hwsize > nvec)
- nvec = msi_info->hwsize;
-
- /*
- * Always allocate a power of 2, and special case device 0 for
- * broken systems where the DevID is not wired (and all devices
- * appear as DevID 0). For that reason, we generously allocate a
- * minimum of 32 MSIs for DevID 0. If you want more because all
- * your devices are aliasing to DevID 0, consider fixing your HW.
- */
- nvec = max(nvec, alias_count);
- if (!info->scratchpad[0].ul)
- minnvec = 32;
- nvec = max_t(int, minnvec, roundup_pow_of_two(nvec));
-
- msi_info = msi_get_domain_info(domain->parent);
- return msi_info->ops->msi_prepare(domain->parent, dev, nvec, info);
-}
-#else /* CONFIG_PCI_MSI */
-#define its_pci_msi_prepare NULL
-#endif /* !CONFIG_PCI_MSI */
-
-static int of_pmsi_get_dev_id(struct irq_domain *domain, struct device *dev,
- u32 *dev_id)
-{
- int ret, index = 0;
-
- /* Suck the DeviceID out of the msi-parent property */
- do {
- struct of_phandle_args args;
-
- ret = of_parse_phandle_with_args(dev->of_node,
- "msi-parent", "#msi-cells",
- index, &args);
- if (args.np == irq_domain_get_of_node(domain)) {
- if (WARN_ON(args.args_count != 1))
- return -EINVAL;
- *dev_id = args.args[0];
- break;
- }
- index++;
- } while (!ret);
-
- return ret;
-}
-
-int __weak iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
-{
- return -1;
-}
-
-static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
- int nvec, msi_alloc_info_t *info)
-{
- struct msi_domain_info *msi_info;
- u32 dev_id;
- int ret;
-
- if (dev->of_node)
- ret = of_pmsi_get_dev_id(domain->parent, dev, &dev_id);
- else
- ret = iort_pmsi_get_dev_id(dev, &dev_id);
- if (ret)
- return ret;
-
- /* ITS specific DeviceID, as the core ITS ignores dev. */
- info->scratchpad[0].ul = dev_id;
-
- /*
- * @domain->msi_domain_info->hwsize contains the size of the device
- * domain, but vector allocation happens one by one.
- */
- msi_info = msi_get_domain_info(domain);
- if (msi_info->hwsize > nvec)
- nvec = msi_info->hwsize;
-
- /* Allocate at least 32 MSIs, and always as a power of 2 */
- nvec = max_t(int, 32, roundup_pow_of_two(nvec));
-
- msi_info = msi_get_domain_info(domain->parent);
- return msi_info->ops->msi_prepare(domain->parent,
- dev, nvec, info);
-}
-
-static bool its_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
- struct irq_domain *real_parent, struct msi_domain_info *info)
-{
- if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info))
- return false;
-
- switch(info->bus_token) {
- case DOMAIN_BUS_PCI_DEVICE_MSI:
- case DOMAIN_BUS_PCI_DEVICE_MSIX:
- /*
- * FIXME: This probably should be done after a (not yet
- * existing) post domain creation callback once to make
- * support for dynamic post-enable MSI-X allocations
- * work without having to reevaluate the domain size
- * over and over. It is known already at allocation
- * time via info->hwsize.
- *
- * That should work perfectly fine for MSI/MSI-X but needs
- * some thoughts for purely software managed MSI domains
- * where the index space is only limited artificially via
- * %MSI_MAX_INDEX.
- */
- info->ops->msi_prepare = its_pci_msi_prepare;
- break;
- case DOMAIN_BUS_DEVICE_MSI:
- case DOMAIN_BUS_WIRED_TO_MSI:
- /*
- * FIXME: See the above PCI prepare comment. The domain
- * size is also known at domain creation time.
- */
- info->ops->msi_prepare = its_pmsi_prepare;
- break;
- default:
- /* Confused. How did the lib return true? */
- WARN_ON_ONCE(1);
- return false;
- }
-
- return true;
-}
-
-const struct msi_parent_ops gic_v3_its_msi_parent_ops = {
- .supported_flags = ITS_MSI_FLAGS_SUPPORTED,
- .required_flags = ITS_MSI_FLAGS_REQUIRED,
- .bus_select_token = DOMAIN_BUS_NEXUS,
- .bus_select_mask = MATCH_PCI_MSI | MATCH_PLATFORM_MSI,
- .prefix = "ITS-",
- .init_dev_msi_info = its_init_dev_msi_info,
-};