--- zzzz-none-000/linux-3.10.107/arch/mips/kernel/smp-cmp.c 2017-06-27 09:49:32.000000000 +0000 +++ vr9-7490-729/linux-3.10.107/arch/mips/kernel/smp-cmp.c 2021-11-10 11:53:54.000000000 +0000 @@ -38,54 +38,209 @@ #include #include #include +#include +#include -static void ipi_call_function(unsigned int cpu) -{ - pr_debug("CPU%d: %s cpu %d status %08x\n", - smp_processor_id(), __func__, cpu, read_c0_status()); +#ifdef CONFIG_EVA +extern int gcmp_present; +extern unsigned long _gcmp_base; +static unsigned long bev_location = -1; - gic_send_ipi(plat_ipi_call_int_xlate(cpu)); +static int rd_bev_location(char *p) +{ + if (p && strlen(p)) { + bev_location = memparse(p, &p); + } else + bev_location = 0xbfc00000; + return 0; } +early_param("force-bev-location", rd_bev_location); + +static void BEV_overlay_segment_map_check(unsigned long excBase, + unsigned long excMask, unsigned long excSize) +{ + unsigned long addr; + + if ((excBase == (IO_BASE + IO_SHIFT)) && (excSize == IO_SIZE)) + return; + printk("WARNING: BEV overlay segment doesn't fit whole I/O reg space, NMI/EJTAG/sRESET may not work\n"); + + if ((MAP_BASE < (excBase + excSize)) && (excBase < VMALLOC_END)) + panic("BEV Overlay segment overlaps VMALLOC area\n"); +#ifdef CONFIG_HIGHMEM + if ((PKMAP_BASE < (excBase + excSize)) && + (excBase < (PKMAP_BASE + (PAGE_SIZE*(LAST_PKMAP-1))))) + panic("BEV Overlay segment overlaps HIGHMEM/PKMAP area\n"); +#endif + for (addr = excBase; addr < (excBase + excSize); addr += PAGE_SIZE) { + if (page_is_ram(__pa(addr>>PAGE_SHIFT))) + panic("BEV Overlay segment overlaps memory at %lx\n",addr); + } +} -static void ipi_resched(unsigned int cpu) +void BEV_overlay_segment(void) { - pr_debug("CPU%d: %s cpu %d status %08x\n", - smp_processor_id(), __func__, cpu, read_c0_status()); + unsigned long RExcBase; + unsigned long RExcExtBase; + unsigned long excBase; + unsigned long excMask; + unsigned long excSize; + unsigned long addr; + char *p; + + printk("IO: BASE = 0x%lx, SHIFT = 0x%lx, SIZE = 0x%lx\n",IO_BASE, IO_SHIFT, IO_SIZE); + RExcBase = GCMPCLCB(RESETBASE); + RExcExtBase = GCMPCLCB(RESETBASEEXT); + printk("GCMP base addr = 0x%lx, CLB: ResetExcBase = 0x%lx, ResetExcExtBase = 0x%lx\n", + _gcmp_base,RExcBase,RExcExtBase); + if ( !(RExcExtBase & 0x1) ) + return; + + if (bev_location == -1) { + if ((p = strstr(arcs_cmdline, "force-bev-location"))) + rd_bev_location(p); + } + if (bev_location != -1) { + addr = fls((IO_BASE + IO_SHIFT) ^ bev_location); +nextSize: + if (addr > 28) + panic("enforced BEV location is too far from I/O reg space\n"); + + excMask = (0xffffffffUL >> (32 - addr)); + excBase = bev_location & ~excMask; + if (((IO_BASE + IO_SHIFT + IO_SIZE - 1) & ~excMask) != excBase) { + addr++; + goto nextSize; + } + excSize = ((excBase | excMask) + 1) - excBase; + printk("Setting BEV = 0x%lx, Overlay segment = 0x%lx, size = 0x%lx\n", + bev_location, excBase, excSize); + + BEV_overlay_segment_map_check(excBase, excMask, excSize); + + GCMPCLCB(RESETBASEEXT) = (GCMPCLCB(RESETBASEEXT) & + ~GCMP_CCB_RESETEXTBASE_BEV_MASK_MSK) | + (excMask & GCMP_CCB_RESETEXTBASE_BEV_MASK_MSK); + GCMPCLCB(RESETBASE) = (GCMPCLCB(RESETBASE) & ~GCMP_CCB_RESETBASE_BEV_MSK) | + bev_location; + RExcBase = GCMPCLCB(RESETBASE); + RExcExtBase = GCMPCLCB(RESETBASEEXT); + + return; + } - gic_send_ipi(plat_ipi_resched_int_xlate(cpu)); + excBase = RExcBase & GCMP_CCB_RESETBASE_BEV_MSK; + excMask = (RExcExtBase & GCMP_CCB_RESETEXTBASE_BEV_MASK_MSK) | + GCMP_CCB_RESETEXTBASE_BEV_MASK_LOWBITS; + excBase &= ~excMask; + excSize = ((excBase | excMask) + 1) - excBase; + printk("BEV Overlay segment = 0x%lx, size = 0x%lx\n",excBase, excSize); + + BEV_overlay_segment_map_check(excBase, excMask, excSize); } +#endif -/* - * FIXME: This isn't restricted to CMP - * The SMVP kernel could use GIC interrupts if available - */ -void cmp_send_ipi_single(int cpu, unsigned int action) +#ifdef CONFIG_EVA +extern int gcmp_present; +extern unsigned long _gcmp_base; +static unsigned long bev_location = -1; + +static int rd_bev_location(char *p) { - unsigned long flags; + if ((strlen(p) > 19) && (*(p + 18) == '=')) { + p += 19; + bev_location = memparse(p, &p); + } else + bev_location = 0xbfc00000; + return 0; +} +early_param("force-bev-location", rd_bev_location); - local_irq_save(flags); +static void BEV_overlay_segment_map_check(unsigned long excBase, + unsigned long excMask, unsigned long excSize) +{ + unsigned long addr; - switch (action) { - case SMP_CALL_FUNCTION: - ipi_call_function(cpu); - break; + if ((excBase == (IO_BASE + IO_SHIFT)) && (excSize == IO_SIZE)) + return; - case SMP_RESCHEDULE_YOURSELF: - ipi_resched(cpu); - break; - } + printk("WARNING: BEV overlay segment doesn't fit whole I/O reg space, NMI/EJTAG/sRESET may not work\n"); - local_irq_restore(flags); + if ((MAP_BASE < (excBase + excSize)) && (excBase < VMALLOC_END)) + panic("BEV Overlay segment overlaps VMALLOC area\n"); +#ifdef CONFIG_HIGHMEM + if ((PKMAP_BASE < (excBase + excSize)) && + (excBase < (PKMAP_BASE + (PAGE_SIZE*(LAST_PKMAP-1))))) + panic("BEV Overlay segment overlaps HIGHMEM/PKMAP area\n"); +#endif + for (addr = excBase; addr < (excBase + excSize); addr += PAGE_SIZE) { + if (page_is_ram(__pa(addr>>PAGE_SHIFT))) + panic("BEV Overlay segment overlaps memory at %lx\n",addr); + } } -static void cmp_send_ipi_mask(const struct cpumask *mask, unsigned int action) +void BEV_overlay_segment(void) { - unsigned int i; + unsigned long RExcBase; + unsigned long RExcExtBase; + unsigned long excBase; + unsigned long excMask; + unsigned long excSize; + unsigned long addr; + char *p; + + printk("IO: BASE = 0x%lx, SHIFT = 0x%lx, SIZE = 0x%lx\n",IO_BASE, IO_SHIFT, IO_SIZE); + RExcBase = GCMPCLCB(RESETBASE); + RExcExtBase = GCMPCLCB(RESETBASEEXT); + printk("GCMP base addr = 0x%lx, CLB: ResetExcBase = 0x%lx, ResetExcExtBase = 0x%lx\n", + _gcmp_base,RExcBase,RExcExtBase); + if ( !(RExcExtBase & 0x1) ) + return; + + if (bev_location == -1) { + if ((p = strstr(arcs_cmdline, "force-bev-location"))) + rd_bev_location(p); + } + if (bev_location != -1) { + addr = fls((IO_BASE + IO_SHIFT) ^ bev_location); +nextSize: + if (addr > 28) + panic("enforced BEV location is too far from I/O reg space\n"); + + excMask = (0xffffffffUL >> (32 - addr)); + excBase = bev_location & ~excMask; + if (((IO_BASE + IO_SHIFT + IO_SIZE - 1) & ~excMask) != excBase) { + addr++; + goto nextSize; + } + excSize = ((excBase | excMask) + 1) - excBase; + printk("Setting BEV = 0x%lx, Overlay segment = 0x%lx, size = 0x%lx\n", + bev_location, excBase, excSize); + + BEV_overlay_segment_map_check(excBase, excMask, excSize); + + GCMPCLCB(RESETBASEEXT) = (GCMPCLCB(RESETBASEEXT) & + ~GCMP_CCB_RESETEXTBASE_BEV_MASK_MSK) | + (excMask & GCMP_CCB_RESETEXTBASE_BEV_MASK_MSK); + GCMPCLCB(RESETBASE) = (GCMPCLCB(RESETBASE) & ~GCMP_CCB_RESETBASE_BEV_MSK) | + bev_location; + RExcBase = GCMPCLCB(RESETBASE); + RExcExtBase = GCMPCLCB(RESETBASEEXT); - for_each_cpu(i, mask) - cmp_send_ipi_single(i, action); + return; + } + + excBase = RExcBase & GCMP_CCB_RESETBASE_BEV_MSK; + excMask = (RExcExtBase & GCMP_CCB_RESETEXTBASE_BEV_MASK_MSK) | + GCMP_CCB_RESETEXTBASE_BEV_MASK_LOWBITS; + excBase &= ~excMask; + excSize = ((excBase | excMask) + 1) - excBase; + printk("BEV Overlay segment = 0x%lx, size = 0x%lx\n",excBase, excSize); + + BEV_overlay_segment_map_check(excBase, excMask, excSize); } +#endif static void cmp_init_secondary(void) { @@ -95,15 +250,20 @@ change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | STATUSF_IP6 | STATUSF_IP7); - /* Enable per-cpu interrupts: platform specific */ - - c->core = (read_c0_ebase() >> 1) & 0x1ff; + c->core = (read_c0_ebase() & 0x3ff) >> (fls(smp_num_siblings)-1); #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC) - c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE; + if (cpu_has_mipsmt) + c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & + TCBIND_CURVPE; #endif #ifdef CONFIG_MIPS_MT_SMTC c->tc_id = (read_c0_tcbind() & TCBIND_CURTC) >> TCBIND_CURTC_SHIFT; #endif + +#ifdef CONFIG_EVA + if (gcmp_present) + BEV_overlay_segment(); +#endif } static void cmp_smp_finish(void) @@ -145,7 +305,7 @@ #if 0 /* Needed? */ - flush_icache_range((unsigned long)gp, + local_flush_icache_range((unsigned long)gp, (unsigned long)(gp + sizeof(struct thread_info))); #endif @@ -177,9 +337,16 @@ } if (cpu_has_mipsmt) { - unsigned int nvpe, mvpconf0 = read_c0_mvpconf0(); + unsigned int nvpe = 1; +#ifdef CONFIG_MIPS_MT_SMP + unsigned int mvpconf0 = read_c0_mvpconf0(); + + nvpe = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1; +#elif defined(CONFIG_MIPS_MT_SMTC) + unsigned int mvpconf0 = read_c0_mvpconf0(); nvpe = ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1; +#endif smp_num_siblings = nvpe; } pr_info("Detected %i available secondary CPU(s)\n", ncpu); @@ -198,8 +365,8 @@ } struct plat_smp_ops cmp_smp_ops = { - .send_ipi_single = cmp_send_ipi_single, - .send_ipi_mask = cmp_send_ipi_mask, + .send_ipi_single = gic_send_ipi_single, + .send_ipi_mask = gic_send_ipi_mask, .init_secondary = cmp_init_secondary, .smp_finish = cmp_smp_finish, .cpus_done = cmp_cpus_done,