diff options
Diffstat (limited to 'arch/mips/netlogic/common')
| -rw-r--r-- | arch/mips/netlogic/common/earlycons.c | 2 | ||||
| -rw-r--r-- | arch/mips/netlogic/common/irq.c | 74 | ||||
| -rw-r--r-- | arch/mips/netlogic/common/reset.S | 98 | ||||
| -rw-r--r-- | arch/mips/netlogic/common/smp.c | 20 | ||||
| -rw-r--r-- | arch/mips/netlogic/common/smpboot.S | 16 | ||||
| -rw-r--r-- | arch/mips/netlogic/common/time.c | 5 |
6 files changed, 156 insertions, 59 deletions
diff --git a/arch/mips/netlogic/common/earlycons.c b/arch/mips/netlogic/common/earlycons.c index 1902fa22d27..769f93032c5 100644 --- a/arch/mips/netlogic/common/earlycons.c +++ b/arch/mips/netlogic/common/earlycons.c @@ -37,9 +37,11 @@ #include <asm/mipsregs.h> #include <asm/netlogic/haldefs.h> +#include <asm/netlogic/common.h> #if defined(CONFIG_CPU_XLP) #include <asm/netlogic/xlp-hal/iomap.h> +#include <asm/netlogic/xlp-hal/xlp.h> #include <asm/netlogic/xlp-hal/uart.h> #elif defined(CONFIG_CPU_XLR) #include <asm/netlogic/xlr/iomap.h> diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c index 1c7e3a1b81a..c100b9afa0a 100644 --- a/arch/mips/netlogic/common/irq.c +++ b/arch/mips/netlogic/common/irq.c @@ -180,6 +180,7 @@ static void __init nlm_init_percpu_irqs(void) #endif } + void nlm_setup_pic_irq(int node, int picirq, int irq, int irt) { struct nlm_pic_irq *pic_data; @@ -202,37 +203,39 @@ void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *)) xirq = nlm_irq_to_xirq(node, irq); pic_data = irq_get_handler_data(xirq); + if (WARN_ON(!pic_data)) + return; pic_data->extra_ack = xack; } static void nlm_init_node_irqs(int node) { - int i, irt; - uint64_t irqmask; struct nlm_soc_info *nodep; + int i, irt; pr_info("Init IRQ for node %d\n", node); nodep = nlm_get_node(node); - irqmask = PERCPU_IRQ_MASK; + nodep->irqmask = PERCPU_IRQ_MASK; for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ; i++) { irt = nlm_irq_to_irt(i); - if (irt == -1) + if (irt == -1) /* unused irq */ continue; - nlm_setup_pic_irq(node, i, i, irt); - /* set interrupts to first cpu in node */ + nodep->irqmask |= 1ull << i; + if (irt == -2) /* not a direct PIC irq */ + continue; + nlm_pic_init_irt(nodep->picbase, irt, i, - node * NLM_CPUS_PER_NODE, 0); - irqmask |= (1ull << i); + node * nlm_threads_per_node(), 0); + nlm_setup_pic_irq(node, i, i, irt); } - nodep->irqmask = irqmask; } void nlm_smp_irq_init(int hwcpuid) { int node, cpu; - node = hwcpuid / NLM_CPUS_PER_NODE; - cpu = hwcpuid % NLM_CPUS_PER_NODE; + node = nlm_cpuid_to_node(hwcpuid); + cpu = hwcpuid % nlm_threads_per_node(); if (cpu == 0 && node != 0) nlm_init_node_irqs(node); @@ -256,13 +259,23 @@ asmlinkage void plat_irq_dispatch(void) return; } +#if defined(CONFIG_PCI_MSI) && defined(CONFIG_CPU_XLP) + /* PCI interrupts need a second level dispatch for MSI bits */ + if (i >= PIC_PCIE_LINK_MSI_IRQ(0) && i <= PIC_PCIE_LINK_MSI_IRQ(3)) { + nlm_dispatch_msi(node, i); + return; + } + if (i >= PIC_PCIE_MSIX_IRQ(0) && i <= PIC_PCIE_MSIX_IRQ(3)) { + nlm_dispatch_msix(node, i); + return; + } + +#endif /* top level irq handling */ do_IRQ(nlm_irq_to_xirq(node, i)); } #ifdef CONFIG_OF -static struct irq_domain *xlp_pic_domain; - static const struct irq_domain_ops xlp_pic_irq_domain_ops = { .xlate = irq_domain_xlate_onetwocell, }; @@ -271,8 +284,9 @@ static int __init xlp_of_pic_init(struct device_node *node, struct device_node *parent) { const int n_picirqs = PIC_IRT_LAST_IRQ - PIC_IRQ_BASE + 1; + struct irq_domain *xlp_pic_domain; struct resource res; - int socid, ret; + int socid, ret, bus; /* we need a hack to get the PIC's SoC chip id */ ret = of_address_to_resource(node, 0, &res); @@ -280,7 +294,34 @@ static int __init xlp_of_pic_init(struct device_node *node, pr_err("PIC %s: reg property not found!\n", node->name); return -EINVAL; } - socid = (res.start >> 18) & 0x3; + + if (cpu_is_xlp9xx()) { + bus = (res.start >> 20) & 0xf; + for (socid = 0; socid < NLM_NR_NODES; socid++) { + if (!nlm_node_present(socid)) + continue; + if (nlm_get_node(socid)->socbus == bus) + break; + } + if (socid == NLM_NR_NODES) { + pr_err("PIC %s: Node mapping for bus %d not found!\n", + node->name, bus); + return -EINVAL; + } + } else { + socid = (res.start >> 18) & 0x3; + if (!nlm_node_present(socid)) { + pr_err("PIC %s: node %d does not exist!\n", + node->name, socid); + return -EINVAL; + } + } + + if (!nlm_node_present(socid)) { + pr_err("PIC %s: node %d does not exist!\n", node->name, socid); + return -EINVAL; + } + xlp_pic_domain = irq_domain_add_legacy(node, n_picirqs, nlm_irq_to_xirq(socid, PIC_IRQ_BASE), PIC_IRQ_BASE, &xlp_pic_irq_domain_ops, NULL); @@ -288,8 +329,7 @@ static int __init xlp_of_pic_init(struct device_node *node, pr_err("PIC %s: Creating legacy domain failed!\n", node->name); return -EINVAL; } - pr_info("Node %d: IRQ domain created for PIC@%pa\n", socid, - &res.start); + pr_info("Node %d: IRQ domain created for PIC@%pR\n", socid, &res); return 0; } diff --git a/arch/mips/netlogic/common/reset.S b/arch/mips/netlogic/common/reset.S index adb18288a6c..701c4bcb9e4 100644 --- a/arch/mips/netlogic/common/reset.S +++ b/arch/mips/netlogic/common/reset.S @@ -32,10 +32,11 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <linux/init.h> #include <asm/asm.h> #include <asm/asm-offsets.h> +#include <asm/cpu.h> +#include <asm/cacheops.h> #include <asm/regdef.h> #include <asm/mipsregs.h> #include <asm/stackframe.h> @@ -50,8 +51,8 @@ #include <asm/netlogic/xlp-hal/cpucontrol.h> #define CP0_EBASE $15 -#define SYS_CPU_COHERENT_BASE(node) CKSEG1ADDR(XLP_DEFAULT_IO_BASE) + \ - XLP_IO_SYS_OFFSET(node) + XLP_IO_PCI_HDRSZ + \ +#define SYS_CPU_COHERENT_BASE CKSEG1ADDR(XLP_DEFAULT_IO_BASE) + \ + XLP_IO_SYS_OFFSET(0) + XLP_IO_PCI_HDRSZ + \ SYS_CPU_NONCOHERENT_MODE * 4 /* Enable XLP features and workarounds in the LSU */ @@ -74,35 +75,67 @@ .endm /* - * Low level flush for L1D cache on XLP, the normal cache ops does - * not do the complete and correct cache flush. + * Allow access to physical mem >64G by enabling ELPA in PAGEGRAIN + * register. This is needed before going to C code since the SP can + * in this region. Called from all HW threads. + */ +.macro xlp_early_mmu_init + mfc0 t0, CP0_PAGEMASK, 1 + li t1, (1 << 29) /* ELPA bit */ + or t0, t1 + mtc0 t0, CP0_PAGEMASK, 1 +.endm + +/* + * L1D cache has to be flushed before enabling threads in XLP. + * On XLP8xx/XLP3xx, we do a low level flush using processor control + * registers. On XLPII CPUs, usual cache instructions work. */ .macro xlp_flush_l1_dcache + mfc0 t0, CP0_EBASE, 0 + andi t0, t0, PRID_IMP_MASK + slt t1, t0, 0x1200 + beqz t1, 15f + nop + + /* XLP8xx low level cache flush */ li t0, LSU_DEBUG_DATA0 li t1, LSU_DEBUG_ADDR li t2, 0 /* index */ li t3, 0x1000 /* loop count */ -1: +11: sll v0, t2, 5 mtcr zero, t0 ori v1, v0, 0x3 /* way0 | write_enable | write_active */ mtcr v1, t1 -2: +12: mfcr v1, t1 andi v1, 0x1 /* wait for write_active == 0 */ - bnez v1, 2b + bnez v1, 12b nop mtcr zero, t0 ori v1, v0, 0x7 /* way1 | write_enable | write_active */ mtcr v1, t1 -3: +13: mfcr v1, t1 andi v1, 0x1 /* wait for write_active == 0 */ - bnez v1, 3b + bnez v1, 13b nop addi t2, 1 - bne t3, t2, 1b + bne t3, t2, 11b + nop + b 17f + nop + + /* XLPII CPUs, Invalidate all 64k of L1 D-cache */ +15: + li t0, 0x80000000 + li t1, 0x80010000 +16: cache Index_Writeback_Inv_D, 0(t0) + addiu t0, t0, 32 + bne t0, t1, 16b nop +17: .endm /* @@ -138,6 +171,17 @@ FEXPORT(nlm_reset_entry) nop 1: /* Entry point on core wakeup */ + mfc0 t0, CP0_EBASE, 0 /* processor ID */ + andi t0, PRID_IMP_MASK + li t1, 0x1500 /* XLP 9xx */ + beq t0, t1, 2f /* does not need to set coherent */ + nop + + li t1, 0x1300 /* XLP 5xx */ + beq t0, t1, 2f /* does not need to set coherent */ + nop + + /* set bit in SYS coherent register for the core */ mfc0 t0, CP0_EBASE, 1 mfc0 t1, CP0_EBASE, 1 srl t1, 5 @@ -149,7 +193,7 @@ FEXPORT(nlm_reset_entry) li t1, 0x1 sll t0, t1, t0 nor t0, t0, zero /* t0 <- ~(1 << core) */ - li t2, SYS_CPU_COHERENT_BASE(0) + li t2, SYS_CPU_COHERENT_BASE add t2, t2, t3 /* t2 <- SYS offset for node */ lw t1, 0(t2) and t1, t1, t0 @@ -159,17 +203,20 @@ FEXPORT(nlm_reset_entry) lw t1, 0(t2) sync +2: /* Configure LSU on Non-0 Cores. */ xlp_config_lsu /* FALL THROUGH */ /* - * Wake up sibling threads from the initial thread in - * a core. + * Wake up sibling threads from the initial thread in a core. */ EXPORT(nlm_boot_siblings) /* core L1D flush before enable threads */ xlp_flush_l1_dcache + /* save ra and sp, will be used later (only for boot cpu) */ + dmtc0 ra, $22, 6 + dmtc0 sp, $22, 7 /* Enable hw threads by writing to MAP_THREADMODE of the core */ li t0, CKSEG1ADDR(RESET_DATA_PHYS) lw t1, BOOT_THREAD_MODE(t0) /* t1 <- thread mode */ @@ -181,8 +228,10 @@ EXPORT(nlm_boot_siblings) /* * The new hardware thread starts at the next instruction * For all the cases other than core 0 thread 0, we will - * jump to the secondary wait function. - */ + * jump to the secondary wait function. + + * NOTE: All GPR contents are lost after the mtcr above! + */ mfc0 v0, CP0_EBASE, 1 andi v0, 0x3ff /* v0 <- node/core */ @@ -196,7 +245,9 @@ EXPORT(nlm_boot_siblings) #endif mtc0 t1, CP0_STATUS - /* mark CPU ready, careful here, previous mtcr trashed registers */ + xlp_early_mmu_init + + /* mark CPU ready */ li t3, CKSEG1ADDR(RESET_DATA_PHYS) ADDIU t1, t3, BOOT_CPU_READY sll v1, v0, 2 @@ -209,14 +260,12 @@ EXPORT(nlm_boot_siblings) nop /* - * For the boot CPU, we have to restore registers and - * return + * For the boot CPU, we have to restore ra and sp and return, rest + * of the registers will be restored by the caller */ -4: dmfc0 t0, $4, 2 /* restore SP from UserLocal */ - li t1, 0xfadebeef - dmtc0 t1, $4, 2 /* restore SP from UserLocal */ - PTR_SUBU sp, t0, PT_SIZE - RESTORE_ALL +4: + dmfc0 ra, $22, 6 + dmfc0 sp, $22, 7 jr ra nop EXPORT(nlm_reset_entry_end) @@ -224,6 +273,7 @@ EXPORT(nlm_reset_entry_end) LEAF(nlm_init_boot_cpu) #ifdef CONFIG_CPU_XLP xlp_config_lsu + xlp_early_mmu_init #endif jr ra nop diff --git a/arch/mips/netlogic/common/smp.c b/arch/mips/netlogic/common/smp.c index 6f8feb9efcf..4fde7ac76cc 100644 --- a/arch/mips/netlogic/common/smp.c +++ b/arch/mips/netlogic/common/smp.c @@ -63,7 +63,7 @@ void nlm_send_ipi_single(int logical_cpu, unsigned int action) uint64_t picbase; cpu = cpu_logical_map(logical_cpu); - node = cpu / NLM_CPUS_PER_NODE; + node = nlm_cpuid_to_node(cpu); picbase = nlm_get_node(node)->picbase; if (action & SMP_CALL_FUNCTION) @@ -135,10 +135,6 @@ void nlm_smp_finish(void) local_irq_enable(); } -void nlm_cpus_done(void) -{ -} - /* * Boot all other cpus in the system, initialize them, and bring them into * the boot function @@ -152,7 +148,7 @@ void nlm_boot_secondary(int logical_cpu, struct task_struct *idle) int cpu, node; cpu = cpu_logical_map(logical_cpu); - node = cpu / NLM_CPUS_PER_NODE; + node = nlm_cpuid_to_node(logical_cpu); nlm_next_sp = (unsigned long)__KSTK_TOS(idle); nlm_next_gp = (unsigned long)task_thread_info(idle); @@ -164,7 +160,7 @@ void nlm_boot_secondary(int logical_cpu, struct task_struct *idle) void __init nlm_smp_setup(void) { unsigned int boot_cpu; - int num_cpus, i, ncore; + int num_cpus, i, ncore, node; volatile u32 *cpu_ready = nlm_get_boot_data(BOOT_CPU_READY); char buf[64]; @@ -187,6 +183,8 @@ void __init nlm_smp_setup(void) __cpu_number_map[i] = num_cpus; __cpu_logical_map[num_cpus] = i; set_cpu_possible(num_cpus, true); + node = nlm_cpuid_to_node(i); + cpumask_set_cpu(num_cpus, &nlm_get_node(node)->cpumask); ++num_cpus; } } @@ -196,7 +194,7 @@ void __init nlm_smp_setup(void) cpumask_scnprintf(buf, ARRAY_SIZE(buf), cpu_possible_mask); pr_info("Possible CPU mask: %s\n", buf); - /* check with the cores we have worken up */ + /* check with the cores we have woken up */ for (ncore = 0, i = 0; i < NLM_NR_NODES; i++) ncore += hweight32(nlm_get_node(i)->coremask); @@ -211,6 +209,7 @@ static int nlm_parse_cpumask(cpumask_t *wakeup_mask) { uint32_t core0_thr_mask, core_thr_mask; int threadmode, i, j; + char buf[64]; core0_thr_mask = 0; for (i = 0; i < NLM_THREADS_PER_CORE; i++) @@ -245,8 +244,8 @@ static int nlm_parse_cpumask(cpumask_t *wakeup_mask) return threadmode; unsupp: - panic("Unsupported CPU mask %lx\n", - (unsigned long)cpumask_bits(wakeup_mask)[0]); + cpumask_scnprintf(buf, ARRAY_SIZE(buf), wakeup_mask); + panic("Unsupported CPU mask %s", buf); return 0; } @@ -275,7 +274,6 @@ struct plat_smp_ops nlm_smp_ops = { .send_ipi_mask = nlm_send_ipi_mask, .init_secondary = nlm_init_secondary, .smp_finish = nlm_smp_finish, - .cpus_done = nlm_cpus_done, .boot_secondary = nlm_boot_secondary, .smp_setup = nlm_smp_setup, .prepare_cpus = nlm_prepare_cpus, diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S index aa6cff0a229..805355b0bd0 100644 --- a/arch/mips/netlogic/common/smpboot.S +++ b/arch/mips/netlogic/common/smpboot.S @@ -32,7 +32,6 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include <linux/init.h> #include <asm/asm.h> #include <asm/asm-offsets.h> @@ -55,8 +54,9 @@ .set noat .set arch=xlr /* for mfcr/mtcr, XLR is sufficient */ -FEXPORT(xlp_boot_core0_siblings) /* "Master" cpu starts from here */ - dmtc0 sp, $4, 2 /* SP saved in UserLocal */ +/* Called by the boot cpu to wake up its sibling threads */ +NESTED(xlp_boot_core0_siblings, PT_SIZE, sp) + /* CPU register contents lost when enabling threads, save them first */ SAVE_ALL sync /* find the location to which nlm_boot_siblings was relocated */ @@ -66,9 +66,12 @@ FEXPORT(xlp_boot_core0_siblings) /* "Master" cpu starts from here */ dsubu t2, t1 daddu t2, t0 /* call it */ - jr t2 + jalr t2 nop - /* not reached */ + RESTORE_ALL + jr ra + nop +END(xlp_boot_core0_siblings) NESTED(nlm_boot_secondary_cpus, 16, sp) /* Initialize CP0 Status */ @@ -98,7 +101,7 @@ END(nlm_boot_secondary_cpus) * In case of RMIboot bootloader which is used on XLR boards, the CPUs * be already woken up and waiting in bootloader code. * This will get them out of the bootloader code and into linux. Needed - * because the bootloader area will be taken and initialized by linux. + * because the bootloader area will be taken and initialized by linux. */ NESTED(nlm_rmiboot_preboot, 16, sp) mfc0 t0, $15, 1 /* read ebase */ @@ -133,6 +136,7 @@ NESTED(nlm_rmiboot_preboot, 16, sp) or t1, t2, v1 /* put in new value */ mtcr t1, t0 /* update core control */ + /* wait for NMI to hit */ 1: wait b 1b nop diff --git a/arch/mips/netlogic/common/time.c b/arch/mips/netlogic/common/time.c index 13391b8a603..0c0a1a606f7 100644 --- a/arch/mips/netlogic/common/time.c +++ b/arch/mips/netlogic/common/time.c @@ -82,6 +82,7 @@ static struct clocksource csrc_pic = { static void nlm_init_pic_timer(void) { uint64_t picbase = nlm_get_node(0)->picbase; + u32 picfreq; nlm_pic_set_timer(picbase, PIC_CLOCK_TIMER, ~0ULL, 0, 0); if (current_cpu_data.cputype == CPU_XLR) { @@ -92,7 +93,9 @@ static void nlm_init_pic_timer(void) csrc_pic.read = nlm_get_pic_timer; } csrc_pic.rating = 1000; - clocksource_register_hz(&csrc_pic, pic_timer_freq()); + picfreq = pic_timer_freq(); + clocksource_register_hz(&csrc_pic, picfreq); + pr_info("PIC clock source added, frequency %d\n", picfreq); } void __init plat_time_init(void) |
