This source file includes following definitions.
- icp_opal_teardown_cpu
- icp_opal_flush_ipi
- icp_opal_get_xirr
- icp_opal_get_irq
- icp_opal_set_cpu_priority
- icp_opal_eoi
- icp_opal_cause_ipi
- icp_opal_ipi_action
- icp_opal_flush_interrupt
- icp_opal_init
   1 
   2 
   3 
   4 
   5 #include <linux/types.h>
   6 #include <linux/kernel.h>
   7 #include <linux/irq.h>
   8 #include <linux/smp.h>
   9 #include <linux/interrupt.h>
  10 #include <linux/cpu.h>
  11 #include <linux/of.h>
  12 
  13 #include <asm/smp.h>
  14 #include <asm/irq.h>
  15 #include <asm/errno.h>
  16 #include <asm/xics.h>
  17 #include <asm/io.h>
  18 #include <asm/opal.h>
  19 #include <asm/kvm_ppc.h>
  20 
  21 static void icp_opal_teardown_cpu(void)
  22 {
  23         int hw_cpu = hard_smp_processor_id();
  24 
  25         
  26         opal_int_set_mfrr(hw_cpu, 0xff);
  27 }
  28 
  29 static void icp_opal_flush_ipi(void)
  30 {
  31         
  32 
  33 
  34 
  35 
  36 
  37 
  38 
  39         if (opal_int_eoi((0x00 << 24) | XICS_IPI) > 0)
  40                 force_external_irq_replay();
  41 }
  42 
  43 static unsigned int icp_opal_get_xirr(void)
  44 {
  45         unsigned int kvm_xirr;
  46         __be32 hw_xirr;
  47         int64_t rc;
  48 
  49         
  50         kvm_xirr = kvmppc_get_xics_latch();
  51         if (kvm_xirr)
  52                 return kvm_xirr;
  53 
  54         
  55         rc = opal_int_get_xirr(&hw_xirr, false);
  56         if (rc < 0)
  57                 return 0;
  58         return be32_to_cpu(hw_xirr);
  59 }
  60 
  61 static unsigned int icp_opal_get_irq(void)
  62 {
  63         unsigned int xirr;
  64         unsigned int vec;
  65         unsigned int irq;
  66 
  67         xirr = icp_opal_get_xirr();
  68         vec = xirr & 0x00ffffff;
  69         if (vec == XICS_IRQ_SPURIOUS)
  70                 return 0;
  71 
  72         irq = irq_find_mapping(xics_host, vec);
  73         if (likely(irq)) {
  74                 xics_push_cppr(vec);
  75                 return irq;
  76         }
  77 
  78         
  79         xics_mask_unknown_vec(vec);
  80 
  81         
  82         if (opal_int_eoi(xirr) > 0)
  83                 force_external_irq_replay();
  84 
  85         return 0;
  86 }
  87 
  88 static void icp_opal_set_cpu_priority(unsigned char cppr)
  89 {
  90         
  91 
  92 
  93 
  94 
  95 
  96 
  97         if (cppr >= DEFAULT_PRIORITY)
  98                 cppr = LOWEST_PRIORITY;
  99 
 100         xics_set_base_cppr(cppr);
 101         opal_int_set_cppr(cppr);
 102         iosync();
 103 }
 104 
 105 static void icp_opal_eoi(struct irq_data *d)
 106 {
 107         unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
 108         int64_t rc;
 109 
 110         iosync();
 111         rc = opal_int_eoi((xics_pop_cppr() << 24) | hw_irq);
 112 
 113         
 114 
 115 
 116 
 117 
 118 
 119         if (rc > 0)
 120                 force_external_irq_replay();
 121 }
 122 
 123 #ifdef CONFIG_SMP
 124 
 125 static void icp_opal_cause_ipi(int cpu)
 126 {
 127         int hw_cpu = get_hard_smp_processor_id(cpu);
 128 
 129         kvmppc_set_host_ipi(cpu);
 130         opal_int_set_mfrr(hw_cpu, IPI_PRIORITY);
 131 }
 132 
 133 static irqreturn_t icp_opal_ipi_action(int irq, void *dev_id)
 134 {
 135         int cpu = smp_processor_id();
 136 
 137         kvmppc_clear_host_ipi(cpu);
 138         opal_int_set_mfrr(get_hard_smp_processor_id(cpu), 0xff);
 139 
 140         return smp_ipi_demux();
 141 }
 142 
 143 
 144 
 145 
 146 
 147 void icp_opal_flush_interrupt(void)
 148 {
 149         unsigned int xirr;
 150         unsigned int vec;
 151 
 152         do {
 153                 xirr = icp_opal_get_xirr();
 154                 vec = xirr & 0x00ffffff;
 155                 if (vec == XICS_IRQ_SPURIOUS)
 156                         break;
 157                 if (vec == XICS_IPI) {
 158                         
 159                         int cpu = smp_processor_id();
 160                         kvmppc_clear_host_ipi(cpu);
 161                         opal_int_set_mfrr(get_hard_smp_processor_id(cpu), 0xff);
 162                 } else {
 163                         pr_err("XICS: hw interrupt 0x%x to offline cpu, "
 164                                "disabling\n", vec);
 165                         xics_mask_unknown_vec(vec);
 166                 }
 167 
 168                 
 169         } while (opal_int_eoi(xirr) > 0);
 170 }
 171 
 172 #endif 
 173 
 174 static const struct icp_ops icp_opal_ops = {
 175         .get_irq        = icp_opal_get_irq,
 176         .eoi            = icp_opal_eoi,
 177         .set_priority   = icp_opal_set_cpu_priority,
 178         .teardown_cpu   = icp_opal_teardown_cpu,
 179         .flush_ipi      = icp_opal_flush_ipi,
 180 #ifdef CONFIG_SMP
 181         .ipi_action     = icp_opal_ipi_action,
 182         .cause_ipi      = icp_opal_cause_ipi,
 183 #endif
 184 };
 185 
 186 int icp_opal_init(void)
 187 {
 188         struct device_node *np;
 189 
 190         np = of_find_compatible_node(NULL, NULL, "ibm,opal-intc");
 191         if (!np)
 192                 return -ENODEV;
 193 
 194         icp_ops = &icp_opal_ops;
 195 
 196         printk("XICS: Using OPAL ICP fallbacks\n");
 197 
 198         return 0;
 199 }
 200