Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9438a86a authored by Steven J. Hill's avatar Steven J. Hill Committed by Ralf Baechle
Browse files

MIPS: Octeon: Add support for accessing the boot vector.



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

Signed-off-by: default avatarSteven J. Hill <steven.hill@cavium.com>
Acked-by: default avatarDavid Daney <david.daney@cavium.com>
Cc: linux-mips@linux-mips.org
Cc: linux-watchdog@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/17206/


Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent d9a46c18
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -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-helper-loop.o cvmx-helper-spi.o cvmx-helper-util.o \
	cvmx-interrupt-decodes.o cvmx-interrupt-rsl.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
+167 −0
Original line number Original line Diff line number Diff line
/*
 * 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);
+85 −0
Original line number Original line Diff line number Diff line
@@ -44,6 +44,55 @@ static struct cvmx_bootmem_desc *cvmx_bootmem_desc;


/* See header file for descriptions of functions */
/* 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
 * Wrapper functions are provided for reading/writing the size and
 * next block values as these may not be directly addressible (in 32
 * 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);
	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,
void *cvmx_bootmem_alloc_named_range(uint64_t size, uint64_t min_addr,
				     uint64_t max_addr, uint64_t align,
				     uint64_t max_addr, uint64_t align,
				     char *name)
				     char *name)
+53 −0
Original line number Original line Diff line number Diff line
/*
 * 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__ */
+28 −0
Original line number Original line Diff line number Diff line
@@ -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,
					    uint64_t max_addr, uint64_t align,
					    char *name);
					    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);
extern int cvmx_bootmem_free_named(char *name);


/**
/**