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

socrates_fpga_pic.c (8424B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *  Copyright (C) 2008 Ilya Yanok, Emcraft Systems
      4 */
      5
      6#include <linux/irq.h>
      7#include <linux/of_address.h>
      8#include <linux/of_irq.h>
      9#include <linux/of_platform.h>
     10#include <linux/io.h>
     11
     12/*
     13 * The FPGA supports 9 interrupt sources, which can be routed to 3
     14 * interrupt request lines of the MPIC. The line to be used can be
     15 * specified through the third cell of FDT property  "interrupts".
     16 */
     17
     18#define SOCRATES_FPGA_NUM_IRQS	9
     19
     20#define FPGA_PIC_IRQCFG		(0x0)
     21#define FPGA_PIC_IRQMASK(n)	(0x4 + 0x4 * (n))
     22
     23#define SOCRATES_FPGA_IRQ_MASK	((1 << SOCRATES_FPGA_NUM_IRQS) - 1)
     24
     25struct socrates_fpga_irq_info {
     26	unsigned int irq_line;
     27	int type;
     28};
     29
     30/*
     31 * Interrupt routing and type table
     32 *
     33 * IRQ_TYPE_NONE means the interrupt type is configurable,
     34 * otherwise it's fixed to the specified value.
     35 */
     36static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = {
     37	[0] = {0, IRQ_TYPE_NONE},
     38	[1] = {0, IRQ_TYPE_LEVEL_HIGH},
     39	[2] = {0, IRQ_TYPE_LEVEL_LOW},
     40	[3] = {0, IRQ_TYPE_NONE},
     41	[4] = {0, IRQ_TYPE_NONE},
     42	[5] = {0, IRQ_TYPE_NONE},
     43	[6] = {0, IRQ_TYPE_NONE},
     44	[7] = {0, IRQ_TYPE_NONE},
     45	[8] = {0, IRQ_TYPE_LEVEL_HIGH},
     46};
     47
     48static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock);
     49
     50static void __iomem *socrates_fpga_pic_iobase;
     51static struct irq_domain *socrates_fpga_pic_irq_host;
     52static unsigned int socrates_fpga_irqs[3];
     53
     54static inline uint32_t socrates_fpga_pic_read(int reg)
     55{
     56	return in_be32(socrates_fpga_pic_iobase + reg);
     57}
     58
     59static inline void socrates_fpga_pic_write(int reg, uint32_t val)
     60{
     61	out_be32(socrates_fpga_pic_iobase + reg, val);
     62}
     63
     64static inline unsigned int socrates_fpga_pic_get_irq(unsigned int irq)
     65{
     66	uint32_t cause;
     67	unsigned long flags;
     68	int i;
     69
     70	/* Check irq line routed to the MPIC */
     71	for (i = 0; i < 3; i++) {
     72		if (irq == socrates_fpga_irqs[i])
     73			break;
     74	}
     75	if (i == 3)
     76		return 0;
     77
     78	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
     79	cause = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(i));
     80	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
     81	for (i = SOCRATES_FPGA_NUM_IRQS - 1; i >= 0; i--) {
     82		if (cause >> (i + 16))
     83			break;
     84	}
     85	return irq_linear_revmap(socrates_fpga_pic_irq_host,
     86			(irq_hw_number_t)i);
     87}
     88
     89static void socrates_fpga_pic_cascade(struct irq_desc *desc)
     90{
     91	struct irq_chip *chip = irq_desc_get_chip(desc);
     92	unsigned int irq = irq_desc_get_irq(desc);
     93	unsigned int cascade_irq;
     94
     95	/*
     96	 * See if we actually have an interrupt, call generic handling code if
     97	 * we do.
     98	 */
     99	cascade_irq = socrates_fpga_pic_get_irq(irq);
    100
    101	if (cascade_irq)
    102		generic_handle_irq(cascade_irq);
    103	chip->irq_eoi(&desc->irq_data);
    104}
    105
    106static void socrates_fpga_pic_ack(struct irq_data *d)
    107{
    108	unsigned long flags;
    109	unsigned int irq_line, hwirq = irqd_to_hwirq(d);
    110	uint32_t mask;
    111
    112	irq_line = fpga_irqs[hwirq].irq_line;
    113	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
    114	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
    115		& SOCRATES_FPGA_IRQ_MASK;
    116	mask |= (1 << (hwirq + 16));
    117	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
    118	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
    119}
    120
    121static void socrates_fpga_pic_mask(struct irq_data *d)
    122{
    123	unsigned long flags;
    124	unsigned int hwirq = irqd_to_hwirq(d);
    125	int irq_line;
    126	u32 mask;
    127
    128	irq_line = fpga_irqs[hwirq].irq_line;
    129	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
    130	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
    131		& SOCRATES_FPGA_IRQ_MASK;
    132	mask &= ~(1 << hwirq);
    133	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
    134	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
    135}
    136
    137static void socrates_fpga_pic_mask_ack(struct irq_data *d)
    138{
    139	unsigned long flags;
    140	unsigned int hwirq = irqd_to_hwirq(d);
    141	int irq_line;
    142	u32 mask;
    143
    144	irq_line = fpga_irqs[hwirq].irq_line;
    145	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
    146	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
    147		& SOCRATES_FPGA_IRQ_MASK;
    148	mask &= ~(1 << hwirq);
    149	mask |= (1 << (hwirq + 16));
    150	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
    151	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
    152}
    153
    154static void socrates_fpga_pic_unmask(struct irq_data *d)
    155{
    156	unsigned long flags;
    157	unsigned int hwirq = irqd_to_hwirq(d);
    158	int irq_line;
    159	u32 mask;
    160
    161	irq_line = fpga_irqs[hwirq].irq_line;
    162	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
    163	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
    164		& SOCRATES_FPGA_IRQ_MASK;
    165	mask |= (1 << hwirq);
    166	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
    167	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
    168}
    169
    170static void socrates_fpga_pic_eoi(struct irq_data *d)
    171{
    172	unsigned long flags;
    173	unsigned int hwirq = irqd_to_hwirq(d);
    174	int irq_line;
    175	u32 mask;
    176
    177	irq_line = fpga_irqs[hwirq].irq_line;
    178	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
    179	mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
    180		& SOCRATES_FPGA_IRQ_MASK;
    181	mask |= (1 << (hwirq + 16));
    182	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(irq_line), mask);
    183	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
    184}
    185
    186static int socrates_fpga_pic_set_type(struct irq_data *d,
    187		unsigned int flow_type)
    188{
    189	unsigned long flags;
    190	unsigned int hwirq = irqd_to_hwirq(d);
    191	int polarity;
    192	u32 mask;
    193
    194	if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE)
    195		return -EINVAL;
    196
    197	switch (flow_type & IRQ_TYPE_SENSE_MASK) {
    198	case IRQ_TYPE_LEVEL_HIGH:
    199		polarity = 1;
    200		break;
    201	case IRQ_TYPE_LEVEL_LOW:
    202		polarity = 0;
    203		break;
    204	default:
    205		return -EINVAL;
    206	}
    207	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
    208	mask = socrates_fpga_pic_read(FPGA_PIC_IRQCFG);
    209	if (polarity)
    210		mask |= (1 << hwirq);
    211	else
    212		mask &= ~(1 << hwirq);
    213	socrates_fpga_pic_write(FPGA_PIC_IRQCFG, mask);
    214	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
    215	return 0;
    216}
    217
    218static struct irq_chip socrates_fpga_pic_chip = {
    219	.name		= "FPGA-PIC",
    220	.irq_ack	= socrates_fpga_pic_ack,
    221	.irq_mask	= socrates_fpga_pic_mask,
    222	.irq_mask_ack	= socrates_fpga_pic_mask_ack,
    223	.irq_unmask	= socrates_fpga_pic_unmask,
    224	.irq_eoi	= socrates_fpga_pic_eoi,
    225	.irq_set_type	= socrates_fpga_pic_set_type,
    226};
    227
    228static int socrates_fpga_pic_host_map(struct irq_domain *h, unsigned int virq,
    229		irq_hw_number_t hwirq)
    230{
    231	/* All interrupts are LEVEL sensitive */
    232	irq_set_status_flags(virq, IRQ_LEVEL);
    233	irq_set_chip_and_handler(virq, &socrates_fpga_pic_chip,
    234				 handle_fasteoi_irq);
    235
    236	return 0;
    237}
    238
    239static int socrates_fpga_pic_host_xlate(struct irq_domain *h,
    240		struct device_node *ct,	const u32 *intspec, unsigned int intsize,
    241		irq_hw_number_t *out_hwirq, unsigned int *out_flags)
    242{
    243	struct socrates_fpga_irq_info *fpga_irq = &fpga_irqs[intspec[0]];
    244
    245	*out_hwirq = intspec[0];
    246	if  (fpga_irq->type == IRQ_TYPE_NONE) {
    247		/* type is configurable */
    248		if (intspec[1] != IRQ_TYPE_LEVEL_LOW &&
    249		    intspec[1] != IRQ_TYPE_LEVEL_HIGH) {
    250			pr_warn("FPGA PIC: invalid irq type, setting default active low\n");
    251			*out_flags = IRQ_TYPE_LEVEL_LOW;
    252		} else {
    253			*out_flags = intspec[1];
    254		}
    255	} else {
    256		/* type is fixed */
    257		*out_flags = fpga_irq->type;
    258	}
    259
    260	/* Use specified interrupt routing */
    261	if (intspec[2] <= 2)
    262		fpga_irq->irq_line = intspec[2];
    263	else
    264		pr_warn("FPGA PIC: invalid irq routing\n");
    265
    266	return 0;
    267}
    268
    269static const struct irq_domain_ops socrates_fpga_pic_host_ops = {
    270	.map    = socrates_fpga_pic_host_map,
    271	.xlate  = socrates_fpga_pic_host_xlate,
    272};
    273
    274void __init socrates_fpga_pic_init(struct device_node *pic)
    275{
    276	unsigned long flags;
    277	int i;
    278
    279	/* Setup an irq_domain structure */
    280	socrates_fpga_pic_irq_host = irq_domain_add_linear(pic,
    281		    SOCRATES_FPGA_NUM_IRQS, &socrates_fpga_pic_host_ops, NULL);
    282	if (socrates_fpga_pic_irq_host == NULL) {
    283		pr_err("FPGA PIC: Unable to allocate host\n");
    284		return;
    285	}
    286
    287	for (i = 0; i < 3; i++) {
    288		socrates_fpga_irqs[i] = irq_of_parse_and_map(pic, i);
    289		if (!socrates_fpga_irqs[i]) {
    290			pr_warn("FPGA PIC: can't get irq%d\n", i);
    291			continue;
    292		}
    293		irq_set_chained_handler(socrates_fpga_irqs[i],
    294					socrates_fpga_pic_cascade);
    295	}
    296
    297	socrates_fpga_pic_iobase = of_iomap(pic, 0);
    298
    299	raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
    300	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(0),
    301			SOCRATES_FPGA_IRQ_MASK << 16);
    302	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(1),
    303			SOCRATES_FPGA_IRQ_MASK << 16);
    304	socrates_fpga_pic_write(FPGA_PIC_IRQMASK(2),
    305			SOCRATES_FPGA_IRQ_MASK << 16);
    306	raw_spin_unlock_irqrestore(&socrates_fpga_pic_lock, flags);
    307
    308	pr_info("FPGA PIC: Setting up Socrates FPGA PIC\n");
    309}