[PATCH v1 07/10] mips: octeon: Add coremask support

Stefan Roese sr at denx.de
Thu Aug 20 07:22:01 CEST 2020


From: Aaron Williams <awilliams at marvell.com>

This patch adds the coremask handling functions.

Signed-off-by: Aaron Williams <awilliams at marvell.com>
Signed-off-by: Stefan Roese <sr at denx.de>
---

 arch/mips/mach-octeon/Makefile                |   1 +
 arch/mips/mach-octeon/cvmx-coremask.c         | 366 +++++++++
 .../mach-octeon/include/mach/cvmx-coremask.h  | 752 ++++++++++++++++++
 3 files changed, 1119 insertions(+)
 create mode 100644 arch/mips/mach-octeon/cvmx-coremask.c
 create mode 100644 arch/mips/mach-octeon/include/mach/cvmx-coremask.h

diff --git a/arch/mips/mach-octeon/Makefile b/arch/mips/mach-octeon/Makefile
index 2e37ca572c..5155f89a1e 100644
--- a/arch/mips/mach-octeon/Makefile
+++ b/arch/mips/mach-octeon/Makefile
@@ -8,3 +8,4 @@ obj-y += cache.o
 obj-y += clock.o
 obj-y += cpu.o
 obj-y += dram.o
