root/arch/powerpc/sysdev/xics/ics-opal.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ics_opal_mangle_server
  2. ics_opal_unmangle_server
  3. ics_opal_unmask_irq
  4. ics_opal_startup
  5. ics_opal_mask_real_irq
  6. ics_opal_mask_irq
  7. ics_opal_set_affinity
  8. ics_opal_host_match
  9. ics_opal_map
  10. ics_opal_mask_unknown
  11. ics_opal_get_server
  12. ics_opal_init

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * ICS backend for OPAL managed interrupts.
   4  *
   5  * Copyright 2011 IBM Corp.
   6  */
   7 
   8 #undef DEBUG
   9 
  10 #include <linux/types.h>
  11 #include <linux/kernel.h>
  12 #include <linux/irq.h>
  13 #include <linux/smp.h>
  14 #include <linux/interrupt.h>
  15 #include <linux/init.h>
  16 #include <linux/cpu.h>
  17 #include <linux/of.h>
  18 #include <linux/spinlock.h>
  19 #include <linux/msi.h>
  20 
  21 #include <asm/prom.h>
  22 #include <asm/smp.h>
  23 #include <asm/machdep.h>
  24 #include <asm/irq.h>
  25 #include <asm/errno.h>
  26 #include <asm/xics.h>
  27 #include <asm/opal.h>
  28 #include <asm/firmware.h>
  29 
  30 static int ics_opal_mangle_server(int server)
  31 {
  32         /* No link for now */
  33         return server << 2;
  34 }
  35 
  36 static int ics_opal_unmangle_server(int server)
  37 {
  38         /* No link for now */
  39         return server >> 2;
  40 }
  41 
  42 static void ics_opal_unmask_irq(struct irq_data *d)
  43 {
  44         unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
  45         int64_t rc;
  46         int server;
  47 
  48         pr_devel("ics-hal: unmask virq %d [hw 0x%x]\n", d->irq, hw_irq);
  49 
  50         if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
  51                 return;
  52 
  53         server = xics_get_irq_server(d->irq, irq_data_get_affinity_mask(d), 0);
  54         server = ics_opal_mangle_server(server);
  55 
  56         rc = opal_set_xive(hw_irq, server, DEFAULT_PRIORITY);
  57         if (rc != OPAL_SUCCESS)
  58                 pr_err("%s: opal_set_xive(irq=%d [hw 0x%x] server=%x)"
  59                        " error %lld\n",
  60                        __func__, d->irq, hw_irq, server, rc);
  61 }
  62 
  63 static unsigned int ics_opal_startup(struct irq_data *d)
  64 {
  65 #ifdef CONFIG_PCI_MSI
  66         /*
  67          * The generic MSI code returns with the interrupt disabled on the
  68          * card, using the MSI mask bits. Firmware doesn't appear to unmask
  69          * at that level, so we do it here by hand.
  70          */
  71         if (irq_data_get_msi_desc(d))
  72                 pci_msi_unmask_irq(d);
  73 #endif
  74 
  75         /* unmask it */
  76         ics_opal_unmask_irq(d);
  77         return 0;
  78 }
  79 
  80 static void ics_opal_mask_real_irq(unsigned int hw_irq)
  81 {
  82         int server = ics_opal_mangle_server(xics_default_server);
  83         int64_t rc;
  84 
  85         if (hw_irq == XICS_IPI)
  86                 return;
  87 
  88         /* Have to set XIVE to 0xff to be able to remove a slot */
  89         rc = opal_set_xive(hw_irq, server, 0xff);
  90         if (rc != OPAL_SUCCESS)
  91                 pr_err("%s: opal_set_xive(0xff) irq=%u returned %lld\n",
  92                        __func__, hw_irq, rc);
  93 }
  94 
  95 static void ics_opal_mask_irq(struct irq_data *d)
  96 {
  97         unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
  98 
  99         pr_devel("ics-hal: mask virq %d [hw 0x%x]\n", d->irq, hw_irq);
 100 
 101         if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
 102                 return;
 103         ics_opal_mask_real_irq(hw_irq);
 104 }
 105 
 106 static int ics_opal_set_affinity(struct irq_data *d,
 107                                  const struct cpumask *cpumask,
 108                                  bool force)
 109 {
 110         unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
 111         __be16 oserver;
 112         int16_t server;
 113         int8_t priority;
 114         int64_t rc;
 115         int wanted_server;
 116 
 117         if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
 118                 return -1;
 119 
 120         rc = opal_get_xive(hw_irq, &oserver, &priority);
 121         if (rc != OPAL_SUCCESS) {
 122                 pr_err("%s: opal_get_xive(irq=%d [hw 0x%x]) error %lld\n",
 123                        __func__, d->irq, hw_irq, rc);
 124                 return -1;
 125         }
 126         server = be16_to_cpu(oserver);
 127 
 128         wanted_server = xics_get_irq_server(d->irq, cpumask, 1);
 129         if (wanted_server < 0) {
 130                 pr_warn("%s: No online cpus in the mask %*pb for irq %d\n",
 131                         __func__, cpumask_pr_args(cpumask), d->irq);
 132                 return -1;
 133         }
 134         server = ics_opal_mangle_server(wanted_server);
 135 
 136         pr_devel("ics-hal: set-affinity irq %d [hw 0x%x] server: 0x%x/0x%x\n",
 137                  d->irq, hw_irq, wanted_server, server);
 138 
 139         rc = opal_set_xive(hw_irq, server, priority);
 140         if (rc != OPAL_SUCCESS) {
 141                 pr_err("%s: opal_set_xive(irq=%d [hw 0x%x] server=%x)"
 142                        " error %lld\n",
 143                        __func__, d->irq, hw_irq, server, rc);
 144                 return -1;
 145         }
 146         return IRQ_SET_MASK_OK;
 147 }
 148 
 149 static struct irq_chip ics_opal_irq_chip = {
 150         .name = "OPAL ICS",
 151         .irq_startup = ics_opal_startup,
 152         .irq_mask = ics_opal_mask_irq,
 153         .irq_unmask = ics_opal_unmask_irq,
 154         .irq_eoi = NULL, /* Patched at init time */
 155         .irq_set_affinity = ics_opal_set_affinity,
 156         .irq_set_type = xics_set_irq_type,
 157         .irq_retrigger = xics_retrigger,
 158 };
 159 
 160 static int ics_opal_map(struct ics *ics, unsigned int virq);
 161 static void ics_opal_mask_unknown(struct ics *ics, unsigned long vec);
 162 static long ics_opal_get_server(struct ics *ics, unsigned long vec);
 163 
 164 static int ics_opal_host_match(struct ics *ics, struct device_node *node)
 165 {
 166         return 1;
 167 }
 168 
 169 /* Only one global & state struct ics */
 170 static struct ics ics_hal = {
 171         .map            = ics_opal_map,
 172         .mask_unknown   = ics_opal_mask_unknown,
 173         .get_server     = ics_opal_get_server,
 174         .host_match     = ics_opal_host_match,
 175 };
 176 
 177 static int ics_opal_map(struct ics *ics, unsigned int virq)
 178 {
 179         unsigned int hw_irq = (unsigned int)virq_to_hw(virq);
 180         int64_t rc;
 181         __be16 server;
 182         int8_t priority;
 183 
 184         if (WARN_ON(hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS))
 185                 return -EINVAL;
 186 
 187         /* Check if HAL knows about this interrupt */
 188         rc = opal_get_xive(hw_irq, &server, &priority);
 189         if (rc != OPAL_SUCCESS)
 190                 return -ENXIO;
 191 
 192         irq_set_chip_and_handler(virq, &ics_opal_irq_chip, handle_fasteoi_irq);
 193         irq_set_chip_data(virq, &ics_hal);
 194 
 195         return 0;
 196 }
 197 
 198 static void ics_opal_mask_unknown(struct ics *ics, unsigned long vec)
 199 {
 200         int64_t rc;
 201         __be16 server;
 202         int8_t priority;
 203 
 204         /* Check if HAL knows about this interrupt */
 205         rc = opal_get_xive(vec, &server, &priority);
 206         if (rc != OPAL_SUCCESS)
 207                 return;
 208 
 209         ics_opal_mask_real_irq(vec);
 210 }
 211 
 212 static long ics_opal_get_server(struct ics *ics, unsigned long vec)
 213 {
 214         int64_t rc;
 215         __be16 server;
 216         int8_t priority;
 217 
 218         /* Check if HAL knows about this interrupt */
 219         rc = opal_get_xive(vec, &server, &priority);
 220         if (rc != OPAL_SUCCESS)
 221                 return -1;
 222         return ics_opal_unmangle_server(be16_to_cpu(server));
 223 }
 224 
 225 int __init ics_opal_init(void)
 226 {
 227         if (!firmware_has_feature(FW_FEATURE_OPAL))
 228                 return -ENODEV;
 229 
 230         /* We need to patch our irq chip's EOI to point to the
 231          * right ICP
 232          */
 233         ics_opal_irq_chip.irq_eoi = icp_ops->eoi;
 234 
 235         /* Register ourselves */
 236         xics_register_ics(&ics_hal);
 237 
 238         pr_info("ICS OPAL backend registered\n");
 239 
 240         return 0;
 241 }

/* [<][>][^][v][top][bottom][index][help] */