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

spear-shirq.c (7519B)


      1/*
      2 * SPEAr platform shared irq layer source file
      3 *
      4 * Copyright (C) 2009-2012 ST Microelectronics
      5 * Viresh Kumar <vireshk@kernel.org>
      6 *
      7 * Copyright (C) 2012 ST Microelectronics
      8 * Shiraz Hashim <shiraz.linux.kernel@gmail.com>
      9 *
     10 * This file is licensed under the terms of the GNU General Public
     11 * License version 2. This program is licensed "as is" without any
     12 * warranty of any kind, whether express or implied.
     13 */
     14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     15
     16#include <linux/err.h>
     17#include <linux/export.h>
     18#include <linux/interrupt.h>
     19#include <linux/io.h>
     20#include <linux/irq.h>
     21#include <linux/irqchip.h>
     22#include <linux/irqdomain.h>
     23#include <linux/of.h>
     24#include <linux/of_address.h>
     25#include <linux/of_irq.h>
     26#include <linux/spinlock.h>
     27
     28/*
     29 * struct spear_shirq: shared irq structure
     30 *
     31 * base:	Base register address
     32 * status_reg:	Status register offset for chained interrupt handler
     33 * mask_reg:	Mask register offset for irq chip
     34 * mask:	Mask to apply to the status register
     35 * virq_base:	Base virtual interrupt number
     36 * nr_irqs:	Number of interrupts handled by this block
     37 * offset:	Bit offset of the first interrupt
     38 * irq_chip:	Interrupt controller chip used for this instance,
     39 *		if NULL group is disabled, but accounted
     40 */
     41struct spear_shirq {
     42	void __iomem		*base;
     43	u32			status_reg;
     44	u32			mask_reg;
     45	u32			mask;
     46	u32			virq_base;
     47	u32			nr_irqs;
     48	u32			offset;
     49	struct irq_chip		*irq_chip;
     50};
     51
     52/* spear300 shared irq registers offsets and masks */
     53#define SPEAR300_INT_ENB_MASK_REG	0x54
     54#define SPEAR300_INT_STS_MASK_REG	0x58
     55
     56static DEFINE_RAW_SPINLOCK(shirq_lock);
     57
     58static void shirq_irq_mask(struct irq_data *d)
     59{
     60	struct spear_shirq *shirq = irq_data_get_irq_chip_data(d);
     61	u32 val, shift = d->irq - shirq->virq_base + shirq->offset;
     62	u32 __iomem *reg = shirq->base + shirq->mask_reg;
     63
     64	raw_spin_lock(&shirq_lock);
     65	val = readl(reg) & ~(0x1 << shift);
     66	writel(val, reg);
     67	raw_spin_unlock(&shirq_lock);
     68}
     69
     70static void shirq_irq_unmask(struct irq_data *d)
     71{
     72	struct spear_shirq *shirq = irq_data_get_irq_chip_data(d);
     73	u32 val, shift = d->irq - shirq->virq_base + shirq->offset;
     74	u32 __iomem *reg = shirq->base + shirq->mask_reg;
     75
     76	raw_spin_lock(&shirq_lock);
     77	val = readl(reg) | (0x1 << shift);
     78	writel(val, reg);
     79	raw_spin_unlock(&shirq_lock);
     80}
     81
     82static struct irq_chip shirq_chip = {
     83	.name		= "spear-shirq",
     84	.irq_mask	= shirq_irq_mask,
     85	.irq_unmask	= shirq_irq_unmask,
     86};
     87
     88static struct spear_shirq spear300_shirq_ras1 = {
     89	.offset		= 0,
     90	.nr_irqs	= 9,
     91	.mask		= ((0x1 << 9) - 1) << 0,
     92	.irq_chip	= &shirq_chip,
     93	.status_reg	= SPEAR300_INT_STS_MASK_REG,
     94	.mask_reg	= SPEAR300_INT_ENB_MASK_REG,
     95};
     96
     97static struct spear_shirq *spear300_shirq_blocks[] = {
     98	&spear300_shirq_ras1,
     99};
    100
    101/* spear310 shared irq registers offsets and masks */
    102#define SPEAR310_INT_STS_MASK_REG	0x04
    103
    104static struct spear_shirq spear310_shirq_ras1 = {
    105	.offset		= 0,
    106	.nr_irqs	= 8,
    107	.mask		= ((0x1 << 8) - 1) << 0,
    108	.irq_chip	= &dummy_irq_chip,
    109	.status_reg	= SPEAR310_INT_STS_MASK_REG,
    110};
    111
    112static struct spear_shirq spear310_shirq_ras2 = {
    113	.offset		= 8,
    114	.nr_irqs	= 5,
    115	.mask		= ((0x1 << 5) - 1) << 8,
    116	.irq_chip	= &dummy_irq_chip,
    117	.status_reg	= SPEAR310_INT_STS_MASK_REG,
    118};
    119
    120static struct spear_shirq spear310_shirq_ras3 = {
    121	.offset		= 13,
    122	.nr_irqs	= 1,
    123	.mask		= ((0x1 << 1) - 1) << 13,
    124	.irq_chip	= &dummy_irq_chip,
    125	.status_reg	= SPEAR310_INT_STS_MASK_REG,
    126};
    127
    128static struct spear_shirq spear310_shirq_intrcomm_ras = {
    129	.offset		= 14,
    130	.nr_irqs	= 3,
    131	.mask		= ((0x1 << 3) - 1) << 14,
    132	.irq_chip	= &dummy_irq_chip,
    133	.status_reg	= SPEAR310_INT_STS_MASK_REG,
    134};
    135
    136static struct spear_shirq *spear310_shirq_blocks[] = {
    137	&spear310_shirq_ras1,
    138	&spear310_shirq_ras2,
    139	&spear310_shirq_ras3,
    140	&spear310_shirq_intrcomm_ras,
    141};
    142
    143/* spear320 shared irq registers offsets and masks */
    144#define SPEAR320_INT_STS_MASK_REG		0x04
    145#define SPEAR320_INT_CLR_MASK_REG		0x04
    146#define SPEAR320_INT_ENB_MASK_REG		0x08
    147
    148static struct spear_shirq spear320_shirq_ras3 = {
    149	.offset		= 0,
    150	.nr_irqs	= 7,
    151	.mask		= ((0x1 << 7) - 1) << 0,
    152	.irq_chip	= &dummy_irq_chip,
    153	.status_reg	= SPEAR320_INT_STS_MASK_REG,
    154};
    155
    156static struct spear_shirq spear320_shirq_ras1 = {
    157	.offset		= 7,
    158	.nr_irqs	= 3,
    159	.mask		= ((0x1 << 3) - 1) << 7,
    160	.irq_chip	= &dummy_irq_chip,
    161	.status_reg	= SPEAR320_INT_STS_MASK_REG,
    162};
    163
    164static struct spear_shirq spear320_shirq_ras2 = {
    165	.offset		= 10,
    166	.nr_irqs	= 1,
    167	.mask		= ((0x1 << 1) - 1) << 10,
    168	.irq_chip	= &dummy_irq_chip,
    169	.status_reg	= SPEAR320_INT_STS_MASK_REG,
    170};
    171
    172static struct spear_shirq spear320_shirq_intrcomm_ras = {
    173	.offset		= 11,
    174	.nr_irqs	= 11,
    175	.mask		= ((0x1 << 11) - 1) << 11,
    176	.irq_chip	= &dummy_irq_chip,
    177	.status_reg	= SPEAR320_INT_STS_MASK_REG,
    178};
    179
    180static struct spear_shirq *spear320_shirq_blocks[] = {
    181	&spear320_shirq_ras3,
    182	&spear320_shirq_ras1,
    183	&spear320_shirq_ras2,
    184	&spear320_shirq_intrcomm_ras,
    185};
    186
    187static void shirq_handler(struct irq_desc *desc)
    188{
    189	struct spear_shirq *shirq = irq_desc_get_handler_data(desc);
    190	u32 pend;
    191
    192	pend = readl(shirq->base + shirq->status_reg) & shirq->mask;
    193	pend >>= shirq->offset;
    194
    195	while (pend) {
    196		int irq = __ffs(pend);
    197
    198		pend &= ~(0x1 << irq);
    199		generic_handle_irq(shirq->virq_base + irq);
    200	}
    201}
    202
    203static void __init spear_shirq_register(struct spear_shirq *shirq,
    204					int parent_irq)
    205{
    206	int i;
    207
    208	if (!shirq->irq_chip)
    209		return;
    210
    211	irq_set_chained_handler_and_data(parent_irq, shirq_handler, shirq);
    212
    213	for (i = 0; i < shirq->nr_irqs; i++) {
    214		irq_set_chip_and_handler(shirq->virq_base + i,
    215					 shirq->irq_chip, handle_simple_irq);
    216		irq_set_chip_data(shirq->virq_base + i, shirq);
    217	}
    218}
    219
    220static int __init shirq_init(struct spear_shirq **shirq_blocks, int block_nr,
    221		struct device_node *np)
    222{
    223	int i, parent_irq, virq_base, hwirq = 0, nr_irqs = 0;
    224	struct irq_domain *shirq_domain;
    225	void __iomem *base;
    226
    227	base = of_iomap(np, 0);
    228	if (!base) {
    229		pr_err("%s: failed to map shirq registers\n", __func__);
    230		return -ENXIO;
    231	}
    232
    233	for (i = 0; i < block_nr; i++)
    234		nr_irqs += shirq_blocks[i]->nr_irqs;
    235
    236	virq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
    237	if (virq_base < 0) {
    238		pr_err("%s: irq desc alloc failed\n", __func__);
    239		goto err_unmap;
    240	}
    241
    242	shirq_domain = irq_domain_add_legacy(np, nr_irqs, virq_base, 0,
    243			&irq_domain_simple_ops, NULL);
    244	if (WARN_ON(!shirq_domain)) {
    245		pr_warn("%s: irq domain init failed\n", __func__);
    246		goto err_free_desc;
    247	}
    248
    249	for (i = 0; i < block_nr; i++) {
    250		shirq_blocks[i]->base = base;
    251		shirq_blocks[i]->virq_base = irq_find_mapping(shirq_domain,
    252				hwirq);
    253
    254		parent_irq = irq_of_parse_and_map(np, i);
    255		spear_shirq_register(shirq_blocks[i], parent_irq);
    256		hwirq += shirq_blocks[i]->nr_irqs;
    257	}
    258
    259	return 0;
    260
    261err_free_desc:
    262	irq_free_descs(virq_base, nr_irqs);
    263err_unmap:
    264	iounmap(base);
    265	return -ENXIO;
    266}
    267
    268static int __init spear300_shirq_of_init(struct device_node *np,
    269					 struct device_node *parent)
    270{
    271	return shirq_init(spear300_shirq_blocks,
    272			ARRAY_SIZE(spear300_shirq_blocks), np);
    273}
    274IRQCHIP_DECLARE(spear300_shirq, "st,spear300-shirq", spear300_shirq_of_init);
    275
    276static int __init spear310_shirq_of_init(struct device_node *np,
    277					 struct device_node *parent)
    278{
    279	return shirq_init(spear310_shirq_blocks,
    280			ARRAY_SIZE(spear310_shirq_blocks), np);
    281}
    282IRQCHIP_DECLARE(spear310_shirq, "st,spear310-shirq", spear310_shirq_of_init);
    283
    284static int __init spear320_shirq_of_init(struct device_node *np,
    285					 struct device_node *parent)
    286{
    287	return shirq_init(spear320_shirq_blocks,
    288			ARRAY_SIZE(spear320_shirq_blocks), np);
    289}
    290IRQCHIP_DECLARE(spear320_shirq, "st,spear320-shirq", spear320_shirq_of_init);