All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/8] Update Octeon watchdog driver.
@ 2017-08-29 15:40 Steven J. Hill
  2017-08-29 15:40 ` [PATCH 1/8] MIPS: Octeon: Add support for accessing the boot vector Steven J. Hill
                   ` (7 more replies)
  0 siblings, 8 replies; 14+ messages in thread
From: Steven J. Hill @ 2017-08-29 15:40 UTC (permalink / raw)
  To: linux-mips, linux-watchdog, ralf

This patchset updates the Octeon watchdog with bug fixes and new
platforms. This code has been tested on our 70xx and 78xx development
boards as well as an EdgeRouter PRO.

* The time it takes for the watchdog to trigger is now 1 second
  for all tested platforms. The various cores have different
  divisor values. Some of these were just plain wrong. Example:
  On our 78xx platform, it took 1m20s for the watchdog to trigger
  and reset the board.
* Support has been added for newer 7xxx SOCs.
* The boot vector code has been simplified and updated.

These watchdog driver changes are dependant on MIPS architecture
code changes. Would the watchdog driver maintainers be willing to
allow Ralf to include the driver code along with the next MIPS
architecture update? Thanks for considering. -Steve


Carlos Munoz (1):
  watchdog: octeon-wdt: Add support for 78XX SOCs.

David Daney (1):
  watchdog: octeon-wdt: Add support for cn68XX SOCs.

Steven J. Hill (6):
  MIPS: Octeon: Add support for accessing the boot vector.
  watchdog: octeon-wdt: Remove old boot vector code.
  MIPS: Octeon: Watchdog registers for 70xx, 73xx, 78xx, F75xx.
  MIPS: Octeon: Make CSR functions node aware.
  MIPS: Octeon: Allow access to CIU3 IRQ domains.
  watchdog: octeon-wdt: File cleaning.

 arch/mips/cavium-octeon/executive/Makefile         |   2 +-
 .../cavium-octeon/executive/cvmx-boot-vector.c     | 167 ++++++++++
 arch/mips/cavium-octeon/executive/cvmx-bootmem.c   |  85 +++++
 arch/mips/cavium-octeon/octeon-irq.c               |   9 +
 arch/mips/include/asm/octeon/cvmx-boot-vector.h    |  53 +++
 arch/mips/include/asm/octeon/cvmx-bootmem.h        |  28 ++
 arch/mips/include/asm/octeon/cvmx-ciu-defs.h       |  10 +
 arch/mips/include/asm/octeon/cvmx.h                |  28 ++
 arch/mips/include/asm/octeon/octeon.h              |   2 +
 drivers/watchdog/octeon-wdt-main.c                 | 354 ++++++++++-----------
 drivers/watchdog/octeon-wdt-nmi.S                  |  42 ++-
 11 files changed, 592 insertions(+), 188 deletions(-)
 create mode 100644 arch/mips/cavium-octeon/executive/cvmx-boot-vector.c
 create mode 100644 arch/mips/include/asm/octeon/cvmx-boot-vector.h

-- 
2.1.4


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 1/8] MIPS: Octeon: Add support for accessing the boot vector.
  2017-08-29 15:40 [PATCH 0/8] Update Octeon watchdog driver Steven J. Hill
@ 2017-08-29 15:40 ` Steven J. Hill
  2017-08-29 15:40 ` [PATCH 2/8] watchdog: octeon-wdt: Remove old boot vector code Steven J. Hill
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Steven J. Hill @ 2017-08-29 15:40 UTC (permalink / raw)
  To: linux-mips, linux-watchdog, ralf

Used by the Octeon watchdog driver to get the address of the
firmware boot vector.

Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
Acked-by: David Daney <david.daney@cavium.com>
---
 arch/mips/cavium-octeon/executive/Makefile         |   2 +-
 .../cavium-octeon/executive/cvmx-boot-vector.c     | 167 +++++++++++++++++++++
 arch/mips/cavium-octeon/executive/cvmx-bootmem.c   |  85 +++++++++++
 arch/mips/include/asm/octeon/cvmx-boot-vector.h    |  53 +++++++
 arch/mips/include/asm/octeon/cvmx-bootmem.h        |  28 ++++
 5 files changed, 334 insertions(+), 1 deletion(-)
 create mode 100644 arch/mips/cavium-octeon/executive/cvmx-boot-vector.c
 create mode 100644 arch/mips/include/asm/octeon/cvmx-boot-vector.h

diff --git a/arch/mips/cavium-octeon/executive/Makefile b/arch/mips/cavium-octeon/executive/Makefile
index b6d6e84..50b4278 100644
--- a/arch/mips/cavium-octeon/executive/Makefile
+++ b/arch/mips/cavium-octeon/executive/Makefile
@@ -16,4 +16,4 @@ obj-y += cvmx-pko.o cvmx-spi.o cvmx-cmd-queue.o \
 	cvmx-helper-loop.o cvmx-helper-spi.o cvmx-helper-util.o \
 	cvmx-interrupt-decodes.o cvmx-interrupt-rsl.o
 
-obj-y += cvmx-helper-errata.o cvmx-helper-jtag.o
+obj-y += cvmx-helper-errata.o cvmx-helper-jtag.o cvmx-boot-vector.o
diff --git a/arch/mips/cavium-octeon/executive/cvmx-boot-vector.c b/arch/mips/cavium-octeon/executive/cvmx-boot-vector.c
new file mode 100644
index 0000000..b7019d2
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-boot-vector.c
@@ -0,0 +1,167 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2004-2017 Cavium, Inc.
+ */
+
+
+/*
+  We install this program at the bootvector:
+------------------------------------
+	.set noreorder
+	.set nomacro
+	.set noat
+reset_vector:
+	dmtc0	$k0, $31, 0	# Save $k0 to DESAVE
+	dmtc0	$k1, $31, 3	# Save $k1 to KScratch2
+
+	mfc0	$k0, $12, 0	# Status
+	mfc0	$k1, $15, 1	# Ebase
+
+	ori	$k0, 0x84	# Enable 64-bit addressing, set
+				# ERL (should already be set)
+	andi	$k1, 0x3ff	# mask out core ID
+
+	mtc0	$k0, $12, 0	# Status
+	sll	$k1, 5
+
+	lui	$k0, 0xbfc0
+	cache	17, 0($0)	# Core-14345, clear L1 Dcache virtual
+				# tags if the core hit an NMI
+
+	ld	$k0, 0x78($k0)	# k0 <- (bfc00078) pointer to the reset vector
+	synci	0($0)		# Invalidate ICache to get coherent
+				# view of target code.
+
+	daddu	$k0, $k0, $k1
+	nop
+
+	ld	$k0, 0($k0)	# k0 <- core specific target address
+	dmfc0	$k1, $31, 3	# Restore $k1 from KScratch2
+
+	beqz	$k0, wait_loop	# Spin in wait loop
+	nop
+
+	jr	$k0
+	nop
+
+	nop			# NOPs needed here to fill delay slots
+	nop			# on endian reversal of previous instructions
+
+wait_loop:
+	wait
+	nop
+
+	b	wait_loop
+	nop
+
+	nop
+	nop
+------------------------------------
+
+0000000000000000 <reset_vector>:
+   0:	40baf800	dmtc0	k0,c0_desave
+   4:	40bbf803	dmtc0	k1,c0_kscratch2
+
+   8:	401a6000	mfc0	k0,c0_status
+   c:	401b7801	mfc0	k1,c0_ebase
+
+  10:	375a0084	ori	k0,k0,0x84
+  14:	337b03ff	andi	k1,k1,0x3ff
+
+  18:	409a6000	mtc0	k0,c0_status
+  1c:	001bd940	sll	k1,k1,0x5
+
+  20:	3c1abfc0	lui	k0,0xbfc0
+  24:	bc110000	cache	0x11,0(zero)
+
+  28:	df5a0078	ld	k0,120(k0)
+  2c:	041f0000	synci	0(zero)
+
+  30:	035bd02d	daddu	k0,k0,k1
+  34:	00000000	nop
+
+  38:	df5a0000	ld	k0,0(k0)
+  3c:	403bf803	dmfc0	k1,c0_kscratch2
+
+  40:	13400005	beqz	k0,58 <wait_loop>
+  44:	00000000	nop
+
+  48:	03400008	jr	k0
+  4c:	00000000	nop
+
+  50:	00000000	nop
+  54:	00000000	nop
+
+0000000000000058 <wait_loop>:
+  58:	42000020	wait
+  5c:	00000000	nop
+
+  60:	1000fffd	b	58 <wait_loop>
+  64:	00000000	nop
+
+  68:	00000000	nop
+  6c:	00000000	nop
+
+ */
+
+#include <asm/octeon/cvmx-boot-vector.h>
+
+static unsigned long long _cvmx_bootvector_data[16] = {
+	0x40baf80040bbf803ull,  /* patch low order 8-bits if no KScratch*/
+	0x401a6000401b7801ull,
+	0x375a0084337b03ffull,
+	0x409a6000001bd940ull,
+	0x3c1abfc0bc110000ull,
+	0xdf5a0078041f0000ull,
+	0x035bd02d00000000ull,
+	0xdf5a0000403bf803ull,  /* patch low order 8-bits if no KScratch*/
+	0x1340000500000000ull,
+	0x0340000800000000ull,
+	0x0000000000000000ull,
+	0x4200002000000000ull,
+	0x1000fffd00000000ull,
+	0x0000000000000000ull,
+	OCTEON_BOOT_MOVEABLE_MAGIC1,
+	0 /* To be filled in with address of vector block*/
+};
+
+/* 2^10 CPUs */
+#define VECTOR_TABLE_SIZE (1024 * sizeof(struct cvmx_boot_vector_element))
+
+static void cvmx_boot_vector_init(void *mem)
+{
+	uint64_t kseg0_mem;
+	int i;
+
+	memset(mem, 0, VECTOR_TABLE_SIZE);
+	kseg0_mem = cvmx_ptr_to_phys(mem) | 0x8000000000000000ull;
+
+	for (i = 0; i < 15; i++) {
+		uint64_t v = _cvmx_bootvector_data[i];
+
+		if (OCTEON_IS_OCTEON1PLUS() && (i == 0 || i == 7))
+			v &= 0xffffffff00000000ull; /* KScratch not availble. */
+		cvmx_write_csr(CVMX_MIO_BOOT_LOC_ADR, i * 8);
+		cvmx_write_csr(CVMX_MIO_BOOT_LOC_DAT, v);
+	}
+	cvmx_write_csr(CVMX_MIO_BOOT_LOC_ADR, 15 * 8);
+	cvmx_write_csr(CVMX_MIO_BOOT_LOC_DAT, kseg0_mem);
+	cvmx_write_csr(CVMX_MIO_BOOT_LOC_CFGX(0), 0x81fc0000);
+}
+
+/**
+ * Get a pointer to the per-core table of reset vector pointers
+ *
+ */
+struct cvmx_boot_vector_element *cvmx_boot_vector_get(void)
+{
+	struct cvmx_boot_vector_element *ret;
+
+	ret = cvmx_bootmem_alloc_named_range_once(VECTOR_TABLE_SIZE, 0,
+		(1ull << 32) - 1, 8, "__boot_vector1__", cvmx_boot_vector_init);
+	return ret;
+}
+EXPORT_SYMBOL(cvmx_boot_vector_get);
diff --git a/arch/mips/cavium-octeon/executive/cvmx-bootmem.c b/arch/mips/cavium-octeon/executive/cvmx-bootmem.c
index 8d54d77..94d97eb 100644
--- a/arch/mips/cavium-octeon/executive/cvmx-bootmem.c
+++ b/arch/mips/cavium-octeon/executive/cvmx-bootmem.c
@@ -44,6 +44,55 @@ static struct cvmx_bootmem_desc *cvmx_bootmem_desc;
 
 /* See header file for descriptions of functions */
 
