^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Driver for ePAPR Embedded Hypervisor PIC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright 2008-2011 Freescale Semiconductor, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Author: Ashish Kalra <ashish.kalra@freescale.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * This file is licensed under the terms of the GNU General Public License
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * version 2. This program is licensed "as is" without any warranty of any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * kind, whether express or implied.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <asm/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <asm/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <asm/machdep.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <asm/ehv_pic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <asm/fsl_hcalls.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static struct ehv_pic *global_ehv_pic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) static DEFINE_SPINLOCK(ehv_pic_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static u32 hwirq_intspec[NR_EHV_PIC_INTS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static u32 __iomem *mpic_percpu_base_vaddr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define IRQ_TYPE_MPIC_DIRECT 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define MPIC_EOI 0x00B0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * Linux descriptor level callbacks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) void ehv_pic_unmask_irq(struct irq_data *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) unsigned int src = virq_to_hw(d->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) ev_int_set_mask(src, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) void ehv_pic_mask_irq(struct irq_data *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) unsigned int src = virq_to_hw(d->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) ev_int_set_mask(src, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) void ehv_pic_end_irq(struct irq_data *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) unsigned int src = virq_to_hw(d->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) ev_int_eoi(src);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) void ehv_pic_direct_end_irq(struct irq_data *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) out_be32(mpic_percpu_base_vaddr + MPIC_EOI / 4, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) int ehv_pic_set_affinity(struct irq_data *d, const struct cpumask *dest,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) bool force)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) unsigned int src = virq_to_hw(d->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) unsigned int config, prio, cpu_dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) int cpuid = irq_choose_cpu(dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) spin_lock_irqsave(&ehv_pic_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) ev_int_get_config(src, &config, &prio, &cpu_dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) ev_int_set_config(src, config, prio, cpuid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) spin_unlock_irqrestore(&ehv_pic_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return IRQ_SET_MASK_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) static unsigned int ehv_pic_type_to_vecpri(unsigned int type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) /* Now convert sense value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) switch (type & IRQ_TYPE_SENSE_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) case IRQ_TYPE_EDGE_RISING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return EHV_PIC_INFO(VECPRI_SENSE_EDGE) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) EHV_PIC_INFO(VECPRI_POLARITY_POSITIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) case IRQ_TYPE_EDGE_FALLING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) case IRQ_TYPE_EDGE_BOTH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return EHV_PIC_INFO(VECPRI_SENSE_EDGE) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) EHV_PIC_INFO(VECPRI_POLARITY_NEGATIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) case IRQ_TYPE_LEVEL_HIGH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) return EHV_PIC_INFO(VECPRI_SENSE_LEVEL) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) EHV_PIC_INFO(VECPRI_POLARITY_POSITIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) case IRQ_TYPE_LEVEL_LOW:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return EHV_PIC_INFO(VECPRI_SENSE_LEVEL) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) EHV_PIC_INFO(VECPRI_POLARITY_NEGATIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) int ehv_pic_set_irq_type(struct irq_data *d, unsigned int flow_type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) unsigned int src = virq_to_hw(d->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) unsigned int vecpri, vold, vnew, prio, cpu_dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (flow_type == IRQ_TYPE_NONE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) flow_type = IRQ_TYPE_LEVEL_LOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) irqd_set_trigger_type(d, flow_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) vecpri = ehv_pic_type_to_vecpri(flow_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) spin_lock_irqsave(&ehv_pic_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) ev_int_get_config(src, &vold, &prio, &cpu_dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) vnew = vold & ~(EHV_PIC_INFO(VECPRI_POLARITY_MASK) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) EHV_PIC_INFO(VECPRI_SENSE_MASK));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) vnew |= vecpri;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * TODO : Add specific interface call for platform to set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * individual interrupt priorities.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * platform currently using static/default priority for all ints
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) prio = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) ev_int_set_config(src, vecpri, prio, cpu_dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) spin_unlock_irqrestore(&ehv_pic_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return IRQ_SET_MASK_OK_NOCOPY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static struct irq_chip ehv_pic_irq_chip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) .irq_mask = ehv_pic_mask_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) .irq_unmask = ehv_pic_unmask_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) .irq_eoi = ehv_pic_end_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) .irq_set_type = ehv_pic_set_irq_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) static struct irq_chip ehv_pic_direct_eoi_irq_chip = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) .irq_mask = ehv_pic_mask_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) .irq_unmask = ehv_pic_unmask_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) .irq_eoi = ehv_pic_direct_end_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) .irq_set_type = ehv_pic_set_irq_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) /* Return an interrupt vector or 0 if no interrupt is pending. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) unsigned int ehv_pic_get_irq(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) BUG_ON(global_ehv_pic == NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) if (global_ehv_pic->coreint_flag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) irq = mfspr(SPRN_EPR); /* if core int mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) ev_int_iack(0, &irq); /* legacy mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) if (irq == 0xFFFF) /* 0xFFFF --> no irq is pending */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) * this will also setup revmap[] in the slow path for the first
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) * time, next calls will always use fast path by indexing revmap
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return irq_linear_revmap(global_ehv_pic->irqhost, irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) static int ehv_pic_host_match(struct irq_domain *h, struct device_node *node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) enum irq_domain_bus_token bus_token)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) /* Exact match, unless ehv_pic node is NULL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) struct device_node *of_node = irq_domain_get_of_node(h);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) return of_node == NULL || of_node == node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) static int ehv_pic_host_map(struct irq_domain *h, unsigned int virq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) irq_hw_number_t hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) struct ehv_pic *ehv_pic = h->host_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) struct irq_chip *chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) /* Default chip */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) chip = &ehv_pic->hc_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (mpic_percpu_base_vaddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) if (hwirq_intspec[hw] & IRQ_TYPE_MPIC_DIRECT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) chip = &ehv_pic_direct_eoi_irq_chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) irq_set_chip_data(virq, chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) * using handle_fasteoi_irq as our irq handler, this will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) * only call the eoi callback and suitable for the MPIC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) * controller which set ISR/IPR automatically and clear the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) * highest priority active interrupt in ISR/IPR when we do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) * a specific eoi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) irq_set_chip_and_handler(virq, chip, handle_fasteoi_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) /* Set default irq type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) irq_set_irq_type(virq, IRQ_TYPE_NONE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) static int ehv_pic_host_xlate(struct irq_domain *h, struct device_node *ct,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) const u32 *intspec, unsigned int intsize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) irq_hw_number_t *out_hwirq, unsigned int *out_flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) * interrupt sense values coming from the guest device tree
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) * interrupt specifiers can have four possible sense and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) * level encoding information and they need to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) * be translated between firmware type & linux type.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) static unsigned char map_of_senses_to_linux_irqtype[4] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) IRQ_TYPE_EDGE_FALLING,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) IRQ_TYPE_EDGE_RISING,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) IRQ_TYPE_LEVEL_LOW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) IRQ_TYPE_LEVEL_HIGH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) *out_hwirq = intspec[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (intsize > 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) hwirq_intspec[intspec[0]] = intspec[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) *out_flags = map_of_senses_to_linux_irqtype[intspec[1] &
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) ~IRQ_TYPE_MPIC_DIRECT];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) *out_flags = IRQ_TYPE_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) static const struct irq_domain_ops ehv_pic_host_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) .match = ehv_pic_host_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) .map = ehv_pic_host_map,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) .xlate = ehv_pic_host_xlate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) void __init ehv_pic_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) struct device_node *np, *np2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) struct ehv_pic *ehv_pic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) int coreint_flag = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) np = of_find_compatible_node(NULL, NULL, "epapr,hv-pic");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) if (!np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) pr_err("ehv_pic_init: could not find epapr,hv-pic node\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if (!of_find_property(np, "has-external-proxy", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) coreint_flag = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) ehv_pic = kzalloc(sizeof(struct ehv_pic), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) if (!ehv_pic) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) ehv_pic->irqhost = irq_domain_add_linear(np, NR_EHV_PIC_INTS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) &ehv_pic_host_ops, ehv_pic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) if (!ehv_pic->irqhost) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) of_node_put(np);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) kfree(ehv_pic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) np2 = of_find_compatible_node(NULL, NULL, "fsl,hv-mpic-per-cpu");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) if (np2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) mpic_percpu_base_vaddr = of_iomap(np2, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (!mpic_percpu_base_vaddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) pr_err("ehv_pic_init: of_iomap failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) of_node_put(np2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) ehv_pic->hc_irq = ehv_pic_irq_chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) ehv_pic->hc_irq.irq_set_affinity = ehv_pic_set_affinity;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) ehv_pic->coreint_flag = coreint_flag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) global_ehv_pic = ehv_pic;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) irq_set_default_host(global_ehv_pic->irqhost);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }