/*1* Open Multi-Processor Interrupt Controller driver2*3* Copyright (C) 2014 Stefan Kristiansson <[email protected]>4* Copyright (C) 2017 Stafford Horne <[email protected]>5*6* This file is licensed under the terms of the GNU General Public License7* version 2. This program is licensed "as is" without any warranty of any8* kind, whether express or implied.9*10* The ompic device handles IPI communication between cores in multi-core11* OpenRISC systems.12*13* Registers14*15* For each CPU the ompic has 2 registers. The control register for sending16* and acking IPIs and the status register for receiving IPIs. The register17* layouts are as follows:18*19* Control register20* +---------+---------+----------+---------+21* | 31 | 30 | 29 .. 16 | 15 .. 0 |22* ----------+---------+----------+----------23* | IRQ ACK | IRQ GEN | DST CORE | DATA |24* +---------+---------+----------+---------+25*26* Status register27* +----------+-------------+----------+---------+28* | 31 | 30 | 29 .. 16 | 15 .. 0 |29* -----------+-------------+----------+---------+30* | Reserved | IRQ Pending | SRC CORE | DATA |31* +----------+-------------+----------+---------+32*33* Architecture34*35* - The ompic generates a level interrupt to the CPU PIC when a message is36* ready. Messages are delivered via the memory bus.37* - The ompic does not have any interrupt input lines.38* - The ompic is wired to the same irq line on each core.39* - Devices are wired to the same irq line on each core.40*41* +---------+ +---------+42* | CPU | | CPU |43* | Core 0 |<==\ (memory access) /==>| Core 1 |44* | [ PIC ]| | | | [ PIC ]|45* +----^-^--+ | | +----^-^--+46* | | v v | |47* <====|=|=================================|=|==> (memory bus)48* | | ^ ^ | |49* (ipi | +------|---------+--------|-------|-+ (device irq)50* irq | | | | |51* core0)| +------|---------|--------|-------+ (ipi irq core1)52* | | | | |53* +----o-o-+ | +--------+ |54* | ompic |<===/ | Device |<===/55* | IPI | +--------+56* +--------+*57*58*/5960#include <linux/io.h>61#include <linux/ioport.h>62#include <linux/interrupt.h>63#include <linux/smp.h>64#include <linux/of.h>65#include <linux/of_irq.h>66#include <linux/of_address.h>6768#include <linux/irqchip.h>6970#define OMPIC_CPUBYTES 871#define OMPIC_CTRL(cpu) (0x0 + (cpu * OMPIC_CPUBYTES))72#define OMPIC_STAT(cpu) (0x4 + (cpu * OMPIC_CPUBYTES))7374#define OMPIC_CTRL_IRQ_ACK (1 << 31)75#define OMPIC_CTRL_IRQ_GEN (1 << 30)76#define OMPIC_CTRL_DST(cpu) (((cpu) & 0x3fff) << 16)7778#define OMPIC_STAT_IRQ_PENDING (1 << 30)7980#define OMPIC_DATA(x) ((x) & 0xffff)8182DEFINE_PER_CPU(unsigned long, ops);8384static void __iomem *ompic_base;8586static inline u32 ompic_readreg(void __iomem *base, loff_t offset)87{88return ioread32be(base + offset);89}9091static void ompic_writereg(void __iomem *base, loff_t offset, u32 data)92{93iowrite32be(data, base + offset);94}9596static void ompic_raise_softirq(const struct cpumask *mask,97unsigned int ipi_msg)98{99unsigned int dst_cpu;100unsigned int src_cpu = smp_processor_id();101102for_each_cpu(dst_cpu, mask) {103set_bit(ipi_msg, &per_cpu(ops, dst_cpu));104105/*106* On OpenRISC the atomic set_bit() call implies a memory107* barrier. Otherwise we would need: smp_wmb(); paired108* with the read in ompic_ipi_handler.109*/110111ompic_writereg(ompic_base, OMPIC_CTRL(src_cpu),112OMPIC_CTRL_IRQ_GEN |113OMPIC_CTRL_DST(dst_cpu) |114OMPIC_DATA(1));115}116}117118static irqreturn_t ompic_ipi_handler(int irq, void *dev_id)119{120unsigned int cpu = smp_processor_id();121unsigned long *pending_ops = &per_cpu(ops, cpu);122unsigned long ops;123124ompic_writereg(ompic_base, OMPIC_CTRL(cpu), OMPIC_CTRL_IRQ_ACK);125while ((ops = xchg(pending_ops, 0)) != 0) {126127/*128* On OpenRISC the atomic xchg() call implies a memory129* barrier. Otherwise we may need an smp_rmb(); paired130* with the write in ompic_raise_softirq.131*/132133do {134unsigned long ipi_msg;135136ipi_msg = __ffs(ops);137ops &= ~(1UL << ipi_msg);138139handle_IPI(ipi_msg);140} while (ops);141}142143return IRQ_HANDLED;144}145146static int __init ompic_of_init(struct device_node *node,147struct device_node *parent)148{149struct resource res;150int irq;151int ret;152153/* Validate the DT */154if (ompic_base) {155pr_err("ompic: duplicate ompic's are not supported");156return -EEXIST;157}158159if (of_address_to_resource(node, 0, &res)) {160pr_err("ompic: reg property requires an address and size");161return -EINVAL;162}163164if (resource_size(&res) < (num_possible_cpus() * OMPIC_CPUBYTES)) {165pr_err("ompic: reg size, currently %d must be at least %d",166resource_size(&res),167(num_possible_cpus() * OMPIC_CPUBYTES));168return -EINVAL;169}170171/* Setup the device */172ompic_base = ioremap(res.start, resource_size(&res));173if (!ompic_base) {174pr_err("ompic: unable to map registers");175return -ENOMEM;176}177178irq = irq_of_parse_and_map(node, 0);179if (irq <= 0) {180pr_err("ompic: unable to parse device irq");181ret = -EINVAL;182goto out_unmap;183}184185ret = request_irq(irq, ompic_ipi_handler, IRQF_PERCPU,186"ompic_ipi", NULL);187if (ret)188goto out_irq_disp;189190set_smp_cross_call(ompic_raise_softirq);191192return 0;193194out_irq_disp:195irq_dispose_mapping(irq);196out_unmap:197iounmap(ompic_base);198ompic_base = NULL;199return ret;200}201IRQCHIP_DECLARE(ompic, "openrisc,ompic", ompic_of_init);202203204