+/**
+ * This macro returns the size of a member of a structure.
+ * Logically it is the same as "sizeof(s::field)" in C++, but
+ * C lacks the "::" operator.
+ */
+#define SIZEOF_FIELD(s, field) sizeof(((s *)NULL)->field)
+
+/**
+ * This macro returns a member of the
+ * cvmx_bootmem_named_block_desc_t structure. These members can't
+ * be directly addressed as they might be in memory not directly
+ * reachable. In the case where bootmem is compiled with
+ * LINUX_HOST, the structure itself might be located on a remote
+ * Octeon. The argument "field" is the member name of the
+ * cvmx_bootmem_named_block_desc_t to read. Regardless of the type
+ * of the field, the return type is always a uint64_t. The "addr"
+ * parameter is the physical address of the structure.
+ */
+#define CVMX_BOOTMEM_NAMED_GET_FIELD(addr, field)			\
+	__cvmx_bootmem_desc_get(addr,					\
+		offsetof(struct cvmx_bootmem_named_block_desc, field),	\
+		SIZEOF_FIELD(struct cvmx_bootmem_named_block_desc, field))
+
+/**
+ * This function is the implementation of the get macros defined
+ * for individual structure members. The argument are generated
+ * by the macros inorder to read only the needed memory.
+ *
+ * @param base   64bit physical address of the complete structure
+ * @param offset Offset from the beginning of the structure to the member being
+ *               accessed.
+ * @param size   Size of the structure member.
+ *
+ * @return Value of the structure member promoted into a uint64_t.
+ */
+static inline uint64_t __cvmx_bootmem_desc_get(uint64_t base, int offset,
+					       int size)
+{
+	base = (1ull << 63) | (base + offset);
+	switch (size) {
+	case 4:
+		return cvmx_read64_uint32(base);
+	case 8:
+		return cvmx_read64_uint64(base);
+	default:
+		return 0;
+	}
+}
+
 /*
  * Wrapper functions are provided for reading/writing the size and
  * next block values as these may not be directly addressible (in 32
@@ -98,6 +147,42 @@ void *cvmx_bootmem_alloc(uint64_t size, uint64_t alignment)
 	return cvmx_bootmem_alloc_range(size, alignment, 0, 0);
 }
 
+void *cvmx_bootmem_alloc_named_range_once(uint64_t size, uint64_t min_addr,
+					  uint64_t max_addr, uint64_t align,
+					  char *name,
+					  void (*init) (void *))
+{
+	int64_t addr;
+	void *ptr;
+	uint64_t named_block_desc_addr;
+
+	named_block_desc_addr = (uint64_t)
+		cvmx_bootmem_phy_named_block_find(name,
+						  (uint32_t)CVMX_BOOTMEM_FLAG_NO_LOCKING);
+
+	if (named_block_desc_addr) {
+		addr = CVMX_BOOTMEM_NAMED_GET_FIELD(named_block_desc_addr,
+						    base_addr);
+		return cvmx_phys_to_ptr(addr);
+	}
+
+	addr = cvmx_bootmem_phy_named_block_alloc(size, min_addr, max_addr,
+						  align, name,
+						  (uint32_t)CVMX_BOOTMEM_FLAG_NO_LOCKING);
+
+	if (addr < 0)
+		return NULL;
+	ptr = cvmx_phys_to_ptr(addr);
+
+	if (init)
+		init(ptr);
+	else
+		memset(ptr, 0, size);
+
+	return ptr;
+}
+EXPORT_SYMBOL(cvmx_bootmem_alloc_named_range_once);
+
 void *cvmx_bootmem_alloc_named_range(uint64_t size, uint64_t min_addr,
 				     uint64_t max_addr, uint64_t align,
 				     char *name)
diff --git a/arch/mips/include/asm/octeon/cvmx-boot-vector.h b/arch/mips/include/asm/octeon/cvmx-boot-vector.h
new file mode 100644
index 0000000..8db0824
--- /dev/null
+++ b/arch/mips/include/asm/octeon/cvmx-boot-vector.h
@@ -0,0 +1,53 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003-2017 Cavium, Inc.
+ */
+
+#ifndef __CVMX_BOOT_VECTOR_H__
+#define __CVMX_BOOT_VECTOR_H__
+
+#include <asm/octeon/octeon.h>
+
+/*
+ * The boot vector table is made up of an array of 1024 elements of
+ * struct cvmx_boot_vector_element.  There is one entry for each
+ * possible MIPS CPUNum, indexed by the CPUNum.
+ *
+ * Once cvmx_boot_vector_get() returns a non-NULL value (indicating
+ * success), NMI to a core will cause execution to transfer to the
+ * target_ptr location for that core's entry in the vector table.
+ *
+ * The struct cvmx_boot_vector_element fields app0, app1, and app2 can
+ * be used by the application that has set the target_ptr in any
+ * application specific manner, they are not touched by the vectoring
+ * code.
+ *
+ * The boot vector code clobbers the CP0_DESAVE register, and on
+ * OCTEON II and later CPUs also clobbers CP0_KScratch2.  All GP
+ * registers are preserved, except on pre-OCTEON II CPUs, where k1 is
+ * clobbered.
+ *
+ */
+
+
+/*
+ * Applications install the boot bus code in cvmx-boot-vector.c, which
+ * uses this magic:
+ */
+#define OCTEON_BOOT_MOVEABLE_MAGIC1 0xdb00110ad358eacdull
+
+struct cvmx_boot_vector_element {
+	/* kseg0 or xkphys address of target code. */
+	uint64_t target_ptr;
+	/* Three application specific arguments. */
+	uint64_t app0;
+	uint64_t app1;
+	uint64_t app2;
+};
+
+struct cvmx_boot_vector_element *cvmx_boot_vector_get(void);
+
+#endif /* __CVMX_BOOT_VECTOR_H__ */
diff --git a/arch/mips/include/asm/octeon/cvmx-bootmem.h b/arch/mips/include/asm/octeon/cvmx-bootmem.h
index 3745625..72d2e40 100644
--- a/arch/mips/include/asm/octeon/cvmx-bootmem.h
+++ b/arch/mips/include/asm/octeon/cvmx-bootmem.h
@@ -255,6 +255,34 @@ extern void *cvmx_bootmem_alloc_named_range(uint64_t size, uint64_t min_addr,
 					    uint64_t max_addr, uint64_t align,
 					    char *name);
 
+/**
+ * Allocate if needed a block of memory from a specific range of the
+ * free list that was passed to the application by the bootloader, and
+ * assign it a name in the global named block table.  (part of the
+ * cvmx_bootmem_descriptor_t structure) Named blocks can later be
+ * freed.  If the requested name block is already allocated, return
+ * the pointer to block of memory.  If request cannot be satisfied
+ * within the address range specified, NULL is returned
+ *
+ * @param size   Size in bytes of block to allocate
+ * @param min_addr  minimum address of range
+ * @param max_addr  maximum address of range
+ * @param align  Alignment of memory to be allocated. (must be a power of 2)
+ * @param name   name of block - must be less than CVMX_BOOTMEM_NAME_LEN bytes
+ * @param init   Initialization function
+ *
+ * The initialization function is optional, if omitted the named block
+ * is initialized to all zeros when it is created, i.e. once.
+ *
+ * @return pointer to block of memory, NULL on error
+ */
+void *cvmx_bootmem_alloc_named_range_once(uint64_t size,
+					  uint64_t min_addr,
+					  uint64_t max_addr,
+					  uint64_t align,
+					  char *name,
+					  void (*init) (void *));
+
 extern int cvmx_bootmem_free_named(char *name);
 
 /**
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2/8] watchdog: octeon-wdt: Remove old boot vector code.
  2017-08-29 15:40 [PATCH 0/8] Update Octeon watchdog driver Steven J. Hill
  2017-08-29 15:40 ` [PATCH 1/8] MIPS: Octeon: Add support for accessing the boot vector Steven J. Hill
@ 2017-08-29 15:40 ` Steven J. Hill
  2017-08-30  4:33   ` Guenter Roeck
  2017-08-29 15:40 ` [PATCH 3/8] MIPS: Octeon: Watchdog registers for 70xx, 73xx, 78xx, F75xx Steven J. Hill
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 14+ messages in thread
From: Steven J. Hill @ 2017-08-29 15:40 UTC (permalink / raw)
  To: linux-mips, linux-watchdog, ralf

Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
Acked-by: David Daney <david.daney@cavium.com>
---
 drivers/watchdog/octeon-wdt-main.c | 134 +++----------------------------------
 drivers/watchdog/octeon-wdt-nmi.S  |  42 +++++++++---
 2 files changed, 44 insertions(+), 132 deletions(-)

diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c
index b5cdceb..fbdd484 100644
--- a/drivers/watchdog/octeon-wdt-main.c
+++ b/drivers/watchdog/octeon-wdt-main.c
@@ -73,6 +73,7 @@
 #include <asm/uasm.h>
 
 #include <asm/octeon/octeon.h>
+#include <asm/octeon/cvmx-boot-vector.h>
 
 /* The count needed to achieve timeout_sec. */
 static unsigned int timeout_cnt;
