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