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-loongson-htpic.c (3076B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *  Copyright (C) 2020, Jiaxun Yang <jiaxun.yang@flygoat.com>
      4 *  Loongson HTPIC IRQ support
      5 */
      6
      7#include <linux/init.h>
      8#include <linux/of_address.h>
      9#include <linux/of_irq.h>
     10#include <linux/irqchip.h>
     11#include <linux/irqchip/chained_irq.h>
     12#include <linux/irq.h>
     13#include <linux/io.h>
     14#include <linux/syscore_ops.h>
     15
     16#include <asm/i8259.h>
     17
     18#define HTPIC_MAX_PARENT_IRQ	4
     19#define HTINT_NUM_VECTORS	8
     20#define HTINT_EN_OFF		0x20
     21
     22struct loongson_htpic {
     23	void __iomem *base;
     24	struct irq_domain *domain;
     25};
     26
     27static struct loongson_htpic *htpic;
     28
     29static void htpic_irq_dispatch(struct irq_desc *desc)
     30{
     31	struct loongson_htpic *priv = irq_desc_get_handler_data(desc);
     32	struct irq_chip *chip = irq_desc_get_chip(desc);
     33	uint32_t pending;
     34
     35	chained_irq_enter(chip, desc);
     36	pending = readl(priv->base);
     37	/* Ack all IRQs at once, otherwise IRQ flood might happen */
     38	writel(pending, priv->base);
     39
     40	if (!pending)
     41		spurious_interrupt();
     42
     43	while (pending) {
     44		int bit = __ffs(pending);
     45
     46		if (unlikely(bit > 15)) {
     47			spurious_interrupt();
     48			break;
     49		}
     50
     51		generic_handle_domain_irq(priv->domain, bit);
     52		pending &= ~BIT(bit);
     53	}
     54	chained_irq_exit(chip, desc);
     55}
     56
     57static void htpic_reg_init(void)
     58{
     59	int i;
     60
     61	for (i = 0; i < HTINT_NUM_VECTORS; i++) {
     62		/* Disable all HT Vectors */
     63		writel(0x0, htpic->base + HTINT_EN_OFF + i * 0x4);
     64		/* Read back to force write */
     65		(void) readl(htpic->base + i * 0x4);
     66		/* Ack all possible pending IRQs */
     67		writel(GENMASK(31, 0), htpic->base + i * 0x4);
     68	}
     69
     70	/* Enable 16 vectors for PIC */
     71	writel(0xffff, htpic->base + HTINT_EN_OFF);
     72}
     73
     74static void htpic_resume(void)
     75{
     76	htpic_reg_init();
     77}
     78
     79struct syscore_ops htpic_syscore_ops = {
     80	.resume		= htpic_resume,
     81};
     82
     83static int __init htpic_of_init(struct device_node *node, struct device_node *parent)
     84{
     85	unsigned int parent_irq[4];
     86	int i, err;
     87	int num_parents = 0;
     88
     89	if (htpic) {
     90		pr_err("loongson-htpic: Only one HTPIC is allowed in the system\n");
     91		return -ENODEV;
     92	}
     93
     94	htpic = kzalloc(sizeof(*htpic), GFP_KERNEL);
     95	if (!htpic)
     96		return -ENOMEM;
     97
     98	htpic->base = of_iomap(node, 0);
     99	if (!htpic->base) {
    100		err = -ENODEV;
    101		goto out_free;
    102	}
    103
    104	htpic->domain = __init_i8259_irqs(node);
    105	if (!htpic->domain) {
    106		pr_err("loongson-htpic: Failed to initialize i8259 IRQs\n");
    107		err = -ENOMEM;
    108		goto out_iounmap;
    109	}
    110
    111	/* Interrupt may come from any of the 4 interrupt line */
    112	for (i = 0; i < HTPIC_MAX_PARENT_IRQ; i++) {
    113		parent_irq[i] = irq_of_parse_and_map(node, i);
    114		if (parent_irq[i] <= 0)
    115			break;
    116
    117		num_parents++;
    118	}
    119
    120	if (!num_parents) {
    121		pr_err("loongson-htpic: Failed to get parent irqs\n");
    122		err = -ENODEV;
    123		goto out_remove_domain;
    124	}
    125
    126	htpic_reg_init();
    127
    128	for (i = 0; i < num_parents; i++) {
    129		irq_set_chained_handler_and_data(parent_irq[i],
    130						htpic_irq_dispatch, htpic);
    131	}
    132
    133	register_syscore_ops(&htpic_syscore_ops);
    134
    135	return 0;
    136
    137out_remove_domain:
    138	irq_domain_remove(htpic->domain);
    139out_iounmap:
    140	iounmap(htpic->base);
    141out_free:
    142	kfree(htpic);
    143	return err;
    144}
    145
    146IRQCHIP_DECLARE(loongson_htpic, "loongson,htpic-1.0", htpic_of_init);