@@ -104,122 +105,10 @@ MODULE_PARM_DESC(nowayout,
 	"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
-static u32 nmi_stage1_insns[64] __initdata;
-/* We need one branch and therefore one relocation per target label. */
-static struct uasm_label labels[5] __initdata;
-static struct uasm_reloc relocs[5] __initdata;
-
-enum lable_id {
-	label_enter_bootloader = 1
-};
-
-/* Some CP0 registers */
-#define K0		26
-#define C0_CVMMEMCTL 11, 7
-#define C0_STATUS 12, 0
-#define C0_EBASE 15, 1
-#define C0_DESAVE 31, 0
+static struct cvmx_boot_vector_element *octeon_wdt_bootvector;
 
 void octeon_wdt_nmi_stage2(void);
 
-static void __init octeon_wdt_build_stage1(void)
-{
-	int i;
-	int len;
-	u32 *p = nmi_stage1_insns;
-#ifdef CONFIG_HOTPLUG_CPU
-	struct uasm_label *l = labels;
-	struct uasm_reloc *r = relocs;
-#endif
-
-	/*
-	 * For the next few instructions running the debugger may
-	 * cause corruption of k0 in the saved registers. Since we're
-	 * about to crash, nobody probably cares.
-	 *
-	 * Save K0 into the debug scratch register
-	 */
-	uasm_i_dmtc0(&p, K0, C0_DESAVE);
-
-	uasm_i_mfc0(&p, K0, C0_STATUS);
-#ifdef CONFIG_HOTPLUG_CPU
-	if (octeon_bootloader_entry_addr)
-		uasm_il_bbit0(&p, &r, K0, ilog2(ST0_NMI),
-			      label_enter_bootloader);
-#endif
-	/* Force 64-bit addressing enabled */
-	uasm_i_ori(&p, K0, K0, ST0_UX | ST0_SX | ST0_KX);
-	uasm_i_mtc0(&p, K0, C0_STATUS);
-
-#ifdef CONFIG_HOTPLUG_CPU
-	if (octeon_bootloader_entry_addr) {
-		uasm_i_mfc0(&p, K0, C0_EBASE);
-		/* Coreid number in K0 */
-		uasm_i_andi(&p, K0, K0, 0xf);
-		/* 8 * coreid in bits 16-31 */
-		uasm_i_dsll_safe(&p, K0, K0, 3 + 16);
-		uasm_i_ori(&p, K0, K0, 0x8001);
-		uasm_i_dsll_safe(&p, K0, K0, 16);
-		uasm_i_ori(&p, K0, K0, 0x0700);
-		uasm_i_drotr_safe(&p, K0, K0, 32);
-		/*
-		 * Should result in: 0x8001,0700,0000,8*coreid which is
-		 * CVMX_CIU_WDOGX(coreid) - 0x0500
-		 *
-		 * Now ld K0, CVMX_CIU_WDOGX(coreid)
-		 */
-		uasm_i_ld(&p, K0, 0x500, K0);
-		/*
-		 * If bit one set handle the NMI as a watchdog event.
-		 * otherwise transfer control to bootloader.
-		 */
-		uasm_il_bbit0(&p, &r, K0, 1, label_enter_bootloader);
-		uasm_i_nop(&p);
-	}
-#endif
-
-	/* Clear Dcache so cvmseg works right. */
-	uasm_i_cache(&p, 1, 0, 0);
-
-	/* Use K0 to do a read/modify/write of CVMMEMCTL */
-	uasm_i_dmfc0(&p, K0, C0_CVMMEMCTL);
-	/* Clear out the size of CVMSEG	*/
-	uasm_i_dins(&p, K0, 0, 0, 6);
-	/* Set CVMSEG to its largest value */
-	uasm_i_ori(&p, K0, K0, 0x1c0 | 54);
-	/* Store the CVMMEMCTL value */
-	uasm_i_dmtc0(&p, K0, C0_CVMMEMCTL);
-
-	/* Load the address of the second stage handler */
-	UASM_i_LA(&p, K0, (long)octeon_wdt_nmi_stage2);
-	uasm_i_jr(&p, K0);
-	uasm_i_dmfc0(&p, K0, C0_DESAVE);
-
-#ifdef CONFIG_HOTPLUG_CPU
-	if (octeon_bootloader_entry_addr) {
-		uasm_build_label(&l, p, label_enter_bootloader);
-		/* Jump to the bootloader and restore K0 */
-		UASM_i_LA(&p, K0, (long)octeon_bootloader_entry_addr);
-		uasm_i_jr(&p, K0);
-		uasm_i_dmfc0(&p, K0, C0_DESAVE);
-	}
-#endif
-	uasm_resolve_relocs(relocs, labels);
-
-	len = (int)(p - nmi_stage1_insns);
-	pr_debug("Synthesized NMI stage 1 handler (%d instructions)\n", len);
-
-	pr_debug("\t.set push\n");
-	pr_debug("\t.set noreorder\n");
-	for (i = 0; i < len; i++)
-		pr_debug("\t.word 0x%08x\n", nmi_stage1_insns[i]);
-	pr_debug("\t.set pop\n");
-
-	if (len > 32)
-		panic("NMI stage 1 handler exceeds 32 instructions, was %d\n",
-		      len);
-}
-
 static int cpu2core(int cpu)
 {
 #ifdef CONFIG_SMP
@@ -402,6 +291,8 @@ static int octeon_wdt_cpu_online(unsigned int cpu)
 
 	core = cpu2core(cpu);
 
+	octeon_wdt_bootvector[core].target_ptr = (u64)octeon_wdt_nmi_stage2;
+
 	/* Disable it before doing anything with the interrupts. */
 	ciu_wdog.u64 = 0;
 	cvmx_write_csr(CVMX_CIU_WDOGX(core), ciu_wdog.u64);
@@ -544,6 +435,12 @@ static int __init octeon_wdt_init(void)
 	int ret;
 	u64 *ptr;
 
+	octeon_wdt_bootvector = cvmx_boot_vector_get();
+	if (!octeon_wdt_bootvector) {
+		pr_err("Error: Cannot allocate boot vector.\n");
+		return -ENOMEM;
+	}
+
 	/*
 	 * Watchdog time expiration length = The 16 bits of LEN
 	 * represent the most significant bits of a 24 bit decrementer
@@ -576,17 +473,6 @@ static int __init octeon_wdt_init(void)
 		return ret;
 	}
 
-	/* Build the NMI handler ... */
-	octeon_wdt_build_stage1();
-
-	/* ... and install it. */
-	ptr = (u64 *) nmi_stage1_insns;
-	for (i = 0; i < 16; i++) {
-		cvmx_write_csr(CVMX_MIO_BOOT_LOC_ADR, i * 8);
-		cvmx_write_csr(CVMX_MIO_BOOT_LOC_DAT, ptr[i]);
-	}
-	cvmx_write_csr(CVMX_MIO_BOOT_LOC_CFGX(0), 0x81fc0000);
-
 	cpumask_clear(&irq_enabled_cpus);
 
 	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "watchdog/octeon:online",
diff --git a/drivers/watchdog/octeon-wdt-nmi.S b/drivers/watchdog/octeon-wdt-nmi.S
index 8a900a5..97f6eb7 100644
--- a/drivers/watchdog/octeon-wdt-nmi.S
+++ b/drivers/watchdog/octeon-wdt-nmi.S
@@ -3,20 +3,40 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2007 Cavium Networks
+ * Copyright (C) 2007-2017 Cavium, Inc.
  */
 #include <asm/asm.h>
 #include <asm/regdef.h>
 
-#define SAVE_REG(r)	sd $r, -32768+6912-(32-r)*8($0)
+#define CVMSEG_BASE	-32768
+#define CVMSEG_SIZE	6912
+#define SAVE_REG(r)	sd $r, CVMSEG_BASE + CVMSEG_SIZE - ((32 - r) * 8)($0)
 
         NESTED(octeon_wdt_nmi_stage2, 0, sp)
 	.set 	push
 	.set 	noreorder
 	.set 	noat
-	/* Save all registers to the top CVMSEG. This shouldn't
+	/* Clear Dcache so cvmseg works right. */
+	cache	1,0($0)
+	/* Use K0 to do a read/modify/write of CVMMEMCTL */
+	dmfc0	k0, $11, 7
+	/* Clear out the size of CVMSEG	*/
+	dins	k0, $0, 0, 6
+	/* Set CVMSEG to its largest value */
+	ori	k0, k0, 0x1c0 | 54
+	/* Store the CVMMEMCTL value */
+	dmtc0	k0, $11, 7
+	/*
+	 * Restore K0 from the debug scratch register, it was saved in
+	 * the boot-vector code.
+	 */
+	dmfc0	k0, $31
+
+	/*
+	 * Save all registers to the top CVMSEG. This shouldn't
 	 * corrupt any state used by the kernel. Also all registers
-	 * should have the value right before the NMI. */
+	 * should have the value right before the NMI.
+	 */
 	SAVE_REG(0)
 	SAVE_REG(1)
 	SAVE_REG(2)
@@ -49,16 +69,22 @@
 	SAVE_REG(29)
 	SAVE_REG(30)
 	SAVE_REG(31)
+	/* Write zero to all CVMSEG locations per Core-15169 */
+	dli	a0, CVMSEG_SIZE - (33 * 8)
+1:	sd	zero, CVMSEG_BASE(a0)
+	daddiu	a0, a0, -8
+	bgez	a0, 1b
+	nop
 	/* Set the stack to begin right below the registers */
-	li	sp, -32768+6912-32*8
+	dli	sp, CVMSEG_BASE + CVMSEG_SIZE - (32 * 8)
 	/* Load the address of the third stage handler */
-	dla	a0, octeon_wdt_nmi_stage3
+	dla	$25, octeon_wdt_nmi_stage3
 	/* Call the third stage handler */
-	jal	a0
+	jal	$25
 	/* a0 is the address of the saved registers */
 	 move	a0, sp
 	/* Loop forvever if we get here. */
-1:	b	1b
+2:	b	2b
 	nop
 	.set pop
 	END(octeon_wdt_nmi_stage2)
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 3/8] MIPS: Octeon: Watchdog registers for 70xx, 73xx, 78xx, F75xx.
  2017-08-29 15:40 [PATCH 0/8] Update Octeon watchdog driver Steven J. Hill
  2017-08-29 15:40 ` [PATCH 1/8] MIPS: Octeon: Add support for accessing the boot vector Steven J. Hill
  2017-08-29 15:40 ` [PATCH 2/8] watchdog: octeon-wdt: Remove old boot vector code Steven J. Hill
@ 2017-08-29 15:40 ` Steven J. Hill
  2017-08-29 15:40 ` [PATCH 4/8] MIPS: Octeon: Make CSR functions node aware Steven J. Hill
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Steven J. Hill @ 2017-08-29 15:40 UTC (permalink / raw)
  To: linux-mips, linux-watchdog, ralf

From: "Steven J. Hill" <Steven.Hill@cavium.com>

Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
Acked-by: David Daney <david.daney@cavium.com>
---
 arch/mips/include/asm/octeon/cvmx-ciu-defs.h | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/mips/include/asm/octeon/cvmx-ciu-defs.h b/arch/mips/include/asm/octeon/cvmx-ciu-defs.h
index 0dd0e40..6e61792 100644
--- a/arch/mips/include/asm/octeon/cvmx-ciu-defs.h
+++ b/arch/mips/include/asm/octeon/cvmx-ciu-defs.h
@@ -128,6 +128,7 @@ static inline uint64_t CVMX_CIU_PP_POKEX(unsigned long offset)
 	case OCTEON_CN52XX & OCTEON_FAMILY_MASK:
 	case OCTEON_CNF71XX & OCTEON_FAMILY_MASK:
 	case OCTEON_CN61XX & OCTEON_FAMILY_MASK:
+	case OCTEON_CN70XX & OCTEON_FAMILY_MASK:
 		return CVMX_ADD_IO_SEG(0x0001070000000580ull) + (offset) * 8;
 	case OCTEON_CN31XX & OCTEON_FAMILY_MASK:
 	case OCTEON_CN50XX & OCTEON_FAMILY_MASK:
@@ -143,6 +144,10 @@ static inline uint64_t CVMX_CIU_PP_POKEX(unsigned long offset)
 		return CVMX_ADD_IO_SEG(0x0001070000000580ull) + (offset) * 8;
 	case OCTEON_CN68XX & OCTEON_FAMILY_MASK:
 		return CVMX_ADD_IO_SEG(0x0001070100100200ull) + (offset) * 8;
+	case OCTEON_CNF75XX & OCTEON_FAMILY_MASK:
+	case OCTEON_CN73XX & OCTEON_FAMILY_MASK:
+	case OCTEON_CN78XX & OCTEON_FAMILY_MASK:
+		return CVMX_ADD_IO_SEG(0x0001010000030000ull) + (offset) * 8;
 	}
 	return CVMX_ADD_IO_SEG(0x0001070000000580ull) + (offset) * 8;
 }
@@ -180,6 +185,7 @@ static inline uint64_t CVMX_CIU_WDOGX(unsigned long offset)
 	case OCTEON_CN52XX & OCTEON_FAMILY_MASK:
 	case OCTEON_CNF71XX & OCTEON_FAMILY_MASK:
 	case OCTEON_CN61XX & OCTEON_FAMILY_MASK:
+	case OCTEON_CN70XX & OCTEON_FAMILY_MASK:
 		return CVMX_ADD_IO_SEG(0x0001070000000500ull) + (offset) * 8;
 	case OCTEON_CN31XX & OCTEON_FAMILY_MASK:
 	case OCTEON_CN50XX & OCTEON_FAMILY_MASK:
@@ -195,6 +201,10 @@ static inline uint64_t CVMX_CIU_WDOGX(unsigned long offset)
 		return CVMX_ADD_IO_SEG(0x0001070000000500ull) + (offset) * 8;
 	case OCTEON_CN68XX & OCTEON_FAMILY_MASK:
 		return CVMX_ADD_IO_SEG(0x0001070100100000ull) + (offset) * 8;
+	case OCTEON_CNF75XX & OCTEON_FAMILY_MASK:
+	case OCTEON_CN73XX & OCTEON_FAMILY_MASK:
+	case OCTEON_CN78XX & OCTEON_FAMILY_MASK:
+		return CVMX_ADD_IO_SEG(0x0001010000020000ull) + (offset) * 8;
 	}
 	return CVMX_ADD_IO_SEG(0x0001070000000500ull) + (offset) * 8;
 }
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 4/8] MIPS: Octeon: Make CSR functions node aware.
  2017-08-29 15:40 [PATCH 0/8] Update Octeon watchdog driver Steven J. Hill
                   ` (2 preceding siblings ...)
  2017-08-29 15:40 ` [PATCH 3/8] MIPS: Octeon: Watchdog registers for 70xx, 73xx, 78xx, F75xx Steven J. Hill
@ 2017-08-29 15:40 ` Steven J. Hill
  2017-08-29 15:40 ` [PATCH 5/8] MIPS: Octeon: Allow access to CIU3 IRQ domains Steven J. Hill
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Steven J. Hill @ 2017-08-29 15:40 UTC (permalink / raw)
  To: linux-mips, linux-watchdog, ralf

From: "Steven J. Hill" <Steven.Hill@cavium.com>

Updates CSR read/write functions to be aware of nodes present in
systems with CIU3 support.

Signed-off-by: Steven J. Hill <Steven.Hill@cavium.com>
Acked-by: David Daney <david.daney@cavium.com>
---
 arch/mips/include/asm/octeon/cvmx.h | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/arch/mips/include/asm/octeon/cvmx.h b/arch/mips/include/asm/octeon/cvmx.h
index e638735..205ab2c 100644
--- a/arch/mips/include/asm/octeon/cvmx.h
+++ b/arch/mips/include/asm/octeon/cvmx.h
@@ -357,6 +357,34 @@ static inline unsigned int cvmx_get_local_core_num(void)
 	return cvmx_get_core_num() & ((1 << CVMX_NODE_NO_SHIFT) - 1);
 }
 
+#define CVMX_NODE_BITS         (2)     /* Number of bits to define a node */
+#define CVMX_MAX_NODES         (1 << CVMX_NODE_BITS)
+#define CVMX_NODE_IO_SHIFT     (36)
+#define CVMX_NODE_MEM_SHIFT    (40)
+#define CVMX_NODE_IO_MASK      ((uint64_t)CVMX_NODE_MASK << CVMX_NODE_IO_SHIFT)
+
+static inline void cvmx_write_csr_node(uint64_t node, uint64_t csr_addr,
+				       uint64_t val)
+{
+	uint64_t composite_csr_addr, node_addr;
+
+	node_addr = (node & CVMX_NODE_MASK) << CVMX_NODE_IO_SHIFT;
+	composite_csr_addr = (csr_addr & ~CVMX_NODE_IO_MASK) | node_addr;
+
+	cvmx_write64_uint64(composite_csr_addr, val);
+	if (((csr_addr >> 40) & 0x7ffff) == (0x118))
+		cvmx_read64_uint64(CVMX_MIO_BOOT_BIST_STAT | node_addr);
+}
+
+static inline uint64_t cvmx_read_csr_node(uint64_t node, uint64_t csr_addr)
+{
+	uint64_t node_addr;
+
+	node_addr = (csr_addr & ~CVMX_NODE_IO_MASK) |
+		    (node & CVMX_NODE_MASK) << CVMX_NODE_IO_SHIFT;
+	return cvmx_read_csr(node_addr);
+}
+
 /**
  * Returns the number of bits set in the provided value.
  * Simple wrapper for POP instruction.
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 5/8] MIPS: Octeon: Allow access to CIU3 IRQ domains.
  2017-08-29 15:40 [PATCH 0/8] Update Octeon watchdog driver Steven J. Hill
                   ` (3 preceding siblings ...)
  2017-08-29 15:40 ` [PATCH 4/8] MIPS: Octeon: Make CSR functions node aware Steven J. Hill
@ 2017-08-29 15:40 ` Steven J. Hill
  2017-08-29 15:40 ` [PATCH 6/8] watchdog: octeon-wdt: File cleaning Steven J. Hill
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Steven J. Hill @ 2017-08-29 15:40 UTC (permalink / raw)
  To: linux-mips, linux-watchdog, ralf

From: "Steven J. Hill" <Steven.Hill@cavium.com>

Add accessor function octeon_irq_get_block_domain() for cores
with a CIU3.

Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
Acked-by: David Daney <david.daney@cavium.com>
---
 arch/mips/cavium-octeon/octeon-irq.c  | 9 +++++++++
 arch/mips/include/asm/octeon/octeon.h | 2 ++
 2 files changed, 11 insertions(+)

diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c
index c1eb1ff..5b3a3f6 100644
--- a/arch/mips/cavium-octeon/octeon-irq.c
+++ b/arch/mips/cavium-octeon/octeon-irq.c
@@ -2963,3 +2963,12 @@ void octeon_fixup_irqs(void)
 }
 
 #endif /* CONFIG_HOTPLUG_CPU */
