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

intc-arcv2.c (5237B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2014 Synopsys, Inc. (www.synopsys.com)
      4 */
      5
      6#include <linux/interrupt.h>
      7#include <linux/module.h>
      8#include <linux/of.h>
      9#include <linux/irqdomain.h>
     10#include <linux/irqchip.h>
     11#include <asm/irq.h>
     12
     13#define NR_EXCEPTIONS	16
     14
     15struct bcr_irq_arcv2 {
     16#ifdef CONFIG_CPU_BIG_ENDIAN
     17	unsigned int pad:3, firq:1, prio:4, exts:8, irqs:8, ver:8;
     18#else
     19	unsigned int ver:8, irqs:8, exts:8, prio:4, firq:1, pad:3;
     20#endif
     21};
     22
     23/*
     24 * Early Hardware specific Interrupt setup
     25 * -Called very early (start_kernel -> setup_arch -> setup_processor)
     26 * -Platform Independent (must for any ARC Core)
     27 * -Needed for each CPU (hence not foldable into init_IRQ)
     28 */
     29void arc_init_IRQ(void)
     30{
     31	unsigned int tmp, irq_prio, i;
     32	struct bcr_irq_arcv2 irq_bcr;
     33
     34	struct aux_irq_ctrl {
     35#ifdef CONFIG_CPU_BIG_ENDIAN
     36		unsigned int res3:18, save_idx_regs:1, res2:1,
     37			     save_u_to_u:1, save_lp_regs:1, save_blink:1,
     38			     res:4, save_nr_gpr_pairs:5;
     39#else
     40		unsigned int save_nr_gpr_pairs:5, res:4,
     41			     save_blink:1, save_lp_regs:1, save_u_to_u:1,
     42			     res2:1, save_idx_regs:1, res3:18;
     43#endif
     44	} ictrl;
     45
     46	*(unsigned int *)&ictrl = 0;
     47
     48#ifndef CONFIG_ARC_IRQ_NO_AUTOSAVE
     49	ictrl.save_nr_gpr_pairs = 6;	/* r0 to r11 (r12 saved manually) */
     50	ictrl.save_blink = 1;
     51	ictrl.save_lp_regs = 1;		/* LP_COUNT, LP_START, LP_END */
     52	ictrl.save_u_to_u = 0;		/* user ctxt saved on kernel stack */
     53	ictrl.save_idx_regs = 1;	/* JLI, LDI, EI */
     54#endif
     55
     56	WRITE_AUX(AUX_IRQ_CTRL, ictrl);
     57
     58	/*
     59	 * ARCv2 core intc provides multiple interrupt priorities (upto 16).
     60	 * Typical builds though have only two levels (0-high, 1-low)
     61	 * Linux by default uses lower prio 1 for most irqs, reserving 0 for
     62	 * NMI style interrupts in future (say perf)
     63	 */
     64
     65	READ_BCR(ARC_REG_IRQ_BCR, irq_bcr);
     66
     67	irq_prio = irq_bcr.prio;	/* Encoded as N-1 for N levels */
     68	pr_info("archs-intc\t: %d priority levels (default %d)%s\n",
     69		irq_prio + 1, ARCV2_IRQ_DEF_PRIO,
     70		irq_bcr.firq ? " FIRQ (not used)":"");
     71
     72	/*
     73	 * Set a default priority for all available interrupts to prevent
     74	 * switching of register banks if Fast IRQ and multiple register banks
     75	 * are supported by CPU.
     76	 * Also disable private-per-core IRQ lines so faulty external HW won't
     77	 * trigger interrupt that kernel is not ready to handle.
     78	 */
     79	for (i = NR_EXCEPTIONS; i < irq_bcr.irqs + NR_EXCEPTIONS; i++) {
     80		write_aux_reg(AUX_IRQ_SELECT, i);
     81		write_aux_reg(AUX_IRQ_PRIORITY, ARCV2_IRQ_DEF_PRIO);
     82
     83		/*
     84		 * Only mask cpu private IRQs here.
     85		 * "common" interrupts are masked at IDU, otherwise it would
     86		 * need to be unmasked at each cpu, with IPIs
     87		 */
     88		if (i < FIRST_EXT_IRQ)
     89			write_aux_reg(AUX_IRQ_ENABLE, 0);
     90	}
     91
     92	/* setup status32, don't enable intr yet as kernel doesn't want */
     93	tmp = read_aux_reg(ARC_REG_STATUS32);
     94	tmp |= ARCV2_IRQ_DEF_PRIO << 1;
     95	tmp &= ~STATUS_IE_MASK;
     96	asm volatile("kflag %0	\n"::"r"(tmp));
     97}
     98
     99static void arcv2_irq_mask(struct irq_data *data)
    100{
    101	write_aux_reg(AUX_IRQ_SELECT, data->hwirq);
    102	write_aux_reg(AUX_IRQ_ENABLE, 0);
    103}
    104
    105static void arcv2_irq_unmask(struct irq_data *data)
    106{
    107	write_aux_reg(AUX_IRQ_SELECT, data->hwirq);
    108	write_aux_reg(AUX_IRQ_ENABLE, 1);
    109}
    110
    111void arcv2_irq_enable(struct irq_data *data)
    112{
    113	/* set default priority */
    114	write_aux_reg(AUX_IRQ_SELECT, data->hwirq);
    115	write_aux_reg(AUX_IRQ_PRIORITY, ARCV2_IRQ_DEF_PRIO);
    116
    117	/*
    118	 * hw auto enables (linux unmask) all by default
    119	 * So no need to do IRQ_ENABLE here
    120	 * XXX: However OSCI LAN need it
    121	 */
    122	write_aux_reg(AUX_IRQ_ENABLE, 1);
    123}
    124
    125static struct irq_chip arcv2_irq_chip = {
    126	.name           = "ARCv2 core Intc",
    127	.irq_mask	= arcv2_irq_mask,
    128	.irq_unmask	= arcv2_irq_unmask,
    129	.irq_enable	= arcv2_irq_enable
    130};
    131
    132static int arcv2_irq_map(struct irq_domain *d, unsigned int irq,
    133			 irq_hw_number_t hw)
    134{
    135	/*
    136	 * core intc IRQs [16, 23]:
    137	 * Statically assigned always private-per-core (Timers, WDT, IPI, PCT)
    138	 */
    139	if (hw < FIRST_EXT_IRQ) {
    140		/*
    141		 * A subsequent request_percpu_irq() fails if percpu_devid is
    142		 * not set. That in turns sets NOAUTOEN, meaning each core needs
    143		 * to call enable_percpu_irq()
    144		 */
    145		irq_set_percpu_devid(irq);
    146		irq_set_chip_and_handler(irq, &arcv2_irq_chip, handle_percpu_irq);
    147	} else {
    148		irq_set_chip_and_handler(irq, &arcv2_irq_chip, handle_level_irq);
    149	}
    150
    151	return 0;
    152}
    153
    154static const struct irq_domain_ops arcv2_irq_ops = {
    155	.xlate = irq_domain_xlate_onecell,
    156	.map = arcv2_irq_map,
    157};
    158
    159
    160static int __init
    161init_onchip_IRQ(struct device_node *intc, struct device_node *parent)
    162{
    163	struct irq_domain *root_domain;
    164	struct bcr_irq_arcv2 irq_bcr;
    165	unsigned int nr_cpu_irqs;
    166
    167	READ_BCR(ARC_REG_IRQ_BCR, irq_bcr);
    168	nr_cpu_irqs = irq_bcr.irqs + NR_EXCEPTIONS;
    169
    170	if (parent)
    171		panic("DeviceTree incore intc not a root irq controller\n");
    172
    173	root_domain = irq_domain_add_linear(intc, nr_cpu_irqs, &arcv2_irq_ops, NULL);
    174	if (!root_domain)
    175		panic("root irq domain not avail\n");
    176
    177	/*
    178	 * Needed for primary domain lookup to succeed
    179	 * This is a primary irqchip, and can never have a parent
    180	 */
    181	irq_set_default_host(root_domain);
    182
    183#ifdef CONFIG_SMP
    184	irq_create_mapping(root_domain, IPI_IRQ);
    185#endif
    186	irq_create_mapping(root_domain, SOFTIRQ_IRQ);
    187
    188	return 0;
    189}
    190
    191IRQCHIP_DECLARE(arc_intc, "snps,archs-intc", init_onchip_IRQ);