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 #undef 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/spinlock.h>
0019 #include <linux/msi.h>
0020 
0021 #include <asm/smp.h>
0022 #include <asm/machdep.h>
0023 #include <asm/irq.h>
0024 #include <asm/errno.h>
0025 #include <asm/xics.h>
0026 #include <asm/opal.h>
0027 #include <asm/firmware.h>
0028 
0029 static int ics_opal_mangle_server(int server)
0030 {
0031     /* No link for now */
0032     return server << 2;
0033 }
0034 
0035 static int ics_opal_unmangle_server(int server)
0036 {
0037     /* No link for now */
0038     return server >> 2;
0039 }
0040 
0041 static void ics_opal_unmask_irq(struct irq_data *d)
0042 {
0043     unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
0044     int64_t rc;
0045     int server;
0046 
0047     pr_devel("ics-hal: unmask virq %d [hw 0x%x]\n", d->irq, hw_irq);
0048 
0049     if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
0050         return;
0051 
0052     server = xics_get_irq_server(d->irq, irq_data_get_affinity_mask(d), 0);
0053     server = ics_opal_mangle_server(server);
0054 
0055     rc = opal_set_xive(hw_irq, server, DEFAULT_PRIORITY);
0056     if (rc != OPAL_SUCCESS)
0057         pr_err("%s: opal_set_xive(irq=%d [hw 0x%x] server=%x)"
0058                " error %lld\n",
0059                __func__, d->irq, hw_irq, server, rc);
0060 }
0061 
0062 static unsigned int ics_opal_startup(struct irq_data *d)
0063 {
0064     ics_opal_unmask_irq(d);
0065     return 0;
0066 }
0067 
0068 static void ics_opal_mask_real_irq(unsigned int hw_irq)
0069 {
0070     int server = ics_opal_mangle_server(xics_default_server);
0071     int64_t rc;
0072 
0073     if (hw_irq == XICS_IPI)
0074         return;
0075 
0076     /* Have to set XIVE to 0xff to be able to remove a slot */
0077     rc = opal_set_xive(hw_irq, server, 0xff);
0078     if (rc != OPAL_SUCCESS)
0079         pr_err("%s: opal_set_xive(0xff) irq=%u returned %lld\n",
0080                __func__, hw_irq, rc);
0081 }
0082 
0083 static void ics_opal_mask_irq(struct irq_data *d)
0084 {
0085     unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
0086 
0087     pr_devel("ics-hal: mask virq %d [hw 0x%x]\n", d->irq, hw_irq);
0088 
0089     if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
0090         return;
0091     ics_opal_mask_real_irq(hw_irq);
0092 }
0093 
0094 static int ics_opal_set_affinity(struct irq_data *d,
0095                  const struct cpumask *cpumask,
0096                  bool force)
0097 {
0098     unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
0099     __be16 oserver;
0100     int16_t server;
0101     int8_t priority;
0102     int64_t rc;
0103     int wanted_server;
0104 
0105     if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
0106         return -1;
0107 
0108     rc = opal_get_xive(hw_irq, &oserver, &priority);
0109     if (rc != OPAL_SUCCESS) {
0110         pr_err("%s: opal_get_xive(irq=%d [hw 0x%x]) error %lld\n",
0111                __func__, d->irq, hw_irq, rc);
0112         return -1;
0113     }
0114     server = be16_to_cpu(oserver);
0115 
0116     wanted_server = xics_get_irq_server(d->irq, cpumask, 1);
0117     if (wanted_server < 0) {
0118         pr_warn("%s: No online cpus in the mask %*pb for irq %d\n",
0119             __func__, cpumask_pr_args(cpumask), d->irq);
0120         return -1;
0121     }
0122     server = ics_opal_mangle_server(wanted_server);
0123 
0124     pr_debug("ics-hal: set-affinity irq %d [hw 0x%x] server: 0x%x/0x%x\n",
0125          d->irq, hw_irq, wanted_server, server);
0126 
0127     rc = opal_set_xive(hw_irq, server, priority);
0128     if (rc != OPAL_SUCCESS) {
0129         pr_err("%s: opal_set_xive(irq=%d [hw 0x%x] server=%x)"
0130                " error %lld\n",
0131                __func__, d->irq, hw_irq, server, rc);
0132         return -1;
0133     }
0134     return IRQ_SET_MASK_OK;
0135 }
0136 
0137 static struct irq_chip ics_opal_irq_chip = {
0138     .name = "OPAL ICS",
0139     .irq_startup = ics_opal_startup,
0140     .irq_mask = ics_opal_mask_irq,
0141     .irq_unmask = ics_opal_unmask_irq,
0142     .irq_eoi = NULL, /* Patched at init time */
0143     .irq_set_affinity = ics_opal_set_affinity,
0144     .irq_set_type = xics_set_irq_type,
0145     .irq_retrigger = xics_retrigger,
0146 };
0147 
0148 static int ics_opal_host_match(struct ics *ics, struct device_node *node)
0149 {
0150     return 1;
0151 }
0152 
0153 static int ics_opal_check(struct ics *ics, unsigned int hw_irq)
0154 {
0155     int64_t rc;
0156     __be16 server;
0157     int8_t priority;
0158 
0159     if (WARN_ON(hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS))
0160         return -EINVAL;
0161 
0162     /* Check if HAL knows about this interrupt */
0163     rc = opal_get_xive(hw_irq, &server, &priority);
0164     if (rc != OPAL_SUCCESS)
0165         return -ENXIO;
0166 
0167     return 0;
0168 }
0169 
0170 static void ics_opal_mask_unknown(struct ics *ics, unsigned long vec)
0171 {
0172     int64_t rc;
0173     __be16 server;
0174     int8_t priority;
0175 
0176     /* Check if HAL knows about this interrupt */
0177     rc = opal_get_xive(vec, &server, &priority);
0178     if (rc != OPAL_SUCCESS)
0179         return;
0180 
0181     ics_opal_mask_real_irq(vec);
0182 }
0183 
0184 static long ics_opal_get_server(struct ics *ics, unsigned long vec)
0185 {
0186     int64_t rc;
0187     __be16 server;
0188     int8_t priority;
0189 
0190     /* Check if HAL knows about this interrupt */
0191     rc = opal_get_xive(vec, &server, &priority);
0192     if (rc != OPAL_SUCCESS)
0193         return -1;
0194     return ics_opal_unmangle_server(be16_to_cpu(server));
0195 }
0196 
0197 /* Only one global & state struct ics */
0198 static struct ics ics_hal = {
0199     .check      = ics_opal_check,
0200     .mask_unknown   = ics_opal_mask_unknown,
0201     .get_server = ics_opal_get_server,
0202     .host_match = ics_opal_host_match,
0203     .chip       = &ics_opal_irq_chip,
0204 };
0205 
0206 int __init ics_opal_init(void)
0207 {
0208     if (!firmware_has_feature(FW_FEATURE_OPAL))
0209         return -ENODEV;
0210 
0211     /* We need to patch our irq chip's EOI to point to the
0212      * right ICP
0213      */
0214     ics_opal_irq_chip.irq_eoi = icp_ops->eoi;
0215 
0216     /* Register ourselves */
0217     xics_register_ics(&ics_hal);
0218 
0219     pr_info("ICS OPAL backend registered\n");
0220 
0221     return 0;
0222 }