+
+struct irq_domain *octeon_irq_get_block_domain(int node, uint8_t block)
+{
+	struct octeon_ciu3_info *ciu3_info;
+
+	ciu3_info = octeon_ciu3_info_per_node[node & CVMX_NODE_MASK];
+	return ciu3_info->domain[block];
+}
+EXPORT_SYMBOL(octeon_irq_get_block_domain);
diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h
index 07c0516..c99c4b6 100644
--- a/arch/mips/include/asm/octeon/octeon.h
+++ b/arch/mips/include/asm/octeon/octeon.h
@@ -362,4 +362,6 @@ extern void octeon_fixup_irqs(void);
 
 extern struct semaphore octeon_bootbus_sem;
 
+struct irq_domain *octeon_irq_get_block_domain(int node, uint8_t block);
+
 #endif /* __ASM_OCTEON_OCTEON_H */
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 6/8] watchdog: octeon-wdt: File cleaning.
  2017-08-29 15:40 [PATCH 0/8] Update Octeon watchdog driver Steven J. Hill
                   ` (4 preceding siblings ...)
  2017-08-29 15:40 ` [PATCH 5/8] MIPS: Octeon: Allow access to CIU3 IRQ domains Steven J. Hill
@ 2017-08-29 15:40 ` Steven J. Hill
  2017-08-30  4:33   ` Guenter Roeck
  2017-08-29 15:40 ` [PATCH 7/8] watchdog: octeon-wdt: Add support for cn68XX SOCs Steven J. Hill
  2017-08-29 15:40 ` [PATCH 8/8] watchdog: octeon-wdt: Add support for 78XX SOCs Steven J. Hill
  7 siblings, 1 reply; 14+ messages in thread
From: Steven J. Hill @ 2017-08-29 15:40 UTC (permalink / raw)
  To: linux-mips, linux-watchdog, ralf

From: "Steven J. Hill" <Steven.Hill@cavium.com>

* Update copyright and company name.
* Remove unused headers.
* Fix variable spelling and data type.
* Use octal values for module parameters.

Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
Acked-by: David Daney <david.daney@cavium.com>
---
 drivers/watchdog/octeon-wdt-main.c | 45 +++++++++++++++++++++++++-------------
 1 file changed, 30 insertions(+), 15 deletions(-)

diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c
index fbdd484..73b5102 100644
--- a/drivers/watchdog/octeon-wdt-main.c
+++ b/drivers/watchdog/octeon-wdt-main.c
@@ -1,7 +1,7 @@
 /*
  * Octeon Watchdog driver
  *
- * Copyright (C) 2007, 2008, 2009, 2010 Cavium Networks
+ * Copyright (C) 2007-2017 Cavium, Inc.
  *
  * Converted to use WATCHDOG_CORE by Aaro Koskinen <aaro.koskinen@iki.fi>.
  *
@@ -59,14 +59,9 @@
 #include <linux/interrupt.h>
 #include <linux/watchdog.h>
 #include <linux/cpumask.h>
-#include <linux/bitops.h>
-#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/cpu.h>
-#include <linux/smp.h>
-#include <linux/fs.h>
 #include <linux/irq.h>
 
 #include <asm/mipsregs.h>
@@ -85,7 +80,7 @@ static unsigned int max_timeout_sec;
 static unsigned int timeout_sec;
 
 /* Set to non-zero when userspace countdown mode active */
-static int do_coundown;
+static bool do_countdown;
 static unsigned int countdown_reset;
 static unsigned int per_cpu_countdown[NR_CPUS];
 
@@ -94,17 +89,22 @@ static cpumask_t irq_enabled_cpus;
 #define WD_TIMO 60			/* Default heartbeat = 60 seconds */
 
 static int heartbeat = WD_TIMO;
-module_param(heartbeat, int, S_IRUGO);
+module_param(heartbeat, int, 0444);
 MODULE_PARM_DESC(heartbeat,
 	"Watchdog heartbeat in seconds. (0 < heartbeat, default="
 				__MODULE_STRING(WD_TIMO) ")");
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, bool, S_IRUGO);
+module_param(nowayout, bool, 0444);
 MODULE_PARM_DESC(nowayout,
 	"Watchdog cannot be stopped once started (default="
 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
+static int disable;
+module_param(disable, int, 0444);
+MODULE_PARM_DESC(disable,
+	"Disable the watchdog entirely (default=0)");
+
 static struct cvmx_boot_vector_element *octeon_wdt_bootvector;
 
 void octeon_wdt_nmi_stage2(void);
@@ -140,7 +140,7 @@ static irqreturn_t octeon_wdt_poke_irq(int cpl, void *dev_id)
 	unsigned int core = cvmx_get_core_num();
 	int cpu = core2cpu(core);
 
-	if (do_coundown) {
+	if (do_countdown) {
 		if (per_cpu_countdown[cpu] > 0) {
 			/* We're alive, poke the watchdog */
 			cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
@@ -324,11 +324,14 @@ static int octeon_wdt_ping(struct watchdog_device __always_unused *wdog)
 	int cpu;
 	int coreid;
 
+	if (disable)
+		return 0;
+
 	for_each_online_cpu(cpu) {
 		coreid = cpu2core(cpu);
 		cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1);
 		per_cpu_countdown[cpu] = countdown_reset;
-		if ((countdown_reset || !do_coundown) &&
+		if ((countdown_reset || !do_countdown) &&
 		    !cpumask_test_cpu(cpu, &irq_enabled_cpus)) {
 			/* We have to enable the irq */
 			int irq = OCTEON_IRQ_WDOG0 + coreid;
@@ -378,6 +381,9 @@ static int octeon_wdt_set_timeout(struct watchdog_device *wdog,
 
 	octeon_wdt_calc_parameters(t);
 
+	if (disable)
+		return 0;
+
 	for_each_online_cpu(cpu) {
 		coreid = cpu2core(cpu);
 		cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1);
@@ -394,13 +400,13 @@ static int octeon_wdt_set_timeout(struct watchdog_device *wdog,
 static int octeon_wdt_start(struct watchdog_device *wdog)
 {
 	octeon_wdt_ping(wdog);
-	do_coundown = 1;
+	do_countdown = 1;
 	return 0;
 }
 
 static int octeon_wdt_stop(struct watchdog_device *wdog)
 {
-	do_coundown = 0;
+	do_countdown = 0;
 	octeon_wdt_ping(wdog);
 	return 0;
 }
@@ -473,6 +479,11 @@ static int __init octeon_wdt_init(void)
 		return ret;
 	}
 
+	if (disable) {
+		pr_notice("disabled\n");
+		return 0;
+	}
+
 	cpumask_clear(&irq_enabled_cpus);
 
 	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "watchdog/octeon:online",
@@ -493,6 +504,10 @@ static int __init octeon_wdt_init(void)
 static void __exit octeon_wdt_cleanup(void)
 {
 	watchdog_unregister_device(&octeon_wdt);
+
+	if (disable)
+		return;
+
 	cpuhp_remove_state(octeon_wdt_online);
 
 	/*
@@ -503,7 +518,7 @@ static void __exit octeon_wdt_cleanup(void)
 }
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Cavium Networks <support@caviumnetworks.com>");
-MODULE_DESCRIPTION("Cavium Networks Octeon Watchdog driver.");
+MODULE_AUTHOR("Cavium Inc. <support@cavium.com>");
+MODULE_DESCRIPTION("Cavium Inc. OCTEON Watchdog driver.");
 module_init(octeon_wdt_init);
 module_exit(octeon_wdt_cleanup);
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 7/8] watchdog: octeon-wdt: Add support for cn68XX SOCs.
  2017-08-29 15:40 [PATCH 0/8] Update Octeon watchdog driver Steven J. Hill
                   ` (5 preceding siblings ...)
  2017-08-29 15:40 ` [PATCH 6/8] watchdog: octeon-wdt: File cleaning Steven J. Hill
@ 2017-08-29 15:40 ` Steven J. Hill
  2017-08-30  4:34   ` Guenter Roeck
  2017-08-29 15:40 ` [PATCH 8/8] watchdog: octeon-wdt: Add support for 78XX SOCs Steven J. Hill
  7 siblings, 1 reply; 14+ messages in thread
From: Steven J. Hill @ 2017-08-29 15:40 UTC (permalink / raw)
  To: linux-mips, linux-watchdog, ralf

From: David Daney <david.daney@cavium.com>

Signed-off-by: David Daney <david.daney@cavium.com>
Signed-off-by: Carlos Munoz <cmunoz@caviumnetworks.com>
Signed-off-by: Chandrakala Chavva <cchavva@caviumnetworks.com>
---
 drivers/watchdog/octeon-wdt-main.c | 48 +++++++++++++++++++++++++++-----------
 1 file changed, 35 insertions(+), 13 deletions(-)

diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c
index 73b5102..410800f 100644
--- a/drivers/watchdog/octeon-wdt-main.c
+++ b/drivers/watchdog/octeon-wdt-main.c
@@ -69,6 +69,9 @@
 
 #include <asm/octeon/octeon.h>
 #include <asm/octeon/cvmx-boot-vector.h>
+#include <asm/octeon/cvmx-ciu2-defs.h>
+
+static int divisor;
 
 /* The count needed to achieve timeout_sec. */
 static unsigned int timeout_cnt;
@@ -227,10 +230,10 @@ void octeon_wdt_nmi_stage3(u64 reg[32])
 	u64 cp0_epc = read_c0_epc();
 
 	/* Delay so output from all cores output is not jumbled together. */
-	__delay(100000000ull * coreid);
+	udelay(85000 * coreid);
 
 	octeon_wdt_write_string("\r\n*** NMI Watchdog interrupt on Core 0x");
-	octeon_wdt_write_hex(coreid, 1);
+	octeon_wdt_write_hex(coreid, 2);
 	octeon_wdt_write_string(" ***\r\n");
 	for (i = 0; i < 32; i++) {
 		octeon_wdt_write_string("\t");
@@ -253,11 +256,28 @@ void octeon_wdt_nmi_stage3(u64 reg[32])
 	octeon_wdt_write_hex(cp0_cause, 16);
 	octeon_wdt_write_string("\r\n");
 
-	octeon_wdt_write_string("\tsum0\t0x");
-	octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU_INTX_SUM0(coreid * 2)), 16);
-	octeon_wdt_write_string("\ten0\t0x");
-	octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU_INTX_EN0(coreid * 2)), 16);
-	octeon_wdt_write_string("\r\n");
+	/* The CIU register is different for each Octeon model. */
+	if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
+		octeon_wdt_write_string("\tsrc_wd\t0x");
+		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_SRC_PPX_IP2_WDOG(coreid)), 16);
+		octeon_wdt_write_string("\ten_wd\t0x");
+		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_EN_PPX_IP2_WDOG(coreid)), 16);
+		octeon_wdt_write_string("\r\n");
+		octeon_wdt_write_string("\tsrc_rml\t0x");
+		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_SRC_PPX_IP2_RML(coreid)), 16);
+		octeon_wdt_write_string("\ten_rml\t0x");
+		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_EN_PPX_IP2_RML(coreid)), 16);
+		octeon_wdt_write_string("\r\n");
+		octeon_wdt_write_string("\tsum\t0x");
+		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_SUM_PPX_IP2(coreid)), 16);
+		octeon_wdt_write_string("\r\n");
+	} else if (!octeon_has_feature(OCTEON_FEATURE_CIU3)) {
+		octeon_wdt_write_string("\tsum0\t0x");
+		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU_INTX_SUM0(coreid * 2)), 16);
+		octeon_wdt_write_string("\ten0\t0x");
+		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU_INTX_EN0(coreid * 2)), 16);
+		octeon_wdt_write_string("\r\n");
+	}
 
 	octeon_wdt_write_string("*** Chip soft reset soon ***\r\n");
 }
@@ -366,7 +386,7 @@ static void octeon_wdt_calc_parameters(int t)
 
 	countdown_reset = periods > 2 ? periods - 2 : 0;
 	heartbeat = t;
