--- zzzz-none-000/linux-4.1.38/drivers/irqchip/irq-gic.c 2017-01-18 18:48:06.000000000 +0000 +++ bcm63-7582-715/linux-4.1.38/drivers/irqchip/irq-gic.c 2020-11-25 10:06:48.000000000 +0000 @@ -20,6 +20,12 @@ * As such, the enable set/clear, pending set/clear and active bit * registers are banked per-cpu for these sources. */ + +#ifdef CONFIG_AVM_FASTIRQ +#include +#define CLIENT_FIQ_PRIO FIQ_PRIO_WATCHDOG +#endif + #include #include #include @@ -44,12 +50,31 @@ #include #include + +#include +#include + #include #include #include "irq-gic-common.h" #include "irqchip.h" +#if defined(CONFIG_AVM_FASTIRQ) + +#include +#include +#include + +#include +#define __BUILD_AVM_CONTEXT_FUNC(func) firq_##func + +#else + +#define __BUILD_AVM_CONTEXT_FUNC(func) func + +#endif + union gic_base { void __iomem *common_base; void __percpu * __iomem *percpu_base; @@ -60,9 +85,11 @@ union gic_base cpu_base; #ifdef CONFIG_CPU_PM u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)]; + u32 saved_spi_security[DIV_ROUND_UP(1020, 32)]; u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)]; u32 saved_spi_target[DIV_ROUND_UP(1020, 4)]; u32 __percpu *saved_ppi_enable; + u32 __percpu *saved_ppi_security; u32 __percpu *saved_ppi_conf; #endif struct irq_domain *domain; @@ -72,7 +99,7 @@ #endif }; -static DEFINE_RAW_SPINLOCK(irq_controller_lock); +DEFINE_RAW_SPINLOCK(irq_controller_lock); /* * The GIC mapping of CPU interfaces does not necessarily match @@ -120,6 +147,35 @@ #define gic_set_base_accessor(d, f) #endif +#ifndef CONFIG_AVM_FASTIRQ_TZ +void __iomem * get_dist_base( unsigned int gic_nr ) +{ + struct gic_chip_data *gic; + + BUG_ON(gic_nr >= MAX_GIC_NR); + + gic = &gic_data[gic_nr]; + + return(gic_data_dist_base(gic)); +} + +#define SCU_PHYS_BASE 0x8001e000 +#define DIST_BASE_PHY (SCU_PHYS_BASE + CA9MP_GIC_DIST_OFF) + +void __iomem * get_cpu_base( unsigned int gic_nr ) +{ + struct gic_chip_data *gic; + + BUG_ON(gic_nr >= MAX_GIC_NR); + + gic = &gic_data[gic_nr]; + + return(gic_data_cpu_base(gic)); +} + +#define CPU_BASE_PHY (SCU_PHYS_BASE + CA9MP_GIC_CPUIF_OFF) +#endif + static inline void __iomem *gic_dist_base(struct irq_data *d) { struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d); @@ -154,6 +210,9 @@ static void gic_mask_irq(struct irq_data *d) { +#if defined(CONFIG_AVM_FASTIRQ) + BUG_ON(avm_gic_fiq_is(gic_irq(d))); +#endif/*--- #if defined(CONFIG_AVM_FASTIRQ) ---*/ gic_poke_irq(d, GIC_DIST_ENABLE_CLEAR); } @@ -162,9 +221,16 @@ gic_poke_irq(d, GIC_DIST_ENABLE_SET); } +#if defined(CONFIG_AVM_FASTIRQ) && !defined(CONFIG_AVM_FASTIRQ_TZ) +unsigned int avm_secmon_gate(unsigned int wr, unsigned int addr, unsigned int val); +#endif static void gic_eoi_irq(struct irq_data *d) { +#if defined(CONFIG_AVM_FASTIRQ) && !defined(CONFIG_AVM_FASTIRQ_TZ) + (void)avm_secmon_gate(1, (CPU_BASE_PHY + GIC_CPU_EOI), gic_irq(d)); +#else writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI); +#endif } static int gic_irq_set_irqchip_state(struct irq_data *d, @@ -250,33 +316,122 @@ if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids) return -EINVAL; - raw_spin_lock_irqsave(&irq_controller_lock, flags); + __BUILD_AVM_CONTEXT_FUNC(raw_spin_lock_irqsave(&irq_controller_lock, flags)); mask = 0xff << shift; bit = gic_cpu_map[cpu] << shift; val = readl_relaxed(reg) & ~mask; writel_relaxed(val | bit, reg); - raw_spin_unlock_irqrestore(&irq_controller_lock, flags); + __BUILD_AVM_CONTEXT_FUNC(raw_spin_unlock_irqrestore(&irq_controller_lock, flags)); return IRQ_SET_MASK_OK; } #endif +#if defined(CONFIG_AVM_FASTIRQ) && !defined(CONFIG_AVM_FASTIRQ_TZ) +/*--------------------------------------------------------------------------------*\ + * Code, um aus dem IRQ in den FIQ zu wechseln und den FIQ-Handler anzuspringen * +\*--------------------------------------------------------------------------------*/ + +static void noinline handle_FIQ(unsigned long flags) +{ + unsigned long addr; + unsigned long flags_save; + + asm volatile( \ + "mrs %1, cpsr \n" \ + "bic %1, %1, #0x1f \n" \ + "orr %1, %1, #0x11 \n" \ + "msr cpsr_fsxc, %1 \n" \ + "isb \n" \ + "msr spsr_fsxc, %2 \n" \ + "movw lr, #:lower16:2f \n" \ + "movt lr, #:upper16:2f \n" \ + "ldr %0, =avm_fiq_handler_begin \n" \ + "bx %0 \n" \ + "1: mov pc, lr \n" \ + "2: \n" \ + : "=r" (addr), "=&r" (flags_save) \ + : "r" (flags) \ + : "cc" \ + ); +} +#endif + static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) { - u32 irqstat, irqnr; + u32 irq_handled, irqstat, irqnr; struct gic_chip_data *gic = &gic_data[0]; void __iomem *cpu_base = gic_data_cpu_base(gic); +#ifndef CONFIG_AVM_FASTIRQ_TZ + unsigned long flags; +#endif + + irq_handled = 0; do { + dsb(); + +#if defined(CONFIG_AVM_FASTIRQ) + + /* NON-SECURE - Zugriff zum Auslesen des Interrupts ... */ +#ifndef CONFIG_AVM_FASTIRQ_TZ + flags = avm_raw_local_fiq_and_iq_disable(); + + irqstat = avm_secmon_gate(0, (CPU_BASE_PHY + GIC_CPU_INTACK), 0); +#else + irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK); +#endif + irqnr = irqstat & GICC_IAR_INT_ID_MASK; + +#ifndef CONFIG_AVM_FASTIRQ_TZ + if (unlikely(irqnr >= 1020))//(unlikely(avm_gic_fiq_is(irqnr))) + { + irqstat = readl_relaxed(cpu_base + OFFSET_ICCHPIR); + irqnr = irqstat & GICC_IAR_INT_ID_MASK; + + if (likely(avm_gic_fiq_is(irqnr))) + { + /* SECURE interrupt, passiert ungluecklicherweise ab und zu ... */ + handle_FIQ(flags); // avm_raw_local_fiq_and_iq_enable(flags) implizit bei Ruecksprung + // mit Modewechsel fuer flags + break; + } + else + { + avm_raw_local_fiq_and_iq_enable(flags); + + /* Interrupt Nr 1020, 1021, 1022 und Nr > 1023 fuer NON-SECURE nicht definiert, einfach Beenden ... */ + /* Spurious Interrupts zählen */ + if(!irq_handled) { + __this_cpu_write(spurious_count, (__this_cpu_read(spurious_count) + 1)); + } + + break; + } + } + + avm_raw_local_fiq_and_iq_enable(flags); +#endif + +#else irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK); irqnr = irqstat & GICC_IAR_INT_ID_MASK; +#endif - if (likely(irqnr > 15 && irqnr < 1021)) { + if (likely(irqnr > 15 && irqnr < 1020)) { + /* NON-SECURE interrupt */ handle_domain_irq(gic->domain, irqnr, regs); + irq_handled = 1; continue; } - if (irqnr < 16) { + if (likely(irqnr < 16)) { + /* NON-SECURE IPI */ +#if defined(CONFIG_AVM_FASTIRQ) && !defined(CONFIG_AVM_FASTIRQ_TZ) + (void)avm_secmon_gate(1, (CPU_BASE_PHY + GIC_CPU_EOI), irqstat); +#else writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI); +#endif + #ifdef CONFIG_SMP /* * Ensure any shared data written by the CPU sending @@ -288,9 +443,18 @@ smp_rmb(); handle_IPI(irqnr, regs); #endif + irq_handled = 1; continue; } +#if defined(CONFIG_AVM_FASTIRQ) + /* Interrupt Nr 1020, 1021, 1022 und Nr > 1023 fuer NON-SECURE nicht definiert, einfach Beenden ... */ + /* Spurious Interrupts zählen */ + if(!irq_handled) { + __this_cpu_write(spurious_count, (__this_cpu_read(spurious_count) + 1)); + } +#endif break; + } while (1); } @@ -303,9 +467,13 @@ chained_irq_enter(chip, desc); - raw_spin_lock(&irq_controller_lock); + __BUILD_AVM_CONTEXT_FUNC(raw_spin_lock(&irq_controller_lock)); +#if defined(CONFIG_AVM_FASTIRQ) && !defined(CONFIG_AVM_FASTIRQ_TZ) + status = avm_secmon_gate(0, (CPU_BASE_PHY + GIC_CPU_INTACK), 0); +#else status = readl_relaxed(gic_data_cpu_base(chip_data) + GIC_CPU_INTACK); - raw_spin_unlock(&irq_controller_lock); +#endif + __BUILD_AVM_CONTEXT_FUNC(raw_spin_unlock(&irq_controller_lock)); gic_irq = (status & GICC_IAR_INT_ID_MASK); if (gic_irq == GICC_INT_SPURIOUS) @@ -407,20 +575,20 @@ unsigned int cpu_mask, cpu = smp_processor_id(); int i; - /* - * Get what the GIC says our CPU mask is. - */ - BUG_ON(cpu >= NR_GIC_CPU_IF); - cpu_mask = gic_get_cpumask(gic); - gic_cpu_map[cpu] = cpu_mask; + /* + * Get what the GIC says our CPU mask is. + */ + BUG_ON(cpu >= NR_GIC_CPU_IF); + cpu_mask = gic_get_cpumask(gic); + gic_cpu_map[cpu] = cpu_mask; - /* - * Clear our mask from the other map entries in case they're - * still undefined. - */ - for (i = 0; i < NR_GIC_CPU_IF; i++) - if (i != cpu) - gic_cpu_map[i] &= ~cpu_mask; + /* + * Clear our mask from the other map entries in case they're + * still undefined. + */ + for (i = 0; i < NR_GIC_CPU_IF; i++) + if (i != cpu) + gic_cpu_map[i] &= ~cpu_mask; gic_cpu_config(dist_base, NULL); @@ -469,6 +637,10 @@ readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4); for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) + gic_data[gic_nr].saved_spi_security[i] = + readl_relaxed(dist_base + GIC_DIST_IGROUP + i * 4); + + for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) gic_data[gic_nr].saved_spi_enable[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4); } @@ -510,6 +682,10 @@ dist_base + GIC_DIST_TARGET + i * 4); for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) + writel_relaxed(gic_data[gic_nr].saved_spi_security[i], + dist_base + GIC_DIST_IGROUP + i * 4); + + for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) writel_relaxed(gic_data[gic_nr].saved_spi_enable[i], dist_base + GIC_DIST_ENABLE_SET + i * 4); @@ -536,6 +712,10 @@ for (i = 0; i < DIV_ROUND_UP(32, 32); i++) ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4); + ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_security); + for (i = 0; i < DIV_ROUND_UP(32, 32); i++) + ptr[i] = readl_relaxed(dist_base + GIC_DIST_IGROUP + i * 4); + ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_conf); for (i = 0; i < DIV_ROUND_UP(32, 16); i++) ptr[i] = readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4); @@ -562,6 +742,10 @@ for (i = 0; i < DIV_ROUND_UP(32, 32); i++) writel_relaxed(ptr[i], dist_base + GIC_DIST_ENABLE_SET + i * 4); + ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_security); + for (i = 0; i < DIV_ROUND_UP(32, 32); i++) + writel_relaxed(ptr[i], dist_base + GIC_DIST_IGROUP + i * 4); + ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_conf); for (i = 0; i < DIV_ROUND_UP(32, 16); i++) writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4); @@ -615,6 +799,10 @@ sizeof(u32)); BUG_ON(!gic->saved_ppi_enable); + gic->saved_ppi_security = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4, + sizeof(u32)); + BUG_ON(!gic->saved_ppi_security); + gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4, sizeof(u32)); BUG_ON(!gic->saved_ppi_conf); @@ -634,7 +822,7 @@ int cpu; unsigned long flags, map = 0; - raw_spin_lock_irqsave(&irq_controller_lock, flags); + __BUILD_AVM_CONTEXT_FUNC(raw_spin_lock_irqsave(&irq_controller_lock, flags)); /* Convert our logical CPU mask into a physical one. */ for_each_cpu(cpu, mask) @@ -647,9 +835,13 @@ dmb(ishst); /* this always happens on GIC0 */ +#ifdef CONFIG_AVM_FASTIRQ_TZ writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT); +#else + writel_relaxed(map << 16 | (1 << 15) | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT); +#endif - raw_spin_unlock_irqrestore(&irq_controller_lock, flags); + __BUILD_AVM_CONTEXT_FUNC(raw_spin_unlock_irqrestore(&irq_controller_lock, flags)); } #endif @@ -718,7 +910,7 @@ cur_target_mask = 0x01010101 << cur_cpu_id; ror_val = (cur_cpu_id - new_cpu_id) & 31; - raw_spin_lock(&irq_controller_lock); + __BUILD_AVM_CONTEXT_FUNC(raw_spin_lock(&irq_controller_lock)); /* Update the target interface for this logical CPU */ gic_cpu_map[cpu] = 1 << new_cpu_id; @@ -738,7 +930,7 @@ } } - raw_spin_unlock(&irq_controller_lock); + __BUILD_AVM_CONTEXT_FUNC(raw_spin_unlock(&irq_controller_lock)); /* * Now let's migrate and clear any potential SGIs that might be @@ -820,12 +1012,17 @@ { unsigned long ret = 0; +#if defined(CONFIG_BCM_KF_GIC_NOOFNODE) && \ + defined(CONFIG_BCM_GIC_NOOFNODE) + if (d->of_node != controller && d->of_node) +#else if (d->of_node != controller) +#endif return -EINVAL; if (intsize < 3) - return -EINVAL; + return -EINVAL; - /* Get the interrupt number and add 16 to skip over SGIs */ + /* Get the interrupt number and add 16 to skip over SGIs */ *out_hwirq = intspec[1] + 16; /* For SPIs, we need to add 16 more to get the GIC irq ID number */ @@ -835,7 +1032,7 @@ *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; return ret; -} + } #ifdef CONFIG_SMP static int gic_secondary_init(struct notifier_block *nfb, unsigned long action, @@ -955,8 +1152,8 @@ if (node) { /* DT case */ gic->domain = irq_domain_add_linear(node, gic_irqs, - &gic_irq_domain_hierarchy_ops, - gic); + &gic_irq_domain_hierarchy_ops, + gic); } else { /* Non-DT case */ /* * For primary GICs, skip over SGIs. @@ -1080,7 +1277,7 @@ static int __init gic_acpi_parse_madt_distributor(struct acpi_subtable_header *header, - const unsigned long end) + const unsigned long end) { struct acpi_madt_generic_distributor *dist;