cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

irq-gic-v3-its-fsl-mc-msi.c (4283B)


      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/acpi.h>
     11#include <linux/acpi_iort.h>
     12#include <linux/of_device.h>
     13#include <linux/of_address.h>
     14#include <linux/irq.h>
     15#include <linux/msi.h>
     16#include <linux/of.h>
     17#include <linux/of_irq.h>
     18#include <linux/fsl/mc.h>
     19
     20static struct irq_chip its_msi_irq_chip = {
     21	.name = "ITS-fMSI",
     22	.irq_mask = irq_chip_mask_parent,
     23	.irq_unmask = irq_chip_unmask_parent,
     24	.irq_eoi = irq_chip_eoi_parent,
     25	.irq_set_affinity = msi_domain_set_affinity
     26};
     27
     28static u32 fsl_mc_msi_domain_get_msi_id(struct irq_domain *domain,
     29					struct fsl_mc_device *mc_dev)
     30{
     31	struct device_node *of_node;
     32	u32 out_id;
     33
     34	of_node = irq_domain_get_of_node(domain);
     35	out_id = of_node ? of_msi_map_id(&mc_dev->dev, of_node, mc_dev->icid) :
     36			iort_msi_map_id(&mc_dev->dev, mc_dev->icid);
     37
     38	return out_id;
     39}
     40
     41static int its_fsl_mc_msi_prepare(struct irq_domain *msi_domain,
     42				  struct device *dev,
     43				  int nvec, msi_alloc_info_t *info)
     44{
     45	struct fsl_mc_device *mc_bus_dev;
     46	struct msi_domain_info *msi_info;
     47
     48	if (!dev_is_fsl_mc(dev))
     49		return -EINVAL;
     50
     51	mc_bus_dev = to_fsl_mc_device(dev);
     52	if (!(mc_bus_dev->flags & FSL_MC_IS_DPRC))
     53		return -EINVAL;
     54
     55	/*
     56	 * Set the device Id to be passed to the GIC-ITS:
     57	 *
     58	 * NOTE: This device id corresponds to the IOMMU stream ID
     59	 * associated with the DPRC object (ICID).
     60	 */
     61	info->scratchpad[0].ul = fsl_mc_msi_domain_get_msi_id(msi_domain,
     62							      mc_bus_dev);
     63	msi_info = msi_get_domain_info(msi_domain->parent);
     64
     65	/* Allocate at least 32 MSIs, and always as a power of 2 */
     66	nvec = max_t(int, 32, roundup_pow_of_two(nvec));
     67	return msi_info->ops->msi_prepare(msi_domain->parent, dev, nvec, info);
     68}
     69
     70static struct msi_domain_ops its_fsl_mc_msi_ops __ro_after_init = {
     71	.msi_prepare = its_fsl_mc_msi_prepare,
     72};
     73
     74static struct msi_domain_info its_fsl_mc_msi_domain_info = {
     75	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
     76	.ops	= &its_fsl_mc_msi_ops,
     77	.chip	= &its_msi_irq_chip,
     78};
     79
     80static const struct of_device_id its_device_id[] = {
     81	{	.compatible	= "arm,gic-v3-its",	},
     82	{},
     83};
     84
     85static void __init its_fsl_mc_msi_init_one(struct fwnode_handle *handle,
     86					  const char *name)
     87{
     88	struct irq_domain *parent;
     89	struct irq_domain *mc_msi_domain;
     90
     91	parent = irq_find_matching_fwnode(handle, DOMAIN_BUS_NEXUS);
     92	if (!parent || !msi_get_domain_info(parent)) {
     93		pr_err("%s: unable to locate ITS domain\n", name);
     94		return;
     95	}
     96
     97	mc_msi_domain = fsl_mc_msi_create_irq_domain(handle,
     98						&its_fsl_mc_msi_domain_info,
     99						parent);
    100	if (!mc_msi_domain) {
    101		pr_err("%s: unable to create fsl-mc domain\n", name);
    102		return;
    103	}
    104
    105	pr_info("fsl-mc MSI: %s domain created\n", name);
    106}
    107
    108#ifdef CONFIG_ACPI
    109static int __init
    110its_fsl_mc_msi_parse_madt(union acpi_subtable_headers *header,
    111			  const unsigned long end)
    112{
    113	struct acpi_madt_generic_translator *its_entry;
    114	struct fwnode_handle *dom_handle;
    115	const char *node_name;
    116	int err = 0;
    117
    118	its_entry = (struct acpi_madt_generic_translator *)header;
    119	node_name = kasprintf(GFP_KERNEL, "ITS@0x%lx",
    120			      (long)its_entry->base_address);
    121
    122	dom_handle = iort_find_domain_token(its_entry->translation_id);
    123	if (!dom_handle) {
    124		pr_err("%s: Unable to locate ITS domain handle\n", node_name);
    125		err = -ENXIO;
    126		goto out;
    127	}
    128
    129	its_fsl_mc_msi_init_one(dom_handle, node_name);
    130
    131out:
    132	kfree(node_name);
    133	return err;
    134}
    135
    136
    137static void __init its_fsl_mc_acpi_msi_init(void)
    138{
    139	acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_TRANSLATOR,
    140			      its_fsl_mc_msi_parse_madt, 0);
    141}
    142#else
    143static inline void its_fsl_mc_acpi_msi_init(void) { }
    144#endif
    145
    146static void __init its_fsl_mc_of_msi_init(void)
    147{
    148	struct device_node *np;
    149
    150	for (np = of_find_matching_node(NULL, its_device_id); np;
    151	     np = of_find_matching_node(np, its_device_id)) {
    152		if (!of_device_is_available(np))
    153			continue;
    154		if (!of_property_read_bool(np, "msi-controller"))
    155			continue;
    156
    157		its_fsl_mc_msi_init_one(of_node_to_fwnode(np),
    158					np->full_name);
    159	}
    160}
    161
    162static int __init its_fsl_mc_msi_init(void)
    163{
    164	its_fsl_mc_of_msi_init();
    165	its_fsl_mc_acpi_msi_init();
    166
    167	return 0;
    168}
    169
    170early_initcall(its_fsl_mc_msi_init);