-	timeout_cnt = ((octeon_get_io_clock_rate() >> 8) * timeout_sec) >> 8;
+	timeout_cnt = ((octeon_get_io_clock_rate() / divisor) * timeout_sec) >> 8;
 }
 
 static int octeon_wdt_set_timeout(struct watchdog_device *wdog,
@@ -437,9 +457,7 @@ static enum cpuhp_state octeon_wdt_online;
  */
 static int __init octeon_wdt_init(void)
 {
-	int i;
 	int ret;
-	u64 *ptr;
 
 	octeon_wdt_bootvector = cvmx_boot_vector_get();
 	if (!octeon_wdt_bootvector) {
@@ -447,10 +465,15 @@ static int __init octeon_wdt_init(void)
 		return -ENOMEM;
 	}
 
+	if (OCTEON_IS_MODEL(OCTEON_CN68XX))
+		divisor = 0x200;
+	else
+		divisor = 0x100;
+
 	/*
 	 * Watchdog time expiration length = The 16 bits of LEN
 	 * represent the most significant bits of a 24 bit decrementer
-	 * that decrements every 256 cycles.
+	 * that decrements every divisor cycle.
 	 *
 	 * Try for a timeout of 5 sec, if that fails a smaller number
 	 * of even seconds,
@@ -458,8 +481,7 @@ static int __init octeon_wdt_init(void)
 	max_timeout_sec = 6;
 	do {
 		max_timeout_sec--;
-		timeout_cnt = ((octeon_get_io_clock_rate() >> 8) *
-			      max_timeout_sec) >> 8;
+		timeout_cnt = ((octeon_get_io_clock_rate() / divisor) * max_timeout_sec) >> 8;
 	} while (timeout_cnt > 65535);
 
 	BUG_ON(timeout_cnt == 0);
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 8/8] watchdog: octeon-wdt: Add support for 78XX SOCs.
  2017-08-29 15:40 [PATCH 0/8] Update Octeon watchdog driver Steven J. Hill
                   ` (6 preceding siblings ...)
  2017-08-29 15:40 ` [PATCH 7/8] watchdog: octeon-wdt: Add support for cn68XX SOCs Steven J. Hill
@ 2017-08-29 15:40 ` Steven J. Hill
  2017-08-30  4:34   ` Guenter Roeck
  7 siblings, 1 reply; 14+ messages in thread
From: Steven J. Hill @ 2017-08-29 15:40 UTC (permalink / raw)
  To: linux-mips, linux-watchdog, ralf

From: Carlos Munoz <carlos.munoz@caviumnetworks.com>

Signed-off-by: Carlos Munoz <carlos.munoz@caviumnetworks.com>
Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
Acked-by: David Daney <david.daney@cavium.com>
---
 drivers/watchdog/octeon-wdt-main.c | 133 ++++++++++++++++++++++++++++---------
 1 file changed, 103 insertions(+), 30 deletions(-)

diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c
index 410800f..0ec419a 100644
--- a/drivers/watchdog/octeon-wdt-main.c
+++ b/drivers/watchdog/octeon-wdt-main.c
@@ -70,6 +70,10 @@
 #include <asm/octeon/octeon.h>
 #include <asm/octeon/cvmx-boot-vector.h>
 #include <asm/octeon/cvmx-ciu2-defs.h>
+#include <asm/octeon/cvmx-rst-defs.h>
+
+/* Watchdog interrupt major block number (8 MSBs of intsn) */
+#define WD_BLOCK_NUMBER		0x01
 
 static int divisor;
 
@@ -91,6 +95,8 @@ static cpumask_t irq_enabled_cpus;
 
 #define WD_TIMO 60			/* Default heartbeat = 60 seconds */
 
+#define CVMX_GSERX_SCRATCH(offset) (CVMX_ADD_IO_SEG(0x0001180090000020ull) + ((offset) & 15) * 0x1000000ull)
+
 static int heartbeat = WD_TIMO;
 module_param(heartbeat, int, 0444);
 MODULE_PARM_DESC(heartbeat,
@@ -115,21 +121,12 @@ void octeon_wdt_nmi_stage2(void);
 static int cpu2core(int cpu)
 {
 #ifdef CONFIG_SMP
-	return cpu_logical_map(cpu);
+	return cpu_logical_map(cpu) & 0x3f;
 #else
 	return cvmx_get_core_num();
 #endif
 }
 
-static int core2cpu(int coreid)
-{
-#ifdef CONFIG_SMP
-	return cpu_number_map(coreid);
-#else
-	return 0;
-#endif
-}
-
 /**
  * Poke the watchdog when an interrupt is received
  *
@@ -140,13 +137,14 @@ static int core2cpu(int coreid)
  */
 static irqreturn_t octeon_wdt_poke_irq(int cpl, void *dev_id)
 {
-	unsigned int core = cvmx_get_core_num();
-	int cpu = core2cpu(core);
+	int cpu = raw_smp_processor_id();
+	unsigned int core = cpu2core(cpu);
+	int node = cpu_to_node(cpu);
 
 	if (do_countdown) {
 		if (per_cpu_countdown[cpu] > 0) {
 			/* We're alive, poke the watchdog */
-			cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
+			cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(core), 1);
 			per_cpu_countdown[cpu]--;
 		} else {
 			/* Bad news, you are about to reboot. */
@@ -155,7 +153,7 @@ static irqreturn_t octeon_wdt_poke_irq(int cpl, void *dev_id)
 		}
 	} else {
 		/* Not open, just ping away... */
-		cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
+		cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(core), 1);
 	}
 	return IRQ_HANDLED;
 }
@@ -280,26 +278,74 @@ void octeon_wdt_nmi_stage3(u64 reg[32])
 	}
 
 	octeon_wdt_write_string("*** Chip soft reset soon ***\r\n");
+
+	/*
+	 * G-30204: We must trigger a soft reset before watchdog
+	 * does an incomplete job of doing it.
+	 */
+	if (OCTEON_IS_OCTEON3() && !OCTEON_IS_MODEL(OCTEON_CN70XX)) {
+		u64 scr;
+		unsigned int node = cvmx_get_node_num();
+		unsigned int lcore = cvmx_get_local_core_num();
+		union cvmx_ciu_wdogx ciu_wdog;
+
+		/*
+		 * Wait for other cores to print out information, but
+		 * not too long.  Do the soft reset before watchdog
+		 * can trigger it.
+		 */
+		do {
+			ciu_wdog.u64 = cvmx_read_csr_node(node, CVMX_CIU_WDOGX(lcore));
+		} while (ciu_wdog.s.cnt > 0x10000);
+
+		scr = cvmx_read_csr_node(0, CVMX_GSERX_SCRATCH(0));
+		scr |= 1 << 11; /* Indicate watchdog in bit 11 */
+		cvmx_write_csr_node(0, CVMX_GSERX_SCRATCH(0), scr);
+		cvmx_write_csr_node(0, CVMX_RST_SOFT_RST, 1);
+	}
+}
+
+static int octeon_wdt_cpu_to_irq(int cpu)
+{
+	unsigned int coreid;
+	int node;
+	int irq;
+
+	coreid = cpu2core(cpu);
+	node = cpu_to_node(cpu);
+
+	if (octeon_has_feature(OCTEON_FEATURE_CIU3)) {
+		struct irq_domain *domain;
+		int hwirq;
+
+		domain = octeon_irq_get_block_domain(node,
+						     WD_BLOCK_NUMBER);
+		hwirq = WD_BLOCK_NUMBER << 12 | 0x200 | coreid;
+		irq = irq_find_mapping(domain, hwirq);
+	} else {
+		irq = OCTEON_IRQ_WDOG0 + coreid;
+	}
+	return irq;
 }
 
 static int octeon_wdt_cpu_pre_down(unsigned int cpu)
 {
 	unsigned int core;
-	unsigned int irq;
+	int node;
 	union cvmx_ciu_wdogx ciu_wdog;
 
 	core = cpu2core(cpu);
 
-	irq = OCTEON_IRQ_WDOG0 + core;
+	node = cpu_to_node(cpu);
 
 	/* Poke the watchdog to clear out its state */
-	cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
+	cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(core), 1);
 
 	/* Disable the hardware. */
 	ciu_wdog.u64 = 0;
-	cvmx_write_csr(CVMX_CIU_WDOGX(core), ciu_wdog.u64);
+	cvmx_write_csr_node(node, CVMX_CIU_WDOGX(core), ciu_wdog.u64);
 
-	free_irq(irq, octeon_wdt_poke_irq);
+	free_irq(octeon_wdt_cpu_to_irq(cpu), octeon_wdt_poke_irq);
 	return 0;
 }
 
@@ -308,33 +354,56 @@ static int octeon_wdt_cpu_online(unsigned int cpu)
 	unsigned int core;
 	unsigned int irq;
 	union cvmx_ciu_wdogx ciu_wdog;
+	int node;
+	struct irq_domain *domain;
+	int hwirq;
 
 	core = cpu2core(cpu);
+	node = cpu_to_node(cpu);
 
 	octeon_wdt_bootvector[core].target_ptr = (u64)octeon_wdt_nmi_stage2;
 
 	/* Disable it before doing anything with the interrupts. */
 	ciu_wdog.u64 = 0;
-	cvmx_write_csr(CVMX_CIU_WDOGX(core), ciu_wdog.u64);
+	cvmx_write_csr_node(node, CVMX_CIU_WDOGX(core), ciu_wdog.u64);
 
 	per_cpu_countdown[cpu] = countdown_reset;
 
-	irq = OCTEON_IRQ_WDOG0 + core;
+	if (octeon_has_feature(OCTEON_FEATURE_CIU3)) {
+		/* Must get the domain for the watchdog block */
+		domain = octeon_irq_get_block_domain(node, WD_BLOCK_NUMBER);
+
+		/* Get a irq for the wd intsn (hardware interrupt) */
+		hwirq = WD_BLOCK_NUMBER << 12 | 0x200 | core;
+		irq = irq_create_mapping(domain, hwirq);
+		irqd_set_trigger_type(irq_get_irq_data(irq),
+				      IRQ_TYPE_EDGE_RISING);
+	} else
+		irq = OCTEON_IRQ_WDOG0 + core;
 
 	if (request_irq(irq, octeon_wdt_poke_irq,
 			IRQF_NO_THREAD, "octeon_wdt", octeon_wdt_poke_irq))
 		panic("octeon_wdt: Couldn't obtain irq %d", irq);
 
+	/* Must set the irq affinity here */
+	if (octeon_has_feature(OCTEON_FEATURE_CIU3)) {
+		cpumask_t mask;
+
+		cpumask_clear(&mask);
+		cpumask_set_cpu(cpu, &mask);
+		irq_set_affinity(irq, &mask);
+	}
+
 	cpumask_set_cpu(cpu, &irq_enabled_cpus);
 
 	/* Poke the watchdog to clear out its state */
-	cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
+	cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(core), 1);
 
 	/* Finally enable the watchdog now that all handlers are installed */
 	ciu_wdog.u64 = 0;
 	ciu_wdog.s.len = timeout_cnt;
 	ciu_wdog.s.mode = 3;	/* 3 = Interrupt + NMI + Soft-Reset */
-	cvmx_write_csr(CVMX_CIU_WDOGX(core), ciu_wdog.u64);
+	cvmx_write_csr_node(node, CVMX_CIU_WDOGX(core), ciu_wdog.u64);
 
 	return 0;
 }
@@ -343,20 +412,20 @@ static int octeon_wdt_ping(struct watchdog_device __always_unused *wdog)
 {
 	int cpu;
 	int coreid;
+	int node;
 
 	if (disable)
 		return 0;
 
 	for_each_online_cpu(cpu) {
 		coreid = cpu2core(cpu);
-		cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1);
+		node = cpu_to_node(cpu);
+		cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(coreid), 1);
 		per_cpu_countdown[cpu] = countdown_reset;
 		if ((countdown_reset || !do_countdown) &&
 		    !cpumask_test_cpu(cpu, &irq_enabled_cpus)) {
 			/* We have to enable the irq */
-			int irq = OCTEON_IRQ_WDOG0 + coreid;
-
-			enable_irq(irq);
+			enable_irq(octeon_wdt_cpu_to_irq(cpu));
 			cpumask_set_cpu(cpu, &irq_enabled_cpus);
 		}
 	}
@@ -395,6 +464,7 @@ static int octeon_wdt_set_timeout(struct watchdog_device *wdog,
 	int cpu;
 	int coreid;
 	union cvmx_ciu_wdogx ciu_wdog;
+	int node;
 
 	if (t <= 0)
 		return -1;
@@ -406,12 +476,13 @@ static int octeon_wdt_set_timeout(struct watchdog_device *wdog,
 
 	for_each_online_cpu(cpu) {
 		coreid = cpu2core(cpu);
-		cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1);
+		node = cpu_to_node(cpu);
+		cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(coreid), 1);
 		ciu_wdog.u64 = 0;
 		ciu_wdog.s.len = timeout_cnt;
 		ciu_wdog.s.mode = 3;	/* 3 = Interrupt + NMI + Soft-Reset */
-		cvmx_write_csr(CVMX_CIU_WDOGX(coreid), ciu_wdog.u64);
-		cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1);
+		cvmx_write_csr_node(node, CVMX_CIU_WDOGX(coreid), ciu_wdog.u64);
+		cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(coreid), 1);
 	}
 	octeon_wdt_ping(wdog); /* Get the irqs back on. */
 	return 0;
@@ -467,6 +538,8 @@ static int __init octeon_wdt_init(void)
 
 	if (OCTEON_IS_MODEL(OCTEON_CN68XX))
 		divisor = 0x200;
+	else if (OCTEON_IS_MODEL(OCTEON_CN78XX))
+		divisor = 0x400;
 	else
 		divisor = 0x100;
 
