Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * ICS backend for OPAL managed interrupts.
0004  *
0005  * Copyright 2011 IBM Corp.
0006  */
0007 
0008 //#define DEBUG
0009 
0010 #include <linux/types.h>
0011 #include <linux/kernel.h>
0012 #include <linux/irq.h>
0013 #include <linux/smp.h>
0014 #include <linux/interrupt.h>
0015 #include <linux/init.h>
0016 #include <linux/cpu.h>
0017 #include <linux/of.h>
0018 #include <linux/of_address.h>
0019 #include <linux/spinlock.h>
0020 #include <linux/msi.h>
0021 #include <linux/list.h>
0022 
0023 #include <asm/smp.h>
0024 #include <asm/machdep.h>
0025 #include <asm/irq.h>
0026 #include <asm/errno.h>
0027 #include <asm/xics.h>
0028 #include <asm/opal.h>
0029 #include <asm/firmware.h>
0030 
0031 struct ics_native {
0032     struct ics      ics;
0033     struct device_node  *node;
0034     void __iomem        *base;
0035     u32                 ibase;
0036     u32                 icount;
0037 };
0038 #define to_ics_native(_ics)     container_of(_ics, struct ics_native, ics)
0039 
0040 static void __iomem *ics_native_xive(struct ics_native *in, unsigned int vec)
0041 {
0042     return in->base + 0x800 + ((vec - in->ibase) << 2);
0043 }
0044 
0045 static void ics_native_unmask_irq(struct irq_data *d)
0046 {
0047     unsigned int vec = (unsigned int)irqd_to_hwirq(d);
0048     struct ics *ics = irq_data_get_irq_chip_data(d);
0049     struct ics_native *in = to_ics_native(ics);
0050     unsigned int server;
0051 
0052     pr_devel("ics-native: unmask virq %d [hw 0x%x]\n", d->irq, vec);
0053 
0054     if (vec < in->ibase || vec >= (in->ibase + in->icount))
0055         return;
0056 
0057     server = xics_get_irq_server(d->irq, irq_data_get_affinity_mask(d), 0);
0058     out_be32(ics_native_xive(in, vec), (server << 8) | DEFAULT_PRIORITY);
0059 }
0060 
0061 static unsigned int ics_native_startup(struct irq_data *d)
0062 {
0063 #ifdef CONFIG_PCI_MSI
0064     /*
0065      * The generic MSI code returns with the interrupt disabled on the
0066      * card, using the MSI mask bits. Firmware doesn't appear to unmask
0067      * at that level, so we do it here by hand.
0068      */
0069     if (irq_data_get_msi_desc(d))
0070         pci_msi_unmask_irq(d);
0071 #endif
0072 
0073     /* unmask it */
0074     ics_native_unmask_irq(d);
0075     return 0;
0076 }
0077 
0078 static void ics_native_do_mask(struct ics_native *in, unsigned int vec)
0079 {
0080     out_be32(ics_native_xive(in, vec), 0xff);
0081 }
0082 
0083 static void ics_native_mask_irq(struct irq_data *d)
0084 {
0085     unsigned int vec = (unsigned int)irqd_to_hwirq(d);
0086     struct ics *ics = irq_data_get_irq_chip_data(d);
0087     struct ics_native *in = to_ics_native(ics);
0088 
0089     pr_devel("ics-native: mask virq %d [hw 0x%x]\n", d->irq, vec);
0090 
0091     if (vec < in->ibase || vec >= (in->ibase + in->icount))
0092         return;
0093     ics_native_do_mask(in, vec);
0094 }
0095 
0096 static int ics_native_set_affinity(struct irq_data *d,
0097                    const struct cpumask *cpumask,
0098                    bool force)
0099 {
0100     unsigned int vec = (unsigned int)irqd_to_hwirq(d);
0101     struct ics *ics = irq_data_get_irq_chip_data(d);
0102     struct ics_native *in = to_ics_native(ics);
0103     int server;
0104     u32 xive;
0105 
0106     if (vec < in->ibase || vec >= (in->ibase + in->icount))
0107         return -EINVAL;
0108 
0109     server = xics_get_irq_server(d->irq, cpumask, 1);
0110     if (server == -1) {
0111         pr_warn("%s: No online cpus in the mask %*pb for irq %d\n",
0112             __func__, cpumask_pr_args(cpumask), d->irq);
0113         return -1;
0114     }
0115 
0116     xive = in_be32(ics_native_xive(in, vec));
0117     xive = (xive & 0xff) | (server << 8);
0118     out_be32(ics_native_xive(in, vec), xive);
0119 
0120     return IRQ_SET_MASK_OK;
0121 }
0122 
0123 static struct irq_chip ics_native_irq_chip = {
0124     .name = "ICS",
0125     .irq_startup        = ics_native_startup,
0126     .irq_mask       = ics_native_mask_irq,
0127     .irq_unmask     = ics_native_unmask_irq,
0128     .irq_eoi        = NULL, /* Patched at init time */
0129     .irq_set_affinity   = ics_native_set_affinity,
0130     .irq_set_type       = xics_set_irq_type,
0131     .irq_retrigger      = xics_retrigger,
0132 };
0133 
0134 static int ics_native_check(struct ics *ics, unsigned int hw_irq)
0135 {
0136     struct ics_native *in = to_ics_native(ics);
0137 
0138     pr_devel("%s: hw_irq=0x%x\n", __func__, hw_irq);
0139 
0140     if (hw_irq < in->ibase || hw_irq >= (in->ibase + in->icount))
0141         return -EINVAL;
0142 
0143     return 0;
0144 }
0145 
0146 static void ics_native_mask_unknown(struct ics *ics, unsigned long vec)
0147 {
0148     struct ics_native *in = to_ics_native(ics);
0149 
0150     if (vec < in->ibase || vec >= (in->ibase + in->icount))
0151         return;
0152 
0153     ics_native_do_mask(in, vec);
0154 }
0155 
0156 static long ics_native_get_server(struct ics *ics, unsigned long vec)
0157 {
0158     struct ics_native *in = to_ics_native(ics);
0159     u32 xive;
0160 
0161     if (vec < in->ibase || vec >= (in->ibase + in->icount))
0162         return -EINVAL;
0163 
0164     xive = in_be32(ics_native_xive(in, vec));
0165     return (xive >> 8) & 0xfff;
0166 }
0167 
0168 static int ics_native_host_match(struct ics *ics, struct device_node *node)
0169 {
0170     struct ics_native *in = to_ics_native(ics);
0171 
0172     return in->node == node;
0173 }
0174 
0175 static struct ics ics_native_template = {
0176     .check      = ics_native_check,
0177     .mask_unknown   = ics_native_mask_unknown,
0178     .get_server = ics_native_get_server,
0179     .host_match = ics_native_host_match,
0180     .chip = &ics_native_irq_chip,
0181 };
0182 
0183 static int __init ics_native_add_one(struct device_node *np)
0184 {
0185     struct ics_native *ics;
0186     u32 ranges[2];
0187     int rc, count;
0188 
0189     ics = kzalloc(sizeof(struct ics_native), GFP_KERNEL);
0190     if (!ics)
0191         return -ENOMEM;
0192     ics->node = of_node_get(np);
0193     memcpy(&ics->ics, &ics_native_template, sizeof(struct ics));
0194 
0195     ics->base = of_iomap(np, 0);
0196     if (!ics->base) {
0197         pr_err("Failed to map %pOFP\n", np);
0198         rc = -ENOMEM;
0199         goto fail;
0200     }
0201 
0202     count = of_property_count_u32_elems(np, "interrupt-ranges");
0203     if (count < 2 || count & 1) {
0204         pr_err("Failed to read interrupt-ranges of %pOFP\n", np);
0205         rc = -EINVAL;
0206         goto fail;
0207     }
0208     if (count > 2) {
0209         pr_warn("ICS %pOFP has %d ranges, only one supported\n",
0210             np, count >> 1);
0211     }
0212     rc = of_property_read_u32_array(np, "interrupt-ranges",
0213                     ranges, 2);
0214     if (rc) {
0215         pr_err("Failed to read interrupt-ranges of %pOFP\n", np);
0216         goto fail;
0217     }
0218     ics->ibase = ranges[0];
0219     ics->icount = ranges[1];
0220 
0221     pr_info("ICS native initialized for sources %d..%d\n",
0222         ics->ibase, ics->ibase + ics->icount - 1);
0223 
0224     /* Register ourselves */
0225     xics_register_ics(&ics->ics);
0226 
0227     return 0;
0228 fail:
0229     of_node_put(ics->node);
0230     kfree(ics);
0231     return rc;
0232 }
0233 
0234 int __init ics_native_init(void)
0235 {
0236     struct device_node *ics;
0237     bool found_one = false;
0238 
0239     /* We need to patch our irq chip's EOI to point to the
0240      * right ICP
0241      */
0242     ics_native_irq_chip.irq_eoi = icp_ops->eoi;
0243 
0244     /* Find native ICS in the device-tree */
0245     for_each_compatible_node(ics, NULL, "openpower,xics-sources") {
0246         if (ics_native_add_one(ics) == 0)
0247             found_one = true;
0248     }
0249 
0250     if (found_one)
0251         pr_info("ICS native backend registered\n");
0252 
0253     return found_one ? 0 : -ENODEV;
0254 }