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-ixp4xx.c (7696B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * irqchip for the IXP4xx interrupt controller
      4 * Copyright (C) 2019 Linus Walleij <linus.walleij@linaro.org>
      5 *
      6 * Based on arch/arm/mach-ixp4xx/common.c
      7 * Copyright 2002 (C) Intel Corporation
      8 * Copyright 2003-2004 (C) MontaVista, Software, Inc.
      9 * Copyright (C) Deepak Saxena <dsaxena@plexity.net>
     10 */
     11#include <linux/bitops.h>
     12#include <linux/gpio/driver.h>
     13#include <linux/irq.h>
     14#include <linux/io.h>
     15#include <linux/irqchip.h>
     16#include <linux/irqdomain.h>
     17#include <linux/of.h>
     18#include <linux/of_address.h>
     19#include <linux/of_irq.h>
     20#include <linux/platform_device.h>
     21#include <linux/cpu.h>
     22
     23#include <asm/exception.h>
     24#include <asm/mach/irq.h>
     25
     26#define IXP4XX_ICPR	0x00 /* Interrupt Status */
     27#define IXP4XX_ICMR	0x04 /* Interrupt Enable */
     28#define IXP4XX_ICLR	0x08 /* Interrupt IRQ/FIQ Select */
     29#define IXP4XX_ICIP	0x0C /* IRQ Status */
     30#define IXP4XX_ICFP	0x10 /* FIQ Status */
     31#define IXP4XX_ICHR	0x14 /* Interrupt Priority */
     32#define IXP4XX_ICIH	0x18 /* IRQ Highest Pri Int */
     33#define IXP4XX_ICFH	0x1C /* FIQ Highest Pri Int */
     34
     35/* IXP43x and IXP46x-only */
     36#define	IXP4XX_ICPR2	0x20 /* Interrupt Status 2 */
     37#define	IXP4XX_ICMR2	0x24 /* Interrupt Enable 2 */
     38#define	IXP4XX_ICLR2	0x28 /* Interrupt IRQ/FIQ Select 2 */
     39#define IXP4XX_ICIP2	0x2C /* IRQ Status */
     40#define IXP4XX_ICFP2	0x30 /* FIQ Status */
     41#define IXP4XX_ICEEN	0x34 /* Error High Pri Enable */
     42
     43/**
     44 * struct ixp4xx_irq - state container for the Faraday IRQ controller
     45 * @irqbase: IRQ controller memory base in virtual memory
     46 * @is_356: if this is an IXP43x, IXP45x or IX46x SoC (with 64 IRQs)
     47 * @irqchip: irqchip for this instance
     48 * @domain: IRQ domain for this instance
     49 */
     50struct ixp4xx_irq {
     51	void __iomem *irqbase;
     52	bool is_356;
     53	struct irq_chip irqchip;
     54	struct irq_domain *domain;
     55};
     56
     57/* Local static state container */
     58static struct ixp4xx_irq ixirq;
     59
     60/* GPIO Clocks */
     61#define IXP4XX_GPIO_CLK_0		14
     62#define IXP4XX_GPIO_CLK_1		15
     63
     64static int ixp4xx_set_irq_type(struct irq_data *d, unsigned int type)
     65{
     66	/* All are level active high (asserted) here */
     67	if (type != IRQ_TYPE_LEVEL_HIGH)
     68		return -EINVAL;
     69	return 0;
     70}
     71
     72static void ixp4xx_irq_mask(struct irq_data *d)
     73{
     74	struct ixp4xx_irq *ixi = irq_data_get_irq_chip_data(d);
     75	u32 val;
     76
     77	if (ixi->is_356 && d->hwirq >= 32) {
     78		val = __raw_readl(ixi->irqbase + IXP4XX_ICMR2);
     79		val &= ~BIT(d->hwirq - 32);
     80		__raw_writel(val, ixi->irqbase + IXP4XX_ICMR2);
     81	} else {
     82		val = __raw_readl(ixi->irqbase + IXP4XX_ICMR);
     83		val &= ~BIT(d->hwirq);
     84		__raw_writel(val, ixi->irqbase + IXP4XX_ICMR);
     85	}
     86}
     87
     88/*
     89 * Level triggered interrupts on GPIO lines can only be cleared when the
     90 * interrupt condition disappears.
     91 */
     92static void ixp4xx_irq_unmask(struct irq_data *d)
     93{
     94	struct ixp4xx_irq *ixi = irq_data_get_irq_chip_data(d);
     95	u32 val;
     96
     97	if (ixi->is_356 && d->hwirq >= 32) {
     98		val = __raw_readl(ixi->irqbase + IXP4XX_ICMR2);
     99		val |= BIT(d->hwirq - 32);
    100		__raw_writel(val, ixi->irqbase + IXP4XX_ICMR2);
    101	} else {
    102		val = __raw_readl(ixi->irqbase + IXP4XX_ICMR);
    103		val |= BIT(d->hwirq);
    104		__raw_writel(val, ixi->irqbase + IXP4XX_ICMR);
    105	}
    106}
    107
    108static asmlinkage void __exception_irq_entry
    109ixp4xx_handle_irq(struct pt_regs *regs)
    110{
    111	struct ixp4xx_irq *ixi = &ixirq;
    112	unsigned long status;
    113	int i;
    114
    115	status = __raw_readl(ixi->irqbase + IXP4XX_ICIP);
    116	for_each_set_bit(i, &status, 32)
    117		generic_handle_domain_irq(ixi->domain, i);
    118
    119	/*
    120	 * IXP465/IXP435 has an upper IRQ status register
    121	 */
    122	if (ixi->is_356) {
    123		status = __raw_readl(ixi->irqbase + IXP4XX_ICIP2);
    124		for_each_set_bit(i, &status, 32)
    125			generic_handle_domain_irq(ixi->domain, i + 32);
    126	}
    127}
    128
    129static int ixp4xx_irq_domain_translate(struct irq_domain *domain,
    130				       struct irq_fwspec *fwspec,
    131				       unsigned long *hwirq,
    132				       unsigned int *type)
    133{
    134	/* We support standard DT translation */
    135	if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) {
    136		*hwirq = fwspec->param[0];
    137		*type = fwspec->param[1];
    138		return 0;
    139	}
    140
    141	if (is_fwnode_irqchip(fwspec->fwnode)) {
    142		if (fwspec->param_count != 2)
    143			return -EINVAL;
    144		*hwirq = fwspec->param[0];
    145		*type = fwspec->param[1];
    146		WARN_ON(*type == IRQ_TYPE_NONE);
    147		return 0;
    148	}
    149
    150	return -EINVAL;
    151}
    152
    153static int ixp4xx_irq_domain_alloc(struct irq_domain *d,
    154				   unsigned int irq, unsigned int nr_irqs,
    155				   void *data)
    156{
    157	struct ixp4xx_irq *ixi = d->host_data;
    158	irq_hw_number_t hwirq;
    159	unsigned int type = IRQ_TYPE_NONE;
    160	struct irq_fwspec *fwspec = data;
    161	int ret;
    162	int i;
    163
    164	ret = ixp4xx_irq_domain_translate(d, fwspec, &hwirq, &type);
    165	if (ret)
    166		return ret;
    167
    168	for (i = 0; i < nr_irqs; i++) {
    169		/*
    170		 * TODO: after converting IXP4xx to only device tree, set
    171		 * handle_bad_irq as default handler and assume all consumers
    172		 * call .set_type() as this is provided in the second cell in
    173		 * the device tree phandle.
    174		 */
    175		irq_domain_set_info(d,
    176				    irq + i,
    177				    hwirq + i,
    178				    &ixi->irqchip,
    179				    ixi,
    180				    handle_level_irq,
    181				    NULL, NULL);
    182		irq_set_probe(irq + i);
    183	}
    184
    185	return 0;
    186}
    187
    188/*
    189 * This needs to be a hierarchical irqdomain to work well with the
    190 * GPIO irqchip (which is lower in the hierarchy)
    191 */
    192static const struct irq_domain_ops ixp4xx_irqdomain_ops = {
    193	.translate = ixp4xx_irq_domain_translate,
    194	.alloc = ixp4xx_irq_domain_alloc,
    195	.free = irq_domain_free_irqs_common,
    196};
    197
    198/**
    199 * ixp4x_irq_setup() - Common setup code for the IXP4xx interrupt controller
    200 * @ixi: State container
    201 * @irqbase: Virtual memory base for the interrupt controller
    202 * @fwnode: Corresponding fwnode abstraction for this controller
    203 * @is_356: if this is an IXP43x, IXP45x or IXP46x SoC variant
    204 */
    205static int __init ixp4xx_irq_setup(struct ixp4xx_irq *ixi,
    206				   void __iomem *irqbase,
    207				   struct fwnode_handle *fwnode,
    208				   bool is_356)
    209{
    210	int nr_irqs;
    211
    212	ixi->irqbase = irqbase;
    213	ixi->is_356 = is_356;
    214
    215	/* Route all sources to IRQ instead of FIQ */
    216	__raw_writel(0x0, ixi->irqbase + IXP4XX_ICLR);
    217
    218	/* Disable all interrupts */
    219	__raw_writel(0x0, ixi->irqbase + IXP4XX_ICMR);
    220
    221	if (is_356) {
    222		/* Route upper 32 sources to IRQ instead of FIQ */
    223		__raw_writel(0x0, ixi->irqbase + IXP4XX_ICLR2);
    224
    225		/* Disable upper 32 interrupts */
    226		__raw_writel(0x0, ixi->irqbase + IXP4XX_ICMR2);
    227
    228		nr_irqs = 64;
    229	} else {
    230		nr_irqs = 32;
    231	}
    232
    233	ixi->irqchip.name = "IXP4xx";
    234	ixi->irqchip.irq_mask = ixp4xx_irq_mask;
    235	ixi->irqchip.irq_unmask	= ixp4xx_irq_unmask;
    236	ixi->irqchip.irq_set_type = ixp4xx_set_irq_type;
    237
    238	ixi->domain = irq_domain_create_linear(fwnode, nr_irqs,
    239					       &ixp4xx_irqdomain_ops,
    240					       ixi);
    241	if (!ixi->domain) {
    242		pr_crit("IXP4XX: can not add primary irqdomain\n");
    243		return -ENODEV;
    244	}
    245
    246	set_handle_irq(ixp4xx_handle_irq);
    247
    248	return 0;
    249}
    250
    251static int __init ixp4xx_of_init_irq(struct device_node *np,
    252				     struct device_node *parent)
    253{
    254	struct ixp4xx_irq *ixi = &ixirq;
    255	void __iomem *base;
    256	struct fwnode_handle *fwnode;
    257	bool is_356;
    258	int ret;
    259
    260	base = of_iomap(np, 0);
    261	if (!base) {
    262		pr_crit("IXP4XX: could not ioremap interrupt controller\n");
    263		return -ENODEV;
    264	}
    265	fwnode = of_node_to_fwnode(np);
    266
    267	/* These chip variants have 64 interrupts */
    268	is_356 = of_device_is_compatible(np, "intel,ixp43x-interrupt") ||
    269		of_device_is_compatible(np, "intel,ixp45x-interrupt") ||
    270		of_device_is_compatible(np, "intel,ixp46x-interrupt");
    271
    272	ret = ixp4xx_irq_setup(ixi, base, fwnode, is_356);
    273	if (ret)
    274		pr_crit("IXP4XX: failed to set up irqchip\n");
    275
    276	return ret;
    277}
    278IRQCHIP_DECLARE(ixp42x, "intel,ixp42x-interrupt",
    279		ixp4xx_of_init_irq);
    280IRQCHIP_DECLARE(ixp43x, "intel,ixp43x-interrupt",
    281		ixp4xx_of_init_irq);
    282IRQCHIP_DECLARE(ixp45x, "intel,ixp45x-interrupt",
    283		ixp4xx_of_init_irq);
    284IRQCHIP_DECLARE(ixp46x, "intel,ixp46x-interrupt",
    285		ixp4xx_of_init_irq);