-- 
2.1.4


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/8] watchdog: octeon-wdt: Remove old boot vector code.
  2017-08-29 15:40 ` [PATCH 2/8] watchdog: octeon-wdt: Remove old boot vector code Steven J. Hill
@ 2017-08-30  4:33   ` Guenter Roeck
  2017-08-30 14:16     ` Steven J. Hill
  0 siblings, 1 reply; 14+ messages in thread
From: Guenter Roeck @ 2017-08-30  4:33 UTC (permalink / raw)
  To: Steven J. Hill; +Cc: linux-mips, linux-watchdog, ralf

On Tue, Aug 29, 2017 at 10:40:32AM -0500, Steven J. Hill wrote:
> Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
> Acked-by: David Daney <david.daney@cavium.com>

Acked-by: Guenter Roeck <linux@roeck-us.net>

I assume this series will go through the mips tree.

Guenter

> ---
>  drivers/watchdog/octeon-wdt-main.c | 134 +++----------------------------------
>  drivers/watchdog/octeon-wdt-nmi.S  |  42 +++++++++---
>  2 files changed, 44 insertions(+), 132 deletions(-)
> 
> diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c
> index b5cdceb..fbdd484 100644
> --- a/drivers/watchdog/octeon-wdt-main.c
> +++ b/drivers/watchdog/octeon-wdt-main.c
> @@ -73,6 +73,7 @@
>  #include <asm/uasm.h>
>  
>  #include <asm/octeon/octeon.h>
> +#include <asm/octeon/cvmx-boot-vector.h>
>  
>  /* The count needed to achieve timeout_sec. */
>  static unsigned int timeout_cnt;
> @@ -104,122 +105,10 @@ MODULE_PARM_DESC(nowayout,
>  	"Watchdog cannot be stopped once started (default="
>  				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
>  
> -static u32 nmi_stage1_insns[64] __initdata;
> -/* We need one branch and therefore one relocation per target label. */
> -static struct uasm_label labels[5] __initdata;
> -static struct uasm_reloc relocs[5] __initdata;
> -
> -enum lable_id {
> -	label_enter_bootloader = 1
> -};
> -
> -/* Some CP0 registers */
> -#define K0		26
> -#define C0_CVMMEMCTL 11, 7
> -#define C0_STATUS 12, 0
> -#define C0_EBASE 15, 1
> -#define C0_DESAVE 31, 0
> +static struct cvmx_boot_vector_element *octeon_wdt_bootvector;
>  
>  void octeon_wdt_nmi_stage2(void);
>  
> -static void __init octeon_wdt_build_stage1(void)
> -{
> -	int i;
> -	int len;
> -	u32 *p = nmi_stage1_insns;
> -#ifdef CONFIG_HOTPLUG_CPU
> -	struct uasm_label *l = labels;
> -	struct uasm_reloc *r = relocs;
> -#endif
> -
> -	/*
> -	 * For the next few instructions running the debugger may
> -	 * cause corruption of k0 in the saved registers. Since we're
> -	 * about to crash, nobody probably cares.
> -	 *
> -	 * Save K0 into the debug scratch register
> -	 */
> -	uasm_i_dmtc0(&p, K0, C0_DESAVE);
> -
> -	uasm_i_mfc0(&p, K0, C0_STATUS);
> -#ifdef CONFIG_HOTPLUG_CPU
> -	if (octeon_bootloader_entry_addr)
> -		uasm_il_bbit0(&p, &r, K0, ilog2(ST0_NMI),
> -			      label_enter_bootloader);
> -#endif
> -	/* Force 64-bit addressing enabled */
> -	uasm_i_ori(&p, K0, K0, ST0_UX | ST0_SX | ST0_KX);
> -	uasm_i_mtc0(&p, K0, C0_STATUS);
> -
> -#ifdef CONFIG_HOTPLUG_CPU
> -	if (octeon_bootloader_entry_addr) {
> -		uasm_i_mfc0(&p, K0, C0_EBASE);
> -		/* Coreid number in K0 */
> -		uasm_i_andi(&p, K0, K0, 0xf);
> -		/* 8 * coreid in bits 16-31 */
> -		uasm_i_dsll_safe(&p, K0, K0, 3 + 16);
> -		uasm_i_ori(&p, K0, K0, 0x8001);
> -		uasm_i_dsll_safe(&p, K0, K0, 16);
> -		uasm_i_ori(&p, K0, K0, 0x0700);
> -		uasm_i_drotr_safe(&p, K0, K0, 32);
> -		/*
> -		 * Should result in: 0x8001,0700,0000,8*coreid which is
> -		 * CVMX_CIU_WDOGX(coreid) - 0x0500
> -		 *
> -		 * Now ld K0, CVMX_CIU_WDOGX(coreid)
> -		 */
> -		uasm_i_ld(&p, K0, 0x500, K0);
> -		/*
> -		 * If bit one set handle the NMI as a watchdog event.
> -		 * otherwise transfer control to bootloader.
> -		 */
> -		uasm_il_bbit0(&p, &r, K0, 1, label_enter_bootloader);
> -		uasm_i_nop(&p);
> -	}
> -#endif
> -
> -	/* Clear Dcache so cvmseg works right. */
> -	uasm_i_cache(&p, 1, 0, 0);
> -
> -	/* Use K0 to do a read/modify/write of CVMMEMCTL */
> -	uasm_i_dmfc0(&p, K0, C0_CVMMEMCTL);
> -	/* Clear out the size of CVMSEG	*/
> -	uasm_i_dins(&p, K0, 0, 0, 6);
> -	/* Set CVMSEG to its largest value */
> -	uasm_i_ori(&p, K0, K0, 0x1c0 | 54);
> -	/* Store the CVMMEMCTL value */
> -	uasm_i_dmtc0(&p, K0, C0_CVMMEMCTL);
> -
> -	/* Load the address of the second stage handler */
> -	UASM_i_LA(&p, K0, (long)octeon_wdt_nmi_stage2);
> -	uasm_i_jr(&p, K0);
> -	uasm_i_dmfc0(&p, K0, C0_DESAVE);
> -
> -#ifdef CONFIG_HOTPLUG_CPU
> -	if (octeon_bootloader_entry_addr) {
> -		uasm_build_label(&l, p, label_enter_bootloader);
> -		/* Jump to the bootloader and restore K0 */
> -		UASM_i_LA(&p, K0, (long)octeon_bootloader_entry_addr);
> -		uasm_i_jr(&p, K0);
> -		uasm_i_dmfc0(&p, K0, C0_DESAVE);
> -	}
> -#endif
> -	uasm_resolve_relocs(relocs, labels);
> -
> -	len = (int)(p - nmi_stage1_insns);
> -	pr_debug("Synthesized NMI stage 1 handler (%d instructions)\n", len);
> -
> -	pr_debug("\t.set push\n");
> -	pr_debug("\t.set noreorder\n");
> -	for (i = 0; i < len; i++)
> -		pr_debug("\t.word 0x%08x\n", nmi_stage1_insns[i]);
> -	pr_debug("\t.set pop\n");
> -
> -	if (len > 32)
> -		panic("NMI stage 1 handler exceeds 32 instructions, was %d\n",
> -		      len);
> -}
> -
>  static int cpu2core(int cpu)
>  {
>  #ifdef CONFIG_SMP
> @@ -402,6 +291,8 @@ static int octeon_wdt_cpu_online(unsigned int cpu)
>  
>  	core = cpu2core(cpu);
>  
> +	octeon_wdt_bootvector[core].target_ptr = (u64)octeon_wdt_nmi_stage2;
> +
>  	/* Disable it before doing anything with the interrupts. */
>  	ciu_wdog.u64 = 0;
>  	cvmx_write_csr(CVMX_CIU_WDOGX(core), ciu_wdog.u64);
> @@ -544,6 +435,12 @@ static int __init octeon_wdt_init(void)
>  	int ret;
>  	u64 *ptr;
>  
> +	octeon_wdt_bootvector = cvmx_boot_vector_get();
> +	if (!octeon_wdt_bootvector) {
> +		pr_err("Error: Cannot allocate boot vector.\n");
> +		return -ENOMEM;
> +	}
> +
>  	/*
>  	 * Watchdog time expiration length = The 16 bits of LEN
>  	 * represent the most significant bits of a 24 bit decrementer
> @@ -576,17 +473,6 @@ static int __init octeon_wdt_init(void)
>  		return ret;
>  	}
>  
> -	/* Build the NMI handler ... */
> -	octeon_wdt_build_stage1();
> -
> -	/* ... and install it. */
> -	ptr = (u64 *) nmi_stage1_insns;
> -	for (i = 0; i < 16; i++) {
> -		cvmx_write_csr(CVMX_MIO_BOOT_LOC_ADR, i * 8);
> -		cvmx_write_csr(CVMX_MIO_BOOT_LOC_DAT, ptr[i]);
> -	}
> -	cvmx_write_csr(CVMX_MIO_BOOT_LOC_CFGX(0), 0x81fc0000);
> -
>  	cpumask_clear(&irq_enabled_cpus);
>  
>  	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "watchdog/octeon:online",
> diff --git a/drivers/watchdog/octeon-wdt-nmi.S b/drivers/watchdog/octeon-wdt-nmi.S
> index 8a900a5..97f6eb7 100644
> --- a/drivers/watchdog/octeon-wdt-nmi.S
> +++ b/drivers/watchdog/octeon-wdt-nmi.S
> @@ -3,20 +3,40 @@
>   * License.  See the file "COPYING" in the main directory of this archive
>   * for more details.
>   *
> - * Copyright (C) 2007 Cavium Networks
> + * Copyright (C) 2007-2017 Cavium, Inc.
>   */
>  #include <asm/asm.h>
>  #include <asm/regdef.h>
>  
> -#define SAVE_REG(r)	sd $r, -32768+6912-(32-r)*8($0)
> +#define CVMSEG_BASE	-32768
> +#define CVMSEG_SIZE	6912
> +#define SAVE_REG(r)	sd $r, CVMSEG_BASE + CVMSEG_SIZE - ((32 - r) * 8)($0)
>  
>          NESTED(octeon_wdt_nmi_stage2, 0, sp)
>  	.set 	push
>  	.set 	noreorder
>  	.set 	noat
> -	/* Save all registers to the top CVMSEG. This shouldn't
> +	/* Clear Dcache so cvmseg works right. */
> +	cache	1,0($0)
> +	/* Use K0 to do a read/modify/write of CVMMEMCTL */
> +	dmfc0	k0, $11, 7
> +	/* Clear out the size of CVMSEG	*/
> +	dins	k0, $0, 0, 6
> +	/* Set CVMSEG to its largest value */
> +	ori	k0, k0, 0x1c0 | 54
> +	/* Store the CVMMEMCTL value */
> +	dmtc0	k0, $11, 7
> +	/*
> +	 * Restore K0 from the debug scratch register, it was saved in
> +	 * the boot-vector code.
> +	 */
> +	dmfc0	k0, $31
> +
> +	/*
> +	 * Save all registers to the top CVMSEG. This shouldn't
>  	 * corrupt any state used by the kernel. Also all registers
> -	 * should have the value right before the NMI. */
> +	 * should have the value right before the NMI.
> +	 */
>  	SAVE_REG(0)
>  	SAVE_REG(1)
>  	SAVE_REG(2)
> @@ -49,16 +69,22 @@
>  	SAVE_REG(29)
>  	SAVE_REG(30)
>  	SAVE_REG(31)
> +	/* Write zero to all CVMSEG locations per Core-15169 */
> +	dli	a0, CVMSEG_SIZE - (33 * 8)
> +1:	sd	zero, CVMSEG_BASE(a0)
> +	daddiu	a0, a0, -8
> +	bgez	a0, 1b
> +	nop
>  	/* Set the stack to begin right below the registers */
> -	li	sp, -32768+6912-32*8
> +	dli	sp, CVMSEG_BASE + CVMSEG_SIZE - (32 * 8)
>  	/* Load the address of the third stage handler */
> -	dla	a0, octeon_wdt_nmi_stage3
> +	dla	$25, octeon_wdt_nmi_stage3
>  	/* Call the third stage handler */
> -	jal	a0
> +	jal	$25
>  	/* a0 is the address of the saved registers */
>  	 move	a0, sp
>  	/* Loop forvever if we get here. */
> -1:	b	1b
> +2:	b	2b
>  	nop
>  	.set pop
>  	END(octeon_wdt_nmi_stage2)
> -- 
> 2.1.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 6/8] watchdog: octeon-wdt: File cleaning.
  2017-08-29 15:40 ` [PATCH 6/8] watchdog: octeon-wdt: File cleaning Steven J. Hill
