12299c49dSSteven J. Hill /* 22299c49dSSteven J. Hill * This file is subject to the terms and conditions of the GNU General Public 32299c49dSSteven J. Hill * License. See the file "COPYING" in the main directory of this archive 42299c49dSSteven J. Hill * for more details. 52299c49dSSteven J. Hill * 62299c49dSSteven J. Hill * Copyright (C) 2008 Ralf Baechle (ralf@linux-mips.org) 72299c49dSSteven J. Hill * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. 82299c49dSSteven J. Hill */ 91f19aee0SMatt Redfearn 101f19aee0SMatt Redfearn #define pr_fmt(fmt) "irq-mips-gic: " fmt 111f19aee0SMatt Redfearn 12357a9c4bSGeert Uytterhoeven #include <linux/bitfield.h> 1339b8d525SRalf Baechle #include <linux/bitmap.h> 14fb8f7be1SAndrew Bresticker #include <linux/clocksource.h> 15da61fcf9SPaul Burton #include <linux/cpuhotplug.h> 1639b8d525SRalf Baechle #include <linux/init.h> 1718743d27SAndrew Bresticker #include <linux/interrupt.h> 18fb8f7be1SAndrew Bresticker #include <linux/irq.h> 1941a83e06SJoel Porquet #include <linux/irqchip.h> 201982752fSMarc Zyngier #include <linux/irqdomain.h> 21a7057270SAndrew Bresticker #include <linux/of_address.h> 22aa493737SPaul Burton #include <linux/percpu.h> 2318743d27SAndrew Bresticker #include <linux/sched.h> 24631330f5SRalf Baechle #include <linux/smp.h> 2539b8d525SRalf Baechle 26e83f7e02SPaul Burton #include <asm/mips-cps.h> 2798b67c37SSteven J. Hill #include <asm/setup.h> 2898b67c37SSteven J. Hill #include <asm/traps.h> 2939b8d525SRalf Baechle 30a7057270SAndrew Bresticker #include <dt-bindings/interrupt-controller/mips-gic.h> 31a7057270SAndrew Bresticker 32b11d4c1fSPaul Burton #define GIC_MAX_INTRS 256 33aa493737SPaul Burton #define GIC_MAX_LONGS BITS_TO_LONGS(GIC_MAX_INTRS) 3498b67c37SSteven J. Hill 35b11d4c1fSPaul Burton /* Add 2 to convert GIC CPU pin to core interrupt */ 36b11d4c1fSPaul Burton #define GIC_CPU_PIN_OFFSET 2 37822350bcSJeffrey Deans 38b11d4c1fSPaul Burton /* Mapped interrupt to pin X, then GIC will generate the vector (X+1). */ 39b11d4c1fSPaul Burton #define GIC_PIN_TO_VEC_OFFSET 1 402af70a96SQais Yousef 41b11d4c1fSPaul Burton /* Convert between local/shared IRQ number and GIC HW IRQ number. */ 42b11d4c1fSPaul Burton #define GIC_LOCAL_HWIRQ_BASE 0 43b11d4c1fSPaul Burton #define GIC_LOCAL_TO_HWIRQ(x) (GIC_LOCAL_HWIRQ_BASE + (x)) 44b11d4c1fSPaul Burton #define GIC_HWIRQ_TO_LOCAL(x) ((x) - GIC_LOCAL_HWIRQ_BASE) 45b11d4c1fSPaul Burton #define GIC_SHARED_HWIRQ_BASE GIC_NUM_LOCAL_INTRS 46b11d4c1fSPaul Burton #define GIC_SHARED_TO_HWIRQ(x) (GIC_SHARED_HWIRQ_BASE + (x)) 47b11d4c1fSPaul Burton #define GIC_HWIRQ_TO_SHARED(x) ((x) - GIC_SHARED_HWIRQ_BASE) 48b11d4c1fSPaul Burton 49582e2b4aSPaul Burton void __iomem *mips_gic_base; 500b271f56SSteven J. Hill 51b0e453ffSWei Yongjun static DEFINE_PER_CPU_READ_MOSTLY(unsigned long[GIC_MAX_LONGS], pcpu_masks); 52822350bcSJeffrey Deans 5395150ae8SAndrew Bresticker static DEFINE_SPINLOCK(gic_lock); 54c49581a4SAndrew Bresticker static struct irq_domain *gic_irq_domain; 552af70a96SQais Yousef static struct irq_domain *gic_ipi_domain; 56fbd55241SAndrew Bresticker static int gic_shared_intrs; 573263d085SAndrew Bresticker static unsigned int gic_cpu_pin; 581b6af71aSJames Hogan static unsigned int timer_cpu_pin; 594a6a3ea3SAndrew Bresticker static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; 6061dc367eSPaul Burton static DECLARE_BITMAP(ipi_resrv, GIC_MAX_INTRS); 6161dc367eSPaul Burton static DECLARE_BITMAP(ipi_available, GIC_MAX_INTRS); 6239b8d525SRalf Baechle 63da61fcf9SPaul Burton static struct gic_all_vpes_chip_data { 64da61fcf9SPaul Burton u32 map; 65da61fcf9SPaul Burton bool mask; 66da61fcf9SPaul Burton } gic_all_vpes_chip_data[GIC_NUM_LOCAL_INTRS]; 67da61fcf9SPaul Burton 687778c4b2SPaul Burton static void gic_clear_pcpu_masks(unsigned int intr) 695f68fea0SAndrew Bresticker { 707778c4b2SPaul Burton unsigned int i; 715f68fea0SAndrew Bresticker 727778c4b2SPaul Burton /* Clear the interrupt's bit in all pcpu_masks */ 737778c4b2SPaul Burton for_each_possible_cpu(i) 747778c4b2SPaul Burton clear_bit(intr, per_cpu_ptr(pcpu_masks, i)); 75835d2b45SPaul Burton } 76835d2b45SPaul Burton 77e9de688dSAndrew Bresticker static bool gic_local_irq_is_routable(int intr) 78e9de688dSAndrew Bresticker { 79e9de688dSAndrew Bresticker u32 vpe_ctl; 80e9de688dSAndrew Bresticker 81e9de688dSAndrew Bresticker /* All local interrupts are routable in EIC mode. */ 82e9de688dSAndrew Bresticker if (cpu_has_veic) 83e9de688dSAndrew Bresticker return true; 84e9de688dSAndrew Bresticker 850d0cf58cSPaul Burton vpe_ctl = read_gic_vl_ctl(); 86e9de688dSAndrew Bresticker switch (intr) { 87e9de688dSAndrew Bresticker case GIC_LOCAL_INT_TIMER: 880d0cf58cSPaul Burton return vpe_ctl & GIC_VX_CTL_TIMER_ROUTABLE; 89e9de688dSAndrew Bresticker case GIC_LOCAL_INT_PERFCTR: 900d0cf58cSPaul Burton return vpe_ctl & GIC_VX_CTL_PERFCNT_ROUTABLE; 91e9de688dSAndrew Bresticker case GIC_LOCAL_INT_FDC: 920d0cf58cSPaul Burton return vpe_ctl & GIC_VX_CTL_FDC_ROUTABLE; 93e9de688dSAndrew Bresticker case GIC_LOCAL_INT_SWINT0: 94e9de688dSAndrew Bresticker case GIC_LOCAL_INT_SWINT1: 950d0cf58cSPaul Burton return vpe_ctl & GIC_VX_CTL_SWINT_ROUTABLE; 96e9de688dSAndrew Bresticker default: 97e9de688dSAndrew Bresticker return true; 98e9de688dSAndrew Bresticker } 99e9de688dSAndrew Bresticker } 100e9de688dSAndrew Bresticker 1013263d085SAndrew Bresticker static void gic_bind_eic_interrupt(int irq, int set) 10298b67c37SSteven J. Hill { 10398b67c37SSteven J. Hill /* Convert irq vector # to hw int # */ 10498b67c37SSteven J. Hill irq -= GIC_PIN_TO_VEC_OFFSET; 10598b67c37SSteven J. Hill 10698b67c37SSteven J. Hill /* Set irq to use shadow set */ 1070d0cf58cSPaul Burton write_gic_vl_eic_shadow_set(irq, set); 10898b67c37SSteven J. Hill } 10998b67c37SSteven J. Hill 110bb11cff3SQais Yousef static void gic_send_ipi(struct irq_data *d, unsigned int cpu) 11139b8d525SRalf Baechle { 112bb11cff3SQais Yousef irq_hw_number_t hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(d)); 113bb11cff3SQais Yousef 1143680746aSPaul Burton write_gic_wedge(GIC_WEDGE_RW | hwirq); 11539b8d525SRalf Baechle } 11639b8d525SRalf Baechle 117e9de688dSAndrew Bresticker int gic_get_c0_compare_int(void) 118e9de688dSAndrew Bresticker { 119e9de688dSAndrew Bresticker if (!gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) 120e9de688dSAndrew Bresticker return MIPS_CPU_IRQ_BASE + cp0_compare_irq; 121e9de688dSAndrew Bresticker return irq_create_mapping(gic_irq_domain, 122e9de688dSAndrew Bresticker GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_TIMER)); 123e9de688dSAndrew Bresticker } 124e9de688dSAndrew Bresticker 125e9de688dSAndrew Bresticker int gic_get_c0_perfcount_int(void) 126e9de688dSAndrew Bresticker { 127e9de688dSAndrew Bresticker if (!gic_local_irq_is_routable(GIC_LOCAL_INT_PERFCTR)) { 1287e3e6cb2SJames Hogan /* Is the performance counter shared with the timer? */ 129e9de688dSAndrew Bresticker if (cp0_perfcount_irq < 0) 130e9de688dSAndrew Bresticker return -1; 131e9de688dSAndrew Bresticker return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; 132e9de688dSAndrew Bresticker } 133e9de688dSAndrew Bresticker return irq_create_mapping(gic_irq_domain, 134e9de688dSAndrew Bresticker GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_PERFCTR)); 135e9de688dSAndrew Bresticker } 136e9de688dSAndrew Bresticker 1376429e2b6SJames Hogan int gic_get_c0_fdc_int(void) 1386429e2b6SJames Hogan { 1396429e2b6SJames Hogan if (!gic_local_irq_is_routable(GIC_LOCAL_INT_FDC)) { 1406429e2b6SJames Hogan /* Is the FDC IRQ even present? */ 1416429e2b6SJames Hogan if (cp0_fdc_irq < 0) 1426429e2b6SJames Hogan return -1; 1436429e2b6SJames Hogan return MIPS_CPU_IRQ_BASE + cp0_fdc_irq; 1446429e2b6SJames Hogan } 1456429e2b6SJames Hogan 1466429e2b6SJames Hogan return irq_create_mapping(gic_irq_domain, 1476429e2b6SJames Hogan GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_FDC)); 1486429e2b6SJames Hogan } 1496429e2b6SJames Hogan 1501b3ed367SRabin Vincent static void gic_handle_shared_int(bool chained) 15139b8d525SRalf Baechle { 152046a6ee2SMarc Zyngier unsigned int intr; 1538f5ee79cSAndrew Bresticker unsigned long *pcpu_mask; 1548f5ee79cSAndrew Bresticker DECLARE_BITMAP(pending, GIC_MAX_INTRS); 15539b8d525SRalf Baechle 15639b8d525SRalf Baechle /* Get per-cpu bitmaps */ 157aa493737SPaul Burton pcpu_mask = this_cpu_ptr(pcpu_masks); 15839b8d525SRalf Baechle 1597778c4b2SPaul Burton if (mips_cm_is64) 160e98fcb2aSPaul Burton __ioread64_copy(pending, addr_gic_pend(), 161e98fcb2aSPaul Burton DIV_ROUND_UP(gic_shared_intrs, 64)); 1627778c4b2SPaul Burton else 163e98fcb2aSPaul Burton __ioread32_copy(pending, addr_gic_pend(), 164e98fcb2aSPaul Burton DIV_ROUND_UP(gic_shared_intrs, 32)); 16539b8d525SRalf Baechle 166fbd55241SAndrew Bresticker bitmap_and(pending, pending, pcpu_mask, gic_shared_intrs); 16739b8d525SRalf Baechle 168cae750baSPaul Burton for_each_set_bit(intr, pending, gic_shared_intrs) { 1691b3ed367SRabin Vincent if (chained) 170046a6ee2SMarc Zyngier generic_handle_domain_irq(gic_irq_domain, 171046a6ee2SMarc Zyngier GIC_SHARED_TO_HWIRQ(intr)); 1721b3ed367SRabin Vincent else 1731fee9db9SMarc Zyngier do_domain_IRQ(gic_irq_domain, 1741fee9db9SMarc Zyngier GIC_SHARED_TO_HWIRQ(intr)); 175d7eb4f2eSQais Yousef } 17639b8d525SRalf Baechle } 17739b8d525SRalf Baechle 178161d049eSThomas Gleixner static void gic_mask_irq(struct irq_data *d) 17939b8d525SRalf Baechle { 1807778c4b2SPaul Burton unsigned int intr = GIC_HWIRQ_TO_SHARED(d->hwirq); 1817778c4b2SPaul Burton 18290019f8fSPaul Burton write_gic_rmask(intr); 1837778c4b2SPaul Burton gic_clear_pcpu_masks(intr); 18439b8d525SRalf Baechle } 18539b8d525SRalf Baechle 186161d049eSThomas Gleixner static void gic_unmask_irq(struct irq_data *d) 18739b8d525SRalf Baechle { 1887778c4b2SPaul Burton unsigned int intr = GIC_HWIRQ_TO_SHARED(d->hwirq); 1897778c4b2SPaul Burton unsigned int cpu; 1907778c4b2SPaul Burton 19190019f8fSPaul Burton write_gic_smask(intr); 1927778c4b2SPaul Burton 1937778c4b2SPaul Burton gic_clear_pcpu_masks(intr); 194d9f82930SPaul Burton cpu = cpumask_first(irq_data_get_effective_affinity_mask(d)); 1957778c4b2SPaul Burton set_bit(intr, per_cpu_ptr(pcpu_masks, cpu)); 19639b8d525SRalf Baechle } 19739b8d525SRalf Baechle 1985561c9e4SAndrew Bresticker static void gic_ack_irq(struct irq_data *d) 1995561c9e4SAndrew Bresticker { 200e9de688dSAndrew Bresticker unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq); 201c49581a4SAndrew Bresticker 2023680746aSPaul Burton write_gic_wedge(irq); 2035561c9e4SAndrew Bresticker } 2045561c9e4SAndrew Bresticker 20595150ae8SAndrew Bresticker static int gic_set_type(struct irq_data *d, unsigned int type) 20695150ae8SAndrew Bresticker { 2075af3e93eSPaul Burton unsigned int irq, pol, trig, dual; 20895150ae8SAndrew Bresticker unsigned long flags; 2095af3e93eSPaul Burton 2105af3e93eSPaul Burton irq = GIC_HWIRQ_TO_SHARED(d->hwirq); 21139b8d525SRalf Baechle 21295150ae8SAndrew Bresticker spin_lock_irqsave(&gic_lock, flags); 21395150ae8SAndrew Bresticker switch (type & IRQ_TYPE_SENSE_MASK) { 21495150ae8SAndrew Bresticker case IRQ_TYPE_EDGE_FALLING: 2155af3e93eSPaul Burton pol = GIC_POL_FALLING_EDGE; 2165af3e93eSPaul Burton trig = GIC_TRIG_EDGE; 2175af3e93eSPaul Burton dual = GIC_DUAL_SINGLE; 21895150ae8SAndrew Bresticker break; 21995150ae8SAndrew Bresticker case IRQ_TYPE_EDGE_RISING: 2205af3e93eSPaul Burton pol = GIC_POL_RISING_EDGE; 2215af3e93eSPaul Burton trig = GIC_TRIG_EDGE; 2225af3e93eSPaul Burton dual = GIC_DUAL_SINGLE; 22395150ae8SAndrew Bresticker break; 22495150ae8SAndrew Bresticker case IRQ_TYPE_EDGE_BOTH: 2255af3e93eSPaul Burton pol = 0; /* Doesn't matter */ 2265af3e93eSPaul Burton trig = GIC_TRIG_EDGE; 2275af3e93eSPaul Burton dual = GIC_DUAL_DUAL; 22895150ae8SAndrew Bresticker break; 22995150ae8SAndrew Bresticker case IRQ_TYPE_LEVEL_LOW: 2305af3e93eSPaul Burton pol = GIC_POL_ACTIVE_LOW; 2315af3e93eSPaul Burton trig = GIC_TRIG_LEVEL; 2325af3e93eSPaul Burton dual = GIC_DUAL_SINGLE; 23395150ae8SAndrew Bresticker break; 23495150ae8SAndrew Bresticker case IRQ_TYPE_LEVEL_HIGH: 23595150ae8SAndrew Bresticker default: 2365af3e93eSPaul Burton pol = GIC_POL_ACTIVE_HIGH; 2375af3e93eSPaul Burton trig = GIC_TRIG_LEVEL; 2385af3e93eSPaul Burton dual = GIC_DUAL_SINGLE; 23995150ae8SAndrew Bresticker break; 24095150ae8SAndrew Bresticker } 24195150ae8SAndrew Bresticker 2425af3e93eSPaul Burton change_gic_pol(irq, pol); 2435af3e93eSPaul Burton change_gic_trig(irq, trig); 2445af3e93eSPaul Burton change_gic_dual(irq, dual); 2455af3e93eSPaul Burton 2465af3e93eSPaul Burton if (trig == GIC_TRIG_EDGE) 247a595fc51SThomas Gleixner irq_set_chip_handler_name_locked(d, &gic_edge_irq_controller, 2484a6a3ea3SAndrew Bresticker handle_edge_irq, NULL); 249a595fc51SThomas Gleixner else 250a595fc51SThomas Gleixner irq_set_chip_handler_name_locked(d, &gic_level_irq_controller, 2514a6a3ea3SAndrew Bresticker handle_level_irq, NULL); 25295150ae8SAndrew Bresticker spin_unlock_irqrestore(&gic_lock, flags); 25395150ae8SAndrew Bresticker 25495150ae8SAndrew Bresticker return 0; 25595150ae8SAndrew Bresticker } 25695150ae8SAndrew Bresticker 25795150ae8SAndrew Bresticker #ifdef CONFIG_SMP 258161d049eSThomas Gleixner static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, 259161d049eSThomas Gleixner bool force) 26039b8d525SRalf Baechle { 261e9de688dSAndrew Bresticker unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq); 26239b8d525SRalf Baechle unsigned long flags; 26307df8bfeSPaul Burton unsigned int cpu; 26439b8d525SRalf Baechle 26507df8bfeSPaul Burton cpu = cpumask_first_and(cpumask, cpu_online_mask); 26607df8bfeSPaul Burton if (cpu >= NR_CPUS) 26714d160abSAndrew Bresticker return -EINVAL; 26839b8d525SRalf Baechle 26939b8d525SRalf Baechle /* Assumption : cpumask refers to a single CPU */ 27039b8d525SRalf Baechle spin_lock_irqsave(&gic_lock, flags); 271c214c035STony Wu 27239b8d525SRalf Baechle /* Re-route this IRQ */ 27307df8bfeSPaul Burton write_gic_map_vp(irq, BIT(mips_cm_vp_id(cpu))); 27439b8d525SRalf Baechle 27539b8d525SRalf Baechle /* Update the pcpu_masks */ 2767778c4b2SPaul Burton gic_clear_pcpu_masks(irq); 2777778c4b2SPaul Burton if (read_gic_mask(irq)) 27807df8bfeSPaul Burton set_bit(irq, per_cpu_ptr(pcpu_masks, cpu)); 27939b8d525SRalf Baechle 28018416e45SMarc Zyngier irq_data_update_effective_affinity(d, cpumask_of(cpu)); 28139b8d525SRalf Baechle spin_unlock_irqrestore(&gic_lock, flags); 28239b8d525SRalf Baechle 2837f15a648SPaul Burton return IRQ_SET_MASK_OK; 28439b8d525SRalf Baechle } 28539b8d525SRalf Baechle #endif 28639b8d525SRalf Baechle 2874a6a3ea3SAndrew Bresticker static struct irq_chip gic_level_irq_controller = { 2884a6a3ea3SAndrew Bresticker .name = "MIPS GIC", 2894a6a3ea3SAndrew Bresticker .irq_mask = gic_mask_irq, 2904a6a3ea3SAndrew Bresticker .irq_unmask = gic_unmask_irq, 2914a6a3ea3SAndrew Bresticker .irq_set_type = gic_set_type, 2924a6a3ea3SAndrew Bresticker #ifdef CONFIG_SMP 2934a6a3ea3SAndrew Bresticker .irq_set_affinity = gic_set_affinity, 2944a6a3ea3SAndrew Bresticker #endif 2954a6a3ea3SAndrew Bresticker }; 2964a6a3ea3SAndrew Bresticker 2974a6a3ea3SAndrew Bresticker static struct irq_chip gic_edge_irq_controller = { 29839b8d525SRalf Baechle .name = "MIPS GIC", 2995561c9e4SAndrew Bresticker .irq_ack = gic_ack_irq, 300161d049eSThomas Gleixner .irq_mask = gic_mask_irq, 301161d049eSThomas Gleixner .irq_unmask = gic_unmask_irq, 30295150ae8SAndrew Bresticker .irq_set_type = gic_set_type, 30339b8d525SRalf Baechle #ifdef CONFIG_SMP 304161d049eSThomas Gleixner .irq_set_affinity = gic_set_affinity, 30539b8d525SRalf Baechle #endif 306bb11cff3SQais Yousef .ipi_send_single = gic_send_ipi, 30739b8d525SRalf Baechle }; 30839b8d525SRalf Baechle 3091b3ed367SRabin Vincent static void gic_handle_local_int(bool chained) 310e9de688dSAndrew Bresticker { 311e9de688dSAndrew Bresticker unsigned long pending, masked; 312046a6ee2SMarc Zyngier unsigned int intr; 313e9de688dSAndrew Bresticker 3149da3c645SPaul Burton pending = read_gic_vl_pend(); 3159da3c645SPaul Burton masked = read_gic_vl_mask(); 316e9de688dSAndrew Bresticker 317e9de688dSAndrew Bresticker bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS); 318e9de688dSAndrew Bresticker 3190f4ed158SPaul Burton for_each_set_bit(intr, &pending, GIC_NUM_LOCAL_INTRS) { 3201b3ed367SRabin Vincent if (chained) 321046a6ee2SMarc Zyngier generic_handle_domain_irq(gic_irq_domain, 322046a6ee2SMarc Zyngier GIC_LOCAL_TO_HWIRQ(intr)); 3231b3ed367SRabin Vincent else 3241fee9db9SMarc Zyngier do_domain_IRQ(gic_irq_domain, 3251fee9db9SMarc Zyngier GIC_LOCAL_TO_HWIRQ(intr)); 326d7eb4f2eSQais Yousef } 327e9de688dSAndrew Bresticker } 328e9de688dSAndrew Bresticker 329e9de688dSAndrew Bresticker static void gic_mask_local_irq(struct irq_data *d) 330e9de688dSAndrew Bresticker { 331e9de688dSAndrew Bresticker int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); 332e9de688dSAndrew Bresticker 3339da3c645SPaul Burton write_gic_vl_rmask(BIT(intr)); 334e9de688dSAndrew Bresticker } 335e9de688dSAndrew Bresticker 336e9de688dSAndrew Bresticker static void gic_unmask_local_irq(struct irq_data *d) 337e9de688dSAndrew Bresticker { 338e9de688dSAndrew Bresticker int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); 339e9de688dSAndrew Bresticker 3409da3c645SPaul Burton write_gic_vl_smask(BIT(intr)); 341e9de688dSAndrew Bresticker } 342e9de688dSAndrew Bresticker 343e9de688dSAndrew Bresticker static struct irq_chip gic_local_irq_controller = { 344e9de688dSAndrew Bresticker .name = "MIPS GIC Local", 345e9de688dSAndrew Bresticker .irq_mask = gic_mask_local_irq, 346e9de688dSAndrew Bresticker .irq_unmask = gic_unmask_local_irq, 347e9de688dSAndrew Bresticker }; 348e9de688dSAndrew Bresticker 349e9de688dSAndrew Bresticker static void gic_mask_local_irq_all_vpes(struct irq_data *d) 350e9de688dSAndrew Bresticker { 351da61fcf9SPaul Burton struct gic_all_vpes_chip_data *cd; 352e9de688dSAndrew Bresticker unsigned long flags; 353da61fcf9SPaul Burton int intr, cpu; 354da61fcf9SPaul Burton 355da61fcf9SPaul Burton intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); 356da61fcf9SPaul Burton cd = irq_data_get_irq_chip_data(d); 357da61fcf9SPaul Burton cd->mask = false; 358e9de688dSAndrew Bresticker 359e9de688dSAndrew Bresticker spin_lock_irqsave(&gic_lock, flags); 360da61fcf9SPaul Burton for_each_online_cpu(cpu) { 361da61fcf9SPaul Burton write_gic_vl_other(mips_cm_vp_id(cpu)); 3629da3c645SPaul Burton write_gic_vo_rmask(BIT(intr)); 363e9de688dSAndrew Bresticker } 364e9de688dSAndrew Bresticker spin_unlock_irqrestore(&gic_lock, flags); 365e9de688dSAndrew Bresticker } 366e9de688dSAndrew Bresticker 367e9de688dSAndrew Bresticker static void gic_unmask_local_irq_all_vpes(struct irq_data *d) 368e9de688dSAndrew Bresticker { 369da61fcf9SPaul Burton struct gic_all_vpes_chip_data *cd; 370e9de688dSAndrew Bresticker unsigned long flags; 371da61fcf9SPaul Burton int intr, cpu; 372da61fcf9SPaul Burton 373da61fcf9SPaul Burton intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); 374da61fcf9SPaul Burton cd = irq_data_get_irq_chip_data(d); 375da61fcf9SPaul Burton cd->mask = true; 376e9de688dSAndrew Bresticker 377e9de688dSAndrew Bresticker spin_lock_irqsave(&gic_lock, flags); 378da61fcf9SPaul Burton for_each_online_cpu(cpu) { 379da61fcf9SPaul Burton write_gic_vl_other(mips_cm_vp_id(cpu)); 3809da3c645SPaul Burton write_gic_vo_smask(BIT(intr)); 381e9de688dSAndrew Bresticker } 382e9de688dSAndrew Bresticker spin_unlock_irqrestore(&gic_lock, flags); 383e9de688dSAndrew Bresticker } 384e9de688dSAndrew Bresticker 385dd098a0eSMarc Zyngier static void gic_all_vpes_irq_cpu_online(void) 386da61fcf9SPaul Burton { 387dd098a0eSMarc Zyngier static const unsigned int local_intrs[] = { 388dd098a0eSMarc Zyngier GIC_LOCAL_INT_TIMER, 389dd098a0eSMarc Zyngier GIC_LOCAL_INT_PERFCTR, 390dd098a0eSMarc Zyngier GIC_LOCAL_INT_FDC, 391dd098a0eSMarc Zyngier }; 392dd098a0eSMarc Zyngier unsigned long flags; 393dd098a0eSMarc Zyngier int i; 394dd098a0eSMarc Zyngier 395dd098a0eSMarc Zyngier spin_lock_irqsave(&gic_lock, flags); 396dd098a0eSMarc Zyngier 397dd098a0eSMarc Zyngier for (i = 0; i < ARRAY_SIZE(local_intrs); i++) { 398dd098a0eSMarc Zyngier unsigned int intr = local_intrs[i]; 399da61fcf9SPaul Burton struct gic_all_vpes_chip_data *cd; 400da61fcf9SPaul Burton 401dd098a0eSMarc Zyngier cd = &gic_all_vpes_chip_data[intr]; 4026d4d367dSPaul Burton write_gic_vl_map(mips_gic_vx_map_reg(intr), cd->map); 403da61fcf9SPaul Burton if (cd->mask) 404da61fcf9SPaul Burton write_gic_vl_smask(BIT(intr)); 405da61fcf9SPaul Burton } 406da61fcf9SPaul Burton 407dd098a0eSMarc Zyngier spin_unlock_irqrestore(&gic_lock, flags); 408dd098a0eSMarc Zyngier } 409dd098a0eSMarc Zyngier 410e9de688dSAndrew Bresticker static struct irq_chip gic_all_vpes_local_irq_controller = { 411e9de688dSAndrew Bresticker .name = "MIPS GIC Local", 412e9de688dSAndrew Bresticker .irq_mask = gic_mask_local_irq_all_vpes, 413e9de688dSAndrew Bresticker .irq_unmask = gic_unmask_local_irq_all_vpes, 414e9de688dSAndrew Bresticker }; 415e9de688dSAndrew Bresticker 41618743d27SAndrew Bresticker static void __gic_irq_dispatch(void) 41739b8d525SRalf Baechle { 4181b3ed367SRabin Vincent gic_handle_local_int(false); 4191b3ed367SRabin Vincent gic_handle_shared_int(false); 42018743d27SAndrew Bresticker } 42118743d27SAndrew Bresticker 422bd0b9ac4SThomas Gleixner static void gic_irq_dispatch(struct irq_desc *desc) 42318743d27SAndrew Bresticker { 4241b3ed367SRabin Vincent gic_handle_local_int(true); 4251b3ed367SRabin Vincent gic_handle_shared_int(true); 42618743d27SAndrew Bresticker } 42718743d27SAndrew Bresticker 428e9de688dSAndrew Bresticker static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq, 4297778c4b2SPaul Burton irq_hw_number_t hw, unsigned int cpu) 430e9de688dSAndrew Bresticker { 431e9de688dSAndrew Bresticker int intr = GIC_HWIRQ_TO_SHARED(hw); 432d9f82930SPaul Burton struct irq_data *data; 433c49581a4SAndrew Bresticker unsigned long flags; 434c49581a4SAndrew Bresticker 435d9f82930SPaul Burton data = irq_get_irq_data(virq); 436d9f82930SPaul Burton 437c49581a4SAndrew Bresticker spin_lock_irqsave(&gic_lock, flags); 438d3e8cf44SPaul Burton write_gic_map_pin(intr, GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin); 4397778c4b2SPaul Burton write_gic_map_vp(intr, BIT(mips_cm_vp_id(cpu))); 440d9f82930SPaul Burton irq_data_update_effective_affinity(data, cpumask_of(cpu)); 441c49581a4SAndrew Bresticker spin_unlock_irqrestore(&gic_lock, flags); 442c49581a4SAndrew Bresticker 443c49581a4SAndrew Bresticker return 0; 444c49581a4SAndrew Bresticker } 445c49581a4SAndrew Bresticker 446b87281e7SPaul Burton static int gic_irq_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, 447c98c1822SQais Yousef const u32 *intspec, unsigned int intsize, 448c98c1822SQais Yousef irq_hw_number_t *out_hwirq, 449c98c1822SQais Yousef unsigned int *out_type) 450c98c1822SQais Yousef { 451c98c1822SQais Yousef if (intsize != 3) 452c98c1822SQais Yousef return -EINVAL; 453c98c1822SQais Yousef 454c98c1822SQais Yousef if (intspec[0] == GIC_SHARED) 455c98c1822SQais Yousef *out_hwirq = GIC_SHARED_TO_HWIRQ(intspec[1]); 456c98c1822SQais Yousef else if (intspec[0] == GIC_LOCAL) 457c98c1822SQais Yousef *out_hwirq = GIC_LOCAL_TO_HWIRQ(intspec[1]); 458c98c1822SQais Yousef else 459c98c1822SQais Yousef return -EINVAL; 460c98c1822SQais Yousef *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; 461c98c1822SQais Yousef 462c98c1822SQais Yousef return 0; 463c98c1822SQais Yousef } 464c98c1822SQais Yousef 4658ada00a6SMatt Redfearn static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, 4668ada00a6SMatt Redfearn irq_hw_number_t hwirq) 467c98c1822SQais Yousef { 468da61fcf9SPaul Burton struct gic_all_vpes_chip_data *cd; 46963b746b1SPaul Burton unsigned long flags; 47063b746b1SPaul Burton unsigned int intr; 471da61fcf9SPaul Burton int err, cpu; 47263b746b1SPaul Burton u32 map; 473c98c1822SQais Yousef 4748ada00a6SMatt Redfearn if (hwirq >= GIC_SHARED_HWIRQ_BASE) { 475b87281e7SPaul Burton /* verify that shared irqs don't conflict with an IPI irq */ 476b87281e7SPaul Burton if (test_bit(GIC_HWIRQ_TO_SHARED(hwirq), ipi_resrv)) 477b87281e7SPaul Burton return -EBUSY; 478c98c1822SQais Yousef 479b87281e7SPaul Burton err = irq_domain_set_hwirq_and_chip(d, virq, hwirq, 480b87281e7SPaul Burton &gic_level_irq_controller, 481b87281e7SPaul Burton NULL); 482b87281e7SPaul Burton if (err) 483b87281e7SPaul Burton return err; 484b87281e7SPaul Burton 48518416e45SMarc Zyngier irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq))); 486b87281e7SPaul Burton return gic_shared_irq_domain_map(d, virq, hwirq, 0); 487c98c1822SQais Yousef } 488c98c1822SQais Yousef 48963b746b1SPaul Burton intr = GIC_HWIRQ_TO_LOCAL(hwirq); 49063b746b1SPaul Burton map = GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin; 49163b746b1SPaul Burton 492dd098a0eSMarc Zyngier /* 493dd098a0eSMarc Zyngier * If adding support for more per-cpu interrupts, keep the the 494dd098a0eSMarc Zyngier * array in gic_all_vpes_irq_cpu_online() in sync. 495dd098a0eSMarc Zyngier */ 49663b746b1SPaul Burton switch (intr) { 497b87281e7SPaul Burton case GIC_LOCAL_INT_TIMER: 49863b746b1SPaul Burton /* CONFIG_MIPS_CMP workaround (see __gic_init) */ 49963b746b1SPaul Burton map = GIC_MAP_PIN_MAP_TO_PIN | timer_cpu_pin; 500df561f66SGustavo A. R. Silva fallthrough; 501b87281e7SPaul Burton case GIC_LOCAL_INT_PERFCTR: 502b87281e7SPaul Burton case GIC_LOCAL_INT_FDC: 503b87281e7SPaul Burton /* 504b87281e7SPaul Burton * HACK: These are all really percpu interrupts, but 505b87281e7SPaul Burton * the rest of the MIPS kernel code does not use the 506b87281e7SPaul Burton * percpu IRQ API for them. 507b87281e7SPaul Burton */ 508da61fcf9SPaul Burton cd = &gic_all_vpes_chip_data[intr]; 509da61fcf9SPaul Burton cd->map = map; 510b87281e7SPaul Burton err = irq_domain_set_hwirq_and_chip(d, virq, hwirq, 511b87281e7SPaul Burton &gic_all_vpes_local_irq_controller, 512da61fcf9SPaul Burton cd); 513b87281e7SPaul Burton if (err) 514b87281e7SPaul Burton return err; 515b87281e7SPaul Burton 516b87281e7SPaul Burton irq_set_handler(virq, handle_percpu_irq); 517b87281e7SPaul Burton break; 518b87281e7SPaul Burton 519b87281e7SPaul Burton default: 520b87281e7SPaul Burton err = irq_domain_set_hwirq_and_chip(d, virq, hwirq, 521b87281e7SPaul Burton &gic_local_irq_controller, 522b87281e7SPaul Burton NULL); 523b87281e7SPaul Burton if (err) 524b87281e7SPaul Burton return err; 525b87281e7SPaul Burton 526b87281e7SPaul Burton irq_set_handler(virq, handle_percpu_devid_irq); 527b87281e7SPaul Burton irq_set_percpu_devid(virq); 528b87281e7SPaul Burton break; 529c98c1822SQais Yousef } 530c98c1822SQais Yousef 53163b746b1SPaul Burton if (!gic_local_irq_is_routable(intr)) 53263b746b1SPaul Burton return -EPERM; 53363b746b1SPaul Burton 53463b746b1SPaul Burton spin_lock_irqsave(&gic_lock, flags); 535da61fcf9SPaul Burton for_each_online_cpu(cpu) { 536da61fcf9SPaul Burton write_gic_vl_other(mips_cm_vp_id(cpu)); 5376d4d367dSPaul Burton write_gic_vo_map(mips_gic_vx_map_reg(intr), map); 53863b746b1SPaul Burton } 53963b746b1SPaul Burton spin_unlock_irqrestore(&gic_lock, flags); 54063b746b1SPaul Burton 54163b746b1SPaul Burton return 0; 542b87281e7SPaul Burton } 543b87281e7SPaul Burton 5448ada00a6SMatt Redfearn static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, 5458ada00a6SMatt Redfearn unsigned int nr_irqs, void *arg) 5468ada00a6SMatt Redfearn { 5478ada00a6SMatt Redfearn struct irq_fwspec *fwspec = arg; 5488ada00a6SMatt Redfearn irq_hw_number_t hwirq; 5498ada00a6SMatt Redfearn 5508ada00a6SMatt Redfearn if (fwspec->param[0] == GIC_SHARED) 5518ada00a6SMatt Redfearn hwirq = GIC_SHARED_TO_HWIRQ(fwspec->param[1]); 5528ada00a6SMatt Redfearn else 5538ada00a6SMatt Redfearn hwirq = GIC_LOCAL_TO_HWIRQ(fwspec->param[1]); 5548ada00a6SMatt Redfearn 5558ada00a6SMatt Redfearn return gic_irq_domain_map(d, virq, hwirq); 5568ada00a6SMatt Redfearn } 5578ada00a6SMatt Redfearn 558b87281e7SPaul Burton void gic_irq_domain_free(struct irq_domain *d, unsigned int virq, 559c98c1822SQais Yousef unsigned int nr_irqs) 560c98c1822SQais Yousef { 561c98c1822SQais Yousef } 562c98c1822SQais Yousef 563b87281e7SPaul Burton static const struct irq_domain_ops gic_irq_domain_ops = { 564b87281e7SPaul Burton .xlate = gic_irq_domain_xlate, 565b87281e7SPaul Burton .alloc = gic_irq_domain_alloc, 566b87281e7SPaul Burton .free = gic_irq_domain_free, 5678ada00a6SMatt Redfearn .map = gic_irq_domain_map, 5682af70a96SQais Yousef }; 5692af70a96SQais Yousef 5702af70a96SQais Yousef static int gic_ipi_domain_xlate(struct irq_domain *d, struct device_node *ctrlr, 5712af70a96SQais Yousef const u32 *intspec, unsigned int intsize, 5722af70a96SQais Yousef irq_hw_number_t *out_hwirq, 5732af70a96SQais Yousef unsigned int *out_type) 5742af70a96SQais Yousef { 5752af70a96SQais Yousef /* 5762af70a96SQais Yousef * There's nothing to translate here. hwirq is dynamically allocated and 5772af70a96SQais Yousef * the irq type is always edge triggered. 5782af70a96SQais Yousef * */ 5792af70a96SQais Yousef *out_hwirq = 0; 5802af70a96SQais Yousef *out_type = IRQ_TYPE_EDGE_RISING; 5812af70a96SQais Yousef 5822af70a96SQais Yousef return 0; 5832af70a96SQais Yousef } 5842af70a96SQais Yousef 5852af70a96SQais Yousef static int gic_ipi_domain_alloc(struct irq_domain *d, unsigned int virq, 5862af70a96SQais Yousef unsigned int nr_irqs, void *arg) 5872af70a96SQais Yousef { 5882af70a96SQais Yousef struct cpumask *ipimask = arg; 589b87281e7SPaul Burton irq_hw_number_t hwirq, base_hwirq; 590b87281e7SPaul Burton int cpu, ret, i; 5912af70a96SQais Yousef 592b87281e7SPaul Burton base_hwirq = find_first_bit(ipi_available, gic_shared_intrs); 593b87281e7SPaul Burton if (base_hwirq == gic_shared_intrs) 594b87281e7SPaul Burton return -ENOMEM; 595b87281e7SPaul Burton 596b87281e7SPaul Burton /* check that we have enough space */ 597b87281e7SPaul Burton for (i = base_hwirq; i < nr_irqs; i++) { 598b87281e7SPaul Burton if (!test_bit(i, ipi_available)) 599b87281e7SPaul Burton return -EBUSY; 600b87281e7SPaul Burton } 601b87281e7SPaul Burton bitmap_clear(ipi_available, base_hwirq, nr_irqs); 602b87281e7SPaul Burton 603b87281e7SPaul Burton /* map the hwirq for each cpu consecutively */ 604b87281e7SPaul Burton i = 0; 605b87281e7SPaul Burton for_each_cpu(cpu, ipimask) { 606b87281e7SPaul Burton hwirq = GIC_SHARED_TO_HWIRQ(base_hwirq + i); 607b87281e7SPaul Burton 608b87281e7SPaul Burton ret = irq_domain_set_hwirq_and_chip(d, virq + i, hwirq, 609b87281e7SPaul Burton &gic_edge_irq_controller, 610b87281e7SPaul Burton NULL); 6112af70a96SQais Yousef if (ret) 612b87281e7SPaul Burton goto error; 6132af70a96SQais Yousef 614b87281e7SPaul Burton ret = irq_domain_set_hwirq_and_chip(d->parent, virq + i, hwirq, 6152af70a96SQais Yousef &gic_edge_irq_controller, 6162af70a96SQais Yousef NULL); 6172af70a96SQais Yousef if (ret) 6182af70a96SQais Yousef goto error; 6192af70a96SQais Yousef 6202af70a96SQais Yousef ret = irq_set_irq_type(virq + i, IRQ_TYPE_EDGE_RISING); 6212af70a96SQais Yousef if (ret) 6222af70a96SQais Yousef goto error; 623b87281e7SPaul Burton 624b87281e7SPaul Burton ret = gic_shared_irq_domain_map(d, virq + i, hwirq, cpu); 625b87281e7SPaul Burton if (ret) 626b87281e7SPaul Burton goto error; 627b87281e7SPaul Burton 628b87281e7SPaul Burton i++; 6292af70a96SQais Yousef } 6302af70a96SQais Yousef 6312af70a96SQais Yousef return 0; 6322af70a96SQais Yousef error: 633b87281e7SPaul Burton bitmap_set(ipi_available, base_hwirq, nr_irqs); 6342af70a96SQais Yousef return ret; 6352af70a96SQais Yousef } 6362af70a96SQais Yousef 637b0e453ffSWei Yongjun static void gic_ipi_domain_free(struct irq_domain *d, unsigned int virq, 6382af70a96SQais Yousef unsigned int nr_irqs) 6392af70a96SQais Yousef { 640b87281e7SPaul Burton irq_hw_number_t base_hwirq; 641b87281e7SPaul Burton struct irq_data *data; 642b87281e7SPaul Burton 643b87281e7SPaul Burton data = irq_get_irq_data(virq); 644b87281e7SPaul Burton if (!data) 645b87281e7SPaul Burton return; 646b87281e7SPaul Burton 647b87281e7SPaul Burton base_hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(data)); 648b87281e7SPaul Burton bitmap_set(ipi_available, base_hwirq, nr_irqs); 6492af70a96SQais Yousef } 6502af70a96SQais Yousef 651b0e453ffSWei Yongjun static int gic_ipi_domain_match(struct irq_domain *d, struct device_node *node, 6522af70a96SQais Yousef enum irq_domain_bus_token bus_token) 6532af70a96SQais Yousef { 6542af70a96SQais Yousef bool is_ipi; 6552af70a96SQais Yousef 6562af70a96SQais Yousef switch (bus_token) { 6572af70a96SQais Yousef case DOMAIN_BUS_IPI: 6582af70a96SQais Yousef is_ipi = d->bus_token == bus_token; 659547aefc4SPaul Burton return (!node || to_of_node(d->fwnode) == node) && is_ipi; 6602af70a96SQais Yousef break; 6612af70a96SQais Yousef default: 6622af70a96SQais Yousef return 0; 6632af70a96SQais Yousef } 6642af70a96SQais Yousef } 6652af70a96SQais Yousef 6660b7e815aSTobias Klauser static const struct irq_domain_ops gic_ipi_domain_ops = { 6672af70a96SQais Yousef .xlate = gic_ipi_domain_xlate, 6682af70a96SQais Yousef .alloc = gic_ipi_domain_alloc, 6692af70a96SQais Yousef .free = gic_ipi_domain_free, 6702af70a96SQais Yousef .match = gic_ipi_domain_match, 671c49581a4SAndrew Bresticker }; 672c49581a4SAndrew Bresticker 673da61fcf9SPaul Burton static int gic_cpu_startup(unsigned int cpu) 674da61fcf9SPaul Burton { 675890f6b55SPaul Burton /* Enable or disable EIC */ 676890f6b55SPaul Burton change_gic_vl_ctl(GIC_VX_CTL_EIC, 677890f6b55SPaul Burton cpu_has_veic ? GIC_VX_CTL_EIC : 0); 678890f6b55SPaul Burton 67925ac19e1SPaul Burton /* Clear all local IRQ masks (ie. disable all local interrupts) */ 68025ac19e1SPaul Burton write_gic_vl_rmask(~0); 68125ac19e1SPaul Burton 682dd098a0eSMarc Zyngier /* Enable desired interrupts */ 683dd098a0eSMarc Zyngier gic_all_vpes_irq_cpu_online(); 684da61fcf9SPaul Burton 685da61fcf9SPaul Burton return 0; 686da61fcf9SPaul Burton } 68739b8d525SRalf Baechle 688fbea7541SPaul Burton static int __init gic_of_init(struct device_node *node, 689fbea7541SPaul Burton struct device_node *parent) 69039b8d525SRalf Baechle { 69125c51dadSPaul Burton unsigned int cpu_vec, i, gicconfig, v[2], num_ipis; 692b2b2e584SPaul Burton unsigned long reserved; 693fbea7541SPaul Burton phys_addr_t gic_base; 694fbea7541SPaul Burton struct resource res; 695fbea7541SPaul Burton size_t gic_len; 69639b8d525SRalf Baechle 697fbea7541SPaul Burton /* Find the first available CPU vector. */ 698b2b2e584SPaul Burton i = 0; 699a08588eaSPaul Burton reserved = (C_SW0 | C_SW1) >> __ffs(C_SW0); 700fbea7541SPaul Burton while (!of_property_read_u32_index(node, "mti,reserved-cpu-vectors", 701fbea7541SPaul Burton i++, &cpu_vec)) 702fbea7541SPaul Burton reserved |= BIT(cpu_vec); 703c0a9f72cSAlex Smith 704b2b2e584SPaul Burton cpu_vec = find_first_zero_bit(&reserved, hweight_long(ST0_IM)); 705b2b2e584SPaul Burton if (cpu_vec == hweight_long(ST0_IM)) { 7061f19aee0SMatt Redfearn pr_err("No CPU vectors available\n"); 707fbea7541SPaul Burton return -ENODEV; 708fbea7541SPaul Burton } 70939b8d525SRalf Baechle 710fbea7541SPaul Burton if (of_address_to_resource(node, 0, &res)) { 711fbea7541SPaul Burton /* 712fbea7541SPaul Burton * Probe the CM for the GIC base address if not specified 713fbea7541SPaul Burton * in the device-tree. 714fbea7541SPaul Burton */ 715fbea7541SPaul Burton if (mips_cm_present()) { 716fbea7541SPaul Burton gic_base = read_gcr_gic_base() & 717fbea7541SPaul Burton ~CM_GCR_GIC_BASE_GICEN; 718fbea7541SPaul Burton gic_len = 0x20000; 719666740fdSMatt Redfearn pr_warn("Using inherited base address %pa\n", 720666740fdSMatt Redfearn &gic_base); 721fbea7541SPaul Burton } else { 7221f19aee0SMatt Redfearn pr_err("Failed to get memory range\n"); 723fbea7541SPaul Burton return -ENODEV; 724fbea7541SPaul Burton } 725fbea7541SPaul Burton } else { 726fbea7541SPaul Burton gic_base = res.start; 727fbea7541SPaul Burton gic_len = resource_size(&res); 728fbea7541SPaul Burton } 72939b8d525SRalf Baechle 730fbea7541SPaul Burton if (mips_cm_present()) { 731fbea7541SPaul Burton write_gcr_gic_base(gic_base | CM_GCR_GIC_BASE_GICEN); 732fbea7541SPaul Burton /* Ensure GIC region is enabled before trying to access it */ 733fbea7541SPaul Burton __sync(); 734fbea7541SPaul Burton } 735fbea7541SPaul Burton 7364bdc0d67SChristoph Hellwig mips_gic_base = ioremap(gic_base, gic_len); 73739b8d525SRalf Baechle 7383680746aSPaul Burton gicconfig = read_gic_config(); 739357a9c4bSGeert Uytterhoeven gic_shared_intrs = FIELD_GET(GIC_CONFIG_NUMINTERRUPTS, gicconfig); 7403680746aSPaul Burton gic_shared_intrs = (gic_shared_intrs + 1) * 8; 74139b8d525SRalf Baechle 74239b8d525SRalf Baechle if (cpu_has_veic) { 74339b8d525SRalf Baechle /* Always use vector 1 in EIC mode */ 74439b8d525SRalf Baechle gic_cpu_pin = 0; 7451b6af71aSJames Hogan timer_cpu_pin = gic_cpu_pin; 74639b8d525SRalf Baechle set_vi_handler(gic_cpu_pin + GIC_PIN_TO_VEC_OFFSET, 74739b8d525SRalf Baechle __gic_irq_dispatch); 74839b8d525SRalf Baechle } else { 74939b8d525SRalf Baechle gic_cpu_pin = cpu_vec - GIC_CPU_PIN_OFFSET; 75039b8d525SRalf Baechle irq_set_chained_handler(MIPS_CPU_IRQ_BASE + cpu_vec, 75139b8d525SRalf Baechle gic_irq_dispatch); 7521b6af71aSJames Hogan /* 7531b6af71aSJames Hogan * With the CMP implementation of SMP (deprecated), other CPUs 7541b6af71aSJames Hogan * are started by the bootloader and put into a timer based 7551b6af71aSJames Hogan * waiting poll loop. We must not re-route those CPU's local 7561b6af71aSJames Hogan * timer interrupts as the wait instruction will never finish, 7571b6af71aSJames Hogan * so just handle whatever CPU interrupt it is routed to by 7581b6af71aSJames Hogan * default. 7591b6af71aSJames Hogan * 7601b6af71aSJames Hogan * This workaround should be removed when CMP support is 7611b6af71aSJames Hogan * dropped. 7621b6af71aSJames Hogan */ 7631b6af71aSJames Hogan if (IS_ENABLED(CONFIG_MIPS_CMP) && 7641b6af71aSJames Hogan gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) { 7650d0cf58cSPaul Burton timer_cpu_pin = read_gic_vl_timer_map() & GIC_MAP_PIN_MAP; 7661b6af71aSJames Hogan irq_set_chained_handler(MIPS_CPU_IRQ_BASE + 7671b6af71aSJames Hogan GIC_CPU_PIN_OFFSET + 7681b6af71aSJames Hogan timer_cpu_pin, 7691b6af71aSJames Hogan gic_irq_dispatch); 7701b6af71aSJames Hogan } else { 7711b6af71aSJames Hogan timer_cpu_pin = gic_cpu_pin; 7721b6af71aSJames Hogan } 77339b8d525SRalf Baechle } 77439b8d525SRalf Baechle 775a7057270SAndrew Bresticker gic_irq_domain = irq_domain_add_simple(node, GIC_NUM_LOCAL_INTRS + 776fbea7541SPaul Burton gic_shared_intrs, 0, 77739b8d525SRalf Baechle &gic_irq_domain_ops, NULL); 778fbea7541SPaul Burton if (!gic_irq_domain) { 7791f19aee0SMatt Redfearn pr_err("Failed to add IRQ domain"); 780fbea7541SPaul Burton return -ENXIO; 781fbea7541SPaul Burton } 78239b8d525SRalf Baechle 7832af70a96SQais Yousef gic_ipi_domain = irq_domain_add_hierarchy(gic_irq_domain, 7842af70a96SQais Yousef IRQ_DOMAIN_FLAG_IPI_PER_CPU, 7852af70a96SQais Yousef GIC_NUM_LOCAL_INTRS + gic_shared_intrs, 7862af70a96SQais Yousef node, &gic_ipi_domain_ops, NULL); 787fbea7541SPaul Burton if (!gic_ipi_domain) { 7881f19aee0SMatt Redfearn pr_err("Failed to add IPI domain"); 789fbea7541SPaul Burton return -ENXIO; 790fbea7541SPaul Burton } 7912af70a96SQais Yousef 79296f0d93aSMarc Zyngier irq_domain_update_bus_token(gic_ipi_domain, DOMAIN_BUS_IPI); 7932af70a96SQais Yousef 79416a8083cSQais Yousef if (node && 79516a8083cSQais Yousef !of_property_read_u32_array(node, "mti,reserved-ipi-vectors", v, 2)) { 79616a8083cSQais Yousef bitmap_set(ipi_resrv, v[0], v[1]); 79716a8083cSQais Yousef } else { 79825c51dadSPaul Burton /* 79925c51dadSPaul Burton * Reserve 2 interrupts per possible CPU/VP for use as IPIs, 80025c51dadSPaul Burton * meeting the requirements of arch/mips SMP. 80125c51dadSPaul Burton */ 80225c51dadSPaul Burton num_ipis = 2 * num_possible_cpus(); 80325c51dadSPaul Burton bitmap_set(ipi_resrv, gic_shared_intrs - num_ipis, num_ipis); 80416a8083cSQais Yousef } 8052af70a96SQais Yousef 806f8dcd9e8SPaul Burton bitmap_copy(ipi_available, ipi_resrv, GIC_MAX_INTRS); 80787888bcbSPaul Burton 80887888bcbSPaul Burton board_bind_eic_interrupt = &gic_bind_eic_interrupt; 80987888bcbSPaul Burton 81087888bcbSPaul Burton /* Setup defaults */ 81187888bcbSPaul Burton for (i = 0; i < gic_shared_intrs; i++) { 81287888bcbSPaul Burton change_gic_pol(i, GIC_POL_ACTIVE_HIGH); 81387888bcbSPaul Burton change_gic_trig(i, GIC_TRIG_LEVEL); 81490019f8fSPaul Burton write_gic_rmask(i); 81539b8d525SRalf Baechle } 816a7057270SAndrew Bresticker 817da61fcf9SPaul Burton return cpuhp_setup_state(CPUHP_AP_IRQ_MIPS_GIC_STARTING, 818da61fcf9SPaul Burton "irqchip/mips/gic:starting", 819da61fcf9SPaul Burton gic_cpu_startup, NULL); 820a7057270SAndrew Bresticker } 821a7057270SAndrew Bresticker IRQCHIP_DECLARE(mips_gic, "mti,gic", gic_of_init); 822