0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/types.h>
0014 #include <linux/kernel.h>
0015 #include <linux/init.h>
0016 #include <linux/irq.h>
0017 #include <linux/irqdomain.h>
0018 #include <linux/smp.h>
0019 #include <linux/interrupt.h>
0020 #include <linux/slab.h>
0021 #include <linux/spinlock.h>
0022 #include <linux/of.h>
0023 #include <linux/of_address.h>
0024
0025 #include <asm/io.h>
0026 #include <asm/irq.h>
0027 #include <asm/smp.h>
0028 #include <asm/machdep.h>
0029 #include <asm/ehv_pic.h>
0030 #include <asm/fsl_hcalls.h>
0031
0032 static struct ehv_pic *global_ehv_pic;
0033 static DEFINE_SPINLOCK(ehv_pic_lock);
0034
0035 static u32 hwirq_intspec[NR_EHV_PIC_INTS];
0036 static u32 __iomem *mpic_percpu_base_vaddr;
0037
0038 #define IRQ_TYPE_MPIC_DIRECT 4
0039 #define MPIC_EOI 0x00B0
0040
0041
0042
0043
0044
0045 void ehv_pic_unmask_irq(struct irq_data *d)
0046 {
0047 unsigned int src = virq_to_hw(d->irq);
0048
0049 ev_int_set_mask(src, 0);
0050 }
0051
0052 void ehv_pic_mask_irq(struct irq_data *d)
0053 {
0054 unsigned int src = virq_to_hw(d->irq);
0055
0056 ev_int_set_mask(src, 1);
0057 }
0058
0059 void ehv_pic_end_irq(struct irq_data *d)
0060 {
0061 unsigned int src = virq_to_hw(d->irq);
0062
0063 ev_int_eoi(src);
0064 }
0065
0066 void ehv_pic_direct_end_irq(struct irq_data *d)
0067 {
0068 out_be32(mpic_percpu_base_vaddr + MPIC_EOI / 4, 0);
0069 }
0070
0071 int ehv_pic_set_affinity(struct irq_data *d, const struct cpumask *dest,
0072 bool force)
0073 {
0074 unsigned int src = virq_to_hw(d->irq);
0075 unsigned int config, prio, cpu_dest;
0076 int cpuid = irq_choose_cpu(dest);
0077 unsigned long flags;
0078
0079 spin_lock_irqsave(&ehv_pic_lock, flags);
0080 ev_int_get_config(src, &config, &prio, &cpu_dest);
0081 ev_int_set_config(src, config, prio, cpuid);
0082 spin_unlock_irqrestore(&ehv_pic_lock, flags);
0083
0084 return IRQ_SET_MASK_OK;
0085 }
0086
0087 static unsigned int ehv_pic_type_to_vecpri(unsigned int type)
0088 {
0089
0090
0091 switch (type & IRQ_TYPE_SENSE_MASK) {
0092 case IRQ_TYPE_EDGE_RISING:
0093 return EHV_PIC_INFO(VECPRI_SENSE_EDGE) |
0094 EHV_PIC_INFO(VECPRI_POLARITY_POSITIVE);
0095
0096 case IRQ_TYPE_EDGE_FALLING:
0097 case IRQ_TYPE_EDGE_BOTH:
0098 return EHV_PIC_INFO(VECPRI_SENSE_EDGE) |
0099 EHV_PIC_INFO(VECPRI_POLARITY_NEGATIVE);
0100
0101 case IRQ_TYPE_LEVEL_HIGH:
0102 return EHV_PIC_INFO(VECPRI_SENSE_LEVEL) |
0103 EHV_PIC_INFO(VECPRI_POLARITY_POSITIVE);
0104
0105 case IRQ_TYPE_LEVEL_LOW:
0106 default:
0107 return EHV_PIC_INFO(VECPRI_SENSE_LEVEL) |
0108 EHV_PIC_INFO(VECPRI_POLARITY_NEGATIVE);
0109 }
0110 }
0111
0112 int ehv_pic_set_irq_type(struct irq_data *d, unsigned int flow_type)
0113 {
0114 unsigned int src = virq_to_hw(d->irq);
0115 unsigned int vecpri, vold, vnew, prio, cpu_dest;
0116 unsigned long flags;
0117
0118 if (flow_type == IRQ_TYPE_NONE)
0119 flow_type = IRQ_TYPE_LEVEL_LOW;
0120
0121 irqd_set_trigger_type(d, flow_type);
0122
0123 vecpri = ehv_pic_type_to_vecpri(flow_type);
0124
0125 spin_lock_irqsave(&ehv_pic_lock, flags);
0126 ev_int_get_config(src, &vold, &prio, &cpu_dest);
0127 vnew = vold & ~(EHV_PIC_INFO(VECPRI_POLARITY_MASK) |
0128 EHV_PIC_INFO(VECPRI_SENSE_MASK));
0129 vnew |= vecpri;
0130
0131
0132
0133
0134
0135
0136
0137 prio = 8;
0138
0139 ev_int_set_config(src, vecpri, prio, cpu_dest);
0140
0141 spin_unlock_irqrestore(&ehv_pic_lock, flags);
0142 return IRQ_SET_MASK_OK_NOCOPY;
0143 }
0144
0145 static struct irq_chip ehv_pic_irq_chip = {
0146 .irq_mask = ehv_pic_mask_irq,
0147 .irq_unmask = ehv_pic_unmask_irq,
0148 .irq_eoi = ehv_pic_end_irq,
0149 .irq_set_type = ehv_pic_set_irq_type,
0150 };
0151
0152 static struct irq_chip ehv_pic_direct_eoi_irq_chip = {
0153 .irq_mask = ehv_pic_mask_irq,
0154 .irq_unmask = ehv_pic_unmask_irq,
0155 .irq_eoi = ehv_pic_direct_end_irq,
0156 .irq_set_type = ehv_pic_set_irq_type,
0157 };
0158
0159
0160 unsigned int ehv_pic_get_irq(void)
0161 {
0162 int irq;
0163
0164 BUG_ON(global_ehv_pic == NULL);
0165
0166 if (global_ehv_pic->coreint_flag)
0167 irq = mfspr(SPRN_EPR);
0168 else
0169 ev_int_iack(0, &irq);
0170
0171 if (irq == 0xFFFF)
0172 return 0;
0173
0174
0175
0176
0177
0178 return irq_linear_revmap(global_ehv_pic->irqhost, irq);
0179 }
0180
0181 static int ehv_pic_host_match(struct irq_domain *h, struct device_node *node,
0182 enum irq_domain_bus_token bus_token)
0183 {
0184
0185 struct device_node *of_node = irq_domain_get_of_node(h);
0186 return of_node == NULL || of_node == node;
0187 }
0188
0189 static int ehv_pic_host_map(struct irq_domain *h, unsigned int virq,
0190 irq_hw_number_t hw)
0191 {
0192 struct ehv_pic *ehv_pic = h->host_data;
0193 struct irq_chip *chip;
0194
0195
0196 chip = &ehv_pic->hc_irq;
0197
0198 if (mpic_percpu_base_vaddr)
0199 if (hwirq_intspec[hw] & IRQ_TYPE_MPIC_DIRECT)
0200 chip = &ehv_pic_direct_eoi_irq_chip;
0201
0202 irq_set_chip_data(virq, chip);
0203
0204
0205
0206
0207
0208
0209
0210 irq_set_chip_and_handler(virq, chip, handle_fasteoi_irq);
0211
0212
0213 irq_set_irq_type(virq, IRQ_TYPE_NONE);
0214
0215 return 0;
0216 }
0217
0218 static int ehv_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
0219 const u32 *intspec, unsigned int intsize,
0220 irq_hw_number_t *out_hwirq, unsigned int *out_flags)
0221
0222 {
0223
0224
0225
0226
0227
0228
0229
0230 static unsigned char map_of_senses_to_linux_irqtype[4] = {
0231 IRQ_TYPE_EDGE_FALLING,
0232 IRQ_TYPE_EDGE_RISING,
0233 IRQ_TYPE_LEVEL_LOW,
0234 IRQ_TYPE_LEVEL_HIGH,
0235 };
0236
0237 *out_hwirq = intspec[0];
0238 if (intsize > 1) {
0239 hwirq_intspec[intspec[0]] = intspec[1];
0240 *out_flags = map_of_senses_to_linux_irqtype[intspec[1] &
0241 ~IRQ_TYPE_MPIC_DIRECT];
0242 } else {
0243 *out_flags = IRQ_TYPE_NONE;
0244 }
0245
0246 return 0;
0247 }
0248
0249 static const struct irq_domain_ops ehv_pic_host_ops = {
0250 .match = ehv_pic_host_match,
0251 .map = ehv_pic_host_map,
0252 .xlate = ehv_pic_host_xlate,
0253 };
0254
0255 void __init ehv_pic_init(void)
0256 {
0257 struct device_node *np, *np2;
0258 struct ehv_pic *ehv_pic;
0259 int coreint_flag = 1;
0260
0261 np = of_find_compatible_node(NULL, NULL, "epapr,hv-pic");
0262 if (!np) {
0263 pr_err("ehv_pic_init: could not find epapr,hv-pic node\n");
0264 return;
0265 }
0266
0267 if (!of_find_property(np, "has-external-proxy", NULL))
0268 coreint_flag = 0;
0269
0270 ehv_pic = kzalloc(sizeof(struct ehv_pic), GFP_KERNEL);
0271 if (!ehv_pic) {
0272 of_node_put(np);
0273 return;
0274 }
0275
0276 ehv_pic->irqhost = irq_domain_add_linear(np, NR_EHV_PIC_INTS,
0277 &ehv_pic_host_ops, ehv_pic);
0278 if (!ehv_pic->irqhost) {
0279 of_node_put(np);
0280 kfree(ehv_pic);
0281 return;
0282 }
0283
0284 np2 = of_find_compatible_node(NULL, NULL, "fsl,hv-mpic-per-cpu");
0285 if (np2) {
0286 mpic_percpu_base_vaddr = of_iomap(np2, 0);
0287 if (!mpic_percpu_base_vaddr)
0288 pr_err("ehv_pic_init: of_iomap failed\n");
0289
0290 of_node_put(np2);
0291 }
0292
0293 ehv_pic->hc_irq = ehv_pic_irq_chip;
0294 ehv_pic->hc_irq.irq_set_affinity = ehv_pic_set_affinity;
0295 ehv_pic->coreint_flag = coreint_flag;
0296
0297 global_ehv_pic = ehv_pic;
0298 irq_set_default_host(global_ehv_pic->irqhost);
0299 }