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


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org>
      4 * Copyright (C) 2006,2007 Eugene Konev <ejka@openwrt.org>
      5 */
      6
      7#include <linux/interrupt.h>
      8#include <linux/io.h>
      9#include <linux/irq.h>
     10
     11#include <asm/irq_cpu.h>
     12#include <asm/mipsregs.h>
     13#include <asm/mach-ar7/ar7.h>
     14
     15#define EXCEPT_OFFSET	0x80
     16#define PACE_OFFSET	0xA0
     17#define CHNLS_OFFSET	0x200
     18
     19#define REG_OFFSET(irq, reg)	((irq) / 32 * 0x4 + reg * 0x10)
     20#define SEC_REG_OFFSET(reg)	(EXCEPT_OFFSET + reg * 0x8)
     21#define SEC_SR_OFFSET		(SEC_REG_OFFSET(0))	/* 0x80 */
     22#define CR_OFFSET(irq)		(REG_OFFSET(irq, 1))	/* 0x10 */
     23#define SEC_CR_OFFSET		(SEC_REG_OFFSET(1))	/* 0x88 */
     24#define ESR_OFFSET(irq)		(REG_OFFSET(irq, 2))	/* 0x20 */
     25#define SEC_ESR_OFFSET		(SEC_REG_OFFSET(2))	/* 0x90 */
     26#define ECR_OFFSET(irq)		(REG_OFFSET(irq, 3))	/* 0x30 */
     27#define SEC_ECR_OFFSET		(SEC_REG_OFFSET(3))	/* 0x98 */
     28#define PIR_OFFSET		(0x40)
     29#define MSR_OFFSET		(0x44)
     30#define PM_OFFSET(irq)		(REG_OFFSET(irq, 5))	/* 0x50 */
     31#define TM_OFFSET(irq)		(REG_OFFSET(irq, 6))	/* 0x60 */
     32
     33#define REG(addr) ((u32 *)(KSEG1ADDR(AR7_REGS_IRQ) + addr))
     34
     35#define CHNL_OFFSET(chnl) (CHNLS_OFFSET + (chnl * 4))
     36
     37static int ar7_irq_base;
     38
     39static void ar7_unmask_irq(struct irq_data *d)
     40{
     41	writel(1 << ((d->irq - ar7_irq_base) % 32),
     42	       REG(ESR_OFFSET(d->irq - ar7_irq_base)));
     43}
     44
     45static void ar7_mask_irq(struct irq_data *d)
     46{
     47	writel(1 << ((d->irq - ar7_irq_base) % 32),
     48	       REG(ECR_OFFSET(d->irq - ar7_irq_base)));
     49}
     50
     51static void ar7_ack_irq(struct irq_data *d)
     52{
     53	writel(1 << ((d->irq - ar7_irq_base) % 32),
     54	       REG(CR_OFFSET(d->irq - ar7_irq_base)));
     55}
     56
     57static void ar7_unmask_sec_irq(struct irq_data *d)
     58{
     59	writel(1 << (d->irq - ar7_irq_base - 40), REG(SEC_ESR_OFFSET));
     60}
     61
     62static void ar7_mask_sec_irq(struct irq_data *d)
     63{
     64	writel(1 << (d->irq - ar7_irq_base - 40), REG(SEC_ECR_OFFSET));
     65}
     66
     67static void ar7_ack_sec_irq(struct irq_data *d)
     68{
     69	writel(1 << (d->irq - ar7_irq_base - 40), REG(SEC_CR_OFFSET));
     70}
     71
     72static struct irq_chip ar7_irq_type = {
     73	.name = "AR7",
     74	.irq_unmask = ar7_unmask_irq,
     75	.irq_mask = ar7_mask_irq,
     76	.irq_ack = ar7_ack_irq
     77};
     78
     79static struct irq_chip ar7_sec_irq_type = {
     80	.name = "AR7",
     81	.irq_unmask = ar7_unmask_sec_irq,
     82	.irq_mask = ar7_mask_sec_irq,
     83	.irq_ack = ar7_ack_sec_irq,
     84};
     85
     86static void __init ar7_irq_init(int base)
     87{
     88	int i;
     89	/*
     90	 * Disable interrupts and clear pending
     91	 */
     92	writel(0xffffffff, REG(ECR_OFFSET(0)));
     93	writel(0xff, REG(ECR_OFFSET(32)));
     94	writel(0xffffffff, REG(SEC_ECR_OFFSET));
     95	writel(0xffffffff, REG(CR_OFFSET(0)));
     96	writel(0xff, REG(CR_OFFSET(32)));
     97	writel(0xffffffff, REG(SEC_CR_OFFSET));
     98
     99	ar7_irq_base = base;
    100
    101	for (i = 0; i < 40; i++) {
    102		writel(i, REG(CHNL_OFFSET(i)));
    103		/* Primary IRQ's */
    104		irq_set_chip_and_handler(base + i, &ar7_irq_type,
    105					 handle_level_irq);
    106		/* Secondary IRQ's */
    107		if (i < 32)
    108			irq_set_chip_and_handler(base + i + 40,
    109						 &ar7_sec_irq_type,
    110						 handle_level_irq);
    111	}
    112
    113	if (request_irq(2, no_action, IRQF_NO_THREAD, "AR7 cascade interrupt",
    114			NULL))
    115		pr_err("Failed to request irq 2 (AR7 cascade interrupt)\n");
    116	if (request_irq(ar7_irq_base, no_action, IRQF_NO_THREAD,
    117			"AR7 cascade interrupt", NULL)) {
    118		pr_err("Failed to request irq %d (AR7 cascade interrupt)\n",
    119		       ar7_irq_base);
    120	}
    121	set_c0_status(IE_IRQ0);
    122}
    123
    124void __init arch_init_irq(void)
    125{
    126	mips_cpu_irq_init();
    127	ar7_irq_init(8);
    128}
    129
    130static void ar7_cascade(void)
    131{
    132	u32 status;
    133	int i, irq;
    134
    135	/* Primary IRQ's */
    136	irq = readl(REG(PIR_OFFSET)) & 0x3f;
    137	if (irq) {
    138		do_IRQ(ar7_irq_base + irq);
    139		return;
    140	}
    141
    142	/* Secondary IRQ's are cascaded through primary '0' */
    143	writel(1, REG(CR_OFFSET(irq)));
    144	status = readl(REG(SEC_SR_OFFSET));
    145	for (i = 0; i < 32; i++) {
    146		if (status & 1) {
    147			do_IRQ(ar7_irq_base + i + 40);
    148			return;
    149		}
    150		status >>= 1;
    151	}
    152
    153	spurious_interrupt();
    154}
    155
    156asmlinkage void plat_irq_dispatch(void)
    157{
    158	unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
    159	if (pending & STATUSF_IP7)		/* cpu timer */
    160		do_IRQ(7);
    161	else if (pending & STATUSF_IP2)		/* int0 hardware line */
    162		ar7_cascade();
    163	else
    164		spurious_interrupt();
    165}