linux/drivers/irqchip/irq-gic-v3-its-fsl-mc-msi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Freescale Management Complex (MC) bus driver MSI support
   4 *
   5 * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
   6 * Author: German Rivera <German.Rivera@freescale.com>
   7 *
   8 */
   9
  10#include <linux/of_device.h>
  11#include <linux/of_address.h>
  12#include <linux/irq.h>
  13#include <linux/msi.h>
  14#include <linux/of.h>
  15#include <linux/of_irq.h>
  16#include <linux/fsl/mc.h>
  17
  18static struct irq_chip its_msi_irq_chip = {
  19        .name = "ITS-fMSI",
  20        .irq_mask = irq_chip_mask_parent,
  21        .irq_unmask = irq_chip_unmask_parent,
  22        .irq_eoi = irq_chip_eoi_parent,
  23        .irq_set_affinity = msi_domain_set_affinity
  24};
  25
  26static int its_fsl_mc_msi_prepare(struct irq_domain *msi_domain,
  27                                  struct device *dev,
  28                                  int nvec, msi_alloc_info_t *info)
  29{
  30        struct fsl_mc_device *mc_bus_dev;
  31        struct msi_domain_info *msi_info;
  32
  33        if (!dev_is_fsl_mc(dev))
  34                return -EINVAL;
  35
  36        mc_bus_dev = to_fsl_mc_device(dev);
  37        if (!(mc_bus_dev->flags & FSL_MC_IS_DPRC))
  38                return -EINVAL;
  39
  40        /*
  41         * Set the device Id to be passed to the GIC-ITS:
  42         *
  43         * NOTE: This device id corresponds to the IOMMU stream ID
  44         * associated with the DPRC object (ICID).
  45         */
  46        info->scratchpad[0].ul = mc_bus_dev->icid;
  47        msi_info = msi_get_domain_info(msi_domain->parent);
  48
  49        /* Allocate at least 32 MSIs, and always as a power of 2 */
  50        nvec = max_t(int, 32, roundup_pow_of_two(nvec));
  51        return msi_info->ops->msi_prepare(msi_domain->parent, dev, nvec, info);
  52}
  53
  54static struct msi_domain_ops its_fsl_mc_msi_ops __ro_after_init = {
  55        .msi_prepare = its_fsl_mc_msi_prepare,
  56};
  57
  58static struct msi_domain_info its_fsl_mc_msi_domain_info = {
  59        .flags  = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
  60        .ops    = &its_fsl_mc_msi_ops,
  61        .chip   = &its_msi_irq_chip,
  62};
  63
  64static const struct of_device_id its_device_id[] = {
  65        {       .compatible     = "arm,gic-v3-its",     },
  66        {},
  67};
  68
  69static int __init its_fsl_mc_msi_init(void)
  70{
  71        struct device_node *np;
  72        struct irq_domain *parent;
  73        struct irq_domain *mc_msi_domain;
  74
  75        for (np = of_find_matching_node(NULL, its_device_id); np;
  76             np = of_find_matching_node(np, its_device_id)) {
  77                if (!of_device_is_available(np))
  78                        continue;
  79                if (!of_property_read_bool(np, "msi-controller"))
  80                        continue;
  81
  82                parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS);
  83                if (!parent || !msi_get_domain_info(parent)) {
  84                        pr_err("%pOF: unable to locate ITS domain\n", np);
  85                        continue;
  86                }
  87
  88                mc_msi_domain = fsl_mc_msi_create_irq_domain(
  89                                                 of_node_to_fwnode(np),
  90                                                 &its_fsl_mc_msi_domain_info,
  91                                                 parent);
  92                if (!mc_msi_domain) {
  93                        pr_err("%pOF: unable to create fsl-mc domain\n", np);
  94                        continue;
  95                }
  96
  97                pr_info("fsl-mc MSI: %pOF domain created\n", np);
  98        }
  99
 100        return 0;
 101}
 102
 103early_initcall(its_fsl_mc_msi_init);
 104