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

ics-rtas.c (5567B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <linux/types.h>
      3#include <linux/kernel.h>
      4#include <linux/irq.h>
      5#include <linux/smp.h>
      6#include <linux/interrupt.h>
      7#include <linux/init.h>
      8#include <linux/cpu.h>
      9#include <linux/of.h>
     10#include <linux/spinlock.h>
     11#include <linux/msi.h>
     12
     13#include <asm/smp.h>
     14#include <asm/machdep.h>
     15#include <asm/irq.h>
     16#include <asm/errno.h>
     17#include <asm/xics.h>
     18#include <asm/rtas.h>
     19
     20/* RTAS service tokens */
     21static int ibm_get_xive;
     22static int ibm_set_xive;
     23static int ibm_int_on;
     24static int ibm_int_off;
     25
     26static void ics_rtas_unmask_irq(struct irq_data *d)
     27{
     28	unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
     29	int call_status;
     30	int server;
     31
     32	pr_devel("xics: unmask virq %d [hw 0x%x]\n", d->irq, hw_irq);
     33
     34	if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
     35		return;
     36
     37	server = xics_get_irq_server(d->irq, irq_data_get_affinity_mask(d), 0);
     38
     39	call_status = rtas_call_reentrant(ibm_set_xive, 3, 1, NULL, hw_irq,
     40					  server, DEFAULT_PRIORITY);
     41	if (call_status != 0) {
     42		printk(KERN_ERR
     43			"%s: ibm_set_xive irq %u server %x returned %d\n",
     44			__func__, hw_irq, server, call_status);
     45		return;
     46	}
     47
     48	/* Now unmask the interrupt (often a no-op) */
     49	call_status = rtas_call_reentrant(ibm_int_on, 1, 1, NULL, hw_irq);
     50	if (call_status != 0) {
     51		printk(KERN_ERR "%s: ibm_int_on irq=%u returned %d\n",
     52			__func__, hw_irq, call_status);
     53		return;
     54	}
     55}
     56
     57static unsigned int ics_rtas_startup(struct irq_data *d)
     58{
     59	/* unmask it */
     60	ics_rtas_unmask_irq(d);
     61	return 0;
     62}
     63
     64static void ics_rtas_mask_real_irq(unsigned int hw_irq)
     65{
     66	int call_status;
     67
     68	if (hw_irq == XICS_IPI)
     69		return;
     70
     71	call_status = rtas_call_reentrant(ibm_int_off, 1, 1, NULL, hw_irq);
     72	if (call_status != 0) {
     73		printk(KERN_ERR "%s: ibm_int_off irq=%u returned %d\n",
     74			__func__, hw_irq, call_status);
     75		return;
     76	}
     77
     78	/* Have to set XIVE to 0xff to be able to remove a slot */
     79	call_status = rtas_call_reentrant(ibm_set_xive, 3, 1, NULL, hw_irq,
     80					  xics_default_server, 0xff);
     81	if (call_status != 0) {
     82		printk(KERN_ERR "%s: ibm_set_xive(0xff) irq=%u returned %d\n",
     83			__func__, hw_irq, call_status);
     84		return;
     85	}
     86}
     87
     88static void ics_rtas_mask_irq(struct irq_data *d)
     89{
     90	unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
     91
     92	pr_devel("xics: mask virq %d [hw 0x%x]\n", d->irq, hw_irq);
     93
     94	if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
     95		return;
     96	ics_rtas_mask_real_irq(hw_irq);
     97}
     98
     99static int ics_rtas_set_affinity(struct irq_data *d,
    100				 const struct cpumask *cpumask,
    101				 bool force)
    102{
    103	unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
    104	int status;
    105	int xics_status[2];
    106	int irq_server;
    107
    108	if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
    109		return -1;
    110
    111	status = rtas_call_reentrant(ibm_get_xive, 1, 3, xics_status, hw_irq);
    112
    113	if (status) {
    114		printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n",
    115			__func__, hw_irq, status);
    116		return -1;
    117	}
    118
    119	irq_server = xics_get_irq_server(d->irq, cpumask, 1);
    120	if (irq_server == -1) {
    121		pr_warn("%s: No online cpus in the mask %*pb for irq %d\n",
    122			__func__, cpumask_pr_args(cpumask), d->irq);
    123		return -1;
    124	}
    125
    126	pr_debug("%s: irq %d [hw 0x%x] server: 0x%x\n", __func__, d->irq,
    127		 hw_irq, irq_server);
    128
    129	status = rtas_call_reentrant(ibm_set_xive, 3, 1, NULL,
    130				     hw_irq, irq_server, xics_status[1]);
    131
    132	if (status) {
    133		printk(KERN_ERR "%s: ibm,set-xive irq=%u returns %d\n",
    134			__func__, hw_irq, status);
    135		return -1;
    136	}
    137
    138	return IRQ_SET_MASK_OK;
    139}
    140
    141static struct irq_chip ics_rtas_irq_chip = {
    142	.name = "XICS",
    143	.irq_startup = ics_rtas_startup,
    144	.irq_mask = ics_rtas_mask_irq,
    145	.irq_unmask = ics_rtas_unmask_irq,
    146	.irq_eoi = NULL, /* Patched at init time */
    147	.irq_set_affinity = ics_rtas_set_affinity,
    148	.irq_set_type = xics_set_irq_type,
    149	.irq_retrigger = xics_retrigger,
    150};
    151
    152static int ics_rtas_check(struct ics *ics, unsigned int hw_irq)
    153{
    154	int status[2];
    155	int rc;
    156
    157	if (WARN_ON(hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS))
    158		return -EINVAL;
    159
    160	/* Check if RTAS knows about this interrupt */
    161	rc = rtas_call_reentrant(ibm_get_xive, 1, 3, status, hw_irq);
    162	if (rc)
    163		return -ENXIO;
    164
    165	return 0;
    166}
    167
    168static void ics_rtas_mask_unknown(struct ics *ics, unsigned long vec)
    169{
    170	ics_rtas_mask_real_irq(vec);
    171}
    172
    173static long ics_rtas_get_server(struct ics *ics, unsigned long vec)
    174{
    175	int rc, status[2];
    176
    177	rc = rtas_call_reentrant(ibm_get_xive, 1, 3, status, vec);
    178	if (rc)
    179		return -1;
    180	return status[0];
    181}
    182
    183static int ics_rtas_host_match(struct ics *ics, struct device_node *node)
    184{
    185	/* IBM machines have interrupt parents of various funky types for things
    186	 * like vdevices, events, etc... The trick we use here is to match
    187	 * everything here except the legacy 8259 which is compatible "chrp,iic"
    188	 */
    189	return !of_device_is_compatible(node, "chrp,iic");
    190}
    191
    192/* Only one global & state struct ics */
    193static struct ics ics_rtas = {
    194	.check		= ics_rtas_check,
    195	.mask_unknown	= ics_rtas_mask_unknown,
    196	.get_server	= ics_rtas_get_server,
    197	.host_match	= ics_rtas_host_match,
    198	.chip = &ics_rtas_irq_chip,
    199};
    200
    201__init int ics_rtas_init(void)
    202{
    203	ibm_get_xive = rtas_token("ibm,get-xive");
    204	ibm_set_xive = rtas_token("ibm,set-xive");
    205	ibm_int_on  = rtas_token("ibm,int-on");
    206	ibm_int_off = rtas_token("ibm,int-off");
    207
    208	/* We enable the RTAS "ICS" if RTAS is present with the
    209	 * appropriate tokens
    210	 */
    211	if (ibm_get_xive == RTAS_UNKNOWN_SERVICE ||
    212	    ibm_set_xive == RTAS_UNKNOWN_SERVICE)
    213		return -ENODEV;
    214
    215	/* We need to patch our irq chip's EOI to point to the
    216	 * right ICP
    217	 */
    218	ics_rtas_irq_chip.irq_eoi = icp_ops->eoi;
    219
    220	/* Register ourselves */
    221	xics_register_ics(&ics_rtas);
    222
    223	return 0;
    224}
    225