unsigned int gic_get_int(void) { unsigned int i; unsigned long *pending, *intrmask, *pcpu_mask; unsigned long *pending_abs, *intrmask_abs; /* Get per-cpu bitmaps */ pending = pending_regs[smp_processor_id()].pending; intrmask = intrmask_regs[smp_processor_id()].intrmask; pcpu_mask = pcpu_masks[smp_processor_id()].pcpu_mask; pending_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED, GIC_SH_PEND_31_0_OFS); intrmask_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED, GIC_SH_MASK_31_0_OFS); for (i = 0; i < BITS_TO_LONGS(GIC_NUM_INTRS); i++) { GICREAD(*pending_abs, pending[i]); GICREAD(*intrmask_abs, intrmask[i]); pending_abs++; intrmask_abs++; } bitmap_and(pending, pending, intrmask, GIC_NUM_INTRS); bitmap_and(pending, pending, pcpu_mask, GIC_NUM_INTRS); i = find_first_bit(pending, GIC_NUM_INTRS); pr_debug("CPU%d: %s pend=%d\n", smp_processor_id(), __func__, i); return i; }
cycle_t gic_read_count(void) { unsigned int hi, hi2, lo; do { GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi); GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), lo); GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_63_32), hi2); } while (hi2 != hi); return (((cycle_t) hi) << 32) + lo; }
/* * Estimate CPU and GIC frequencies. */ static void __init estimate_frequencies(void) { unsigned long flags; unsigned int count, start; #ifdef CONFIG_IRQ_GIC unsigned int giccount = 0, gicstart = 0; #endif #if defined(CONFIG_KVM_GUEST) && CONFIG_KVM_GUEST_TIMER_FREQ mips_hpt_frequency = CONFIG_KVM_GUEST_TIMER_FREQ * 1000000; return; #endif local_irq_save(flags); /* Start counter exactly on falling edge of update flag. */ while (CMOS_READ(RTC_REG_A) & RTC_UIP); while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); /* Initialize counters. */ start = read_c0_count(); #ifdef CONFIG_IRQ_GIC if (gic_present) GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), gicstart); #endif /* Read counter exactly on falling edge of update flag. */ while (CMOS_READ(RTC_REG_A) & RTC_UIP); while (!(CMOS_READ(RTC_REG_A) & RTC_UIP)); count = read_c0_count(); #ifdef CONFIG_IRQ_GIC if (gic_present) GICREAD(GIC_REG(SHARED, GIC_SH_COUNTER_31_00), giccount); #endif local_irq_restore(flags); count -= start; mips_hpt_frequency = count; #ifdef CONFIG_IRQ_GIC if (gic_present) { giccount -= gicstart; gic_frequency = giccount; } #endif }
void __init gic_init(unsigned long gic_base_addr, unsigned long gic_addrspace_size, struct gic_intr_map *intr_map, unsigned int intr_map_size, unsigned int irqbase) { unsigned int gicconfig; _gic_base = (unsigned long) ioremap_nocache(gic_base_addr, gic_addrspace_size); _irqbase = irqbase; _intrmap = intr_map; _mapsize = intr_map_size; GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig); numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >> GIC_SH_CONFIG_NUMINTRS_SHF; numintrs = ((numintrs + 1) * 8); numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >> GIC_SH_CONFIG_NUMVPES_SHF; pr_debug("%s called\n", __func__); gic_basic_init(); }
void __init gic_init(unsigned long gic_base_addr, unsigned long gic_addrspace_size, struct gic_intr_map *intr_map, unsigned int intr_map_size, unsigned int irqbase) { unsigned int gicconfig; int numvpes, numintrs; _gic_base = (unsigned long) ioremap_nocache(gic_base_addr, gic_addrspace_size); _irqbase = irqbase; GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig); numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >> GIC_SH_CONFIG_NUMINTRS_SHF; numintrs = ((numintrs + 1) * 8); numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >> GIC_SH_CONFIG_NUMVPES_SHF; #ifdef CONFIG_RALINK_SOC numvpes = numvpes + 1; #endif pr_debug("%s called\n", __func__); gic_basic_init(numintrs, numvpes, intr_map, intr_map_size); }
void __init arch_init_irq(void) { int i; unsigned int gic_rev; mips_cpu_irq_init(); if (cpu_has_vint) set_vi_handler(cp0_compare_irq, mips_timer_dispatch); if (gcmp_present) { GCMPGCB(GICBA) = GIC_BASE_ADDR | GCMP_GCB_GICBA_EN_MSK; gic_present = 1; } if (gic_present) { #if defined (CONFIG_MIPS_GIC_IPI) gic_call_int_base = GIC_IPI_CALL_VPE0; gic_resched_int_base = GIC_IPI_RESCHED_VPE0; fill_ipi_map(); #endif gic_init(GIC_BASE_ADDR, GIC_ADDRSPACE_SZ, gic_intr_map, ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE); GICREAD(GIC_REG(SHARED, GIC_SH_REVISIONID), gic_rev); printk("MIPS GIC RevID: %d.%d\n", (gic_rev >> 8) & 0xff, gic_rev & 0xff); if (cpu_has_vint) { pr_info("Setting up vectored interrupts\n"); set_vi_handler(2 + GIC_CPU_INT0, gic_irq_dispatch); // CPU #if defined (CONFIG_MIPS_GIC_IPI) set_vi_handler(2 + GIC_CPU_INT1, gic_irq_dispatch); // IPI resched set_vi_handler(2 + GIC_CPU_INT2, gic_irq_dispatch); // IPI call #endif set_vi_handler(2 + GIC_CPU_INT3, gic_irq_dispatch); // FE set_vi_handler(2 + GIC_CPU_INT4, gic_irq_dispatch); // PCIe } #if defined (CONFIG_MIPS_GIC_IPI) set_c0_status(STATUSF_IP7 | STATUSF_IP6 | STATUSF_IP5 | STATUSF_IP2 | STATUSF_IP4 | STATUSF_IP3); /* setup ipi interrupts */ for (i = 0; i < nr_cpu_ids; i++) { arch_init_ipiirq(MIPS_GIC_IRQ_BASE + GIC_RESCHED_INT(i), &irq_resched); arch_init_ipiirq(MIPS_GIC_IRQ_BASE + GIC_CALL_INT(i), &irq_call); } #else set_c0_status(STATUSF_IP7 | STATUSF_IP6 | STATUSF_IP5 | STATUSF_IP2); #endif /* set hardware irq, mapped to GIC shared (skip 0, 1, 2, 5, 7) */ for (i = 3; i <= 31; i++) { if (i != 5 && i != 7) irq_set_handler(MIPS_GIC_IRQ_BASE + i, handle_level_irq); } } else {
/* This is Malta specific and needs to be exported */ static void __init vpe_local_setup(unsigned int numvpes) { int i; #ifdef CONFIG_RALINK_SOC unsigned long timer_interrupt = GIC_INT_TMR, perf_interrupt = GIC_INT_PERFCTR; #else unsigned long timer_interrupt = 5, perf_interrupt = 5; #endif unsigned int vpe_ctl; #ifdef CONFIG_RALINK_SOC if (cpu_has_veic) { /* GIC timer interrupt -> CPU HW Int X (vector X+2) -> map to pin X+2-1 (since GIC adds 1) */ timer_interrupt += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET); /* GIC perfcnt interrupt -> CPU HW Int X (vector X+2) -> map to pin X+2-1 (since GIC adds 1) */ perf_interrupt += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET); } #endif /* * Setup the default performance counter timer interrupts * for all VPEs */ for (i = 0; i < numvpes; i++) { GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); /* Are Interrupts locally routable? */ GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl); if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK) GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), GIC_MAP_TO_PIN_MSK | timer_interrupt); #ifdef CONFIG_RALINK_SOC if (cpu_has_veic) { set_vi_handler(timer_interrupt+GIC_PIN_TO_VEC_OFFSET, gic_eic_tmr_irq_dispatch); } #endif if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK) GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), GIC_MAP_TO_PIN_MSK | perf_interrupt); #ifdef CONFIG_RALINK_SOC if (cpu_has_veic) { set_vi_handler(perf_interrupt+GIC_PIN_TO_VEC_OFFSET, gic_eic_tmr_irq_dispatch); } #endif } }
/* This is Malta specific and needs to be exported */ static void vpe_local_setup(unsigned int numvpes) { int i; unsigned long timer_interrupt = 5, perf_interrupt = 5; unsigned int vpe_ctl; /* * Setup the default performance counter timer interrupts * for all VPEs */ for (i = 0; i < numvpes; i++) { GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); /* Are Interrupts locally routable? */ GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl); if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK) GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), GIC_MAP_TO_PIN_MSK | timer_interrupt); if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK) GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), GIC_MAP_TO_PIN_MSK | perf_interrupt); } }
static int __init of_gic_init(struct device_node *node, struct device_node *parent) { struct irq_domain *domain; struct resource gcmp = { 0 }, gic = { 0 }; unsigned int gic_rev; int i; if (of_address_to_resource(node, 0, &gic)) panic("Failed to get gic memory range"); if (request_mem_region(gic.start, resource_size(&gic), gic.name) < 0) panic("Failed to request gic memory"); if (of_address_to_resource(node, 2, &gcmp)) panic("Failed to get gic memory range"); if (request_mem_region(gcmp.start, resource_size(&gcmp), gcmp.name) < 0) panic("Failed to request gcmp memory"); _gcmp_base = (unsigned long) ioremap_nocache(gcmp.start, resource_size(&gcmp)); if (!_gcmp_base) panic("Failed to remap gcmp memory\n"); if ((GCMPGCB(GCMPB) & GCMP_GCB_GCMPB_GCMPBASE_MSK) != gcmp.start) panic("Failed to find gcmp core\n"); /* tell the gcmp where to find the gic */ GCMPGCB(GICBA) = gic.start | GCMP_GCB_GICBA_EN_MSK; gic_present = 1; if (cpu_has_vint) { set_vi_handler(2, gic_irqdispatch); set_vi_handler(3, gic_irqdispatch); set_vi_handler(4, gic_irqdispatch); set_vi_handler(7, vi_timer_irqdispatch); } gic_fill_map(); gic_init(gic.start, resource_size(&gic), gic_intr_map, ARRAY_SIZE(gic_intr_map), MIPS_GIC_IRQ_BASE); GICREAD(GIC_REG(SHARED, GIC_SH_REVISIONID), gic_rev); pr_info("gic: revision %d.%d\n", (gic_rev >> 8) & 0xff, gic_rev & 0xff); domain = irq_domain_add_legacy(node, GIC_NUM_INTRS, MIPS_GIC_IRQ_BASE, 0, &irq_domain_ops, NULL); if (!domain) panic("Failed to add irqdomain"); #if defined(CONFIG_MIPS_MT_SMP) for (i = 0; i < nr_cpu_ids; i++) { setup_irq(MIPS_GIC_IRQ_BASE + GIC_RESCHED_INT(i), &irq_resched); setup_irq(MIPS_GIC_IRQ_BASE + GIC_CALL_INT(i), &irq_call); } #endif change_c0_status(ST0_IM, STATUSF_IP7 | STATUSF_IP4 | STATUSF_IP3 | STATUSF_IP2); return 0; }