From 220d9122e8c5a467fdeefc1857e077f29a623bfd Mon Sep 17 00:00:00 2001 From: Jayachandran C <jchandra@broadcom.com> Date: Mon, 14 Jan 2013 15:11:54 +0000 Subject: MIPS: Netlogic: Optimize EIMR/EIRR accesses in 32-bit Provide functions ack_c0_eirr(), set_c0_eimr(), clear_c0_eimr() and read_c0_eirr_and_eimr() that do the EIMR and EIRR operations and update the interrupt handling code to use these functions. Also, use the EIMR register functions to mask interrupts in the irq code. The 64-bit interrupt request and mask registers (EIRR and EIMR) are accessed when the interrupts are off, and the common operations are to set or clear a bit in these registers. Using the 64-bit c0 access functions for these operations is not optimal in 32-bit, because it will disable/restore interrupts and split/join the 64-bit value during each register access. Signed-off-by: Jayachandran C <jchandra@broadcom.com> Patchwork: http://patchwork.linux-mips.org/patch/4790/ Signed-off-by: John Crispin <blogic@openwrt.org> --- arch/mips/include/asm/netlogic/mips-extns.h | 79 +++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) (limited to 'arch/mips/include/asm/netlogic') diff --git a/arch/mips/include/asm/netlogic/mips-extns.h b/arch/mips/include/asm/netlogic/mips-extns.h index 32ba6d95d47..cc4296595df 100644 --- a/arch/mips/include/asm/netlogic/mips-extns.h +++ b/arch/mips/include/asm/netlogic/mips-extns.h @@ -68,6 +68,85 @@ do { \ __write_64bit_c0_register($9, 7, (val)); \ } while (0) +/* + * Handling the 64 bit EIMR and EIRR registers in 32-bit mode with + * standard functions will be very inefficient. This provides + * optimized functions for the normal operations on the registers. + * + * Call with interrupts disabled. + */ +static inline void ack_c0_eirr(int irq) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set mips64\n\t" + ".set noat\n\t" + "li $1, 1\n\t" + "dsllv $1, $1, %0\n\t" + "dmtc0 $1, $9, 6\n\t" + ".set pop" + : : "r" (irq)); +} + +static inline void set_c0_eimr(int irq) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set mips64\n\t" + ".set noat\n\t" + "li $1, 1\n\t" + "dsllv %0, $1, %0\n\t" + "dmfc0 $1, $9, 7\n\t" + "or $1, %0\n\t" + "dmtc0 $1, $9, 7\n\t" + ".set pop" + : "+r" (irq)); +} + +static inline void clear_c0_eimr(int irq) +{ + __asm__ __volatile__( + ".set push\n\t" + ".set mips64\n\t" + ".set noat\n\t" + "li $1, 1\n\t" + "dsllv %0, $1, %0\n\t" + "dmfc0 $1, $9, 7\n\t" + "or $1, %0\n\t" + "xor $1, %0\n\t" + "dmtc0 $1, $9, 7\n\t" + ".set pop" + : "+r" (irq)); +} + +/* + * Read c0 eimr and c0 eirr, do AND of the two values, the result is + * the interrupts which are raised and are not masked. + */ +static inline uint64_t read_c0_eirr_and_eimr(void) +{ + uint64_t val; + +#ifdef CONFIG_64BIT + val = read_c0_eimr() & read_c0_eirr(); +#else + __asm__ __volatile__( + ".set push\n\t" + ".set mips64\n\t" + ".set noat\n\t" + "dmfc0 %M0, $9, 6\n\t" + "dmfc0 %L0, $9, 7\n\t" + "and %M0, %L0\n\t" + "dsll %L0, %M0, 32\n\t" + "dsra %M0, %M0, 32\n\t" + "dsra %L0, %L0, 32\n\t" + ".set pop" + : "=r" (val)); +#endif + + return val; +} + static inline int hard_smp_processor_id(void) { return __read_32bit_c0_register($15, 1) & 0x3ff; -- cgit v1.2.3-70-g09d2 From a69ba6293d11b7dfd395a742f3449d6ddda8ecad Mon Sep 17 00:00:00 2001 From: Jayachandran C <jchandra@broadcom.com> Date: Mon, 14 Jan 2013 15:11:56 +0000 Subject: MIPS: Netlogic: Split XLP L1 i-cache among threads Since we now use r4k cache code for Netlogic XLP, it is better to split L1 icache among the active threads, so that threads won't step on each other while flushing icache. The L1 dcache is already split among the threads in the core. Signed-off-by: Jayachandran C <jchandra@broadcom.com> Patchwork: http://patchwork.linux-mips.org/patch/4787/ Signed-off-by: John Crispin <blogic@openwrt.org> --- arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h | 2 ++ arch/mips/netlogic/common/smpboot.S | 6 ++++++ 2 files changed, 8 insertions(+) (limited to 'arch/mips/include/asm/netlogic') diff --git a/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h b/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h index 7b63a6b722a..6d2e58a9a54 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/cpucontrol.h @@ -46,6 +46,8 @@ #define CPU_BLOCKID_FPU 9 #define CPU_BLOCKID_MAP 10 +#define ICU_DEFEATURE 0x100 + #define LSU_DEFEATURE 0x304 #define LSU_DEBUG_ADDR 0x305 #define LSU_DEBUG_DATA0 0x306 diff --git a/arch/mips/netlogic/common/smpboot.S b/arch/mips/netlogic/common/smpboot.S index a0b74874beb..d772a87fe84 100644 --- a/arch/mips/netlogic/common/smpboot.S +++ b/arch/mips/netlogic/common/smpboot.S @@ -69,6 +69,12 @@ #endif mtcr t1, t0 + li t0, ICU_DEFEATURE + mfcr t1, t0 + ori t1, 0x1000 /* Enable Icache partitioning */ + mtcr t1, t0 + + #ifdef XLP_AX_WORKAROUND li t0, SCHED_DEFEATURE lui t1, 0x0100 /* Disable BRU accepting ALU ops */ -- cgit v1.2.3-70-g09d2 From 4e45e542cd742c1c3e30e7f252640644c66548b5 Mon Sep 17 00:00:00 2001 From: Jayachandran C <jchandra@broadcom.com> Date: Mon, 14 Jan 2013 15:11:57 +0000 Subject: MIPS: Netlogic: Use PIC timer as a clocksource The XLR/XLS/XLP PIC has a 8 countdown timers which run at the PIC frequencey. One of these can be used as a clocksource to provide timestamps that is common across cores. This can be used in place of the count/compare clocksource which is per-CPU. On XLR/XLS PIC registers are 32-bit, so we just use the lower 32-bits of the PIC counter. On XLP, the whole 64-bit can be used. Provide common macros and functions for PIC timer registers on XLR/XLS and XLP, and use them to register a PIC clocksource. Signed-off-by: Jayachandran C <jchandra@broadcom.com> Patchwork: http://patchwork.linux-mips.org/patch/4786/ Signed-off-by: John Crispin <blogic@openwrt.org> --- arch/mips/include/asm/netlogic/xlp-hal/pic.h | 12 +++++-- arch/mips/include/asm/netlogic/xlr/pic.h | 48 +++++++++++++++++++++++-- arch/mips/netlogic/common/irq.c | 2 +- arch/mips/netlogic/common/time.c | 52 ++++++++++++++++++++++++++++ arch/mips/netlogic/xlr/platform.c | 2 +- arch/mips/netlogic/xlr/setup.c | 2 +- 6 files changed, 110 insertions(+), 8 deletions(-) (limited to 'arch/mips/include/asm/netlogic') diff --git a/arch/mips/include/asm/netlogic/xlp-hal/pic.h b/arch/mips/include/asm/netlogic/xlp-hal/pic.h index b2e53a5383a..ea6768c3e9f 100644 --- a/arch/mips/include/asm/netlogic/xlp-hal/pic.h +++ b/arch/mips/include/asm/netlogic/xlp-hal/pic.h @@ -261,6 +261,8 @@ #define PIC_LOCAL_SCHEDULING 1 #define PIC_GLOBAL_SCHEDULING 0 +#define PIC_CLK_HZ 133333333 + #define nlm_read_pic_reg(b, r) nlm_read_reg64(b, r) #define nlm_write_pic_reg(b, r, v) nlm_write_reg64(b, r, v) #define nlm_get_pic_pcibase(node) nlm_pcicfg_base(XLP_IO_PIC_OFFSET(node)) @@ -315,6 +317,12 @@ nlm_pic_read_timer(uint64_t base, int timer) return nlm_read_pic_reg(base, PIC_TIMER_COUNT(timer)); } +static inline uint32_t +nlm_pic_read_timer32(uint64_t base, int timer) +{ + return (uint32_t)nlm_read_pic_reg(base, PIC_TIMER_COUNT(timer)); +} + static inline void nlm_pic_write_timer(uint64_t base, int timer, uint64_t value) { @@ -376,9 +384,9 @@ nlm_pic_ack(uint64_t base, int irt_num) } static inline void -nlm_pic_init_irt(uint64_t base, int irt, int irq, int hwt) +nlm_pic_init_irt(uint64_t base, int irt, int irq, int hwt, int en) { - nlm_pic_write_irt_direct(base, irt, 0, 0, 0, irq, hwt); + nlm_pic_write_irt_direct(base, irt, en, 0, 0, irq, hwt); } int nlm_irq_to_irt(int irq); diff --git a/arch/mips/include/asm/netlogic/xlr/pic.h b/arch/mips/include/asm/netlogic/xlr/pic.h index 9a691b1f91b..effa3377ded 100644 --- a/arch/mips/include/asm/netlogic/xlr/pic.h +++ b/arch/mips/include/asm/netlogic/xlr/pic.h @@ -35,10 +35,11 @@ #ifndef _ASM_NLM_XLR_PIC_H #define _ASM_NLM_XLR_PIC_H -#define PIC_CLKS_PER_SEC 66666666ULL +#define PIC_CLK_HZ 66666666 /* PIC hardware interrupt numbers */ #define PIC_IRT_WD_INDEX 0 #define PIC_IRT_TIMER_0_INDEX 1 +#define PIC_IRT_TIMER_INDEX(i) ((i) + PIC_IRT_TIMER_0_INDEX) #define PIC_IRT_TIMER_1_INDEX 2 #define PIC_IRT_TIMER_2_INDEX 3 #define PIC_IRT_TIMER_3_INDEX 4 @@ -99,6 +100,7 @@ /* PIC Registers */ #define PIC_CTRL 0x00 +#define PIC_CTRL_STE 8 /* timer enable start bit */ #define PIC_IPI 0x04 #define PIC_INT_ACK 0x06 @@ -251,12 +253,52 @@ nlm_pic_ack(uint64_t base, int irt) } static inline void -nlm_pic_init_irt(uint64_t base, int irt, int irq, int hwt) +nlm_pic_init_irt(uint64_t base, int irt, int irq, int hwt, int en) { nlm_write_reg(base, PIC_IRT_0(irt), (1u << hwt)); /* local scheduling, invalid, level by default */ nlm_write_reg(base, PIC_IRT_1(irt), - (1 << 30) | (1 << 6) | irq); + (en << 30) | (1 << 6) | irq); +} + +static inline uint64_t +nlm_pic_read_timer(uint64_t base, int timer) +{ + uint32_t up1, up2, low; + + up1 = nlm_read_reg(base, PIC_TIMER_COUNT_1(timer)); + low = nlm_read_reg(base, PIC_TIMER_COUNT_0(timer)); + up2 = nlm_read_reg(base, PIC_TIMER_COUNT_1(timer)); + + if (up1 != up2) /* wrapped, get the new low */ + low = nlm_read_reg(base, PIC_TIMER_COUNT_0(timer)); + return ((uint64_t)up2 << 32) | low; + +} + +static inline uint32_t +nlm_pic_read_timer32(uint64_t base, int timer) +{ + return nlm_read_reg(base, PIC_TIMER_COUNT_0(timer)); +} + +static inline void +nlm_pic_set_timer(uint64_t base, int timer, uint64_t value, int irq, int cpu) +{ + uint32_t up, low; + uint64_t pic_ctrl = nlm_read_reg(base, PIC_CTRL); + int en; + + en = (irq > 0); + up = value >> 32; + low = value & 0xFFFFFFFF; + nlm_write_reg(base, PIC_TIMER_MAXVAL_0(timer), low); + nlm_write_reg(base, PIC_TIMER_MAXVAL_1(timer), up); + nlm_pic_init_irt(base, PIC_IRT_TIMER_INDEX(timer), irq, cpu, 0); + + /* enable the timer */ + pic_ctrl |= (1 << (PIC_CTRL_STE + timer)); + nlm_write_reg(base, PIC_CTRL, pic_ctrl); } #endif #endif /* _ASM_NLM_XLR_PIC_H */ diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c index d42cd1a2a12..642f1e4c271 100644 --- a/arch/mips/netlogic/common/irq.c +++ b/arch/mips/netlogic/common/irq.c @@ -217,7 +217,7 @@ static void nlm_init_node_irqs(int node) nlm_setup_pic_irq(node, i, i, irt); /* set interrupts to first cpu in node */ nlm_pic_init_irt(nodep->picbase, irt, i, - node * NLM_CPUS_PER_NODE); + node * NLM_CPUS_PER_NODE, 0); irqmask |= (1ull << i); } nodep->irqmask = irqmask; diff --git a/arch/mips/netlogic/common/time.c b/arch/mips/netlogic/common/time.c index bd3e498157f..20f89bc0507 100644 --- a/arch/mips/netlogic/common/time.c +++ b/arch/mips/netlogic/common/time.c @@ -35,16 +35,68 @@ #include <linux/init.h> #include <asm/time.h> +#include <asm/cpu-features.h> + #include <asm/netlogic/interrupt.h> #include <asm/netlogic/common.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/pic.h> +#elif defined(CONFIG_CPU_XLR) +#include <asm/netlogic/xlr/iomap.h> +#include <asm/netlogic/xlr/pic.h> +#include <asm/netlogic/xlr/xlr.h> +#else +#error "Unknown CPU" +#endif unsigned int __cpuinit get_c0_compare_int(void) { return IRQ_TIMER; } +static cycle_t nlm_get_pic_timer(struct clocksource *cs) +{ + uint64_t picbase = nlm_get_node(0)->picbase; + + return ~nlm_pic_read_timer(picbase, PIC_CLOCK_TIMER); +} + +static cycle_t nlm_get_pic_timer32(struct clocksource *cs) +{ + uint64_t picbase = nlm_get_node(0)->picbase; + + return ~nlm_pic_read_timer32(picbase, PIC_CLOCK_TIMER); +} + +static struct clocksource csrc_pic = { + .name = "PIC", + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static void nlm_init_pic_timer(void) +{ + uint64_t picbase = nlm_get_node(0)->picbase; + + nlm_pic_set_timer(picbase, PIC_CLOCK_TIMER, ~0ULL, 0, 0); + if (current_cpu_data.cputype == CPU_XLR) { + csrc_pic.mask = CLOCKSOURCE_MASK(32); + csrc_pic.read = nlm_get_pic_timer32; + } else { + csrc_pic.mask = CLOCKSOURCE_MASK(64); + csrc_pic.read = nlm_get_pic_timer; + } + csrc_pic.rating = 1000; + clocksource_register_hz(&csrc_pic, PIC_CLK_HZ); +} + void __init plat_time_init(void) { + nlm_init_pic_timer(); mips_hpt_frequency = nlm_get_cpu_frequency(); pr_info("MIPS counter frequency [%ld]\n", (unsigned long)mips_hpt_frequency); diff --git a/arch/mips/netlogic/xlr/platform.c b/arch/mips/netlogic/xlr/platform.c index 507230eeb76..ce838f95135 100644 --- a/arch/mips/netlogic/xlr/platform.c +++ b/arch/mips/netlogic/xlr/platform.c @@ -64,7 +64,7 @@ void nlm_xlr_uart_out(struct uart_port *p, int offset, int value) .iotype = UPIO_MEM32, \ .flags = (UPF_SKIP_TEST | \ UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF),\ - .uartclk = PIC_CLKS_PER_SEC, \ + .uartclk = PIC_CLK_HZ, \ .type = PORT_16550A, \ .serial_in = nlm_xlr_uart_in, \ .serial_out = nlm_xlr_uart_out, \ diff --git a/arch/mips/netlogic/xlr/setup.c b/arch/mips/netlogic/xlr/setup.c index c5ce6992ac4..54b301c809e 100644 --- a/arch/mips/netlogic/xlr/setup.c +++ b/arch/mips/netlogic/xlr/setup.c @@ -70,7 +70,7 @@ static void __init nlm_early_serial_setup(void) s.iotype = UPIO_MEM32; s.regshift = 2; s.irq = PIC_UART_0_IRQ; - s.uartclk = PIC_CLKS_PER_SEC; + s.uartclk = PIC_CLK_HZ; s.serial_in = nlm_xlr_uart_in; s.serial_out = nlm_xlr_uart_out; s.mapbase = uart_base; -- cgit v1.2.3-70-g09d2