+obj-y += cvmx-coremask.o
diff --git a/arch/mips/mach-octeon/cvmx-coremask.c b/arch/mips/mach-octeon/cvmx-coremask.c
new file mode 100644
index 0000000000..cff8c08b97
--- /dev/null
+++ b/arch/mips/mach-octeon/cvmx-coremask.c
@@ -0,0 +1,366 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018-2020 Marvell International Ltd.
+ */
+
+#include <env.h>
+#include <errno.h>
+
+#include <linux/compat.h>
+#include <linux/ctype.h>
+
+#include <mach/cvmx-regs.h>
+#include <mach/cvmx-coremask.h>
+#include <mach/cvmx-fuse.h>
+#include <mach/octeon-model.h>
+#include <mach/octeon-feature.h>
+
+struct cvmx_coremask *get_coremask_override(struct cvmx_coremask *pcm)
+{
+	struct cvmx_coremask pcm_override = CVMX_COREMASK_MAX;
+	char *cptr;
+
+	/* The old code sets the number of cores to be to 16 in this case. */
+	cvmx_coremask_set_cores(pcm, 0, 16);
+
+	if (OCTEON_IS_OCTEON2() || OCTEON_IS_OCTEON3())
+		cvmx_coremask_copy(pcm, &pcm_override);
+
+	cptr = env_get("coremask_override");
+	if (cptr) {
+		if (cvmx_coremask_str2bmp(pcm, cptr) < 0)
+			return NULL;
+	}
+
+	return pcm;
+}
+
+/* Validate the coremask that is passed to a boot* function. */
+int validate_coremask(struct cvmx_coremask *pcm)
+{
+	struct cvmx_coremask coremask_override;
+	struct cvmx_coremask fuse_coremask;
+
+	if (!get_coremask_override(&coremask_override))
+		return -1;
+
+	octeon_get_available_coremask(&fuse_coremask);
+
+	if (!cvmx_coremask_is_subset(&fuse_coremask, pcm)) {
+		puts("ERROR: Can't boot cores that don't exist!\n");
+		puts("Available coremask:\n");
+		cvmx_coremask_print(&fuse_coremask);
+		return -1;
+	}
+
+	if (!cvmx_coremask_is_subset(&coremask_override, pcm)) {
+		struct cvmx_coremask print_cm;
+
+		puts("Notice: coremask changed from:\n");
+		cvmx_coremask_print(pcm);
+		puts("based on coremask_override of:\n");
+		cvmx_coremask_print(&coremask_override);
+		cvmx_coremask_and(&print_cm, pcm, &coremask_override);
+		puts("to:\n");
+		cvmx_coremask_print(&print_cm);
+	}
+
+	return 0;
+}
+
+/**
+ * In CIU_FUSE for the 78XX, odd and even cores are separated out.
+ * For example, a CIU_FUSE value of 0xfffffefffffe indicates that bits 0 and 1
+ * are set.
+ * This function converts the bit number in the CIU_FUSE register to a
+ * physical core number.
+ */
+static int convert_ciu_fuse_to_physical_core(int core, int max_cores)
+{
+	if (!octeon_has_feature(OCTEON_FEATURE_CIU3))
+		return core;
+	else if (!OCTEON_IS_MODEL(OCTEON_CN78XX))
+		return core;
+	else if (core < (max_cores / 2))
+		return core * 2;
+	else
+		return ((core - (max_cores / 2)) * 2) + 1;
+}
+
+/**
+ * Get the total number of fuses blown as well as the number blown per tad.
+ *
+ * @param	coremask	fuse coremask
+ * @param[out]	tad_blown_count	number of cores blown for each tad
+ * @param	num_tads	number of tads
+ * @param	max_cores	maximum number of cores
+ *
+ * @return	void
+ */
+void fill_tad_corecount(u64 coremask, int tad_blown_count[], int num_tads,
+			int max_cores)
+{
+	int core, physical_core;
+
+	for (core = 0; core < max_cores; core++) {
+		if (!(coremask & (1ULL << core))) {
+			int tad;
+
+			physical_core =
+				convert_ciu_fuse_to_physical_core(core,
+								  max_cores);
+			tad = physical_core % num_tads;
+			tad_blown_count[tad]++;
+		}
+	}
+}
+
+u64 get_core_pattern(int num_tads, int max_cores)
+{
+	u64 pattern = 1ULL;
+	int cnt;
+
+	for (cnt = 1; cnt < (max_cores / num_tads); cnt++)
+		pattern |= pattern << num_tads;
+
+	return pattern;
+}
+
+/**
+ * For CN78XX and CN68XX this function returns the logical coremask from the
+ * CIU_FUSE register value. For other models there is no difference.
+ *
+ * @param ciu_fuse_value	fuse value from CIU_FUSE register
+ * @return logical coremask of CIU_FUSE value.
+ */
+u64 get_logical_coremask(u64 ciu_fuse_value)
+{
+	int tad_blown_count[MAX_CORE_TADS] = {0};
+	int tad;
+	u64 logical_coremask = 0;
+	u64 tad_mask, pattern;
+	int num_tads, max_cores;
+
+	if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
+		num_tads = 8;
+		max_cores = 48;
+	} else if (OCTEON_IS_MODEL(OCTEON_CN73XX) ||
+		   OCTEON_IS_MODEL(OCTEON_CNF75XX)) {
+		num_tads = 4;
+		max_cores = 16;
+	} else if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
+		num_tads = 4;
+		max_cores = 32;
+	} else {
+		/* Most Octeon devices don't need any mapping. */
+		return ciu_fuse_value;
+	}
+
+	pattern = get_core_pattern(num_tads, max_cores);
+	fill_tad_corecount(ciu_fuse_value, tad_blown_count,
+			   num_tads, max_cores);
+
+	for (tad = 0; tad < num_tads; tad++) {
+		tad_mask = pattern << tad;
+		logical_coremask |= tad_mask >> (tad_blown_count[tad] * num_tads);
+	}
+	return logical_coremask;
+}
+
+/**
+ * Returns the available coremask either from env or fuses.
+ * If the fuses are blown and locked, they are the definitive coremask.
+ *
+ * @param pcm	pointer to coremask to fill in
+ * @return pointer to coremask
+ */
+struct cvmx_coremask *octeon_get_available_coremask(struct cvmx_coremask *pcm)
+{
+	u8 node_mask = 0x01;	/* ToDo: Currently only one node is supported */
+	u64 ciu_fuse;
+	u64 cores;
+
+	cvmx_coremask_clear_all(pcm);
+
+	if (octeon_has_feature(OCTEON_FEATURE_CIU3)) {
+		int node;
+
+		cvmx_coremask_for_each_node(node, node_mask) {
+			ciu_fuse = (csr_rd(CVMX_CIU_FUSE) &
+				    0x0000FFFFFFFFFFFFULL);
+
+			ciu_fuse = get_logical_coremask(ciu_fuse);
+			cvmx_coremask_set64_node(pcm, node, ciu_fuse);
+		}
+
+		return pcm;
+	}
+
+	ciu_fuse = (csr_rd(CVMX_CIU_FUSE) & 0x0000FFFFFFFFFFFFULL);
+	ciu_fuse = get_logical_coremask(ciu_fuse);
+
+	if (OCTEON_IS_MODEL(OCTEON_CN68XX))
+		cvmx_coremask_set64(pcm, ciu_fuse);
+
+	/* Get number of cores from fuse register, convert to coremask */
+	cores = __builtin_popcountll(ciu_fuse);
+
+	cvmx_coremask_set_cores(pcm, 0, cores);
+
+	return pcm;
+}
+
+int cvmx_coremask_str2bmp(struct cvmx_coremask *pcm, char *hexstr)
+{
+	int i, j;
+	int l;		/* length of the hexstr in characters */
+	int lb;		/* number of bits taken by hexstr */
+	int hldr_offset;/* holder's offset within the coremask */
+	int hldr_xsz;	/* holder's size in the number of hex digits */
+	u64 h;
+	char c;
+
+#define MINUS_ONE (hexstr[0] == '-' && hexstr[1] == '1' && hexstr[2] == 0)
+	if (MINUS_ONE) {
+		cvmx_coremask_set_all(pcm);
+		return 0;
+	}
+
+	/* Skip '0x' from hexstr */
+	if (hexstr[0] == '0' && (hexstr[1] == 'x' || hexstr[1] == 'X'))
+		hexstr += 2;
+
+	if (!strlen(hexstr)) {
+		printf("%s: Error: hex string is empty\n", __func__);
+		return -2;
+	}
+
+	/* Trim leading zeros */
+	while (*hexstr == '0')
+		hexstr++;
+
+	cvmx_coremask_clear_all(pcm);
+	l = strlen(hexstr);
+
+	/* If length is 0 then the hex string must be all zeros */
+	if (l == 0)
+		return 0;
+
+	for (i = 0; i < l; i++) {
+		if (isxdigit((int)hexstr[i]) == 0) {
+			printf("%s: Non-hex digit within hexstr\n", __func__);
+			return -2;
+		}
+	}
+
+	lb = (l - 1) * 4;
+	if (hexstr[0] > '7')
+		lb += 4;
+	else if (hexstr[0] > '3')
+		lb += 3;
+	else if (hexstr[0] > '1')
+		lb += 2;
+	else
+		lb += 1;
+	if (lb > CVMX_MIPS_MAX_CORES) {
+		printf("%s: hexstr (%s) is too long\n", __func__, hexstr);
+		return -1;
+	}
+
+	hldr_offset = 0;
+	hldr_xsz = 2 * sizeof(u64);
+	for (i = l; i > 0; i -= hldr_xsz) {
+		c = hexstr[i];
+		hexstr[i] = 0;
+		j = i - hldr_xsz;
+		if (j < 0)
+			j = 0;
+		h = simple_strtoull(&hexstr[j], NULL, 16);
+		if (errno == EINVAL) {
+			printf("%s: strtou returns w/ EINVAL\n", __func__);
+			return -2;
+		}
+		pcm->coremask_bitmap[hldr_offset] = h;
+		hexstr[i] = c;
+		hldr_offset++;
+	}
+
+	return 0;
+}
+
+void cvmx_coremask_print(const struct cvmx_coremask *pcm)
+{
+	int i, j;
+	int start;
+	int found = 0;
+
+	/*
+	 * Print one node per line. Since the bitmap is stored LSB to MSB
+	 * we reverse the order when printing.
+	 */
+	if (!octeon_has_feature(OCTEON_FEATURE_MULTINODE)) {
+		start = 0;
+		for (j = CVMX_COREMASK_MAX_CORES_PER_NODE -
+			     CVMX_COREMASK_HLDRSZ;
+		     j >= 0; j -= CVMX_COREMASK_HLDRSZ) {
+			if (pcm->coremask_bitmap[j / CVMX_COREMASK_HLDRSZ] != 0)
+				start = 1;
+			if (start) {
+				printf(" 0x%llx",
+				       (u64)pcm->coremask_bitmap[j /
+						CVMX_COREMASK_HLDRSZ]);
+			}
+		}
+
+		if (start)
+			found = 1;
+
+		/*
+		 * If the coremask is empty print <EMPTY> so it is not
+		 * confusing
+		 */
+		if (!found)
+			printf("<EMPTY>");
+		printf("\n");
+
+		return;
+	}
+
+	for (i = 0; i < CVMX_MAX_USED_CORES_BMP;
+	     i += CVMX_COREMASK_MAX_CORES_PER_NODE) {
+		printf("%s  node %d:", i > 0 ? "\n" : "",
+		       cvmx_coremask_core_to_node(i));
+		start = 0;
+
+		for (j = i + CVMX_COREMASK_MAX_CORES_PER_NODE -
+			     CVMX_COREMASK_HLDRSZ;
+		     j >= i;
+		     j -= CVMX_COREMASK_HLDRSZ) {
+			/* Don't start printing until we get a non-zero word. */
+			if (pcm->coremask_bitmap[j / CVMX_COREMASK_HLDRSZ] != 0)
+				start = 1;
+
+			if (start) {
+				printf(" 0x%llx", (u64)pcm->coremask_bitmap[j /
+							CVMX_COREMASK_HLDRSZ]);
+			}
+		}
+
+		if (start)
+			found = 1;
+	}
+
+	i /= CVMX_COREMASK_HLDRSZ;
+	for (; i < CVMX_COREMASK_BMPSZ; i++) {
+		if (pcm->coremask_bitmap[i]) {
+			printf("  EXTRA GARBAGE[%i]: %016llx\n", i,
+			       (u64)pcm->coremask_bitmap[i]);
+		}
+	}
+
+	/* If the coremask is empty print <EMPTY> so it is not confusing */
+	if (!found)
+		printf("<EMPTY>");
+
+	printf("\n");
+}
diff --git a/arch/mips/mach-octeon/include/mach/cvmx-coremask.h b/arch/mips/mach-octeon/include/mach/cvmx-coremask.h
new file mode 100644
index 0000000000..c34ff46d3a
--- /dev/null
+++ b/arch/mips/mach-octeon/include/mach/cvmx-coremask.h
@@ -0,0 +1,752 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2020 Marvell International Ltd.
+ */
+
+/**
+ * Module to support operations on bitmap of cores. Coremask can be used to
+ * select a specific core, a group of cores, or all available cores, for
+ * initialization and differentiation of roles within a single shared binary
+ * executable image.
+ *
+ * The core numbers used in this file are the same value as what is found in
+ * the COP0_EBASE register and the rdhwr 0 instruction.
+ *
+ * For the CN78XX and other multi-node environments the core numbers are not
+ * contiguous.  The core numbers for the CN78XX are as follows:
+ *
+ * Node 0:	Cores 0 - 47
+ * Node 1:	Cores 128 - 175
+ * Node 2:	Cores 256 - 303
+ * Node 3:	Cores 384 - 431
+ *
+ * The coremask environment generally tries to be node agnostic in order to
+ * provide future compatibility if more cores are added to future processors
+ * or more nodes are supported.
+ */
+
+#ifndef __CVMX_COREMASK_H__
+#define __CVMX_COREMASK_H__
+
+#include "cvmx-regs.h"
+
+/* bits per holder */
+#define CVMX_COREMASK_HLDRSZ	((int)(sizeof(u64) * 8))
+
+/** Maximum allowed cores per node */
+#define CVMX_COREMASK_MAX_CORES_PER_NODE	(1 << CVMX_NODE_NO_SHIFT)
+
+/** Maximum number of bits actually used in the coremask */
+#define CVMX_MAX_USED_CORES_BMP	(1 << (CVMX_NODE_NO_SHIFT + CVMX_NODE_BITS))
+
+/* the number of valid bits in and the mask of the most significant holder */
+#define CVMX_COREMASK_MSHLDR_NBITS			\
+	(CVMX_MIPS_MAX_CORES % CVMX_COREMASK_HLDRSZ)
+
+#define CVMX_COREMASK_MSHLDR_MASK				\
+	((CVMX_COREMASK_MSHLDR_NBITS) ?				\
+	 (((u64)1 << CVMX_COREMASK_MSHLDR_NBITS) - 1) :		\
+	 ((u64)-1))
+
+/* cvmx_coremask size in u64 */
+#define CVMX_COREMASK_BMPSZ					\
+	((int)(CVMX_MIPS_MAX_CORES / CVMX_COREMASK_HLDRSZ +	\
+	       (CVMX_COREMASK_MSHLDR_NBITS != 0)))
+
+#define CVMX_COREMASK_USED_BMPSZ				\
+	(CVMX_MAX_USED_CORES_BMP / CVMX_COREMASK_HLDRSZ)
+
+#define CVMX_COREMASK_BMP_NODE_CORE_IDX(node, core)			\
+	((((node) << CVMX_NODE_NO_SHIFT) + (core)) / CVMX_COREMASK_HLDRSZ)
+/**
+ * Maximum available coremask.
+ */
+#define CVMX_COREMASK_MAX				\
+	{ {						\
+			0x0000FFFFFFFFFFFF, 0,		\
+				0x0000FFFFFFFFFFFF, 0,	\
+				0x0000FFFFFFFFFFFF, 0,	\
+				0x0000FFFFFFFFFFFF, 0,	\
+				0, 0,			\
+				0, 0,			\
+				0, 0,			\
+				0, 0} }
+
+/**
+ * Empty coremask
+ */
+#define CVMX_COREMASK_EMPTY					\
+	{ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }
+
+struct cvmx_coremask {
+	u64 coremask_bitmap[CVMX_COREMASK_BMPSZ];
+};
+
+/**
+ * Macro to iterate through all available cores in a coremask
+ *
+ * @param core - core variable to use to iterate
+ * @param pcm - pointer to core mask
+ *
+ * Use this like a for statement
+ */
+#define cvmx_coremask_for_each_core(core, pcm)			\
+	for ((core) = -1;					\
+	     (core) = cvmx_coremask_next_core((core), pcm),	\
+		     (core) >= 0;)
+
+/**
+ * Given a node and node mask, return the next available node.
+ *
+ * @param node		starting node number
+ * @param node_mask	node mask to use to find the next node
+ *
+ * @return next node number or -1 if no more nodes are available
+ */
+static inline int cvmx_coremask_next_node(int node, u8 node_mask)
+{
+	int next_offset;
+
+	next_offset = __builtin_ffs(node_mask >> (node + 1));
+	if (next_offset == 0)
+		return -1;
+	else
+		return node + next_offset;
+}
+
+/**
+ * Iterate through all nodes in a node mask
+ *
+ * @param node		node iterator variable
+ * @param node_mask	mask to use for iterating
+ *
+ * Use this like a for statement
+ */
+#define cvmx_coremask_for_each_node(node, node_mask)		\
+	for ((node) = __builtin_ffs(node_mask) - 1;		\
+	     (node) >= 0 && (node) < CVMX_MAX_NODES;		\
+	     (node) = cvmx_coremask_next_node(node, node_mask))
+
+/**
+ * Is ``core'' set in the coremask?
+ *
+ * @param pcm is the pointer to the coremask.
+ * @param core
+ * @return 1 if core is set and 0 if not.
+ */
+static inline int cvmx_coremask_is_core_set(const struct cvmx_coremask *pcm,
+					    int core)
+{
+	int n, i;
+
+	n = core % CVMX_COREMASK_HLDRSZ;
+	i = core / CVMX_COREMASK_HLDRSZ;
+
+	return (pcm->coremask_bitmap[i] & ((u64)1 << n)) != 0;
+}
+
+/**
+ * Is ``current core'' set in the coremask?
+ *
+ * @param pcm is the pointer to the coremask.
+ * @return 1 if core is set and 0 if not.
+ */
+static inline int cvmx_coremask_is_self_set(const struct cvmx_coremask *pcm)
+{
+	return cvmx_coremask_is_core_set(pcm, (int)cvmx_get_core_num());
+}
+
+/**
+ * Is coremask empty?
+ * @param pcm is the pointer to the coremask.
+ * @return 1 if *pcm is empty (all zeros), 0 if not empty.
+ */
+static inline int cvmx_coremask_is_empty(const struct cvmx_coremask *pcm)
+{
+	int i;
+
+	for (i = 0; i < CVMX_COREMASK_USED_BMPSZ; i++)
+		if (pcm->coremask_bitmap[i] != 0)
+			return 0;
+
+	return 1;
+}
+
+/**
+ * Set ``core'' in the coremask.
+ *
+ * @param pcm is the pointer to the coremask.
+ * @param core
+ * @return 0.
+ */
+static inline int cvmx_coremask_set_core(struct cvmx_coremask *pcm, int core)
+{
+	int n, i;
+
+	n = core % CVMX_COREMASK_HLDRSZ;
+	i = core / CVMX_COREMASK_HLDRSZ;
+	pcm->coremask_bitmap[i] |= ((u64)1 << n);
+
+	return 0;
+}
+
+/**
+ * Set ``current core'' in the coremask.
+ *
+ * @param pcm is the pointer to the coremask.
+ * @return 0.
+ */
+static inline int cvmx_coremask_set_self(struct cvmx_coremask *pcm)
+{
+	return cvmx_coremask_set_core(pcm, (int)cvmx_get_core_num());
+}
+
+/**
+ * Clear ``core'' from the coremask.
+ *
+ * @param pcm is the pointer to the coremask.
+ * @param core
+ * @return 0.
+ */
+static inline int cvmx_coremask_clear_core(struct cvmx_coremask *pcm, int core)
+{
+	int n, i;
+
+	n = core % CVMX_COREMASK_HLDRSZ;
+	i = core / CVMX_COREMASK_HLDRSZ;
+	pcm->coremask_bitmap[i] &= ~((u64)1 << n);
+
+	return 0;
+}
+
+/**
+ * Clear ``current core'' from the coremask.
+ *
+ * @param pcm is the pointer to the coremask.
+ * @return 0.
+ */
+static inline int cvmx_coremask_clear_self(struct cvmx_coremask *pcm)
+{
+	return cvmx_coremask_clear_core(pcm, cvmx_get_core_num());
+}
+
+/**
+ * Toggle ``core'' in the coremask.
+ *
+ * @param pcm is the pointer to the coremask.
+ * @param core
+ * @return 0.
+ */
+static inline int cvmx_coremask_toggle_core(struct cvmx_coremask *pcm, int core)
+{
+	int n, i;
+
+	n = core % CVMX_COREMASK_HLDRSZ;
+	i = core / CVMX_COREMASK_HLDRSZ;
+	pcm->coremask_bitmap[i] ^= ((u64)1 << n);
+
+	return 0;
+}
+
+/**
+ * Toggle ``current core'' in the coremask.
+ *
+ * @param pcm is the pointer to the coremask.
+ * @return 0.
+ */
+static inline int cvmx_coremask_toggle_self(struct cvmx_coremask *pcm)
+{
+	return cvmx_coremask_toggle_core(pcm, cvmx_get_core_num());
+}
+
+/**
+ * Set the lower 64-bit of the coremask.
+ * @param pcm	pointer to coremask
+ * @param coremask_64	64-bit coremask to apply to the first node (0)
+ */
+static inline void cvmx_coremask_set64(struct cvmx_coremask *pcm,
+				       u64 coremask_64)
+{
+	pcm->coremask_bitmap[0] = coremask_64;
+}
+
+/**
+ * Set the 64-bit of the coremask for a particular node.
+ * @param pcm	pointer to coremask
+ * @param node	node to set
+ * @param coremask_64	64-bit coremask to apply to the specified node
+ */
+static inline void cvmx_coremask_set64_node(struct cvmx_coremask *pcm,
+					    u8 node,
+					    u64 coremask_64)
+{
+	pcm->coremask_bitmap[CVMX_COREMASK_BMP_NODE_CORE_IDX(node, 0)] =
+		coremask_64;
+}
+
+/**
+ * Gets the lower 64-bits of the coremask
+ *
+ * @param[in] pcm - pointer to coremask
+ * @return 64-bit coremask for the first node
+ */
+static inline u64 cvmx_coremask_get64(const struct cvmx_coremask *pcm)
+{
+	return pcm->coremask_bitmap[0];
+}
+
+/**
+ * Gets the lower 64-bits of the coremask for the specified node
+ *
+ * @param[in] pcm - pointer to coremask
+ * @param node - node to get coremask for
+ * @return 64-bit coremask for the first node
+ */
+static inline u64 cvmx_coremask_get64_node(const struct cvmx_coremask *pcm,
+					   u8 node)
+{
+	return pcm->coremask_bitmap[CVMX_COREMASK_BMP_NODE_CORE_IDX(node, 0)];
+}
+
+/**
+ * Gets the lower 32-bits of the coremask for compatibility
+ *
+ * @param[in] pcm - pointer to coremask
+ * @return 32-bit coremask for the first node
+ * @deprecated This function is to maintain compatibility with older
+ *             SDK applications and may disappear at some point.
+ * This function is not compatible with the CN78XX or any other
+ * Octeon device with more than 32 cores.
+ */
+static inline u32 cvmx_coremask_get32(const struct cvmx_coremask *pcm)
+{
+	return pcm->coremask_bitmap[0] & 0xffffffff;
+}
+
+/*
+ * cvmx_coremask_cmp() returns an integer less than, equal to, or
+ * greater than zero if *pcm1 is found, respectively, to be less than,
+ * to match, or be greater than *pcm2.
+ */
+static inline int cvmx_coremask_cmp(const struct cvmx_coremask *pcm1,
+				    const struct cvmx_coremask *pcm2)
+{
+	int i;
+
+	/* Start from highest node for arithemtically correct result */
+	for (i = CVMX_COREMASK_USED_BMPSZ - 1; i >= 0; i--)
+		if (pcm1->coremask_bitmap[i] != pcm2->coremask_bitmap[i]) {
+			return (pcm1->coremask_bitmap[i] >
+				pcm2->coremask_bitmap[i]) ? 1 : -1;
+		}
+
+	return 0;
+}
+
+/*
+ * cvmx_coremask_OPx(pcm1, pcm2[, pcm3]), where OPx can be
+ * - and
+ * - or
+ * - xor
+ * - not
+ * ...
+ * For binary operators, pcm3 <-- pcm1 OPX pcm2.
+ * For unaries, pcm2 <-- OPx pcm1.
+ */
+#define CVMX_COREMASK_BINARY_DEFUN(binary_op, op)		\
+	static inline int cvmx_coremask_##binary_op(		\
+		struct cvmx_coremask *pcm1,				\
+		const struct cvmx_coremask *pcm2,			\
+		const struct cvmx_coremask *pcm3)			\
+	{							\
+		int i;						\
+								\
+		for (i = 0; i < CVMX_COREMASK_USED_BMPSZ; i++)	\
+			pcm1->coremask_bitmap[i] =		\
+				pcm2->coremask_bitmap[i]	\
+				op				\
+				pcm3->coremask_bitmap[i];	\
+								\
+		return 0;					\
+	}
+
+#define CVMX_COREMASK_UNARY_DEFUN(unary_op, op)			\
+	static inline int cvmx_coremask_##unary_op(		\
+		struct cvmx_coremask *pcm1,				\
+		const struct cvmx_coremask *pcm2)			\
+	{							\
+		int i;						\
+								\
+		for (i = 0; i < CVMX_COREMASK_USED_BMPSZ; i++)	\
+			pcm1->coremask_bitmap[i] =		\
+				op				\
+				pcm2->coremask_bitmap[i];	\
+								\
+		return 0;					\
+	}
+
+/* cvmx_coremask_and(pcm1, pcm2, pcm3): pcm1 = pmc2 & pmc3 */
+CVMX_COREMASK_BINARY_DEFUN(and, &)
+/* cvmx_coremask_or(pcm1, pcm2, pcm3): pcm1 = pmc2 | pmc3  */
+CVMX_COREMASK_BINARY_DEFUN(or, |)
+/* cvmx_coremask_xor(pcm1, pcm2, pcm3): pcm1 = pmc2 ^ pmc3 */
+CVMX_COREMASK_BINARY_DEFUN(xor, ^)
+/* cvmx_coremask_maskoff(pcm1, pcm2, pcm3): pcm1 = pmc2 & ~pmc3 */
+CVMX_COREMASK_BINARY_DEFUN(maskoff, & ~)
+/* cvmx_coremask_not(pcm1, pcm2): pcm1 = ~pcm2       */
+CVMX_COREMASK_UNARY_DEFUN(not, ~)
+/* cvmx_coremask_fill(pcm1, pcm2): pcm1 = -1      */
+CVMX_COREMASK_UNARY_DEFUN(fill, -1 |)
+/* cvmx_coremask_clear(pcm1, pcm2): pcm1 = 0     */
+CVMX_COREMASK_UNARY_DEFUN(clear, 0 &)
+/* cvmx_coremask_dup(pcm1, pcm2): pcm1 = pcm2       */
+CVMX_COREMASK_UNARY_DEFUN(dup, +)
+
+/*
+ * Macros using the unary functions defined w/
+ * CVMX_COREMASK_UNARY_DEFUN
+ * - set *pcm to its complement
+ * - set all bits in *pcm to 0
+ * - set all (valid) bits in *pcm to 1
+ */
+#define cvmx_coremask_complement(pcm)	cvmx_coremask_not(pcm, pcm)
+/* On clear, even clear the unused bits */
+#define cvmx_coremask_clear_all(pcm)					\
+	*(pcm) = (struct cvmx_coremask)CVMX_COREMASK_EMPTY
+#define cvmx_coremask_set_all(pcm)	cvmx_coremask_fill(pcm, NULL)
+
+/*
+ * convert a string of hex digits to struct cvmx_coremask
+ *
+ * @param pcm
+ * @param hexstr can be
+ *	- "[1-9A-Fa-f][0-9A-Fa-f]*", or
+ *	- "-1" to set the bits for all the cores.
+ * return
+ *	 0 for success,
+ *	-1 for string too long (i.e., hexstr takes more bits than
+ *	   CVMX_MIPS_MAX_CORES),
+ *	-2 for conversion problems from hex string to an unsigned
+ *	   long long, e.g., non-hex char in hexstr, and
+ *	-3 for hexstr starting with '0'.
+ * NOTE:
+ *	This function clears the bitmask in *pcm before the conversion.
+ */
+int cvmx_coremask_str2bmp(struct cvmx_coremask *pcm, char *hexstr);
+
+/*
+ * convert a struct cvmx_coremask to a string of hex digits
+ *
+ * @param pcm
+ * @param hexstr is "[1-9A-Fa-f][0-9A-Fa-f]*"
+ *
+ * return 0.
+ */
+int cvmx_coremask_bmp2str(const struct cvmx_coremask *pcm, char *hexstr);
+
+/*
+ * Returns the index of the lowest bit in a coremask holder.
+ */
+static inline int cvmx_coremask_lowest_bit(u64 h)
+{
+	return __builtin_ctzll(h);
+}
+
+/*
+ * Returns the 0-based index of the highest bit in a coremask holder.
+ */
+static inline int cvmx_coremask_highest_bit(u64 h)
+{
+	return (64 - __builtin_clzll(h) - 1);
+}
+
+/**
+ * Returns the last core within the coremask and -1 when the coremask
+ * is empty.
+ *
+ * @param[in] pcm - pointer to coremask
+ * @returns last core set in the coremask or -1 if all clear
+ *
+ */
+static inline int cvmx_coremask_get_last_core(const struct cvmx_coremask *pcm)
+{
+	int i;
+	int found = -1;
+
+	for (i = 0; i < CVMX_COREMASK_USED_BMPSZ; i++) {
+		if (pcm->coremask_bitmap[i])
+			found = i;
+	}
+
+	if (found == -1)
+		return -1;
+
+	return found * CVMX_COREMASK_HLDRSZ +
+		cvmx_coremask_highest_bit(pcm->coremask_bitmap[found]);
+}
+
+/**
+ * Returns the first core within the coremask and -1 when the coremask
+ * is empty.
+ *
+ * @param[in] pcm - pointer to coremask
+ * @returns first core set in the coremask or -1 if all clear
+ *
+ */
+static inline int cvmx_coremask_get_first_core(const struct cvmx_coremask *pcm)
+{
+	int i;
+
+	for (i = 0; i < CVMX_COREMASK_USED_BMPSZ; i++)
+		if (pcm->coremask_bitmap[i])
+			break;
+
+	if (i == CVMX_COREMASK_USED_BMPSZ)
+		return -1;
+
+	return i * CVMX_COREMASK_HLDRSZ +
+		cvmx_coremask_lowest_bit(pcm->coremask_bitmap[i]);
+}
+
+/**
+ * Given a core and coremask, return the next available core in the coremask
+ * or -1 if none are available.
+ *
+ * @param core - starting core to check (can be -1 for core 0)
+ * @param pcm - pointer to coremask to check for the next core.
+ *
+ * @return next core following the core parameter or -1 if no more cores.
+ */
+static inline int cvmx_coremask_next_core(int core,
+					  const struct cvmx_coremask *pcm)
+{
+	int n, i;
+
+	core++;
+	n = core % CVMX_COREMASK_HLDRSZ;
+	i = core / CVMX_COREMASK_HLDRSZ;
+
+	if (pcm->coremask_bitmap[i] != 0) {
+		for (; n < CVMX_COREMASK_HLDRSZ; n++)
+			if (pcm->coremask_bitmap[i] & (1ULL << n))
+				return ((i * CVMX_COREMASK_HLDRSZ) + n);
+	}
+
+	for (i = i + 1; i < CVMX_COREMASK_USED_BMPSZ; i++) {
+		if (pcm->coremask_bitmap[i] != 0)
+			return (i * CVMX_COREMASK_HLDRSZ) +
+				cvmx_coremask_lowest_bit(pcm->coremask_bitmap[i]);
+	}
+	return -1;
+}
+
+/**
+ * Compute coremask for count cores starting with start_core.
+ * Note that the coremask for multi-node processors may have
+ * gaps.
+ *
+ * @param[out]  pcm        pointer to core mask data structure
+ * @param	start_core starting code number
+ * @param       count      number of cores
+ *
+ */
+static inline void cvmx_coremask_set_cores(struct cvmx_coremask *pcm,
+					   unsigned int start_core,
+					   unsigned int count)
+{
+	int node;
+	int core;	/** Current core in node */
+	int cores_in_node;
+	int i;
+
+	assert(CVMX_MAX_CORES < CVMX_COREMASK_HLDRSZ);
+	node = start_core >> CVMX_NODE_NO_SHIFT;
+	core = start_core & ((1 << CVMX_NODE_NO_SHIFT) - 1);
+	assert(core < CVMX_MAX_CORES);
+
+	cvmx_coremask_clear_all(pcm);
+	while (count > 0) {
+		if (count + core > CVMX_MAX_CORES)
+			cores_in_node = CVMX_MAX_CORES - core;
+		else
+			cores_in_node = count;
+
+		i = CVMX_COREMASK_BMP_NODE_CORE_IDX(node, core);
+		pcm->coremask_bitmap[i] = ((1ULL << cores_in_node) - 1) << core;
+		count -= cores_in_node;
+		core = 0;
+		node++;
+	}
+}
+
+/**
+ * Makes a copy of a coremask
+ *
+ * @param[out] dest - pointer to destination coremask
+ * @param[in]  src  - pointer to source coremask
+ */
+static inline void cvmx_coremask_copy(struct cvmx_coremask *dest,
+				      const struct cvmx_coremask *src)
+{
+	memcpy(dest, src, sizeof(*dest));
+}
+
+/**
+ * Test to see if the specified core is first core in coremask.
+ *
+ * @param[in]  pcm  pointer to the coremask to test against
+ * @param[in]  core core to check
+ *
+ * @return  1 if the core is first core in the coremask, 0 otherwise
+ *
+ */
+static inline int cvmx_coremask_is_core_first_core(const struct cvmx_coremask *pcm,
+						   unsigned int core)
+{
+	int n, i;
+
+	n = core / CVMX_COREMASK_HLDRSZ;
+
+	for (i = 0; i < n; i++)
+		if (pcm->coremask_bitmap[i] != 0)
+			return 0;
+
+	/* From now on we only care about the core number within an entry */
+	core &= (CVMX_COREMASK_HLDRSZ - 1);
+	if (__builtin_ffsll(pcm->coremask_bitmap[n]) < (core + 1))
+		return 0;
+
+	return (__builtin_ffsll(pcm->coremask_bitmap[n]) == core + 1);
+}
+
+/*
+ * NOTE:
+ * cvmx_coremask_is_first_core() was retired due to improper usage.
+ * For inquiring about the current core being the initializing
+ * core for an application, use cvmx_is_init_core().
+ * For simply inquring if the current core is numerically
+ * lowest in a given mask, use :
+ *	cvmx_coremask_is_core_first_core( pcm, dvmx_get_core_num())
+ */
+
+/**
+ * Returns the number of 1 bits set in a coremask
+ *
+ * @param[in] pcm - pointer to core mask
+ *
+ * @return number of bits set in the coremask
+ */
+static inline int cvmx_coremask_get_core_count(const struct cvmx_coremask *pcm)
+{
+	int i;
+	int count = 0;
+
+	for (i = 0; i < CVMX_COREMASK_USED_BMPSZ; i++)
+		count += __builtin_popcountll(pcm->coremask_bitmap[i]);
+
+	return count;
+}
+
+/**
+ * For multi-node systems, return the node a core belongs to.
+ *
+ * @param core - core number (0-1023)
+ *
+ * @return node number core belongs to
+ */
+static inline int cvmx_coremask_core_to_node(int core)
+{
+	return (core >> CVMX_NODE_NO_SHIFT) & CVMX_NODE_MASK;
+}
+
+/**
+ * Given a core number on a multi-node system, return the core number for a
+ * particular node.
+ *
+ * @param core - global core number
+ *
+ * @returns core number local to the node.
+ */
+static inline int cvmx_coremask_core_on_node(int core)
+{
+	return (core & ((1 << CVMX_NODE_NO_SHIFT) - 1));
+}
+
+/**
+ * Returns if one coremask is a subset of another coremask
+ *
+ * @param main - main coremask to test
+ * @param subset - subset coremask to test
+ *
+ * @return 0 if the subset contains cores not in the main coremask or 1 if
+ *         the subset is fully contained in the main coremask.
+ */
+static inline int cvmx_coremask_is_subset(const struct cvmx_coremask *main,
+					  const struct cvmx_coremask *subset)
+{
+	int i;
+
+	for (i = 0; i < CVMX_COREMASK_USED_BMPSZ; i++)
+		if ((main->coremask_bitmap[i] & subset->coremask_bitmap[i]) !=
+		    subset->coremask_bitmap[i])
+			return 0;
+	return 1;
+}
+
+/**
+ * Returns if one coremask intersects another coremask
+ *
+ * @param c1 - main coremask to test
+ * @param c2 - subset coremask to test
+ *
+ * @return 1 if coremask c1 intersects coremask c2, 0 if they are exclusive
+ */
+static inline int cvmx_coremask_intersects(const struct cvmx_coremask *c1,
+					   const struct cvmx_coremask *c2)
+{
+	int i;
+
+	for (i = 0; i < CVMX_COREMASK_USED_BMPSZ; i++)
+		if ((c1->coremask_bitmap[i] & c2->coremask_bitmap[i]) != 0)
+			return 1;
+	return 0;
+}
+
+/**
+ * Masks a single node of a coremask
+ *
+ * @param pcm - coremask to mask [inout]
+ * @param node       - node number to mask against
+ */
+static inline void cvmx_coremask_mask_node(struct cvmx_coremask *pcm, int node)
+{
+	int i;
+
+	for (i = 0; i < CVMX_COREMASK_BMP_NODE_CORE_IDX(node, 0); i++)
+		pcm->coremask_bitmap[i] = 0;
+
+	for (i = CVMX_COREMASK_BMP_NODE_CORE_IDX(node + 1, 0);
+	     i < CVMX_COREMASK_USED_BMPSZ; i++)
+		pcm->coremask_bitmap[i] = 0;
+}
+
+/**
+ * Prints out a coremask in the form of node X: 0x... 0x...
+ *
+ * @param[in] pcm - pointer to core mask
+ *
+ * @return nothing
+ */
+void cvmx_coremask_print(const struct cvmx_coremask *pcm);
+
+static inline void cvmx_coremask_dprint(const struct cvmx_coremask *pcm)
+{
+	if (IS_ENABLED(DEBUG))
+		cvmx_coremask_print(pcm);
+}
+
+struct cvmx_coremask *octeon_get_available_coremask(struct cvmx_coremask *pcm);
+
+int validate_coremask(struct cvmx_coremask *pcm);
+
+#endif /* __CVMX_COREMASK_H__ */
-- 
2.28.0



More information about the U-Boot mailing list