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-or1k-pic.c (4416B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
      4 * Copyright (C) 2014 Stefan Kristansson <stefan.kristiansson@saunalahti.fi>
      5 */
      6
      7#include <linux/irq.h>
      8#include <linux/irqchip.h>
      9#include <linux/of.h>
     10#include <linux/of_irq.h>
     11#include <linux/of_address.h>
     12
     13/* OR1K PIC implementation */
     14
     15struct or1k_pic_dev {
     16	struct irq_chip chip;
     17	irq_flow_handler_t handle;
     18	unsigned long flags;
     19};
     20
     21/*
     22 * We're a couple of cycles faster than the generic implementations with
     23 * these 'fast' versions.
     24 */
     25
     26static void or1k_pic_mask(struct irq_data *data)
     27{
     28	mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq));
     29}
     30
     31static void or1k_pic_unmask(struct irq_data *data)
     32{
     33	mtspr(SPR_PICMR, mfspr(SPR_PICMR) | (1UL << data->hwirq));
     34}
     35
     36static void or1k_pic_ack(struct irq_data *data)
     37{
     38	mtspr(SPR_PICSR, (1UL << data->hwirq));
     39}
     40
     41static void or1k_pic_mask_ack(struct irq_data *data)
     42{
     43	mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq));
     44	mtspr(SPR_PICSR, (1UL << data->hwirq));
     45}
     46
     47/*
     48 * There are two oddities with the OR1200 PIC implementation:
     49 * i)  LEVEL-triggered interrupts are latched and need to be cleared
     50 * ii) the interrupt latch is cleared by writing a 0 to the bit,
     51 *     as opposed to a 1 as mandated by the spec
     52 */
     53static void or1k_pic_or1200_ack(struct irq_data *data)
     54{
     55	mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq));
     56}
     57
     58static void or1k_pic_or1200_mask_ack(struct irq_data *data)
     59{
     60	mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq));
     61	mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq));
     62}
     63
     64static struct or1k_pic_dev or1k_pic_level = {
     65	.chip = {
     66		.name = "or1k-PIC-level",
     67		.irq_unmask = or1k_pic_unmask,
     68		.irq_mask = or1k_pic_mask,
     69	},
     70	.handle = handle_level_irq,
     71	.flags = IRQ_LEVEL | IRQ_NOPROBE,
     72};
     73
     74static struct or1k_pic_dev or1k_pic_edge = {
     75	.chip = {
     76		.name = "or1k-PIC-edge",
     77		.irq_unmask = or1k_pic_unmask,
     78		.irq_mask = or1k_pic_mask,
     79		.irq_ack = or1k_pic_ack,
     80		.irq_mask_ack = or1k_pic_mask_ack,
     81	},
     82	.handle = handle_edge_irq,
     83	.flags = IRQ_LEVEL | IRQ_NOPROBE,
     84};
     85
     86static struct or1k_pic_dev or1k_pic_or1200 = {
     87	.chip = {
     88		.name = "or1200-PIC",
     89		.irq_unmask = or1k_pic_unmask,
     90		.irq_mask = or1k_pic_mask,
     91		.irq_ack = or1k_pic_or1200_ack,
     92		.irq_mask_ack = or1k_pic_or1200_mask_ack,
     93	},
     94	.handle = handle_level_irq,
     95	.flags = IRQ_LEVEL | IRQ_NOPROBE,
     96};
     97
     98static struct irq_domain *root_domain;
     99
    100static inline int pic_get_irq(int first)
    101{
    102	int hwirq;
    103
    104	hwirq = ffs(mfspr(SPR_PICSR) >> first);
    105	if (!hwirq)
    106		return NO_IRQ;
    107	else
    108		hwirq = hwirq + first - 1;
    109
    110	return hwirq;
    111}
    112
    113static void or1k_pic_handle_irq(struct pt_regs *regs)
    114{
    115	int irq = -1;
    116
    117	while ((irq = pic_get_irq(irq + 1)) != NO_IRQ)
    118		generic_handle_domain_irq(root_domain, irq);
    119}
    120
    121static int or1k_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
    122{
    123	struct or1k_pic_dev *pic = d->host_data;
    124
    125	irq_set_chip_and_handler(irq, &pic->chip, pic->handle);
    126	irq_set_status_flags(irq, pic->flags);
    127
    128	return 0;
    129}
    130
    131static const struct irq_domain_ops or1k_irq_domain_ops = {
    132	.xlate = irq_domain_xlate_onecell,
    133	.map = or1k_map,
    134};
    135
    136/*
    137 * This sets up the IRQ domain for the PIC built in to the OpenRISC
    138 * 1000 CPU.  This is the "root" domain as these are the interrupts
    139 * that directly trigger an exception in the CPU.
    140 */
    141static int __init or1k_pic_init(struct device_node *node,
    142				 struct or1k_pic_dev *pic)
    143{
    144	/* Disable all interrupts until explicitly requested */
    145	mtspr(SPR_PICMR, (0UL));
    146
    147	root_domain = irq_domain_add_linear(node, 32, &or1k_irq_domain_ops,
    148					    pic);
    149
    150	set_handle_irq(or1k_pic_handle_irq);
    151
    152	return 0;
    153}
    154
    155static int __init or1k_pic_or1200_init(struct device_node *node,
    156				       struct device_node *parent)
    157{
    158	return or1k_pic_init(node, &or1k_pic_or1200);
    159}
    160IRQCHIP_DECLARE(or1k_pic_or1200, "opencores,or1200-pic", or1k_pic_or1200_init);
    161IRQCHIP_DECLARE(or1k_pic, "opencores,or1k-pic", or1k_pic_or1200_init);
    162
    163static int __init or1k_pic_level_init(struct device_node *node,
    164				      struct device_node *parent)
    165{
    166	return or1k_pic_init(node, &or1k_pic_level);
    167}
    168IRQCHIP_DECLARE(or1k_pic_level, "opencores,or1k-pic-level",
    169		or1k_pic_level_init);
    170
    171static int __init or1k_pic_edge_init(struct device_node *node,
    172				     struct device_node *parent)
    173{
    174	return or1k_pic_init(node, &or1k_pic_edge);
    175}
    176IRQCHIP_DECLARE(or1k_pic_edge, "opencores,or1k-pic-edge", or1k_pic_edge_init);