linux/arch/powerpc/sysdev/xics/icp-native.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright 2011 IBM Corporation.
   4 */
   5
   6#include <linux/types.h>
   7#include <linux/kernel.h>
   8#include <linux/irq.h>
   9#include <linux/smp.h>
  10#include <linux/interrupt.h>
  11#include <linux/init.h>
  12#include <linux/cpu.h>
  13#include <linux/of.h>
  14#include <linux/spinlock.h>
  15#include <linux/module.h>
  16
  17#include <asm/prom.h>
  18#include <asm/io.h>
  19#include <asm/smp.h>
  20#include <asm/irq.h>
  21#include <asm/errno.h>
  22#include <asm/xics.h>
  23#include <asm/kvm_ppc.h>
  24#include <asm/dbell.h>
  25
  26struct icp_ipl {
  27        union {
  28                u32 word;
  29                u8 bytes[4];
  30        } xirr_poll;
  31        union {
  32                u32 word;
  33                u8 bytes[4];
  34        } xirr;
  35        u32 dummy;
  36        union {
  37                u32 word;
  38                u8 bytes[4];
  39        } qirr;
  40        u32 link_a;
  41        u32 link_b;
  42        u32 link_c;
  43};
  44
  45static struct icp_ipl __iomem *icp_native_regs[NR_CPUS];
  46
  47static inline unsigned int icp_native_get_xirr(void)
  48{
  49        int cpu = smp_processor_id();
  50        unsigned int xirr;
  51
  52        /* Handled an interrupt latched by KVM */
  53        xirr = kvmppc_get_xics_latch();
  54        if (xirr)
  55                return xirr;
  56
  57        return in_be32(&icp_native_regs[cpu]->xirr.word);
  58}
  59
  60static inline void icp_native_set_xirr(unsigned int value)
  61{
  62        int cpu = smp_processor_id();
  63
  64        out_be32(&icp_native_regs[cpu]->xirr.word, value);
  65}
  66
  67static inline void icp_native_set_cppr(u8 value)
  68{
  69        int cpu = smp_processor_id();
  70
  71        out_8(&icp_native_regs[cpu]->xirr.bytes[0], value);
  72}
  73
  74static inline void icp_native_set_qirr(int n_cpu, u8 value)
  75{
  76        out_8(&icp_native_regs[n_cpu]->qirr.bytes[0], value);
  77}
  78
  79static void icp_native_set_cpu_priority(unsigned char cppr)
  80{
  81        xics_set_base_cppr(cppr);
  82        icp_native_set_cppr(cppr);
  83        iosync();
  84}
  85
  86void icp_native_eoi(struct irq_data *d)
  87{
  88        unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
  89
  90        iosync();
  91        icp_native_set_xirr((xics_pop_cppr() << 24) | hw_irq);
  92}
  93
  94static void icp_native_teardown_cpu(void)
  95{
  96        int cpu = smp_processor_id();
  97
  98        /* Clear any pending IPI */
  99        icp_native_set_qirr(cpu, 0xff);
 100}
 101
 102static void icp_native_flush_ipi(void)
 103{
 104        /* We take the ipi irq but and never return so we
 105         * need to EOI the IPI, but want to leave our priority 0
 106         *
 107         * should we check all the other interrupts too?
 108         * should we be flagging idle loop instead?
 109         * or creating some task to be scheduled?
 110         */
 111
 112        icp_native_set_xirr((0x00 << 24) | XICS_IPI);
 113}
 114
 115static unsigned int icp_native_get_irq(void)
 116{
 117        unsigned int xirr = icp_native_get_xirr();
 118        unsigned int vec = xirr & 0x00ffffff;
 119        unsigned int irq;
 120
 121        if (vec == XICS_IRQ_SPURIOUS)
 122                return 0;
 123
 124        irq = irq_find_mapping(xics_host, vec);
 125        if (likely(irq)) {
 126                xics_push_cppr(vec);
 127                return irq;
 128        }
 129
 130        /* We don't have a linux mapping, so have rtas mask it. */
 131        xics_mask_unknown_vec(vec);
 132
 133        /* We might learn about it later, so EOI it */
 134        icp_native_set_xirr(xirr);
 135
 136        return 0;
 137}
 138
 139#ifdef CONFIG_SMP
 140
 141static void icp_native_cause_ipi(int cpu)
 142{
 143        kvmppc_set_host_ipi(cpu);
 144        icp_native_set_qirr(cpu, IPI_PRIORITY);
 145}
 146
 147#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
 148void icp_native_cause_ipi_rm(int cpu)
 149{
 150        /*
 151         * Currently not used to send IPIs to another CPU
 152         * on the same core. Only caller is KVM real mode.
 153         * Need the physical address of the XICS to be
 154         * previously saved in kvm_hstate in the paca.
 155         */
 156        void __iomem *xics_phys;
 157
 158        /*
 159         * Just like the cause_ipi functions, it is required to
 160         * include a full barrier before causing the IPI.
 161         */
 162        xics_phys = paca_ptrs[cpu]->kvm_hstate.xics_phys;
 163        mb();
 164        __raw_rm_writeb(IPI_PRIORITY, xics_phys + XICS_MFRR);
 165}
 166#endif
 167
 168/*
 169 * Called when an interrupt is received on an off-line CPU to
 170 * clear the interrupt, so that the CPU can go back to nap mode.
 171 */
 172void icp_native_flush_interrupt(void)
 173{
 174        unsigned int xirr = icp_native_get_xirr();
 175        unsigned int vec = xirr & 0x00ffffff;
 176
 177        if (vec == XICS_IRQ_SPURIOUS)
 178                return;
 179        if (vec == XICS_IPI) {
 180                /* Clear pending IPI */
 181                int cpu = smp_processor_id();
 182                kvmppc_clear_host_ipi(cpu);
 183                icp_native_set_qirr(cpu, 0xff);
 184        } else {
 185                pr_err("XICS: hw interrupt 0x%x to offline cpu, disabling\n",
 186                       vec);
 187                xics_mask_unknown_vec(vec);
 188        }
 189        /* EOI the interrupt */
 190        icp_native_set_xirr(xirr);
 191}
 192
 193void xics_wake_cpu(int cpu)
 194{
 195        icp_native_set_qirr(cpu, IPI_PRIORITY);
 196}
 197EXPORT_SYMBOL_GPL(xics_wake_cpu);
 198
 199static irqreturn_t icp_native_ipi_action(int irq, void *dev_id)
 200{
 201        int cpu = smp_processor_id();
 202
 203        kvmppc_clear_host_ipi(cpu);
 204        icp_native_set_qirr(cpu, 0xff);
 205
 206        return smp_ipi_demux();
 207}
 208
 209#endif /* CONFIG_SMP */
 210
 211static int __init icp_native_map_one_cpu(int hw_id, unsigned long addr,
 212                                         unsigned long size)
 213{
 214        char *rname;
 215        int i, cpu = -1;
 216
 217        /* This may look gross but it's good enough for now, we don't quite
 218         * have a hard -> linux processor id matching.
 219         */
 220        for_each_possible_cpu(i) {
 221                if (!cpu_present(i))
 222                        continue;
 223                if (hw_id == get_hard_smp_processor_id(i)) {
 224                        cpu = i;
 225                        break;
 226                }
 227        }
 228
 229        /* Fail, skip that CPU. Don't print, it's normal, some XICS come up
 230         * with way more entries in there than you have CPUs
 231         */
 232        if (cpu == -1)
 233                return 0;
 234
 235        rname = kasprintf(GFP_KERNEL, "CPU %d [0x%x] Interrupt Presentation",
 236                          cpu, hw_id);
 237
 238        if (!request_mem_region(addr, size, rname)) {
 239                pr_warn("icp_native: Could not reserve ICP MMIO for CPU %d, interrupt server #0x%x\n",
 240                        cpu, hw_id);
 241                return -EBUSY;
 242        }
 243
 244        icp_native_regs[cpu] = ioremap(addr, size);
 245        kvmppc_set_xics_phys(cpu, addr);
 246        if (!icp_native_regs[cpu]) {
 247                pr_warn("icp_native: Failed ioremap for CPU %d, interrupt server #0x%x, addr %#lx\n",
 248                        cpu, hw_id, addr);
 249                release_mem_region(addr, size);
 250                return -ENOMEM;
 251        }
 252        return 0;
 253}
 254
 255static int __init icp_native_init_one_node(struct device_node *np,
 256                                           unsigned int *indx)
 257{
 258        unsigned int ilen;
 259        const __be32 *ireg;
 260        int i;
 261        int reg_tuple_size;
 262        int num_servers = 0;
 263
 264        /* This code does the theorically broken assumption that the interrupt
 265         * server numbers are the same as the hard CPU numbers.
 266         * This happens to be the case so far but we are playing with fire...
 267         * should be fixed one of these days. -BenH.
 268         */
 269        ireg = of_get_property(np, "ibm,interrupt-server-ranges", &ilen);
 270
 271        /* Do that ever happen ? we'll know soon enough... but even good'old
 272         * f80 does have that property ..
 273         */
 274        WARN_ON((ireg == NULL) || (ilen != 2*sizeof(u32)));
 275
 276        if (ireg) {
 277                *indx = of_read_number(ireg, 1);
 278                if (ilen >= 2*sizeof(u32))
 279                        num_servers = of_read_number(ireg + 1, 1);
 280        }
 281
 282        ireg = of_get_property(np, "reg", &ilen);
 283        if (!ireg) {
 284                pr_err("icp_native: Can't find interrupt reg property");
 285                return -1;
 286        }
 287
 288        reg_tuple_size = (of_n_addr_cells(np) + of_n_size_cells(np)) * 4;
 289        if (((ilen % reg_tuple_size) != 0)
 290            || (num_servers && (num_servers != (ilen / reg_tuple_size)))) {
 291                pr_err("icp_native: ICP reg len (%d) != num servers (%d)",
 292                       ilen / reg_tuple_size, num_servers);
 293                return -1;
 294        }
 295
 296        for (i = 0; i < (ilen / reg_tuple_size); i++) {
 297                struct resource r;
 298                int err;
 299
 300                err = of_address_to_resource(np, i, &r);
 301                if (err) {
 302                        pr_err("icp_native: Could not translate ICP MMIO"
 303                               " for interrupt server 0x%x (%d)\n", *indx, err);
 304                        return -1;
 305                }
 306
 307                if (icp_native_map_one_cpu(*indx, r.start, resource_size(&r)))
 308                        return -1;
 309
 310                (*indx)++;
 311        }
 312        return 0;
 313}
 314
 315static const struct icp_ops icp_native_ops = {
 316        .get_irq        = icp_native_get_irq,
 317        .eoi            = icp_native_eoi,
 318        .set_priority   = icp_native_set_cpu_priority,
 319        .teardown_cpu   = icp_native_teardown_cpu,
 320        .flush_ipi      = icp_native_flush_ipi,
 321#ifdef CONFIG_SMP
 322        .ipi_action     = icp_native_ipi_action,
 323        .cause_ipi      = icp_native_cause_ipi,
 324#endif
 325};
 326
 327int __init icp_native_init(void)
 328{
 329        struct device_node *np;
 330        u32 indx = 0;
 331        int found = 0;
 332
 333        for_each_compatible_node(np, NULL, "ibm,ppc-xicp")
 334                if (icp_native_init_one_node(np, &indx) == 0)
 335                        found = 1;
 336        if (!found) {
 337                for_each_node_by_type(np,
 338                        "PowerPC-External-Interrupt-Presentation") {
 339                                if (icp_native_init_one_node(np, &indx) == 0)
 340                                        found = 1;
 341                }
 342        }
 343
 344        if (found == 0)
 345                return -ENODEV;
 346
 347        icp_ops = &icp_native_ops;
 348
 349        return 0;
 350}
 351