@ 2017-08-30  4:33   ` Guenter Roeck
  0 siblings, 0 replies; 14+ messages in thread
From: Guenter Roeck @ 2017-08-30  4:33 UTC (permalink / raw)
  To: Steven J. Hill; +Cc: linux-mips, linux-watchdog, ralf

On Tue, Aug 29, 2017 at 10:40:36AM -0500, Steven J. Hill wrote:
> From: "Steven J. Hill" <Steven.Hill@cavium.com>
> 
> * Update copyright and company name.
> * Remove unused headers.
> * Fix variable spelling and data type.
> * Use octal values for module parameters.
> 
> Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
> Acked-by: David Daney <david.daney@cavium.com>

Acked-by: Guenter Roeck <linux@roeck-us.net>

> ---
>  drivers/watchdog/octeon-wdt-main.c | 45 +++++++++++++++++++++++++-------------
>  1 file changed, 30 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c
> index fbdd484..73b5102 100644
> --- a/drivers/watchdog/octeon-wdt-main.c
> +++ b/drivers/watchdog/octeon-wdt-main.c
> @@ -1,7 +1,7 @@
>  /*
>   * Octeon Watchdog driver
>   *
> - * Copyright (C) 2007, 2008, 2009, 2010 Cavium Networks
> + * Copyright (C) 2007-2017 Cavium, Inc.
>   *
>   * Converted to use WATCHDOG_CORE by Aaro Koskinen <aaro.koskinen@iki.fi>.
>   *
> @@ -59,14 +59,9 @@
>  #include <linux/interrupt.h>
>  #include <linux/watchdog.h>
>  #include <linux/cpumask.h>
> -#include <linux/bitops.h>
> -#include <linux/kernel.h>
>  #include <linux/module.h>
> -#include <linux/string.h>
>  #include <linux/delay.h>
>  #include <linux/cpu.h>
> -#include <linux/smp.h>
> -#include <linux/fs.h>
>  #include <linux/irq.h>
>  
>  #include <asm/mipsregs.h>
> @@ -85,7 +80,7 @@ static unsigned int max_timeout_sec;
>  static unsigned int timeout_sec;
>  
>  /* Set to non-zero when userspace countdown mode active */
> -static int do_coundown;
> +static bool do_countdown;
>  static unsigned int countdown_reset;
>  static unsigned int per_cpu_countdown[NR_CPUS];
>  
> @@ -94,17 +89,22 @@ static cpumask_t irq_enabled_cpus;
>  #define WD_TIMO 60			/* Default heartbeat = 60 seconds */
>  
>  static int heartbeat = WD_TIMO;
> -module_param(heartbeat, int, S_IRUGO);
> +module_param(heartbeat, int, 0444);
>  MODULE_PARM_DESC(heartbeat,
>  	"Watchdog heartbeat in seconds. (0 < heartbeat, default="
>  				__MODULE_STRING(WD_TIMO) ")");
>  
>  static bool nowayout = WATCHDOG_NOWAYOUT;
> -module_param(nowayout, bool, S_IRUGO);
> +module_param(nowayout, bool, 0444);
>  MODULE_PARM_DESC(nowayout,
>  	"Watchdog cannot be stopped once started (default="
>  				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
>  
> +static int disable;
> +module_param(disable, int, 0444);
> +MODULE_PARM_DESC(disable,
> +	"Disable the watchdog entirely (default=0)");
> +
>  static struct cvmx_boot_vector_element *octeon_wdt_bootvector;
>  
>  void octeon_wdt_nmi_stage2(void);
> @@ -140,7 +140,7 @@ static irqreturn_t octeon_wdt_poke_irq(int cpl, void *dev_id)
>  	unsigned int core = cvmx_get_core_num();
>  	int cpu = core2cpu(core);
>  
> -	if (do_coundown) {
> +	if (do_countdown) {
>  		if (per_cpu_countdown[cpu] > 0) {
>  			/* We're alive, poke the watchdog */
>  			cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
> @@ -324,11 +324,14 @@ static int octeon_wdt_ping(struct watchdog_device __always_unused *wdog)
>  	int cpu;
>  	int coreid;
>  
> +	if (disable)
> +		return 0;
> +
>  	for_each_online_cpu(cpu) {
>  		coreid = cpu2core(cpu);
>  		cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1);
>  		per_cpu_countdown[cpu] = countdown_reset;
> -		if ((countdown_reset || !do_coundown) &&
> +		if ((countdown_reset || !do_countdown) &&
>  		    !cpumask_test_cpu(cpu, &irq_enabled_cpus)) {
>  			/* We have to enable the irq */
>  			int irq = OCTEON_IRQ_WDOG0 + coreid;
> @@ -378,6 +381,9 @@ static int octeon_wdt_set_timeout(struct watchdog_device *wdog,
>  
>  	octeon_wdt_calc_parameters(t);
>  
> +	if (disable)
> +		return 0;
> +
>  	for_each_online_cpu(cpu) {
>  		coreid = cpu2core(cpu);
>  		cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1);
> @@ -394,13 +400,13 @@ static int octeon_wdt_set_timeout(struct watchdog_device *wdog,
>  static int octeon_wdt_start(struct watchdog_device *wdog)
>  {
>  	octeon_wdt_ping(wdog);
> -	do_coundown = 1;
> +	do_countdown = 1;
>  	return 0;
>  }
>  
>  static int octeon_wdt_stop(struct watchdog_device *wdog)
>  {
> -	do_coundown = 0;
> +	do_countdown = 0;
>  	octeon_wdt_ping(wdog);
>  	return 0;
>  }
> @@ -473,6 +479,11 @@ static int __init octeon_wdt_init(void)
>  		return ret;
>  	}
>  
> +	if (disable) {
> +		pr_notice("disabled\n");
> +		return 0;
> +	}
> +
>  	cpumask_clear(&irq_enabled_cpus);
>  
>  	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "watchdog/octeon:online",
> @@ -493,6 +504,10 @@ static int __init octeon_wdt_init(void)
>  static void __exit octeon_wdt_cleanup(void)
>  {
>  	watchdog_unregister_device(&octeon_wdt);
> +
> +	if (disable)
> +		return;
> +
>  	cpuhp_remove_state(octeon_wdt_online);
>  
>  	/*
> @@ -503,7 +518,7 @@ static void __exit octeon_wdt_cleanup(void)
>  }
>  
>  MODULE_LICENSE("GPL");
> -MODULE_AUTHOR("Cavium Networks <support@caviumnetworks.com>");
> -MODULE_DESCRIPTION("Cavium Networks Octeon Watchdog driver.");
> +MODULE_AUTHOR("Cavium Inc. <support@cavium.com>");
> +MODULE_DESCRIPTION("Cavium Inc. OCTEON Watchdog driver.");
>  module_init(octeon_wdt_init);
>  module_exit(octeon_wdt_cleanup);
> -- 
> 2.1.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 7/8] watchdog: octeon-wdt: Add support for cn68XX SOCs.
  2017-08-29 15:40 ` [PATCH 7/8] watchdog: octeon-wdt: Add support for cn68XX SOCs Steven J. Hill
@ 2017-08-30  4:34   ` Guenter Roeck
  0 siblings, 0 replies; 14+ messages in thread
From: Guenter Roeck @ 2017-08-30  4:34 UTC (permalink / raw)
  To: Steven J. Hill; +Cc: linux-mips, linux-watchdog, ralf

On Tue, Aug 29, 2017 at 10:40:37AM -0500, Steven J. Hill wrote:
> From: David Daney <david.daney@cavium.com>
> 
> Signed-off-by: David Daney <david.daney@cavium.com>
> Signed-off-by: Carlos Munoz <cmunoz@caviumnetworks.com>
> Signed-off-by: Chandrakala Chavva <cchavva@caviumnetworks.com>

Acked-by: Guenter Roeck <linux@roeck-us.net>

> ---
>  drivers/watchdog/octeon-wdt-main.c | 48 +++++++++++++++++++++++++++-----------
>  1 file changed, 35 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c
> index 73b5102..410800f 100644
> --- a/drivers/watchdog/octeon-wdt-main.c
> +++ b/drivers/watchdog/octeon-wdt-main.c
> @@ -69,6 +69,9 @@
>  
>  #include <asm/octeon/octeon.h>
>  #include <asm/octeon/cvmx-boot-vector.h>
> +#include <asm/octeon/cvmx-ciu2-defs.h>
> +
> +static int divisor;
>  
>  /* The count needed to achieve timeout_sec. */
>  static unsigned int timeout_cnt;
> @@ -227,10 +230,10 @@ void octeon_wdt_nmi_stage3(u64 reg[32])
>  	u64 cp0_epc = read_c0_epc();
>  
>  	/* Delay so output from all cores output is not jumbled together. */
> -	__delay(100000000ull * coreid);
> +	udelay(85000 * coreid);
>  
>  	octeon_wdt_write_string("\r\n*** NMI Watchdog interrupt on Core 0x");
> -	octeon_wdt_write_hex(coreid, 1);
> +	octeon_wdt_write_hex(coreid, 2);
>  	octeon_wdt_write_string(" ***\r\n");
>  	for (i = 0; i < 32; i++) {
>  		octeon_wdt_write_string("\t");
> @@ -253,11 +256,28 @@ void octeon_wdt_nmi_stage3(u64 reg[32])
>  	octeon_wdt_write_hex(cp0_cause, 16);
>  	octeon_wdt_write_string("\r\n");
>  
> -	octeon_wdt_write_string("\tsum0\t0x");
> -	octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU_INTX_SUM0(coreid * 2)), 16);
> -	octeon_wdt_write_string("\ten0\t0x");
> -	octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU_INTX_EN0(coreid * 2)), 16);
> -	octeon_wdt_write_string("\r\n");
> +	/* The CIU register is different for each Octeon model. */
> +	if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
> +		octeon_wdt_write_string("\tsrc_wd\t0x");
> +		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_SRC_PPX_IP2_WDOG(coreid)), 16);
> +		octeon_wdt_write_string("\ten_wd\t0x");
> +		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_EN_PPX_IP2_WDOG(coreid)), 16);
> +		octeon_wdt_write_string("\r\n");
> +		octeon_wdt_write_string("\tsrc_rml\t0x");
> +		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_SRC_PPX_IP2_RML(coreid)), 16);
> +		octeon_wdt_write_string("\ten_rml\t0x");
> +		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_EN_PPX_IP2_RML(coreid)), 16);
> +		octeon_wdt_write_string("\r\n");
> +		octeon_wdt_write_string("\tsum\t0x");
> +		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU2_SUM_PPX_IP2(coreid)), 16);
> +		octeon_wdt_write_string("\r\n");
> +	} else if (!octeon_has_feature(OCTEON_FEATURE_CIU3)) {
> +		octeon_wdt_write_string("\tsum0\t0x");
> +		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU_INTX_SUM0(coreid * 2)), 16);
> +		octeon_wdt_write_string("\ten0\t0x");
> +		octeon_wdt_write_hex(cvmx_read_csr(CVMX_CIU_INTX_EN0(coreid * 2)), 16);
> +		octeon_wdt_write_string("\r\n");
> +	}
>  
>  	octeon_wdt_write_string("*** Chip soft reset soon ***\r\n");
>  }
> @@ -366,7 +386,7 @@ static void octeon_wdt_calc_parameters(int t)
>  
>  	countdown_reset = periods > 2 ? periods - 2 : 0;
>  	heartbeat = t;
> -	timeout_cnt = ((octeon_get_io_clock_rate() >> 8) * timeout_sec) >> 8;
> +	timeout_cnt = ((octeon_get_io_clock_rate() / divisor) * timeout_sec) >> 8;
>  }
>  
>  static int octeon_wdt_set_timeout(struct watchdog_device *wdog,
> @@ -437,9 +457,7 @@ static enum cpuhp_state octeon_wdt_online;
>   */
>  static int __init octeon_wdt_init(void)
>  {
> -	int i;
>  	int ret;
> -	u64 *ptr;
>  
>  	octeon_wdt_bootvector = cvmx_boot_vector_get();
>  	if (!octeon_wdt_bootvector) {
> @@ -447,10 +465,15 @@ static int __init octeon_wdt_init(void)
>  		return -ENOMEM;
>  	}
>  
> +	if (OCTEON_IS_MODEL(OCTEON_CN68XX))
> +		divisor = 0x200;
> +	else
> +		divisor = 0x100;
> +
>  	/*
>  	 * Watchdog time expiration length = The 16 bits of LEN
>  	 * represent the most significant bits of a 24 bit decrementer
> -	 * that decrements every 256 cycles.
> +	 * that decrements every divisor cycle.
>  	 *
>  	 * Try for a timeout of 5 sec, if that fails a smaller number
>  	 * of even seconds,
> @@ -458,8 +481,7 @@ static int __init octeon_wdt_init(void)
>  	max_timeout_sec = 6;
>  	do {
>  		max_timeout_sec--;
> -		timeout_cnt = ((octeon_get_io_clock_rate() >> 8) *
> -			      max_timeout_sec) >> 8;
> +		timeout_cnt = ((octeon_get_io_clock_rate() / divisor) * max_timeout_sec) >> 8;
>  	} while (timeout_cnt > 65535);
>  
>  	BUG_ON(timeout_cnt == 0);
> -- 
> 2.1.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 8/8] watchdog: octeon-wdt: Add support for 78XX SOCs.
  2017-08-29 15:40 ` [PATCH 8/8] watchdog: octeon-wdt: Add support for 78XX SOCs Steven J. Hill
