0001
0002
0003
0004
0005
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
0032 return server << 2;
0033 }
0034
0035 static int ics_opal_unmangle_server(int server)
0036 {
0037
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
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,
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
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
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
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
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
0212
0213
0214 ics_opal_irq_chip.irq_eoi = icp_ops->eoi;
0215
0216
0217 xics_register_ics(&ics_hal);
0218
0219 pr_info("ICS OPAL backend registered\n");
0220
0221 return 0;
0222 }