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-opal.c (5210B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * ICS backend for OPAL managed interrupts.
      4 *
      5 * Copyright 2011 IBM Corp.
      6 */
      7
      8#undef DEBUG
      9
     10#include <linux/types.h>
     11#include <linux/kernel.h>
     12#include <linux/irq.h>
     13#include <linux/smp.h>
     14#include <linux/interrupt.h>
     15#include <linux/init.h>
     16#include <linux/cpu.h>
     17#include <linux/of.h>
     18#include <linux/spinlock.h>
     19#include <linux/msi.h>
     20
     21#include <asm/smp.h>
     22#include <asm/machdep.h>
     23#include <asm/irq.h>
     24#include <asm/errno.h>
     25#include <asm/xics.h>
     26#include <asm/opal.h>
     27#include <asm/firmware.h>
     28
     29static int ics_opal_mangle_server(int server)
     30{
     31	/* No link for now */
     32	return server << 2;
     33}
     34
     35static int ics_opal_unmangle_server(int server)
     36{
     37	/* No link for now */
     38	return server >> 2;
     39}
     40
     41static void ics_opal_unmask_irq(struct irq_data *d)
     42{
     43	unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
     44	int64_t rc;
     45	int server;
     46
     47	pr_devel("ics-hal: unmask virq %d [hw 0x%x]\n", d->irq, hw_irq);
     48
     49	if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
     50		return;
     51
     52	server = xics_get_irq_server(d->irq, irq_data_get_affinity_mask(d), 0);
     53	server = ics_opal_mangle_server(server);
     54
     55	rc = opal_set_xive(hw_irq, server, DEFAULT_PRIORITY);
     56	if (rc != OPAL_SUCCESS)
     57		pr_err("%s: opal_set_xive(irq=%d [hw 0x%x] server=%x)"
     58		       " error %lld\n",
     59		       __func__, d->irq, hw_irq, server, rc);
     60}
     61
     62static unsigned int ics_opal_startup(struct irq_data *d)
     63{
     64	ics_opal_unmask_irq(d);
     65	return 0;
     66}
     67
     68static void ics_opal_mask_real_irq(unsigned int hw_irq)
     69{
     70	int server = ics_opal_mangle_server(xics_default_server);
     71	int64_t rc;
     72
     73	if (hw_irq == XICS_IPI)
     74		return;
     75
     76	/* Have to set XIVE to 0xff to be able to remove a slot */
     77	rc = opal_set_xive(hw_irq, server, 0xff);
     78	if (rc != OPAL_SUCCESS)
     79		pr_err("%s: opal_set_xive(0xff) irq=%u returned %lld\n",
     80		       __func__, hw_irq, rc);
     81}
     82
     83static void ics_opal_mask_irq(struct irq_data *d)
     84{
     85	unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
     86
     87	pr_devel("ics-hal: mask virq %d [hw 0x%x]\n", d->irq, hw_irq);
     88
     89	if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
     90		return;
     91	ics_opal_mask_real_irq(hw_irq);
     92}
     93
     94static int ics_opal_set_affinity(struct irq_data *d,
     95				 const struct cpumask *cpumask,
     96				 bool force)
     97{
     98	unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
     99	__be16 oserver;
    100	int16_t server;
    101	int8_t priority;
    102	int64_t rc;
    103	int wanted_server;
    104
    105	if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
    106		return -1;
    107
    108	rc = opal_get_xive(hw_irq, &oserver, &priority);
    109	if (rc != OPAL_SUCCESS) {
    110		pr_err("%s: opal_get_xive(irq=%d [hw 0x%x]) error %lld\n",
    111		       __func__, d->irq, hw_irq, rc);
    112		return -1;
    113	}
    114	server = be16_to_cpu(oserver);
    115
    116	wanted_server = xics_get_irq_server(d->irq, cpumask, 1);
    117	if (wanted_server < 0) {
    118		pr_warn("%s: No online cpus in the mask %*pb for irq %d\n",
    119			__func__, cpumask_pr_args(cpumask), d->irq);
    120		return -1;
    121	}
    122	server = ics_opal_mangle_server(wanted_server);
    123
    124	pr_debug("ics-hal: set-affinity irq %d [hw 0x%x] server: 0x%x/0x%x\n",
    125		 d->irq, hw_irq, wanted_server, server);
    126
    127	rc = opal_set_xive(hw_irq, server, priority);
    128	if (rc != OPAL_SUCCESS) {
    129		pr_err("%s: opal_set_xive(irq=%d [hw 0x%x] server=%x)"
    130		       " error %lld\n",
    131		       __func__, d->irq, hw_irq, server, rc);
    132		return -1;
    133	}
    134	return IRQ_SET_MASK_OK;
    135}
    136
    137static struct irq_chip ics_opal_irq_chip = {
    138	.name = "OPAL ICS",
    139	.irq_startup = ics_opal_startup,
    140	.irq_mask = ics_opal_mask_irq,
    141	.irq_unmask = ics_opal_unmask_irq,
    142	.irq_eoi = NULL, /* Patched at init time */
    143	.irq_set_affinity = ics_opal_set_affinity,
    144	.irq_set_type = xics_set_irq_type,
    145	.irq_retrigger = xics_retrigger,
    146};
    147
    148static int ics_opal_host_match(struct ics *ics, struct device_node *node)
    149{
    150	return 1;
    151}
    152
    153static int ics_opal_check(struct ics *ics, unsigned int hw_irq)
    154{
    155	int64_t rc;
    156	__be16 server;
    157	int8_t priority;
    158
    159	if (WARN_ON(hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS))
    160		return -EINVAL;
    161
    162	/* Check if HAL knows about this interrupt */
    163	rc = opal_get_xive(hw_irq, &server, &priority);
    164	if (rc != OPAL_SUCCESS)
    165		return -ENXIO;
    166
    167	return 0;
    168}
    169
    170static void ics_opal_mask_unknown(struct ics *ics, unsigned long vec)
    171{
    172	int64_t rc;
    173	__be16 server;
    174	int8_t priority;
    175
    176	/* Check if HAL knows about this interrupt */
    177	rc = opal_get_xive(vec, &server, &priority);
    178	if (rc != OPAL_SUCCESS)
    179		return;
    180
    181	ics_opal_mask_real_irq(vec);
    182}
    183
    184static long ics_opal_get_server(struct ics *ics, unsigned long vec)
    185{
    186	int64_t rc;
    187	__be16 server;
    188	int8_t priority;
    189
    190	/* Check if HAL knows about this interrupt */
    191	rc = opal_get_xive(vec, &server, &priority);
    192	if (rc != OPAL_SUCCESS)
    193		return -1;
    194	return ics_opal_unmangle_server(be16_to_cpu(server));
    195}
    196
    197/* Only one global & state struct ics */
    198static struct ics ics_hal = {
    199	.check		= ics_opal_check,
    200	.mask_unknown	= ics_opal_mask_unknown,
    201	.get_server	= ics_opal_get_server,
    202	.host_match	= ics_opal_host_match,
    203	.chip		= &ics_opal_irq_chip,
    204};
    205
    206int __init ics_opal_init(void)
    207{
    208	if (!firmware_has_feature(FW_FEATURE_OPAL))
    209		return -ENODEV;
    210
    211	/* We need to patch our irq chip's EOI to point to the
    212	 * right ICP
    213	 */
    214	ics_opal_irq_chip.irq_eoi = icp_ops->eoi;
    215
    216	/* Register ourselves */
    217	xics_register_ics(&ics_hal);
    218
    219	pr_info("ICS OPAL backend registered\n");
    220
    221	return 0;
    222}