@ 2017-08-30  4:34   ` Guenter Roeck
  0 siblings, 0 replies; 14+ messages in thread
From: Guenter Roeck @ 2017-08-30  4:34 UTC (permalink / raw)
  To: Steven J. Hill; +Cc: linux-mips, linux-watchdog, ralf

On Tue, Aug 29, 2017 at 10:40:38AM -0500, Steven J. Hill wrote:
> From: Carlos Munoz <carlos.munoz@caviumnetworks.com>
> 
> Signed-off-by: Carlos Munoz <carlos.munoz@caviumnetworks.com>
> Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
> Acked-by: David Daney <david.daney@cavium.com>

Acked-by: Guenter Roeck <linux@roeck-us.net>

> ---
>  drivers/watchdog/octeon-wdt-main.c | 133 ++++++++++++++++++++++++++++---------
>  1 file changed, 103 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c
> index 410800f..0ec419a 100644
> --- a/drivers/watchdog/octeon-wdt-main.c
> +++ b/drivers/watchdog/octeon-wdt-main.c
> @@ -70,6 +70,10 @@
>  #include <asm/octeon/octeon.h>
>  #include <asm/octeon/cvmx-boot-vector.h>
>  #include <asm/octeon/cvmx-ciu2-defs.h>
> +#include <asm/octeon/cvmx-rst-defs.h>
> +
> +/* Watchdog interrupt major block number (8 MSBs of intsn) */
> +#define WD_BLOCK_NUMBER		0x01
>  
>  static int divisor;
>  
> @@ -91,6 +95,8 @@ static cpumask_t irq_enabled_cpus;
>  
>  #define WD_TIMO 60			/* Default heartbeat = 60 seconds */
>  
> +#define CVMX_GSERX_SCRATCH(offset) (CVMX_ADD_IO_SEG(0x0001180090000020ull) + ((offset) & 15) * 0x1000000ull)
> +
>  static int heartbeat = WD_TIMO;
>  module_param(heartbeat, int, 0444);
>  MODULE_PARM_DESC(heartbeat,
> @@ -115,21 +121,12 @@ void octeon_wdt_nmi_stage2(void);
>  static int cpu2core(int cpu)
>  {
>  #ifdef CONFIG_SMP
> -	return cpu_logical_map(cpu);
> +	return cpu_logical_map(cpu) & 0x3f;
>  #else
>  	return cvmx_get_core_num();
>  #endif
>  }
>  
> -static int core2cpu(int coreid)
> -{
> -#ifdef CONFIG_SMP
> -	return cpu_number_map(coreid);
> -#else
> -	return 0;
> -#endif
> -}
> -
>  /**
>   * Poke the watchdog when an interrupt is received
>   *
> @@ -140,13 +137,14 @@ static int core2cpu(int coreid)
>   */
>  static irqreturn_t octeon_wdt_poke_irq(int cpl, void *dev_id)
>  {
> -	unsigned int core = cvmx_get_core_num();
> -	int cpu = core2cpu(core);
> +	int cpu = raw_smp_processor_id();
> +	unsigned int core = cpu2core(cpu);
> +	int node = cpu_to_node(cpu);
>  
>  	if (do_countdown) {
>  		if (per_cpu_countdown[cpu] > 0) {
>  			/* We're alive, poke the watchdog */
> -			cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
> +			cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(core), 1);
>  			per_cpu_countdown[cpu]--;
>  		} else {
>  			/* Bad news, you are about to reboot. */
> @@ -155,7 +153,7 @@ static irqreturn_t octeon_wdt_poke_irq(int cpl, void *dev_id)
>  		}
>  	} else {
>  		/* Not open, just ping away... */
> -		cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
> +		cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(core), 1);
>  	}
>  	return IRQ_HANDLED;
>  }
> @@ -280,26 +278,74 @@ void octeon_wdt_nmi_stage3(u64 reg[32])
>  	}
>  
>  	octeon_wdt_write_string("*** Chip soft reset soon ***\r\n");
> +
> +	/*
> +	 * G-30204: We must trigger a soft reset before watchdog
> +	 * does an incomplete job of doing it.
> +	 */
> +	if (OCTEON_IS_OCTEON3() && !OCTEON_IS_MODEL(OCTEON_CN70XX)) {
> +		u64 scr;
> +		unsigned int node = cvmx_get_node_num();
> +		unsigned int lcore = cvmx_get_local_core_num();
> +		union cvmx_ciu_wdogx ciu_wdog;
> +
> +		/*
> +		 * Wait for other cores to print out information, but
> +		 * not too long.  Do the soft reset before watchdog
> +		 * can trigger it.
> +		 */
> +		do {
> +			ciu_wdog.u64 = cvmx_read_csr_node(node, CVMX_CIU_WDOGX(lcore));
> +		} while (ciu_wdog.s.cnt > 0x10000);
> +
> +		scr = cvmx_read_csr_node(0, CVMX_GSERX_SCRATCH(0));
> +		scr |= 1 << 11; /* Indicate watchdog in bit 11 */
> +		cvmx_write_csr_node(0, CVMX_GSERX_SCRATCH(0), scr);
> +		cvmx_write_csr_node(0, CVMX_RST_SOFT_RST, 1);
> +	}
> +}
> +
> +static int octeon_wdt_cpu_to_irq(int cpu)
> +{
> +	unsigned int coreid;
> +	int node;
> +	int irq;
> +
> +	coreid = cpu2core(cpu);
> +	node = cpu_to_node(cpu);
> +
> +	if (octeon_has_feature(OCTEON_FEATURE_CIU3)) {
> +		struct irq_domain *domain;
> +		int hwirq;
> +
> +		domain = octeon_irq_get_block_domain(node,
> +						     WD_BLOCK_NUMBER);
> +		hwirq = WD_BLOCK_NUMBER << 12 | 0x200 | coreid;
> +		irq = irq_find_mapping(domain, hwirq);
> +	} else {
> +		irq = OCTEON_IRQ_WDOG0 + coreid;
> +	}
> +	return irq;
>  }
>  
>  static int octeon_wdt_cpu_pre_down(unsigned int cpu)
>  {
>  	unsigned int core;
> -	unsigned int irq;
> +	int node;
>  	union cvmx_ciu_wdogx ciu_wdog;
>  
>  	core = cpu2core(cpu);
>  
> -	irq = OCTEON_IRQ_WDOG0 + core;
> +	node = cpu_to_node(cpu);
>  
>  	/* Poke the watchdog to clear out its state */
> -	cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
> +	cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(core), 1);
>  
>  	/* Disable the hardware. */
>  	ciu_wdog.u64 = 0;
> -	cvmx_write_csr(CVMX_CIU_WDOGX(core), ciu_wdog.u64);
> +	cvmx_write_csr_node(node, CVMX_CIU_WDOGX(core), ciu_wdog.u64);
>  
> -	free_irq(irq, octeon_wdt_poke_irq);
> +	free_irq(octeon_wdt_cpu_to_irq(cpu), octeon_wdt_poke_irq);
>  	return 0;
>  }
>  
> @@ -308,33 +354,56 @@ static int octeon_wdt_cpu_online(unsigned int cpu)
>  	unsigned int core;
>  	unsigned int irq;
>  	union cvmx_ciu_wdogx ciu_wdog;
> +	int node;
> +	struct irq_domain *domain;
> +	int hwirq;
>  
>  	core = cpu2core(cpu);
> +	node = cpu_to_node(cpu);
>  
>  	octeon_wdt_bootvector[core].target_ptr = (u64)octeon_wdt_nmi_stage2;
>  
>  	/* Disable it before doing anything with the interrupts. */
>  	ciu_wdog.u64 = 0;
> -	cvmx_write_csr(CVMX_CIU_WDOGX(core), ciu_wdog.u64);
> +	cvmx_write_csr_node(node, CVMX_CIU_WDOGX(core), ciu_wdog.u64);
>  
>  	per_cpu_countdown[cpu] = countdown_reset;
>  
> -	irq = OCTEON_IRQ_WDOG0 + core;
> +	if (octeon_has_feature(OCTEON_FEATURE_CIU3)) {
> +		/* Must get the domain for the watchdog block */
> +		domain = octeon_irq_get_block_domain(node, WD_BLOCK_NUMBER);
> +
> +		/* Get a irq for the wd intsn (hardware interrupt) */
> +		hwirq = WD_BLOCK_NUMBER << 12 | 0x200 | core;
> +		irq = irq_create_mapping(domain, hwirq);
> +		irqd_set_trigger_type(irq_get_irq_data(irq),
> +				      IRQ_TYPE_EDGE_RISING);
> +	} else
> +		irq = OCTEON_IRQ_WDOG0 + core;
>  
>  	if (request_irq(irq, octeon_wdt_poke_irq,
>  			IRQF_NO_THREAD, "octeon_wdt", octeon_wdt_poke_irq))
>  		panic("octeon_wdt: Couldn't obtain irq %d", irq);
>  
> +	/* Must set the irq affinity here */
> +	if (octeon_has_feature(OCTEON_FEATURE_CIU3)) {
> +		cpumask_t mask;
> +
> +		cpumask_clear(&mask);
> +		cpumask_set_cpu(cpu, &mask);
> +		irq_set_affinity(irq, &mask);
> +	}
> +
>  	cpumask_set_cpu(cpu, &irq_enabled_cpus);
>  
>  	/* Poke the watchdog to clear out its state */
> -	cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1);
> +	cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(core), 1);
>  
>  	/* Finally enable the watchdog now that all handlers are installed */
>  	ciu_wdog.u64 = 0;
>  	ciu_wdog.s.len = timeout_cnt;
>  	ciu_wdog.s.mode = 3;	/* 3 = Interrupt + NMI + Soft-Reset */
> -	cvmx_write_csr(CVMX_CIU_WDOGX(core), ciu_wdog.u64);
> +	cvmx_write_csr_node(node, CVMX_CIU_WDOGX(core), ciu_wdog.u64);
>  
>  	return 0;
>  }
> @@ -343,20 +412,20 @@ static int octeon_wdt_ping(struct watchdog_device __always_unused *wdog)
>  {
>  	int cpu;
>  	int coreid;
> +	int node;
>  
>  	if (disable)
>  		return 0;
>  
>  	for_each_online_cpu(cpu) {
>  		coreid = cpu2core(cpu);
> -		cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1);
> +		node = cpu_to_node(cpu);
> +		cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(coreid), 1);
>  		per_cpu_countdown[cpu] = countdown_reset;
>  		if ((countdown_reset || !do_countdown) &&
>  		    !cpumask_test_cpu(cpu, &irq_enabled_cpus)) {
>  			/* We have to enable the irq */
> -			int irq = OCTEON_IRQ_WDOG0 + coreid;
> -
> -			enable_irq(irq);
> +			enable_irq(octeon_wdt_cpu_to_irq(cpu));
>  			cpumask_set_cpu(cpu, &irq_enabled_cpus);
>  		}
>  	}
> @@ -395,6 +464,7 @@ static int octeon_wdt_set_timeout(struct watchdog_device *wdog,
>  	int cpu;
>  	int coreid;
>  	union cvmx_ciu_wdogx ciu_wdog;
> +	int node;
>  
>  	if (t <= 0)
>  		return -1;
> @@ -406,12 +476,13 @@ static int octeon_wdt_set_timeout(struct watchdog_device *wdog,
>  
>  	for_each_online_cpu(cpu) {
>  		coreid = cpu2core(cpu);
> -		cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1);
> +		node = cpu_to_node(cpu);
> +		cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(coreid), 1);
>  		ciu_wdog.u64 = 0;
>  		ciu_wdog.s.len = timeout_cnt;
>  		ciu_wdog.s.mode = 3;	/* 3 = Interrupt + NMI + Soft-Reset */
> -		cvmx_write_csr(CVMX_CIU_WDOGX(coreid), ciu_wdog.u64);
> -		cvmx_write_csr(CVMX_CIU_PP_POKEX(coreid), 1);
> +		cvmx_write_csr_node(node, CVMX_CIU_WDOGX(coreid), ciu_wdog.u64);
> +		cvmx_write_csr_node(node, CVMX_CIU_PP_POKEX(coreid), 1);
>  	}
>  	octeon_wdt_ping(wdog); /* Get the irqs back on. */
>  	return 0;
> @@ -467,6 +538,8 @@ static int __init octeon_wdt_init(void)
>  
>  	if (OCTEON_IS_MODEL(OCTEON_CN68XX))
>  		divisor = 0x200;
> +	else if (OCTEON_IS_MODEL(OCTEON_CN78XX))
> +		divisor = 0x400;
>  	else
>  		divisor = 0x100;
>  
> -- 
> 2.1.4
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-watchdog" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/8] watchdog: octeon-wdt: Remove old boot vector code.
  2017-08-30  4:33   ` Guenter Roeck
@ 2017-08-30 14:16     ` Steven J. Hill
  0 siblings, 0 replies; 14+ messages in thread
From: Steven J. Hill @ 2017-08-30 14:16 UTC (permalink / raw)
  To: Guenter Roeck; +Cc: linux-mips, linux-watchdog, ralf

On 08/29/2017 11:33 PM, Guenter Roeck wrote:
> On Tue, Aug 29, 2017 at 10:40:32AM -0500, Steven J. Hill wrote:
>> Signed-off-by: Steven J. Hill <steven.hill@cavium.com>
>> Acked-by: David Daney <david.daney@cavium.com>
> 
> Acked-by: Guenter Roeck <linux@roeck-us.net>
> 
> I assume this series will go through the mips tree.
> 
Hello Guenter.

Yes, we will have Ralf or James take this driver with the next MIPS
push upstream. Thanks for your Ack.

Steve

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2017-08-30 14:16 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-08-29 15:40 [PATCH 0/8] Update Octeon watchdog driver Steven J. Hill
2017-08-29 15:40 ` [PATCH 1/8] MIPS: Octeon: Add support for accessing the boot vector Steven J. Hill
2017-08-29 15:40 ` [PATCH 2/8] watchdog: octeon-wdt: Remove old boot vector code Steven J. Hill
2017-08-30  4:33   ` Guenter Roeck
2017-08-30 14:16     ` Steven J. Hill
2017-08-29 15:40 ` [PATCH 3/8] MIPS: Octeon: Watchdog registers for 70xx, 73xx, 78xx, F75xx Steven J. Hill
2017-08-29 15:40 ` [PATCH 4/8] MIPS: Octeon: Make CSR functions node aware Steven J. Hill
2017-08-29 15:40 ` [PATCH 5/8] MIPS: Octeon: Allow access to CIU3 IRQ domains Steven J. Hill
2017-08-29 15:40 ` [PATCH 6/8] watchdog: octeon-wdt: File cleaning Steven J. Hill
2017-08-30  4:33   ` Guenter Roeck
2017-08-29 15:40 ` [PATCH 7/8] watchdog: octeon-wdt: Add support for cn68XX SOCs Steven J. Hill
2017-08-30  4:34   ` Guenter Roeck
2017-08-29 15:40 ` [PATCH 8/8] watchdog: octeon-wdt: Add support for 78XX SOCs Steven J. Hill
2017-08-30  4:34   ` Guenter Roeck

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.