From b0ce80588d107f5132243110d70e2bcd95e39d88 Mon Sep 17 00:00:00 2001 From: Aaron Williams Date: Thu, 20 Aug 2020 07:22:01 +0200 Subject: [PATCH] mips: octeon: Add coremask support This patch adds the coremask handling functions. Signed-off-by: Aaron Williams Signed-off-by: Stefan Roese --- 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 +#include + +#include +#include + +#include +#include +#include +#include +#include + +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 so it is not + * confusing + */ + if (!found) + printf(""); + 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 so it is not confusing */ + if (!found) + printf(""); + + 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.39.5