From 498721033cd33b2f73642006271f5612b6edf933 Mon Sep 17 00:00:00 2001 From: Vijayenthiran Subramaniam Date: Mon, 6 Jan 2020 17:34:36 +0530 Subject: [PATCH 01/15] cmn600: include encoding bits while calculation x and y position Depending upon the mesh size (X and Y dimensions), CMN-600 supports two different width for encoding the X and Y positions in the node id value. If both X and Y size of the mesh is equal or less than 4, 2 bits are used to encode the X and Y position in the node id. If X and Y size are between 5 and 8 included, 3 bits are used to encode. This is not considered while calculating the X and Y position from the node info value which leads to wrong values if the encoding bits are of size 3. This patch fixes the X and Y position calculation to include the encoding bits. Change-Id: I74ef3c39c4907f2a45aaf1023c981576f02c6539 Signed-off-by: Vijayenthiran Subramaniam --- module/cmn600/src/cmn600.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/module/cmn600/src/cmn600.c b/module/cmn600/src/cmn600.c index cc1a4bddb..f556ead76 100644 --- a/module/cmn600/src/cmn600.c +++ b/module/cmn600/src/cmn600.c @@ -10,6 +10,9 @@ #include #include +static unsigned int encoding_bits; +static unsigned int mask_bits; + unsigned int get_node_child_count(void *node_base) { struct node_header *node = node_base; @@ -143,20 +146,19 @@ const char *get_node_type_name(enum node_type node_type) unsigned int get_node_pos_x(void *node_base) { struct node_header *node = node_base; - return (unsigned int)((node->NODE_INFO >> 21) & 0x3); + return (get_node_id(node) >> (CMN600_NODE_ID_Y_POS + encoding_bits)) & + mask_bits; } unsigned int get_node_pos_y(void *node_base) { struct node_header *node = node_base; - return (unsigned int)((node->NODE_INFO >> 19) & 0x3); + return (get_node_id(node) >> CMN600_NODE_ID_Y_POS) & mask_bits; } struct cmn600_cfgm_reg *get_root_node(uintptr_t base, unsigned int hnd_node_id, unsigned int mesh_size_x, unsigned int mesh_size_y) { - unsigned int encoding_bits; - unsigned int mask_bits; unsigned int node_pos_x; unsigned int node_pos_y; unsigned int node_port; -- GitLab From 59830c783c13e8763b2fcb76f8caa318a060aefa Mon Sep 17 00:00:00 2001 From: Vijayenthiran Subramaniam Date: Fri, 3 Jan 2020 16:58:35 +0530 Subject: [PATCH 02/15] cmn600: ccix: remove rnsam setup for cxg_ra register At the beginning of the ccix setup, RN-SAM setup function is called with the CXG-RA register. This is not required and doing so breaks the FVP platforms. This patch removes this function call. Change-Id: I98d1ced1c9e9ccdc93d23659ef002a7932c3c1bd Signed-off-by: Vijayenthiran Subramaniam --- module/cmn600/src/cmn600_ccix.c | 1 - 1 file changed, 1 deletion(-) diff --git a/module/cmn600/src/cmn600_ccix.c b/module/cmn600/src/cmn600_ccix.c index dcd110f9d..6957f1895 100644 --- a/module/cmn600/src/cmn600_ccix.c +++ b/module/cmn600/src/cmn600_ccix.c @@ -409,7 +409,6 @@ int ccix_setup(struct cmn600_ctx *ctx, void *remote_config) struct mod_cmn600_ccix_remote_node_config * ccix_remote_config = (struct mod_cmn600_ccix_remote_node_config *)remote_config; - cmn600_setup_sam((struct cmn600_rnsam_reg *)((uint32_t)ctx->cxg_ra_reg)); ctx->log_api->log(MOD_LOG_GROUP_DEBUG, MOD_NAME "Programming CCIX gateway...\n"); -- GitLab From 2fb581eed5409cdeb6cd7092696cf852d9f4ad8f Mon Sep 17 00:00:00 2001 From: Vijayenthiran Subramaniam Date: Wed, 6 Nov 2019 17:11:23 +0530 Subject: [PATCH 03/15] cmn600: improve cxla discovery logic There are two improvements that can be made to the existing CXLA node discovery procedure. First, the CXLA node id need not be passed through the config data. This was initially necessitated to avoid accessing the external CXLA node when it is not powered up. This can be improved by using the device type information from the cross point's (XP) port connect info register and skip over it during the discovery process and avoid having to provide the CXLA node id from the config data. Second, with the improved discovery logic, the external RN-SAM count is incremented only for the external child nodes which are discovered as RN-SAM device. With this, RN-F and host RA count need not be decreased by one. Change-Id: Ia870ac69045957215c7c2fdbce774a230e6fda00 Signed-off-by: Vijayenthiran Subramaniam --- module/cmn600/include/mod_cmn600.h | 4 --- module/cmn600/src/cmn600.c | 13 ++++++++ module/cmn600/src/cmn600.h | 32 +++++++++++++++++- module/cmn600/src/cmn600_ccix.c | 4 +-- module/cmn600/src/mod_cmn600.c | 43 ++++++++++++++++++------- product/n1sdp/scp_ramfw/config_cmn600.c | 3 -- 6 files changed, 77 insertions(+), 22 deletions(-) diff --git a/module/cmn600/include/mod_cmn600.h b/module/cmn600/include/mod_cmn600.h index 8a38712b8..ab3976125 100644 --- a/module/cmn600/include/mod_cmn600.h +++ b/module/cmn600/include/mod_cmn600.h @@ -1,4 +1,3 @@ - /* * Arm SCP/MCP Software * Copyright (c) 2017-2020, Arm Limited and Contributors. All rights reserved. @@ -132,9 +131,6 @@ struct mod_cmn600_config { /*! Host SA count */ unsigned int sa_count; - /*! Host CXG LA Node id */ - unsigned int cxgla_node_id; - /*! Table of region memory map entries */ const struct mod_cmn600_memory_region_map *mmap_table; diff --git a/module/cmn600/src/cmn600.c b/module/cmn600/src/cmn600.c index f556ead76..c0a454559 100644 --- a/module/cmn600/src/cmn600.c +++ b/module/cmn600/src/cmn600.c @@ -76,6 +76,19 @@ bool is_child_external(void *node_base, unsigned int child_index) return !!(node->CHILD_POINTER[child_index] & (UINT64_C(1) << 31)); } +bool get_port_number(unsigned int child_node_id) +{ + return (child_node_id >> CMN600_NODE_ID_PORT_POS) & + CMN600_NODE_ID_PORT_MASK; +} + +unsigned int get_device_type(void *mxp_base, bool port) +{ + struct cmn600_mxp_reg *mxp = mxp_base; + return mxp->PORT_CONNECT_INFO[port] & + CMN600_MXP_PORT_CONNECT_INFO_DEVICE_TYPE_MASK; +} + uint64_t sam_encode_region_size(uint64_t size) { uint64_t blocks; diff --git a/module/cmn600/src/cmn600.h b/module/cmn600/src/cmn600.h index 400b4ea7d..6814cd987 100644 --- a/module/cmn600/src/cmn600.h +++ b/module/cmn600/src/cmn600.h @@ -44,6 +44,12 @@ enum node_type { NODE_TYPE_CXLA = 0x102, }; +enum device_type { + DEVICE_TYPE_CXHA = 0x11, // 0b10001 + DEVICE_TYPE_CXRA = 0x12, // 0b10010 + DEVICE_TYPE_CXRH = 0x13, // 0b10011 +}; + /* Common node header */ struct node_header { FWK_R uint64_t NODE_INFO; @@ -359,7 +365,8 @@ struct cmn600_cfgm_reg { */ struct cmn600_mxp_reg { FWK_R uint64_t NODE_INFO; - uint8_t RESERVED0[0x80 - 0x8]; + FWK_R uint64_t PORT_CONNECT_INFO[2]; + uint8_t RESERVED0[0x80 - 0x18]; FWK_R uint64_t CHILD_INFO; uint8_t RESERVED1[0x100 - 0x88]; FWK_R uint64_t CHILD_POINTER[16]; @@ -538,6 +545,8 @@ struct cmn600_hni_reg { #define CMN600_NODE_ID_PORT_MASK 0x1 #define CMN600_NODE_ID_Y_POS 3 +#define CMN600_MXP_PORT_CONNECT_INFO_DEVICE_TYPE_MASK UINT64_C(0x1F) + #define CMN600_ROOT_NODE_OFFSET_PORT_POS 14 #define CMN600_ROOT_NODE_OFFSET_Y_POS 20 @@ -630,6 +639,27 @@ unsigned int get_child_node_id(void *node_base, unsigned int child_index); */ bool is_child_external(void *node_base, unsigned int child_index); +/* + * Returns the port number from the child node id. + * + * \param child_node_id Child node id calculated from the child pointer. + * + * \retval port number (either 0 or 1). + */ +bool get_port_number(unsigned int child_node_id); + +/* + * Returns the device type from the MXP's port connect info register. + * + * \param mxp_base Pointer to the cross point node descriptor + * \pre The cross point node pointer must be valid + * \param port Port number + * \pre The port number should be either 0 or 1. + * + * \retval device type (por_mxp_por_mxp_device_port_connect_info_p[port] & 0x1F) + */ +unsigned int get_device_type(void *mxp_base, bool port); + /* * Convert a memory region size into a size format used by the CMN600 registers * The format is the binary logarithm of the memory region size represented as diff --git a/module/cmn600/src/cmn600_ccix.c b/module/cmn600/src/cmn600_ccix.c index 6957f1895..7c930745f 100644 --- a/module/cmn600/src/cmn600_ccix.c +++ b/module/cmn600/src/cmn600_ccix.c @@ -420,10 +420,10 @@ int ccix_setup(struct cmn600_ctx *ctx, void *remote_config) (ctx->external_rnsam_count <= (0xFF + 1))); /* Number of local RN-F */ - rnf_cnt = ctx->external_rnsam_count - 1; + rnf_cnt = ctx->external_rnsam_count; /* Number of local RAs */ - local_ra_cnt = ctx->internal_rnsam_count + ctx->external_rnsam_count - 1; + local_ra_cnt = ctx->internal_rnsam_count + ctx->external_rnsam_count; /* Set initial RAID value to 0. */ ctx->raid_value = 0; diff --git a/module/cmn600/src/mod_cmn600.c b/module/cmn600/src/mod_cmn600.c index c98efa657..675ae0ed6 100644 --- a/module/cmn600/src/mod_cmn600.c +++ b/module/cmn600/src/mod_cmn600.c @@ -97,6 +97,7 @@ static int cmn600_discovery(void) unsigned int xp_idx; unsigned int node_count; unsigned int node_idx; + bool xp_port; struct cmn600_mxp_reg *xp; struct node_header *node; const struct mod_cmn600_config *config = ctx->config; @@ -128,17 +129,27 @@ static int cmn600_discovery(void) /* External nodes */ if (is_child_external(xp, node_idx)) { - ctx->external_rnsam_count++; - - if (get_child_node_id(xp, node_idx) == config->cxgla_node_id) - ctx->cxla_reg = (void *)node; - - ctx->log_api->log(MOD_LOG_GROUP_DEBUG, - MOD_NAME " Found external node ID:%d\n", - get_child_node_id(xp, node_idx)); - - /* Internal nodes */ - } else { + xp_port = get_port_number(get_child_node_id(xp, node_idx)); + + /* + * If the device type is CXRH, CXHA, or CXRA, then the external + * child node is CXLA as every CXRH, CXHA, or CXRA node has a + * corresponding external CXLA node. + */ + if ((get_device_type(xp, xp_port) == DEVICE_TYPE_CXRH) || + (get_device_type(xp, xp_port) == DEVICE_TYPE_CXHA) || + (get_device_type(xp, xp_port) == DEVICE_TYPE_CXRA)) { + ctx->cxla_reg = (void *)node; + ctx->log_api->log(MOD_LOG_GROUP_DEBUG, + MOD_NAME " Found CXLA at node ID: %d\n", + get_child_node_id(xp, node_idx)); + } else { /* External RN-SAM Node */ + ctx->external_rnsam_count++; + ctx->log_api->log(MOD_LOG_GROUP_DEBUG, + MOD_NAME " Found external node ID: %d\n", + get_child_node_id(xp, node_idx)); + } + } else { /* Internal nodes */ switch (get_node_type(node)) { case NODE_TYPE_HN_F: if (ctx->hnf_count >= MAX_HNF_COUNT) { @@ -231,6 +242,7 @@ static void cmn600_configure(void) { unsigned int xp_count; unsigned int xp_idx; + bool xp_port; unsigned int node_count; unsigned int node_idx; unsigned int xrnsam_entry; @@ -257,6 +269,13 @@ static void cmn600_configure(void) if (is_child_external(xp, node_idx)) { unsigned int node_id = get_child_node_id(xp, node_idx); + xp_port = get_port_number(get_child_node_id(xp, node_idx)); + + /* Skip if the device type is CXG */ + if ((get_device_type(xp, xp_port) == DEVICE_TYPE_CXRH) || + (get_device_type(xp, xp_port) == DEVICE_TYPE_CXHA) || + (get_device_type(xp, xp_port) == DEVICE_TYPE_CXRA)) + continue; fwk_assert(xrnsam_entry < ctx->external_rnsam_count); @@ -532,7 +551,7 @@ static int cmn600_ccix_config_get( return FWK_E_DATA; ctx->ccix_host_info.host_ra_count = - ctx->internal_rnsam_count + ctx->external_rnsam_count - 1; + ctx->internal_rnsam_count + ctx->external_rnsam_count; ctx->ccix_host_info.host_sa_count = ctx->config->sa_count; ccix_capabilities_get(ctx); diff --git a/product/n1sdp/scp_ramfw/config_cmn600.c b/product/n1sdp/scp_ramfw/config_cmn600.c index 13ba53fef..6ed04bc70 100644 --- a/product/n1sdp/scp_ramfw/config_cmn600.c +++ b/product/n1sdp/scp_ramfw/config_cmn600.c @@ -21,8 +21,6 @@ #define NODE_ID_HND 0x68 #define NODE_ID_SBSX 0x64 #define NODE_ID_CCIX 0x0 -#define NODE_ID_CXGLA 0x2 - static const unsigned int snf_table[] = { DMC0_ID, /* Maps to HN-F logical node 0 */ @@ -173,7 +171,6 @@ const struct fwk_module_config config_cmn600 = { .snf_table = snf_table, .snf_count = FWK_ARRAY_SIZE(snf_table), .sa_count = 2, - .cxgla_node_id = NODE_ID_CXGLA, .mmap_table = mmap, .mmap_count = FWK_ARRAY_SIZE(mmap), .chip_addr_space = UINT64_C(4) * FWK_TIB, -- GitLab From 5a0a0684a3ff0ee76e09f98ba6c51f2c56411a3a Mon Sep 17 00:00:00 2001 From: Vijayenthiran Subramaniam Date: Thu, 14 Nov 2019 13:22:35 +0530 Subject: [PATCH 04/15] cmn600: rename unique_ha_ldid_value to unique_remote_rnf_ldid_value The cmn600 context member variable unique_ha_ldid_value is used to keep track of the unique LDID value of the remote caching agent (RN-F). Rename it to unique_remote_rnf_ldid_value to align with the purpose of the variable. This patch also removes the variable from the cmn600 context structure since it is been used only within the ccix_setup function. Change-Id: Ib44cad5671e9717469148cf1d9213ca3118cde1d Signed-off-by: Vijayenthiran Subramaniam --- module/cmn600/include/internal/cmn600_ctx.h | 2 -- module/cmn600/src/cmn600_ccix.c | 14 ++++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/module/cmn600/include/internal/cmn600_ctx.h b/module/cmn600/include/internal/cmn600_ctx.h index 6a8435af6..05558de0e 100644 --- a/module/cmn600/include/internal/cmn600_ctx.h +++ b/module/cmn600/include/internal/cmn600_ctx.h @@ -1,4 +1,3 @@ - /* * Arm SCP/MCP Software * Copyright (c) 2019-2020, Arm Limited and Contributors. All rights reserved. @@ -77,7 +76,6 @@ struct cmn600_ctx { unsigned int cxg_ha_node_id; unsigned int cxg_ha_id_remote; uint8_t raid_value; - uint8_t unique_ha_ldid_value; struct cmn600_cxg_ra_reg *cxg_ra_reg; struct cmn600_cxg_ha_reg *cxg_ha_reg; struct cmn600_cxla_reg *cxla_reg; diff --git a/module/cmn600/src/cmn600_ccix.c b/module/cmn600/src/cmn600_ccix.c index 7c930745f..c929db41c 100644 --- a/module/cmn600/src/cmn600_ccix.c +++ b/module/cmn600/src/cmn600_ccix.c @@ -404,6 +404,7 @@ int ccix_setup(struct cmn600_ctx *ctx, void *remote_config) uint8_t offset_id; uint8_t rnf_cnt; uint8_t local_ra_cnt; + uint8_t unique_remote_rnf_ldid_value; int status; struct mod_cmn600_ccix_remote_node_config * ccix_remote_config = @@ -454,10 +455,10 @@ int ccix_setup(struct cmn600_ctx *ctx, void *remote_config) } /* - * Unique_ha_ldid_value is used to keep track of the + * unique_remote_rnf_ldid_value is used to keep track of the * ldid of the remote RNF agents */ - ctx->unique_ha_ldid_value = rnf_cnt; + unique_remote_rnf_ldid_value = rnf_cnt; if (ctx->chip_id == 0) offset_id = local_ra_cnt; @@ -469,15 +470,16 @@ int ccix_setup(struct cmn600_ctx *ctx, void *remote_config) /* Program the CXHA raid to ldid LUT */ program_cxg_ha_raid_to_ldid_lut(ctx, remote_agent_id, - ctx->unique_ha_ldid_value); + unique_remote_rnf_ldid_value); /* * Program HN-F ldid to CHI node id for * remote RN-F agents */ - program_hnf_ldid_to_chi_node_id_reg(ctx, ctx->unique_ha_ldid_value, - ctx->cxg_ha_node_id, REMOTE_CCIX_NODE); + program_hnf_ldid_to_chi_node_id_reg(ctx, + unique_remote_rnf_ldid_value, ctx->cxg_ha_node_id, + REMOTE_CCIX_NODE); - ctx->unique_ha_ldid_value++; + unique_remote_rnf_ldid_value++; } if (ctx->chip_id == 0) -- GitLab From 77d2016cfc10936517fdefa5084b45a04716a8ea Mon Sep 17 00:00:00 2001 From: Vijayenthiran Subramaniam Date: Thu, 14 Nov 2019 13:54:49 +0530 Subject: [PATCH 05/15] cmn600: increase max ranage of HN-F, RN-D, RN-I CMN-600 controller with revision upto r1p3 supports a maximum of 32 HN-F, RN-D and RN-I. This patch fixes the maximum count of these components. Change-Id: Idd92a7f017beb05b1c58ab61f9c058dcf726ebe9 Signed-off-by: Vijayenthiran Subramaniam --- module/cmn600/include/internal/cmn600_ctx.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/module/cmn600/include/internal/cmn600_ctx.h b/module/cmn600/include/internal/cmn600_ctx.h index 05558de0e..67e9ef649 100644 --- a/module/cmn600/include/internal/cmn600_ctx.h +++ b/module/cmn600/include/internal/cmn600_ctx.h @@ -26,9 +26,9 @@ struct external_rnsam_tuple { }; /* Max Node Counts */ -#define MAX_HNF_COUNT 4 -#define MAX_RND_COUNT 8 -#define MAX_RNI_COUNT 8 +#define MAX_HNF_COUNT 32 +#define MAX_RND_COUNT 32 +#define MAX_RNI_COUNT 32 struct cmn600_ctx { const struct mod_cmn600_config *config; @@ -61,7 +61,7 @@ struct cmn600_ctx { * parameters are known */ unsigned int rnd_count; - uint8_t rnd_ldid[8]; + uint8_t rnd_ldid[MAX_RND_COUNT]; /* * RN-I nodes. The driver keeps a list of RN-I pointers to @@ -69,7 +69,7 @@ struct cmn600_ctx { * parameters are known */ unsigned int rni_count; - uint8_t rni_ldid[8]; + uint8_t rni_ldid[MAX_RNI_COUNT]; /* CCIX specific registers */ unsigned int cxg_ha_id; -- GitLab From 5268c5f0060e4f935f92be792b9a0991d4d2462a Mon Sep 17 00:00:00 2001 From: Vijayenthiran Subramaniam Date: Thu, 14 Nov 2019 14:41:31 +0530 Subject: [PATCH 06/15] cmn600: add rnf count to cmn600 context Currently the RN-F count is considered equal to the total external RN-SAM count. This is done with an assumption that all the RN-F nodes in the mesh has no built-in SAM (RN-F ESAM type). If a mesh contains RN-F nodes with built-in SAM, then the RN-SAM corresponding to the RN-F will be discovered as internal RN-SAM. Add RN-F count as part of cmn600 context and use it in place of the external RN-SAM count. Change-Id: I9257e11b95b865eaf864ec8d9ba804c02e1ff2eb Signed-off-by: Vijayenthiran Subramaniam --- module/cmn600/include/internal/cmn600_ctx.h | 6 ++++++ module/cmn600/src/cmn600_ccix.c | 8 ++------ module/cmn600/src/mod_cmn600.c | 17 +++++++++++++++++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/module/cmn600/include/internal/cmn600_ctx.h b/module/cmn600/include/internal/cmn600_ctx.h index 67e9ef649..2ae3ba822 100644 --- a/module/cmn600/include/internal/cmn600_ctx.h +++ b/module/cmn600/include/internal/cmn600_ctx.h @@ -28,6 +28,7 @@ struct external_rnsam_tuple { /* Max Node Counts */ #define MAX_HNF_COUNT 32 #define MAX_RND_COUNT 32 +#define MAX_RNF_COUNT 32 #define MAX_RNI_COUNT 32 struct cmn600_ctx { @@ -63,6 +64,11 @@ struct cmn600_ctx { unsigned int rnd_count; uint8_t rnd_ldid[MAX_RND_COUNT]; + /* + * RN-F nodes. The driver keeps track of the total number of the RN-F nodes. + */ + unsigned int rnf_count; + /* * RN-I nodes. The driver keeps a list of RN-I pointers to * configure them once the system has been fully discovered and all diff --git a/module/cmn600/src/cmn600_ccix.c b/module/cmn600/src/cmn600_ccix.c index c929db41c..b8d1b3a42 100644 --- a/module/cmn600/src/cmn600_ccix.c +++ b/module/cmn600/src/cmn600_ccix.c @@ -402,7 +402,6 @@ int ccix_setup(struct cmn600_ctx *ctx, void *remote_config) uint8_t agent_id; uint8_t remote_agent_id; uint8_t offset_id; - uint8_t rnf_cnt; uint8_t local_ra_cnt; uint8_t unique_remote_rnf_ldid_value; int status; @@ -420,9 +419,6 @@ int ccix_setup(struct cmn600_ctx *ctx, void *remote_config) fwk_assert((ctx->external_rnsam_count > 1) && (ctx->external_rnsam_count <= (0xFF + 1))); - /* Number of local RN-F */ - rnf_cnt = ctx->external_rnsam_count; - /* Number of local RAs */ local_ra_cnt = ctx->internal_rnsam_count + ctx->external_rnsam_count; @@ -434,7 +430,7 @@ int ccix_setup(struct cmn600_ctx *ctx, void *remote_config) else offset_id = local_ra_cnt; - for (rnf_ldid = 0; rnf_ldid < rnf_cnt; rnf_ldid++) { + for (rnf_ldid = 0; rnf_ldid < ctx->rnf_count; rnf_ldid++) { agent_id = ctx->raid_value + offset_id; /* Program RAID values in CXRA LDID to RAID LUT */ @@ -458,7 +454,7 @@ int ccix_setup(struct cmn600_ctx *ctx, void *remote_config) * unique_remote_rnf_ldid_value is used to keep track of the * ldid of the remote RNF agents */ - unique_remote_rnf_ldid_value = rnf_cnt; + unique_remote_rnf_ldid_value = ctx->rnf_count; if (ctx->chip_id == 0) offset_id = local_ra_cnt; diff --git a/module/cmn600/src/mod_cmn600.c b/module/cmn600/src/mod_cmn600.c index 675ae0ed6..5fbda15aa 100644 --- a/module/cmn600/src/mod_cmn600.c +++ b/module/cmn600/src/mod_cmn600.c @@ -208,16 +208,33 @@ static int cmn600_discovery(void) } } + /* + * RN-F nodes does not have node type identifier and hence the count cannot + * be determined during the discovery process. RN-F count will be total + * RN-SAM count minus the total RN-D, RN-I and CXHA count combined. + */ + ctx->rnf_count = ctx->internal_rnsam_count + ctx->external_rnsam_count - + (ctx->rnd_count + ctx->rni_count + ctx->ccix_host_info.host_ha_count++); + + if (ctx->rnf_count > MAX_RNF_COUNT) { + ctx->log_api->log(MOD_LOG_GROUP_ERROR, + MOD_NAME "rnf count %d > max limit (%d)\n", + ctx->rnf_count, MAX_RNF_COUNT); + return FWK_E_RANGE; + } + ctx->log_api->log(MOD_LOG_GROUP_DEBUG, MOD_NAME "Total internal RN-SAM nodes: %d\n" MOD_NAME "Total external RN-SAM nodes: %d\n" MOD_NAME "Total HN-F nodes: %d\n" MOD_NAME "Total RN-D nodes: %d\n" + MOD_NAME "Total RN-F nodes: %d\n", MOD_NAME "Total RN-I nodes: %d\n", ctx->internal_rnsam_count, ctx->external_rnsam_count, ctx->hnf_count, ctx->rnd_count, + ctx->rnf_count, ctx->rni_count); if (ctx->cxla_reg) { -- GitLab From ac39d7eb0f01f4b23c79a5fbe5202139db30830d Mon Sep 17 00:00:00 2001 From: Vijayenthiran Subramaniam Date: Mon, 18 Nov 2019 12:54:52 +0530 Subject: [PATCH 07/15] cmn600: ccix: use name `rnf` for caching request agents Currently remote caching request agent counts is named as `remote_ra_count`. To make it more explicit that it is a caching agent, rename as `remote_rnf_count`. Change-Id: I6dbbc9cd2ed2884d68fb1068cc031af98f0600f0 Signed-off-by: Vijayenthiran Subramaniam --- module/cmn600/include/mod_cmn600.h | 8 +++++--- module/cmn600/src/cmn600_ccix.c | 2 +- product/n1sdp/module/n1sdp_c2c/src/mod_n1sdp_c2c_i2c.c | 4 ++-- .../module/scmi_ccix_config/src/mod_scmi_ccix_config.c | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/module/cmn600/include/mod_cmn600.h b/module/cmn600/include/mod_cmn600.h index ab3976125..05dfd3ddd 100644 --- a/module/cmn600/include/mod_cmn600.h +++ b/module/cmn600/include/mod_cmn600.h @@ -170,10 +170,12 @@ struct mod_cmn600_ccix_ha_mmap { * \brief CMN600 CCIX configuration data from remote node */ struct mod_cmn600_ccix_remote_node_config { - /*! Remote RA count */ - uint8_t remote_ra_count; + /*! + * Count of remote caching agent (RN-F) that can send request to local HNs + */ + uint8_t remote_rnf_count; - /*! Remote HA count */ + /*! Remote SA count */ uint8_t remote_sa_count; /*! Remote HA count */ diff --git a/module/cmn600/src/cmn600_ccix.c b/module/cmn600/src/cmn600_ccix.c index b8d1b3a42..b2f09d0ec 100644 --- a/module/cmn600/src/cmn600_ccix.c +++ b/module/cmn600/src/cmn600_ccix.c @@ -461,7 +461,7 @@ int ccix_setup(struct cmn600_ctx *ctx, void *remote_config) else offset_id = 0; - for (i = 0; i < ccix_remote_config->remote_ra_count; i++) { + for (i = 0; i < ccix_remote_config->remote_rnf_count; i++) { remote_agent_id = i + offset_id; /* Program the CXHA raid to ldid LUT */ diff --git a/product/n1sdp/module/n1sdp_c2c/src/mod_n1sdp_c2c_i2c.c b/product/n1sdp/module/n1sdp_c2c/src/mod_n1sdp_c2c_i2c.c index 5956e25f4..e735bfbc7 100644 --- a/product/n1sdp/module/n1sdp_c2c/src/mod_n1sdp_c2c_i2c.c +++ b/product/n1sdp/module/n1sdp_c2c/src/mod_n1sdp_c2c_i2c.c @@ -367,7 +367,7 @@ static int n1sdp_c2c_multichip_run_command(uint8_t cmd, bool run_in_slave) break; case N1SDP_C2C_CMD_CMN600_SET_CONFIG: - remote_config.remote_ra_count = 2; + remote_config.remote_rnf_count = 2; remote_config.remote_sa_count = 0; remote_config.remote_ha_count = 1; remote_config.ccix_tc = CCIX_VC1_TC; @@ -645,7 +645,7 @@ static int n1sdp_c2c_process_command(void) break; case N1SDP_C2C_CMD_CMN600_SET_CONFIG: - remote_config.remote_ra_count = 2; + remote_config.remote_rnf_count = 2; remote_config.remote_sa_count = 0; remote_config.remote_ha_count = 1; remote_config.ccix_tc = CCIX_VC1_TC; diff --git a/product/n1sdp/module/scmi_ccix_config/src/mod_scmi_ccix_config.c b/product/n1sdp/module/scmi_ccix_config/src/mod_scmi_ccix_config.c index 88faf63a0..bc8206cff 100644 --- a/product/n1sdp/module/scmi_ccix_config/src/mod_scmi_ccix_config.c +++ b/product/n1sdp/module/scmi_ccix_config/src/mod_scmi_ccix_config.c @@ -271,7 +271,7 @@ static int scmi_ccix_config_protocol_set_handler(fwk_id_t service_id, goto exit; } - ccix_ep_config.remote_ra_count = + ccix_ep_config.remote_rnf_count = (uint8_t)(params->agent_count & RA_COUNT_MASK); ccix_ep_config.remote_ha_count = (uint8_t)((params->agent_count & HA_COUNT_MASK) >> HA_COUNT_BIT_POS); -- GitLab From b6dd9fa6ce50e05d5226959b97b6022e4e0bfb44 Mon Sep 17 00:00:00 2001 From: Vijayenthiran Subramaniam Date: Thu, 14 Nov 2019 19:24:40 +0530 Subject: [PATCH 08/15] cmn600: ccix: improve agent_id and remote_agent_id calculation Improve agent_id's offset_id and remote_agent_id calculation to make it more generic for multi-chip scenario. Change-Id: I69347761d5e61a8c785e33dd0d32d5243bd98ca1 Signed-off-by: Vijayenthiran Subramaniam --- module/cmn600/src/cmn600_ccix.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/module/cmn600/src/cmn600_ccix.c b/module/cmn600/src/cmn600_ccix.c index b2f09d0ec..73a43b3ae 100644 --- a/module/cmn600/src/cmn600_ccix.c +++ b/module/cmn600/src/cmn600_ccix.c @@ -402,6 +402,7 @@ int ccix_setup(struct cmn600_ctx *ctx, void *remote_config) uint8_t agent_id; uint8_t remote_agent_id; uint8_t offset_id; + unsigned int block; uint8_t local_ra_cnt; uint8_t unique_remote_rnf_ldid_value; int status; @@ -425,10 +426,7 @@ int ccix_setup(struct cmn600_ctx *ctx, void *remote_config) /* Set initial RAID value to 0. */ ctx->raid_value = 0; - if (ctx->chip_id == 0) - offset_id = 0; - else - offset_id = local_ra_cnt; + offset_id = ctx->chip_id * local_ra_cnt; for (rnf_ldid = 0; rnf_ldid < ctx->rnf_count; rnf_ldid++) { agent_id = ctx->raid_value + offset_id; @@ -456,13 +454,20 @@ int ccix_setup(struct cmn600_ctx *ctx, void *remote_config) */ unique_remote_rnf_ldid_value = ctx->rnf_count; - if (ctx->chip_id == 0) - offset_id = local_ra_cnt; - else - offset_id = 0; - for (i = 0; i < ccix_remote_config->remote_rnf_count; i++) { - remote_agent_id = i + offset_id; + block = i / ctx->rnf_count; + + /* + * The remote_agent_id should not include the current chip's agent ids. + * If `block` is less than the current chip_id, then include the agent + * ids of chip 0 till (not including) current chip. If the block is + * equal or greater than the current chip, then include the agent id + * from next chip till the max chip. + */ + if (block < ctx->chip_id) + remote_agent_id = i + (ctx->rnf_count * block); + else + remote_agent_id = i + (ctx->rnf_count * block) + local_ra_cnt; /* Program the CXHA raid to ldid LUT */ program_cxg_ha_raid_to_ldid_lut(ctx, remote_agent_id, @@ -478,10 +483,7 @@ int ccix_setup(struct cmn600_ctx *ctx, void *remote_config) unique_remote_rnf_ldid_value++; } - if (ctx->chip_id == 0) - offset_id = 0; - else - offset_id = local_ra_cnt; + offset_id = ctx->chip_id * local_ra_cnt; for (i = 0; i < ctx->rnd_count; i++) { rnd_ldid = ctx->rnd_ldid[i]; -- GitLab From e4c0427095349774812b0125547e7c33a2d33003 Mon Sep 17 00:00:00 2001 From: Vijayenthiran Subramaniam Date: Tue, 19 Nov 2019 14:59:05 +0530 Subject: [PATCH 09/15] cmn600: fix hased memory region calculation in sam programming In SAM programming sequence, region count for the SYS_CACHE_GRP_REGION registers are not incremented. Having a second entry for SYS_CACHE_GRP_REGION register in config data might overwrite the existing entry or get programmed in a wrong region. To avoid this, use `region_sys_count` as counter for the entries going to SYS_CACHE_GRP_REGION register. This patch also adds bounds checking for the region count of hashed and non-hased memory regions. Change-Id: I32d0daf20790a91929c14285a42a03094a2eff6e Signed-off-by: Vijayenthiran Subramaniam --- module/cmn600/src/cmn600.h | 2 ++ module/cmn600/src/mod_cmn600.c | 34 ++++++++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/module/cmn600/src/cmn600.h b/module/cmn600/src/cmn600.h index 6814cd987..b733eadf8 100644 --- a/module/cmn600/src/cmn600.h +++ b/module/cmn600/src/cmn600.h @@ -508,6 +508,8 @@ struct cmn600_hni_reg { #define CMN600_RNSAM_REGION_ENTRY_VALID UINT64_C(0x0000000000000001) #define CMN600_RNSAM_REGION_ENTRY_MASK UINT64_C(0xFFFFFFFF) #define CMN600_RNSAM_REGION_ENTRIES_PER_GROUP 2 +#define CMN600_RNSAM_MAX_HASH_MEM_REGION_ENTRIES 4 +#define CMN600_RNSAM_MAX_NON_HASH_MEM_REGION_ENTRIES 20 #define CMN600_RNSAM_STATUS_UNSTALL UINT64_C(0x0000000000000002) diff --git a/module/cmn600/src/mod_cmn600.c b/module/cmn600/src/mod_cmn600.c index 5fbda15aa..c171f565d 100644 --- a/module/cmn600/src/mod_cmn600.c +++ b/module/cmn600/src/mod_cmn600.c @@ -328,7 +328,7 @@ int cmn600_setup_sam(struct cmn600_rnsam_reg *rnsam) { unsigned int region_idx; unsigned int region_io_count = 0; - unsigned int region_sys_count = 1; + unsigned int region_sys_count = 0; const struct mod_cmn600_memory_region_map *region; const struct mod_cmn600_config *config = ctx->config; unsigned int bit_pos; @@ -362,16 +362,25 @@ int cmn600_setup_sam(struct cmn600_rnsam_reg *rnsam) base + region->size - 1, mmap_type_name[region->type]); - group = region_io_count / CMN600_RNSAM_REGION_ENTRIES_PER_GROUP; - bit_pos = (region_io_count % CMN600_RNSAM_REGION_ENTRIES_PER_GROUP) * - CMN600_RNSAM_REGION_ENTRY_BITS_WIDTH; - switch (region->type) { case MOD_CMN600_MEMORY_REGION_TYPE_IO: case MOD_CMN600_REGION_TYPE_CCIX: /* * Configure memory region */ + if (region_io_count > + CMN600_RNSAM_MAX_NON_HASH_MEM_REGION_ENTRIES) { + ctx->log_api->log(MOD_LOG_GROUP_ERROR, MOD_NAME + "Non-Hashed Memory can have maximum of %d regions only", + CMN600_RNSAM_MAX_NON_HASH_MEM_REGION_ENTRIES); + return FWK_E_DATA; + } + + group = region_io_count / CMN600_RNSAM_REGION_ENTRIES_PER_GROUP; + bit_pos = (region_io_count % + CMN600_RNSAM_REGION_ENTRIES_PER_GROUP) * + CMN600_RNSAM_REGION_ENTRY_BITS_WIDTH; + sam_node_type = (region->type == MOD_CMN600_MEMORY_REGION_TYPE_IO) ? SAM_NODE_TYPE_HN_I : SAM_NODE_TYPE_CXRA; @@ -401,12 +410,25 @@ int cmn600_setup_sam(struct cmn600_rnsam_reg *rnsam) /* * Configure memory region */ + if (region_sys_count >= CMN600_RNSAM_MAX_HASH_MEM_REGION_ENTRIES) { + ctx->log_api->log(MOD_LOG_GROUP_ERROR, MOD_NAME + "Hashed Memory can have maximum of %d regions only", + CMN600_RNSAM_MAX_HASH_MEM_REGION_ENTRIES); + return FWK_E_DATA; + } + + group = region_sys_count / CMN600_RNSAM_REGION_ENTRIES_PER_GROUP; + bit_pos = (region_sys_count % + CMN600_RNSAM_REGION_ENTRIES_PER_GROUP) * + CMN600_RNSAM_REGION_ENTRY_BITS_WIDTH; configure_region(&rnsam->SYS_CACHE_GRP_REGION[group], bit_pos, region->base, region->size, SAM_NODE_TYPE_HN_F); - break; + + region_sys_count++; + break; case MOD_CMN600_REGION_TYPE_SYSCACHE_NONHASH: group = region_sys_count / CMN600_RNSAM_REGION_ENTRIES_PER_GROUP; -- GitLab From 7adeee3c6c07aeb1c62fba077e5f9b0c9c61bb1b Mon Sep 17 00:00:00 2001 From: Vijayenthiran Subramaniam Date: Fri, 25 Oct 2019 11:43:33 +0530 Subject: [PATCH 10/15] cmn600: add support to get revision number CMN-600 supports several revisions ranging from r1p0 to r3p1 and each revision adds new features. CMN-600 has peripheral id register to retrieve the revision number. In order to enable features depending upon the revision, add support to retrieve the revision number from peripheral id register. Change-Id: I9f8647d3f5ee21a4b67ac9836f88ffbe600774f4 Signed-off-by: Vijayenthiran Subramaniam --- module/cmn600/src/cmn600.c | 5 +++++ module/cmn600/src/cmn600.h | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/module/cmn600/src/cmn600.c b/module/cmn600/src/cmn600.c index c0a454559..2d4e96d29 100644 --- a/module/cmn600/src/cmn600.c +++ b/module/cmn600/src/cmn600.c @@ -70,6 +70,11 @@ unsigned int get_child_node_id(void *node_base, return device_id; } +unsigned int get_cmn600_revision(struct cmn600_cfgm_reg *root) +{ + return (root->PERIPH_ID[1] & CMN600_PERIPH_ID_2_MASK); +} + bool is_child_external(void *node_base, unsigned int child_index) { struct node_header *node = node_base; diff --git a/module/cmn600/src/cmn600.h b/module/cmn600/src/cmn600.h index b733eadf8..fb63d325e 100644 --- a/module/cmn600/src/cmn600.h +++ b/module/cmn600/src/cmn600.h @@ -552,6 +552,18 @@ struct cmn600_hni_reg { #define CMN600_ROOT_NODE_OFFSET_PORT_POS 14 #define CMN600_ROOT_NODE_OFFSET_Y_POS 20 +/* Peripheral ID Revision Numbers */ +#define CMN600_PERIPH_ID_2_REV_R1_P0 ((0x00 << 4) + (0x0B)) +#define CMN600_PERIPH_ID_2_REV_R1_P1 ((0x01 << 4) + (0x0B)) +#define CMN600_PERIPH_ID_2_REV_R1_P2 ((0x02 << 4) + (0x0B)) +#define CMN600_PERIPH_ID_2_REV_R1_P3 ((0x03 << 4) + (0x0B)) +#define CMN600_PERIPH_ID_2_REV_R2_P0 ((0x04 << 4) + (0x0B)) +#define CMN600_PERIPH_ID_2_REV_R3_P0 ((0x05 << 4) + (0x0B)) +#define CMN600_PERIPH_ID_2_REV_R3_P1 ((0x06 << 4) + (0x0B)) + +/* Peripheral ID Revision Numbers */ +#define CMN600_PERIPH_ID_2_MASK UINT64_C(0xFF) + /* * Retrieve the number of child nodes of a given node * @@ -627,6 +639,15 @@ void *get_child_node(uintptr_t base, void *node_base, unsigned int child_index); */ unsigned int get_child_node_id(void *node_base, unsigned int child_index); +/* + * Retrieve the revision number of CMN-600. + * + * \param root Pointer to the CMN-600 configuration master register. + * + * \return CMN-600 revision as integer value. + */ +unsigned int get_cmn600_revision(struct cmn600_cfgm_reg *root); + /* * Verify if a child node (given a parent node base and child index) is an * external node from the CMN600 instance point of view. -- GitLab From ccc6597967ce4a88d74f2dd2217070a77c98505c Mon Sep 17 00:00:00 2001 From: Vijayenthiran Subramaniam Date: Fri, 25 Oct 2019 11:39:38 +0530 Subject: [PATCH 11/15] cmn600: add support for HN-F with CAL CMN-600 supports upto 64 HN-Fs from r2p0. This is enabled by pairing two HN-Fs at a crosspoint using CAL, supporting upto 32 CAL instances in a mesh. This patch adds support to enable or disable the use of HN-F CAL mode in RN-SAM programming. Change-Id: I606c2a54c50e12bfb195298e675ae1eb286544b2 Signed-off-by: Vijayenthiran Subramaniam --- module/cmn600/include/mod_cmn600.h | 8 +++ module/cmn600/src/cmn600.c | 6 +++ module/cmn600/src/cmn600.h | 15 ++++++ module/cmn600/src/mod_cmn600.c | 63 ++++++++++++++++++++++-- product/n1sdp/scp_ramfw/config_cmn600.c | 1 + product/rdn1e1/scp_ramfw/config_cmn600.c | 1 + product/sgi575/scp_ramfw/config_cmn600.c | 1 + 7 files changed, 91 insertions(+), 4 deletions(-) diff --git a/module/cmn600/include/mod_cmn600.h b/module/cmn600/include/mod_cmn600.h index 05dfd3ddd..c3f0dd7b4 100644 --- a/module/cmn600/include/mod_cmn600.h +++ b/module/cmn600/include/mod_cmn600.h @@ -148,6 +148,14 @@ struct mod_cmn600_config { /*! API ID for getting chip ID information */ fwk_id_t chipinfo_api_id; + + /*! + * \brief HN-F with CAL support flag + * \details When set to true, enables HN-F with CAL support. This flag will + * be used only if HN-F is found to be connected to CAL (When connected to + * a CAL port, node id of HN-F will be a odd number). + */ + bool hnf_cal_mode; }; /*! diff --git a/module/cmn600/src/cmn600.c b/module/cmn600/src/cmn600.c index 2d4e96d29..c892474f8 100644 --- a/module/cmn600/src/cmn600.c +++ b/module/cmn600/src/cmn600.c @@ -75,6 +75,12 @@ unsigned int get_cmn600_revision(struct cmn600_cfgm_reg *root) return (root->PERIPH_ID[1] & CMN600_PERIPH_ID_2_MASK); } +bool is_cal_mode_supported(struct cmn600_cfgm_reg *root) +{ + return (get_cmn600_revision(root) >= CMN600_PERIPH_ID_2_REV_R2_P0) ? + true : false; +} + bool is_child_external(void *node_base, unsigned int child_index) { struct node_header *node = node_base; diff --git a/module/cmn600/src/cmn600.h b/module/cmn600/src/cmn600.h index fb63d325e..28fd5c748 100644 --- a/module/cmn600/src/cmn600.h +++ b/module/cmn600/src/cmn600.h @@ -17,6 +17,7 @@ #define CMN600_MAX_NUM_RNF 32 #define CMN600_MAX_NUM_HNF 32 +#define CMN600_MAX_NUM_SCG 4 #define SAM_GRANULARITY (64 * FWK_MIB) @@ -93,6 +94,8 @@ struct cmn600_rnsam_reg { FWK_RW uint64_t SYS_CACHE_GRP_HN_COUNT; FWK_RW uint64_t SYS_CACHE_GRP_SN_NODEID[8]; FWK_RW uint64_t SYS_CACHE_GRP_SN_SAM_CFG[2]; + uint8_t RESERVED5[0xF10 - 0xD58]; + FWK_RW uint64_t SYS_CACHE_GRP_CAL_MODE; }; /* @@ -510,6 +513,8 @@ struct cmn600_hni_reg { #define CMN600_RNSAM_REGION_ENTRIES_PER_GROUP 2 #define CMN600_RNSAM_MAX_HASH_MEM_REGION_ENTRIES 4 #define CMN600_RNSAM_MAX_NON_HASH_MEM_REGION_ENTRIES 20 +#define CMN600_RNSAM_SCG_HNF_CAL_MODE_EN UINT64_C(0x01) +#define CMN600_RNSAM_SCG_HNF_CAL_MODE_SHIFT 16 #define CMN600_RNSAM_STATUS_UNSTALL UINT64_C(0x0000000000000002) @@ -752,4 +757,14 @@ unsigned int get_node_pos_y(void *node_base); struct cmn600_cfgm_reg *get_root_node(uintptr_t base, unsigned int hnd_node_id, unsigned int mesh_size_x, unsigned int mesh_size_y); +/* + * Check if CMN600 supports CAL mode. CAL mode is supported from CMN600 r2p0. + * + * \param root Pointer to the root node descriptor + * + * \retval true if the CMN600 revision is found to be r2p0 or above + * \retval false if the CMN600 revision is found to be r1p3 or below + */ +bool is_cal_mode_supported(struct cmn600_cfgm_reg *root); + #endif /* CMN600_H */ diff --git a/module/cmn600/src/mod_cmn600.c b/module/cmn600/src/mod_cmn600.c index c171f565d..27501a11a 100644 --- a/module/cmn600/src/mod_cmn600.c +++ b/module/cmn600/src/mod_cmn600.c @@ -31,23 +31,55 @@ struct cmn600_ctx *ctx; static void process_node_hnf(struct cmn600_hnf_reg *hnf) { unsigned int logical_id; + unsigned int node_id; unsigned int group; unsigned int bit_pos; unsigned int region_idx; unsigned int region_sub_count = 0; const struct mod_cmn600_memory_region_map *region; const struct mod_cmn600_config *config = ctx->config; + static unsigned int cal_mode_factor = 1; uint64_t base_offset; logical_id = get_node_logical_id(hnf); + node_id = get_node_id(hnf); + + /* + * If CAL mode is set, only even numbered hnf node should be added to the + * sys_cache_grp_hn_nodeid registers and hnf_count should be incremented + * only for the even numbered hnf nodes. + */ + if (config->hnf_cal_mode == true && (node_id % 2 == 1) && + is_cal_mode_supported(ctx->root)) { + + /* Factor to manipulate the group and bit_pos */ + cal_mode_factor = 2; + + /* + * Reduce the hnf_count as the current hnf node is not getting included + * in the sys_cache_grp_hn_nodeid register + */ + ctx->hnf_count--; + } assert(logical_id < config->snf_count); - group = logical_id / CMN600_HNF_CACHE_GROUP_ENTRIES_PER_GROUP; - bit_pos = CMN600_HNF_CACHE_GROUP_ENTRY_BITS_WIDTH * - (logical_id % CMN600_HNF_CACHE_GROUP_ENTRIES_PER_GROUP); + group = logical_id / + (CMN600_HNF_CACHE_GROUP_ENTRIES_PER_GROUP * cal_mode_factor); + bit_pos = (CMN600_HNF_CACHE_GROUP_ENTRY_BITS_WIDTH / cal_mode_factor) * + (logical_id % (CMN600_HNF_CACHE_GROUP_ENTRIES_PER_GROUP * + cal_mode_factor)); - ctx->hnf_cache_group[group] += ((uint64_t)get_node_id(hnf)) << bit_pos; + /* + * If CAL mode is set, add only even numbered hnd node to + * sys_cache_grp_hn_nodeid registers + */ + if (config->hnf_cal_mode == true && is_cal_mode_supported(ctx->root)) { + if (node_id % 2 == 0) + ctx->hnf_cache_group[group] += ((uint64_t)get_node_id(hnf)) << + bit_pos; + } else + ctx->hnf_cache_group[group] += ((uint64_t)get_node_id(hnf)) << bit_pos; /* Set target node */ hnf->SAM_CONTROL = config->snf_table[logical_id]; @@ -223,6 +255,14 @@ static int cmn600_discovery(void) return FWK_E_RANGE; } + /* When CAL is present, the number of HN-Fs must be even. */ + if ((ctx->hnf_count % 2 != 0) && (config->hnf_cal_mode == true)) { + ctx->log_api->log(MOD_LOG_GROUP_ERROR, + MOD_NAME "hnf count: %d should be even when CAL mode is set\n", + ctx->hnf_count); + return FWK_E_DATA; + } + ctx->log_api->log(MOD_LOG_GROUP_DEBUG, MOD_NAME "Total internal RN-SAM nodes: %d\n" MOD_NAME "Total external RN-SAM nodes: %d\n" @@ -336,6 +376,8 @@ int cmn600_setup_sam(struct cmn600_rnsam_reg *rnsam) unsigned int group_count; enum sam_node_type sam_node_type; uint64_t base; + unsigned int scg_region = 0; + unsigned int scg_regions_enabled[CMN600_MAX_NUM_SCG] = {0, 0, 0, 0}; ctx->log_api->log(MOD_LOG_GROUP_DEBUG, MOD_NAME "Configuring SAM for node %d\n", @@ -427,6 +469,11 @@ int cmn600_setup_sam(struct cmn600_rnsam_reg *rnsam) region->size, SAM_NODE_TYPE_HN_F); + /* Mark corresponding region as enabled */ + scg_region = (2 * group) + (bit_pos/32); + fwk_assert(scg_region < CMN600_MAX_NUM_SCG); + scg_regions_enabled[scg_region] = 1; + region_sys_count++; break; @@ -473,6 +520,14 @@ int cmn600_setup_sam(struct cmn600_rnsam_reg *rnsam) /* Program the number of HNFs */ rnsam->SYS_CACHE_GRP_HN_COUNT = ctx->hnf_count; + /* Use CAL mode only if the CMN600 revision is r2p0 or above */ + if (is_cal_mode_supported(ctx->root) && config->hnf_cal_mode) { + for (region_idx = 0; region_idx < CMN600_MAX_NUM_SCG; region_idx++) + rnsam->SYS_CACHE_GRP_CAL_MODE = scg_regions_enabled[region_idx] * + (CMN600_RNSAM_SCG_HNF_CAL_MODE_EN << + (region_idx * CMN600_RNSAM_SCG_HNF_CAL_MODE_SHIFT)); + } + /* Enable RNSAM */ rnsam->STATUS = CMN600_RNSAM_STATUS_UNSTALL; __sync_synchronize(); diff --git a/product/n1sdp/scp_ramfw/config_cmn600.c b/product/n1sdp/scp_ramfw/config_cmn600.c index 6ed04bc70..faf0e9b63 100644 --- a/product/n1sdp/scp_ramfw/config_cmn600.c +++ b/product/n1sdp/scp_ramfw/config_cmn600.c @@ -179,5 +179,6 @@ const struct fwk_module_config config_cmn600 = { .chipinfo_api_id = FWK_ID_API_INIT(FWK_MODULE_IDX_N1SDP_SYSTEM, MOD_N1SDP_SYSTEM_API_IDX_CHIPINFO), .chipinfo_mod_id = FWK_ID_MODULE_INIT(FWK_MODULE_IDX_N1SDP_SYSTEM), + .hnf_cal_mode = false, }), }; diff --git a/product/rdn1e1/scp_ramfw/config_cmn600.c b/product/rdn1e1/scp_ramfw/config_cmn600.c index 7130c9fb4..051061a5c 100644 --- a/product/rdn1e1/scp_ramfw/config_cmn600.c +++ b/product/rdn1e1/scp_ramfw/config_cmn600.c @@ -107,5 +107,6 @@ const struct fwk_module_config config_cmn600 = { CLOCK_IDX_INTERCONNECT), .chipinfo_api_id = FWK_ID_NONE_INIT, .chipinfo_mod_id = FWK_ID_NONE_INIT, + .hnf_cal_mode = false, }), }; diff --git a/product/sgi575/scp_ramfw/config_cmn600.c b/product/sgi575/scp_ramfw/config_cmn600.c index 1902bac9f..71052ed01 100644 --- a/product/sgi575/scp_ramfw/config_cmn600.c +++ b/product/sgi575/scp_ramfw/config_cmn600.c @@ -105,5 +105,6 @@ const struct fwk_module_config config_cmn600 = { CLOCK_IDX_INTERCONNECT), .chipinfo_api_id = FWK_ID_NONE_INIT, .chipinfo_mod_id = FWK_ID_NONE_INIT, + .hnf_cal_mode = false, }), }; -- GitLab From 424353b82515df029bc925578c5425dd2a89c4e4 Mon Sep 17 00:00:00 2001 From: Vijayenthiran Subramaniam Date: Mon, 18 Nov 2019 16:56:00 +0530 Subject: [PATCH 12/15] cmn600: ccix: add support for smp mode Add support to verify if the CMN-600 hardware supports SMP mode (in case of revision r2p0) or enable SMP mode (in case of revision r3p0 and above). Change-Id: Id4975a0aa4febb7544670ed06422f2a58d30400e Signed-off-by: Vijayenthiran Subramaniam --- module/cmn600/include/internal/cmn600_ccix.h | 8 ++- module/cmn600/include/mod_cmn600.h | 3 ++ module/cmn600/src/cmn600_ccix.c | 51 ++++++++++++++++++- .../module/n1sdp_c2c/src/mod_n1sdp_c2c_i2c.c | 2 + 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/module/cmn600/include/internal/cmn600_ccix.h b/module/cmn600/include/internal/cmn600_ccix.h index 5fae2f965..160d570b5 100644 --- a/module/cmn600/include/internal/cmn600_ccix.h +++ b/module/cmn600/include/internal/cmn600_ccix.h @@ -63,7 +63,7 @@ struct cmn600_cxg_ha_reg { uint8_t RESERVED2[0x980-0x908]; FWK_RW uint64_t CXG_HA_SEC_REG_GRP_OVERRIDE; uint8_t RESERVED3[0xA08-0x988]; - FWK_RW uint64_t CXG_AUX_CTRL; + FWK_RW uint64_t CXG_HA_AUX_CTRL; uint8_t RESERVED4[0xC00-0xA10]; FWK_RW uint64_t CXG_HA_RNF_RAID_TO_LDID_REG[8]; FWK_RW uint64_t CXG_HA_AGENTID_TO_LINKID_REG[8]; @@ -177,6 +177,8 @@ struct cxg_wait_condition_data { #define CXG_RA_AGENTID_TO_LINKID_VAL_OFFSET 0xF20 #define CXG_RA_REQUEST_TRACKER_DEPTH_MASK UINT64_C(0x0000000001FF0000) #define CXG_RA_REQUEST_TRACKER_DEPTH_VAL 16 +#define CXG_RA_UNIT_INFO_SMP_MODE_RO_MASK (UINT64_C(1) << 61) +#define CXG_RA_AUX_CTRL_SMP_MODE_RW_SHIFT_VAL (16) /* CCIX Gateway (CXG) Home Agent (HA) defines */ @@ -190,6 +192,8 @@ struct cxg_wait_condition_data { #define CXG_HA_SNOOP_TRACKER_DEPTH_VAL 36 #define CXG_HA_WDB_DEPTH_MASK UINT64_C(0x0000000007FC0000) #define CXG_HA_WDB_DEPTH_VAL 18 +#define CXG_HA_UNIT_INFO_SMP_MODE_RO_MASK (UINT64_C(1) << 63) +#define CXG_HA_AUX_CTRL_SMP_MODE_RW_SHIFT_VAL (16) /* CCIX Gateway (CXG) Link Agent (LA) defines */ @@ -211,6 +215,8 @@ struct cxg_wait_condition_data { #define CXLA_PCIE_HDR_TRAFFIC_CLASS_SHIFT_VAL 12 #define CXLA_PCIE_HDR_VENDOR_ID_SHIFT_VAL 32 +#define CXLA_AUX_CTRL_SMP_MODE_SHIFT_VAL (47) + /* CCIX Gateway (CXG) link control & status defines */ #define CXG_LINK_CTRL_EN_MASK UINT64_C(0x0000000000000001) diff --git a/module/cmn600/include/mod_cmn600.h b/module/cmn600/include/mod_cmn600.h index c3f0dd7b4..42eefc185 100644 --- a/module/cmn600/include/mod_cmn600.h +++ b/module/cmn600/include/mod_cmn600.h @@ -207,6 +207,9 @@ struct mod_cmn600_ccix_remote_node_config { /*! Remote HA memory map table count */ uint8_t remote_ha_mmap_count; + /*! SMP mode */ + bool smp_mode; + /*! Remote HA memory map table */ struct mod_cmn600_ccix_ha_mmap remote_ha_mmap[MAX_HA_MMAP_ENTRIES]; diff --git a/module/cmn600/src/cmn600_ccix.c b/module/cmn600/src/cmn600_ccix.c index 73a43b3ae..7e5cfa8c1 100644 --- a/module/cmn600/src/cmn600_ccix.c +++ b/module/cmn600/src/cmn600_ccix.c @@ -9,10 +9,10 @@ #include #include #include +#include #include #include - #define MOD_NAME "[CMN600] " static bool cxg_link_wait_condition(void *data) @@ -79,6 +79,47 @@ static bool cxg_link_wait_condition(void *data) } } +static int enable_smp_mode(struct cmn600_ctx *ctx) +{ + if (get_cmn600_revision(ctx->root) == CMN600_PERIPH_ID_2_REV_R2_P0) { + /* + * CMN-600 revision r2p0 uses read-only bits from the CXG_RA and CXG_HA + * registers to determine whether the SMP Mode is enabled in hardware. + */ + if (((ctx->cxg_ra_reg->CXG_RA_UNIT_INFO & + CXG_RA_UNIT_INFO_SMP_MODE_RO_MASK) != + CXG_RA_UNIT_INFO_SMP_MODE_RO_MASK) || + ((ctx->cxg_ha_reg->CXG_HA_UNIT_INFO & + CXG_HA_UNIT_INFO_SMP_MODE_RO_MASK) != + CXG_HA_UNIT_INFO_SMP_MODE_RO_MASK)) { + ctx->log_api->log(MOD_LOG_GROUP_INFO, MOD_NAME + "SMP Mode not supported\n"); + return FWK_E_SUPPORT; + } + + ctx->log_api->log(MOD_LOG_GROUP_INFO, MOD_NAME "SMP Mode supported\n"); + return FWK_SUCCESS; + } else if (get_cmn600_revision(ctx->root) >= CMN600_PERIPH_ID_2_REV_R3_P0) { + /* + * CMN-600 revision r3p0 and above allows the software to configure the + * SMP mode + */ + ctx->cxg_ra_reg->CXG_RA_AUX_CTRL |= + (1 << CXG_RA_AUX_CTRL_SMP_MODE_RW_SHIFT_VAL); + ctx->cxg_ha_reg->CXG_HA_AUX_CTRL |= + (1 << CXG_HA_AUX_CTRL_SMP_MODE_RW_SHIFT_VAL); + ctx->cxla_reg->CXLA_AUX_CTRL |= + ((uint64_t)0x1 << CXLA_AUX_CTRL_SMP_MODE_SHIFT_VAL); + ctx->log_api->log(MOD_LOG_GROUP_INFO, MOD_NAME "SMP MODE enabled\n"); + return FWK_SUCCESS; + } + + /* + * CMN-600 revision till r1p3 does not provide registers to read or + * configure SMP Mode. + */ + return FWK_SUCCESS; +} static void program_cxg_ra_rnf_ldid_to_raid_reg(struct cmn600_ctx *ctx, uint8_t ldid_value, uint8_t raid) @@ -407,7 +448,7 @@ int ccix_setup(struct cmn600_ctx *ctx, void *remote_config) uint8_t unique_remote_rnf_ldid_value; int status; - struct mod_cmn600_ccix_remote_node_config * ccix_remote_config = + struct mod_cmn600_ccix_remote_node_config *ccix_remote_config = (struct mod_cmn600_ccix_remote_node_config *)remote_config; ctx->log_api->log(MOD_LOG_GROUP_DEBUG, @@ -423,6 +464,12 @@ int ccix_setup(struct cmn600_ctx *ctx, void *remote_config) /* Number of local RAs */ local_ra_cnt = ctx->internal_rnsam_count + ctx->external_rnsam_count; + if (ccix_remote_config->smp_mode == true) { + status = enable_smp_mode(ctx); + if (status != FWK_SUCCESS) + return status; + } + /* Set initial RAID value to 0. */ ctx->raid_value = 0; diff --git a/product/n1sdp/module/n1sdp_c2c/src/mod_n1sdp_c2c_i2c.c b/product/n1sdp/module/n1sdp_c2c/src/mod_n1sdp_c2c_i2c.c index e735bfbc7..d450fb085 100644 --- a/product/n1sdp/module/n1sdp_c2c/src/mod_n1sdp_c2c_i2c.c +++ b/product/n1sdp/module/n1sdp_c2c/src/mod_n1sdp_c2c_i2c.c @@ -375,6 +375,7 @@ static int n1sdp_c2c_multichip_run_command(uint8_t cmd, bool run_in_slave) remote_config.pcie_bus_num = 1; remote_config.ccix_link_id = 0; remote_config.ccix_opt_tlp = CCIX_OPT_TLP_EN; + remote_config.smp_mode = true; remote_config.remote_ha_mmap_count = 1; remote_config.remote_ha_mmap[0].ha_id = 0x1; remote_config.remote_ha_mmap[0].base = (4ULL * FWK_TIB); @@ -653,6 +654,7 @@ static int n1sdp_c2c_process_command(void) remote_config.pcie_bus_num = 1; remote_config.ccix_link_id = 0; remote_config.ccix_opt_tlp = CCIX_OPT_TLP_EN; + remote_config.smp_mode = true; remote_config.remote_ha_mmap_count = 1; remote_config.remote_ha_mmap[0].ha_id = 0x0; remote_config.remote_ha_mmap[0].base = 0; -- GitLab From dbc2e5a6d7fd69ea723a6e9a973d947b38b4f56b Mon Sep 17 00:00:00 2001 From: Vijayenthiran Subramaniam Date: Mon, 18 Nov 2019 19:28:21 +0530 Subject: [PATCH 13/15] cmn600: add check to validate the size of SAM configuration The size of the RN SAM, HN-F SAM and RA SAM should be a power of two. Add assertion to verify this. Change-Id: I1e54bab38bb5c2cb9b1ba94e44c63787085ff579 Signed-off-by: Vijayenthiran Subramaniam --- module/cmn600/src/cmn600.c | 3 +++ module/cmn600/src/cmn600_ccix.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/module/cmn600/src/cmn600.c b/module/cmn600/src/cmn600.c index c892474f8..609e1f106 100644 --- a/module/cmn600/src/cmn600.c +++ b/module/cmn600/src/cmn600.c @@ -108,6 +108,9 @@ uint64_t sam_encode_region_size(uint64_t size) /* Size must be a multiple of SAM_GRANULARITY */ assert((size % SAM_GRANULARITY) == 0); + /* Size also must be a power of two */ + assert((size & (size - 1)) == 0); + blocks = size / SAM_GRANULARITY; result = fwk_math_log2(blocks); diff --git a/module/cmn600/src/cmn600_ccix.c b/module/cmn600/src/cmn600_ccix.c index 7e5cfa8c1..cd1c23ef5 100644 --- a/module/cmn600/src/cmn600_ccix.c +++ b/module/cmn600/src/cmn600_ccix.c @@ -282,6 +282,10 @@ static void program_cxg_ra_sam_addr_region(struct cmn600_ctx *ctx, /* Size must be a multiple of SAM_GRANULARITY */ fwk_assert((config->remote_ha_mmap[i].size % (64 * 1024)) == 0); + /* Size also must be a power of two */ + fwk_assert((config->remote_ha_mmap[i].size & + (config->remote_ha_mmap[i].size - 1)) == 0); + blocks = config->remote_ha_mmap[i].size / (64 * 1024); sz = fwk_math_log2(blocks); ctx->cxg_ra_reg->CXG_RA_SAM_ADDR_REGION_REG[i] = -- GitLab From 41711b3a82e5487c710149ffa25b0dca62a8fd71 Mon Sep 17 00:00:00 2001 From: Vijayenthiran Subramaniam Date: Mon, 18 Nov 2019 20:00:35 +0530 Subject: [PATCH 14/15] cmn600: ccix: add check for alignment of region base of CXRA SAM The region base of the CXRA SAM should be naturally aligned to the region size. Add assertion to verify this. Change-Id: I583edbe518b9f7f2370ebdd4021fe7867ede014a Signed-off-by: Vijayenthiran Subramaniam --- module/cmn600/src/cmn600_ccix.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/module/cmn600/src/cmn600_ccix.c b/module/cmn600/src/cmn600_ccix.c index cd1c23ef5..b7b2d0093 100644 --- a/module/cmn600/src/cmn600_ccix.c +++ b/module/cmn600/src/cmn600_ccix.c @@ -286,6 +286,10 @@ static void program_cxg_ra_sam_addr_region(struct cmn600_ctx *ctx, fwk_assert((config->remote_ha_mmap[i].size & (config->remote_ha_mmap[i].size - 1)) == 0); + /* Region base should be naturally aligned to the region size */ + fwk_assert(config->remote_ha_mmap[i].base % + config->remote_ha_mmap[i].size == 0); + blocks = config->remote_ha_mmap[i].size / (64 * 1024); sz = fwk_math_log2(blocks); ctx->cxg_ra_reg->CXG_RA_SAM_ADDR_REGION_REG[i] = -- GitLab From c85e5c11729369506bfc2e891fb9ee6e61016d86 Mon Sep 17 00:00:00 2001 From: Vijayenthiran Subramaniam Date: Sat, 6 Jul 2019 14:40:15 +0530 Subject: [PATCH 15/15] module: add support for CMN Rhodes interconnect Add initial support for CMN Rhodes interconnect controller. This include configuring SAM tables, programming the nodes and sufficient support for single chip operation. Change-Id: I7358b29cd2cce4a8ab6b476e4b83e87e21b32f65 Signed-off-by: Vijayenthiran Subramaniam --- .../include/internal/cmn_rhodes_ctx.h | 51 ++ module/cmn_rhodes/include/mod_cmn_rhodes.h | 137 ++++ module/cmn_rhodes/src/Makefile | 13 + module/cmn_rhodes/src/cmn_rhodes.c | 220 +++++++ module/cmn_rhodes/src/cmn_rhodes.h | 388 ++++++++++++ module/cmn_rhodes/src/mod_cmn_rhodes.c | 588 ++++++++++++++++++ 6 files changed, 1397 insertions(+) create mode 100644 module/cmn_rhodes/include/internal/cmn_rhodes_ctx.h create mode 100644 module/cmn_rhodes/include/mod_cmn_rhodes.h create mode 100644 module/cmn_rhodes/src/Makefile create mode 100644 module/cmn_rhodes/src/cmn_rhodes.c create mode 100644 module/cmn_rhodes/src/cmn_rhodes.h create mode 100644 module/cmn_rhodes/src/mod_cmn_rhodes.c diff --git a/module/cmn_rhodes/include/internal/cmn_rhodes_ctx.h b/module/cmn_rhodes/include/internal/cmn_rhodes_ctx.h new file mode 100644 index 000000000..1c7842f1f --- /dev/null +++ b/module/cmn_rhodes/include/internal/cmn_rhodes_ctx.h @@ -0,0 +1,51 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * CMN_RHODES Context structure Interface + */ + +#ifndef INTERNAL_CMN_RHODES_CTX_H +#define INTERNAL_CMN_RHODES_CTX_H + +#include +#include +#include +#include +#include + +static struct cmn_rhodes_ctx { + const struct mod_cmn_rhodes_config *config; + + struct cmn_rhodes_cfgm_reg *root; + + /* Number of HN-F (system cache) nodes in the system */ + unsigned int hnf_count; + uint64_t *hnf_cache_group; + uint64_t *sn_nodeid_group; + + /* + * External RN-SAMs. The driver keeps a list of tuples (node identifier and + * node pointers). The configuration of these nodes is via the SAM API. + */ + unsigned int external_rnsam_count; + struct external_rnsam_tuple *external_rnsam_table; + + /* + * Internal RN-SAMs. The driver keeps a list of RN-SAM pointers to + * configure them once the system has been fully discovered and all + * parameters are known + */ + unsigned int internal_rnsam_count; + struct cmn_rhodes_rnsam_reg **internal_rnsam_table; + + struct mod_log_api *log_api; + + bool initialized; +} *ctx; + + +#endif /* INTERNAL_CMN600_CTX_H */ diff --git a/module/cmn_rhodes/include/mod_cmn_rhodes.h b/module/cmn_rhodes/include/mod_cmn_rhodes.h new file mode 100644 index 000000000..8312e061d --- /dev/null +++ b/module/cmn_rhodes/include/mod_cmn_rhodes.h @@ -0,0 +1,137 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MOD_CMN_RHODES_H +#define MOD_CMN_RHODES_H + +#include + +/*! + * \addtogroup GroupModules Modules + * @{ + */ + +/*! + * \defgroup GroupModuleCMN_RHODES CMN_RHODES + * + * \brief Arm Coherent Mesh Network (CMN) RHODES module + * + * \details This module adds support for the CMN_RHODES interconnect + * @{ + */ + +/*! + * \brief Module API indices + */ +enum mod_cmn_rhodes_api_idx { + /*! Index of the PPU_V1 power state observer API */ + MOD_CMN_RHODES_API_IDX_PPU_OBSERVER, + + /*! Number of APIs */ + MOD_CMN_RHODES_API_COUNT +}; + +/*! + * \brief Memory region configuration type + */ +enum mod_cmn_rhodes_mem_region_type { + /*! Input/Output region (serviced by dedicated HN-I and HN-D nodes) */ + MOD_CMN_RHODES_MEM_REGION_TYPE_IO, + + /*! + * Region backed by the system cache (serviced by all HN-F nodes in the + * system) + */ + MOD_CMN_RHODES_MEM_REGION_TYPE_SYSCACHE, + + /*! + * Sub region of the system cache for non-hashed access (serviced by + * dedicated SN-F nodes). + */ + MOD_CMN_RHODES_REGION_TYPE_SYSCACHE_SUB, +}; + +/*! + * \brief Memory region map descriptor + */ +struct mod_cmn_rhodes_mem_region_map { + /*! Base address */ + uint64_t base; + + /*! Region size in bytes */ + uint64_t size; + + /*! Region configuration type */ + enum mod_cmn_rhodes_mem_region_type type; + + /*! + * \brief Target node identifier + * + * \note Not used for \ref + * mod_cmn_rhodes_mem_region_type. + * MOD_CMN_RHODES_MEM_REGION_TYPE_SYSCACHE + * memory regions as it uses the pool of HN-F nodes available in the + * system + */ + unsigned int node_id; +}; + +/*! + * \brief CMN_RHODES configuration data + */ +struct mod_cmn_rhodes_config { + /*! Peripheral base address. */ + uintptr_t base; + + /*! Size along x-axis of the interconnect mesh */ + unsigned int mesh_size_x; + + /*! Size along y-axis of the interconnect mesh */ + unsigned int mesh_size_y; + + /*! Default HN-D node identifier containing the global configuration */ + unsigned int hnd_node_id; + + /*! + * \brief Table of SN-Fs used as targets for the HN-F nodes + * + * \details Each entry of this table corresponds to a HN-F node in the + * system. The HN-F's logical identifiers are used as indices in this + * table + */ + const unsigned int *snf_table; + + /*! Number of entries in the \ref snf_table */ + size_t snf_count; + + /*! Table of region memory map entries */ + const struct mod_cmn_rhodes_mem_region_map *mmap_table; + + /*! Number of entries in the \ref mmap_table */ + size_t mmap_count; + + /*! Identifier of the clock that this device depends on */ + fwk_id_t clock_id; + + /*! + * \brief HN-F with CAL support flag + * \details When set to true, enables HN-F with CAL support. This flag will + * be used only if HN-F is found to be connected to CAL (When connected to + * a CAL port, node id of HN-F will be a odd number). + */ + bool hnf_cal_mode; +}; + +/*! + * @} + */ + +/*! + * @} + */ + +#endif /* MOD_CMN_RHODES_H */ diff --git a/module/cmn_rhodes/src/Makefile b/module/cmn_rhodes/src/Makefile new file mode 100644 index 000000000..b7b87dbf7 --- /dev/null +++ b/module/cmn_rhodes/src/Makefile @@ -0,0 +1,13 @@ +# +# Arm SCP/MCP Software +# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +BS_LIB_NAME := CMN_RHODES + +BS_LIB_SOURCES = mod_cmn_rhodes.c +BS_LIB_SOURCES += cmn_rhodes.c + +include $(BS_DIR)/lib.mk diff --git a/module/cmn_rhodes/src/cmn_rhodes.c b/module/cmn_rhodes/src/cmn_rhodes.c new file mode 100644 index 000000000..3ebe8f632 --- /dev/null +++ b/module/cmn_rhodes/src/cmn_rhodes.c @@ -0,0 +1,220 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +/* + * Encoding bits size of the X and Y position in the Node info value. + * If X and Y dimension are less than 4, encoding bits size will be 2. + * If X and Y dimension are between 5 and 8, encoding bits size will be 3. + */ +static unsigned int encoding_bits; +static unsigned int mask_bits; + +unsigned int get_node_child_count(void *node_base) +{ + struct node_header *node = node_base; + return node->CHILD_INFO & CMN_RHODES_CHILD_INFO_COUNT; +} + +enum node_type get_node_type(void *node_base) +{ + struct node_header *node = node_base; + return (enum node_type)(node->NODE_INFO & CMN_RHODES_NODE_INFO_TYPE); +} + +unsigned int get_node_id(void *node_base) +{ + struct node_header *node = node_base; + return (node->NODE_INFO & CMN_RHODES_NODE_INFO_ID) >> + CMN_RHODES_NODE_INFO_ID_POS; +} + +unsigned int get_node_logical_id(void *node_base) +{ + struct node_header *node = node_base; + return (node->NODE_INFO & CMN_RHODES_NODE_INFO_LOGICAL_ID) >> + CMN_RHODES_NODE_INFO_LOGICAL_ID_POS; +} + +void *get_child_node(uintptr_t base, void *node_base, unsigned int child_index) +{ + struct node_header *node = node_base; + uint32_t child_pointer; + unsigned int offset; + void *child_node; + + child_pointer = node->CHILD_POINTER[child_index]; + offset = child_pointer & CMN_RHODES_CHILD_POINTER_OFFSET; + + child_node = (void *)(base + offset); + return child_node; +} + +unsigned int get_child_node_id(void *node_base, + unsigned int child_index) +{ + struct node_header *node = node_base; + uint32_t node_pointer; + unsigned int node_id; + + node_pointer = (node->CHILD_POINTER[child_index] & + CMN_RHODES_CHILD_POINTER_EXT_NODE_POINTER) >> + CMN_RHODES_CHILD_POINTER_EXT_NODE_POINTER_POS; + + /* + * For mesh widths using 2 bits each for X,Y encoding: + * NodeID[1:0] = DeviceID[3:2] + * NodeID[2] = DeviceID[0] + * NodeID[4:3] = NODE POINTER[7:6] + * NodeID[6:5] = NODE POINTER[9:8] + * + * For mesh widths using 3 bits each for X,Y encoding: + * NodeID[1:0] = DeviceID[3:2] + * NodeID[2] = DeviceID[0] + * NodeID[5:3] = NODE POINTER[8:6] + * NodeID[8:6] = NODE POINTER[11:9] + */ + node_id = (((node_pointer >> 6) & 0xff) << 3) | + ((node_pointer & 0x1) << 2) | + ((node_pointer >> 2) & 0x3); + + return node_id; +} + +bool is_child_external(void *node_base, unsigned int child_index) +{ + struct node_header *node = node_base; + return !!(node->CHILD_POINTER[child_index] & (1U << 31)); +} + +bool get_port_number(unsigned int child_node_id) +{ + return (child_node_id >> CMN_RHODES_NODE_ID_PORT_POS) & + CMN_RHODES_NODE_ID_PORT_MASK; +} + +unsigned int get_device_type(void *mxp_base, bool port) +{ + struct cmn_rhodes_mxp_reg *mxp = mxp_base; + return mxp->PORT_CONNECT_INFO[port] & + CMN_RHODES_MXP_PORT_CONNECT_INFO_DEVICE_TYPE_MASK; +} + +uint64_t sam_encode_region_size(uint64_t size) +{ + uint64_t blocks; + uint64_t result; + + /* Size must be a multiple of SAM_GRANULARITY */ + fwk_assert((size % SAM_GRANULARITY) == 0); + + blocks = size / SAM_GRANULARITY; + result = fwk_math_log2(blocks); + + return result; +} + +void configure_region(volatile uint64_t *reg, uint64_t base, uint64_t size, + enum sam_node_type node_type) +{ + uint64_t value; + + fwk_assert(reg); + fwk_assert((base % size) == 0); + + value = CMN_RHODES_RNSAM_REGION_ENTRY_VALID; + value |= node_type << CMN_RHODES_RNSAM_REGION_ENTRY_TYPE_POS; + value |= sam_encode_region_size(size) << + CMN_RHODES_RNSAM_REGION_ENTRY_SIZE_POS; + value |= (base / SAM_GRANULARITY) << CMN_RHODES_RNSAM_REGION_ENTRY_BASE_POS; + + *reg = value; +} + +static const char * const type_to_name[] = { + [NODE_TYPE_INVALID] = "", + [NODE_TYPE_DVM] = "DVM", + [NODE_TYPE_CFG] = "CFG", + [NODE_TYPE_DTC] = "DTC", + [NODE_TYPE_HN_I] = "HN-I", + [NODE_TYPE_HN_F] = "HN-F", + [NODE_TYPE_XP] = "XP", + [NODE_TYPE_SBSX] = "SBSX", + [NODE_TYPE_RN_I] = "RN-I", + [NODE_TYPE_RN_D] = "RN-D", + [NODE_TYPE_RN_SAM] = "RN-SAM", +}; + +static const char * const type_to_name_cml[] = { + [NODE_TYPE_CXRA - NODE_TYPE_CML_BASE] = "CXRA", + [NODE_TYPE_CXHA - NODE_TYPE_CML_BASE] = "CXHA", + [NODE_TYPE_CXLA - NODE_TYPE_CML_BASE] = "CXLA", + +}; + +const char *get_node_type_name(enum node_type node_type) +{ + /* Base node IDs */ + if (node_type <= NODE_TYPE_RN_SAM) + return type_to_name[node_type]; + + /* CML node IDs */ + if ((node_type >= NODE_TYPE_CML_BASE) && + (node_type <= NODE_TYPE_CXLA)) + return type_to_name_cml[node_type - NODE_TYPE_CML_BASE]; + + /* Invalid node IDs */ + return type_to_name[NODE_TYPE_INVALID]; +} + +unsigned int get_node_pos_x(void *node_base) +{ + struct node_header *node = node_base; + return (get_node_id(node) >> (CMN_RHODES_NODE_ID_Y_POS + encoding_bits)) & + mask_bits; +} + +unsigned int get_node_pos_y(void *node_base) +{ + struct node_header *node = node_base; + return (get_node_id(node) >> CMN_RHODES_NODE_ID_Y_POS) & mask_bits; +} + +struct cmn_rhodes_cfgm_reg *get_root_node(uintptr_t base, + unsigned int hnd_node_id, unsigned int mesh_size_x, + unsigned int mesh_size_y) +{ + unsigned int node_pos_x; + unsigned int node_pos_y; + unsigned int node_port; + uintptr_t offset; + + /* + * Determine the number of bits used to represent each node coordinate based + * on the mesh size as per CMN_RHODES specification. + */ + encoding_bits = ((mesh_size_x > 4) || (mesh_size_y > 4)) ? 3 : 2; + + /* Extract node coordinates from the node identifier */ + mask_bits = (1 << encoding_bits) - 1; + node_pos_y = (hnd_node_id >> CMN_RHODES_NODE_ID_Y_POS) & mask_bits; + node_pos_x = (hnd_node_id >> (CMN_RHODES_NODE_ID_Y_POS + encoding_bits)) & + mask_bits; + node_port = (hnd_node_id >> CMN_RHODES_NODE_ID_PORT_POS) & + CMN_RHODES_NODE_ID_PORT_MASK; + + /* Calculate node address offset */ + offset = (node_pos_y << CMN_RHODES_ROOT_NODE_OFFSET_Y_POS) | + (node_pos_x << (CMN_RHODES_ROOT_NODE_OFFSET_Y_POS + + encoding_bits)) | + (node_port << CMN_RHODES_ROOT_NODE_OFFSET_PORT_POS); + + return (struct cmn_rhodes_cfgm_reg *)(base + offset); +} diff --git a/module/cmn_rhodes/src/cmn_rhodes.h b/module/cmn_rhodes/src/cmn_rhodes.h new file mode 100644 index 000000000..ad698c37b --- /dev/null +++ b/module/cmn_rhodes/src/cmn_rhodes.h @@ -0,0 +1,388 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Description: + * Definitions and utility functions for the CMN RHODES module. + */ + +#ifndef CMN_RHODES_H +#define CMN_RHODES_H + +#include +#include +#include + +/* Max Node Counts */ +#define MAX_HNF_COUNT 64 +#define MAX_RND_COUNT 32 +#define MAX_RNI_COUNT 32 +#define MAX_RNF_COUNT 64 + +/* Maximum System Cache Group regions supported by CMN-Rhodes */ +#define MAX_SCG_COUNT 4 + +/* SAM Granularity of RN-SAM and HN-F SAM */ +#define SAM_GRANULARITY (64 * FWK_MIB) + +/* External nodes that require RN-SAM mapping during run-time */ +struct external_rnsam_tuple { + unsigned int node_id; + struct cmn_rhodes_rnsam_reg *node; +}; + +enum node_type { + NODE_TYPE_INVALID = 0x0, + NODE_TYPE_DVM = 0x1, + NODE_TYPE_CFG = 0x2, + NODE_TYPE_DTC = 0x3, + NODE_TYPE_HN_I = 0x4, + NODE_TYPE_HN_F = 0x5, + NODE_TYPE_XP = 0x6, + NODE_TYPE_SBSX = 0x7, + NODE_TYPE_RN_I = 0xA, + NODE_TYPE_RN_D = 0xD, + NODE_TYPE_RN_SAM = 0xF, + /* Coherent Multichip Link (CML) node types */ + NODE_TYPE_CML_BASE = 0x100, + NODE_TYPE_CXRA = 0x100, + NODE_TYPE_CXHA = 0x101, + NODE_TYPE_CXLA = 0x102, +}; + +enum device_type { + DEVICE_TYPE_CXHA = 0x11, // 0b10001 + DEVICE_TYPE_CXRA = 0x12, // 0b10010 + DEVICE_TYPE_CXRH = 0x13, // 0b10011 +}; + +/* Common node header */ +struct node_header { + FWK_R uint64_t NODE_INFO; + uint8_t RESERVED0[0x80 - 0x8]; + FWK_R uint64_t CHILD_INFO; + uint8_t RESERVED1[0x100 - 0x88]; + FWK_R uint64_t CHILD_POINTER[256]; +}; + +enum sam_node_type { + SAM_NODE_TYPE_HN_F = 0, + SAM_NODE_TYPE_HN_I = 1, + SAM_NODE_TYPE_CXRA = 2, + SAM_NODE_TYPE_COUNT +}; + +/* + * Request Node System Address Map (RN-SAM) registers + */ +struct cmn_rhodes_rnsam_reg { + FWK_R uint64_t NODE_INFO; + uint8_t RESERVED0[0x80 - 0x8]; + FWK_R uint64_t CHILD_INFO; + uint8_t RESERVED1[0x900 - 0x88]; + FWK_R uint64_t UNIT_INFO; + uint8_t RESERVED2[0xC00 - 0x908]; + FWK_RW uint64_t NON_HASH_MEM_REGION[20]; + uint8_t RESERVED3[0xD80 - 0xCA0]; + FWK_RW uint64_t NON_HASH_TGT_NODEID[5]; + uint8_t RESERVED4[0xE00 - 0xDA8]; + FWK_RW uint64_t SYS_CACHE_GRP_REGION[4]; + uint8_t RESERVED5[0xEA0 - 0xE20]; + FWK_RW uint64_t SYS_CACHE_GRP_HN_COUNT; + uint8_t RESERVED6[0xF00 - 0xEA8]; + FWK_RW uint64_t SYS_CACHE_GRP_HN_NODEID[16]; + uint8_t RESERVED7[0x1000 - 0xF80]; + FWK_RW uint64_t SYS_CACHE_GRP_SN_NODEID[16]; + uint8_t RESERVED8[0x1100 - 0x1080]; + FWK_RW uint64_t STATUS; + uint8_t RESERVED9[0x1120 - 0x1108]; + FWK_RW uint64_t SYS_CACHE_GRP_CAL_MODE; +}; + +/* + * Fully Coherent Home Node (HN-F) registers + */ +struct cmn_rhodes_hnf_reg { + FWK_R uint64_t NODE_INFO; + uint8_t RESERVED0[0x80 - 0x8]; + FWK_R uint64_t CHILD_INFO; + uint8_t RESERVED1[0x900 - 0x88]; + FWK_R uint64_t UNIT_INFO; + uint8_t RESERVED2[0xD00 - 0x908]; + FWK_RW uint64_t SAM_CONTROL; + FWK_RW uint64_t SAM_MEMREGION[2]; + uint8_t RESERVED8[0x1C00 - 0xD18]; + FWK_RW uint64_t PPU_PWPR; +}; + +/* + * Configuration slave registers + */ +struct cmn_rhodes_cfgm_reg { + FWK_R uint64_t NODE_INFO; + FWK_RW uint64_t PERIPH_ID[4]; + FWK_RW uint64_t COMPONENT_ID[2]; + uint8_t RESERVED0[0x80 - 0x38]; + FWK_R uint64_t CHILD_INFO; +}; + +/* + * Crosspoint (XP) registers + */ +struct cmn_rhodes_mxp_reg { + FWK_R uint64_t NODE_INFO; + FWK_R uint64_t PORT_CONNECT_INFO[2]; + uint8_t RESERVED0[0x80 - 0x18]; + FWK_R uint64_t CHILD_INFO; + uint8_t RESERVED1[0x100 - 0x88]; + FWK_R uint64_t CHILD_POINTER[16]; +}; + +#define CMN_RHODES_NODE_INFO_TYPE UINT64_C(0x000000000000FFFF) +#define CMN_RHODES_NODE_INFO_ID UINT64_C(0x00000000FFFF0000) +#define CMN_RHODES_NODE_INFO_ID_POS 16 +#define CMN_RHODES_NODE_INFO_LOGICAL_ID UINT64_C(0x0000FFFF00000000) +#define CMN_RHODES_NODE_INFO_LOGICAL_ID_POS 32 + +#define CMN_RHODES_CHILD_INFO_COUNT UINT64_C(0x000000000000FFFF) + +#define CMN_RHODES_CHILD_POINTER_OFFSET UINT64_C(0x000000000FFFFFFF) +#define CMN_RHODES_CHILD_POINTER_EXT UINT64_C(0x0000000080000000) + +/* External child node */ +#define CMN_RHODES_CHILD_POINTER_EXT_REGISTER_OFFSET UINT64_C(0x00003FFF) +#define CMN_RHODES_CHILD_POINTER_EXT_NODE_POINTER UINT64_C(0x0FFFC000) +#define CMN_RHODES_CHILD_POINTER_EXT_NODE_POINTER_POS 14 + +/* Used by NON_HASH_MEM_REGIONx and SYS_CACHE_GRP_REGIONx group registers */ +#define CMN_RHODES_RNSAM_REGION_ENTRY_TYPE_POS 2 +#define CMN_RHODES_RNSAM_REGION_ENTRY_SIZE_POS 56 +#define CMN_RHODES_RNSAM_REGION_ENTRY_BASE_POS 26 +#define CMN_RHODES_RNSAM_REGION_ENTRY_BITS_WIDTH 64 +#define CMN_RHODES_RNSAM_REGION_ENTRY_VALID UINT64_C(0x0000000000000001) +#define CMN_RHODES_RNSAM_REGION_ENTRIES_PER_GROUP 1 +#define CMN_RHODES_RNSAM_SYS_CACHE_GRP_SN_NODEID_ENTRIES_PER_GROUP 4 +#define CMN_RHODES_RNSAM_SCG_HNF_CAL_MODE_EN UINT64_C(0x01) +#define CMN_RHODES_RNSAM_SCG_HNF_CAL_MODE_SHIFT 16 + +#define CMN_RHODES_RNSAM_STATUS_UNSTALL UINT64_C(0x0000000000000002) +#define CMN_RHODES_RNSAM_STATUS_DEFAULT_NODEID_POS 48 + +#define CMN_RHODES_RNSAM_NON_HASH_TGT_NODEID_ENTRY_BITS_WIDTH 12 +#define CMN_RHODES_RNSAM_NON_HASH_TGT_NODEID_ENTRY_MASK UINT64_C(0xFFF) +#define CMN_RHODES_RNSAM_NON_HASH_TGT_NODEID_ENTRIES_PER_GROUP 4 + +#define CMN_RHODES_HNF_SAM_MEMREGION_SIZE_POS 12 +#define CMN_RHODES_HNF_SAM_MEMREGION_BASE_POS 26 +#define CMN_RHODES_HNF_SAM_MEMREGION_VALID UINT64_C(0x8000000000000000) + +#define CMN_RHODES_HNF_CACHE_GROUP_ENTRIES_MAX 64 +#define CMN_RHODES_HNF_CACHE_GROUP_ENTRIES_PER_GROUP 4 +#define CMN_RHODES_HNF_CACHE_GROUP_ENTRY_BITS_WIDTH 12 + +#define CMN_RHODES_PPU_PWPR_POLICY_OFF UINT64_C(0x0000000000000000) +#define CMN_RHODES_PPU_PWPR_POLICY_MEM_RET UINT64_C(0x0000000000000002) +#define CMN_RHODES_PPU_PWPR_POLICY_FUNC_RET UINT64_C(0x000000000000007) +#define CMN_RHODES_PPU_PWPR_POLICY_ON UINT64_C(0x0000000000000008) +#define CMN_RHODES_PPU_PWPR_OPMODE_NOSFSLC UINT64_C(0x0000000000000000) +#define CMN_RHODES_PPU_PWPR_OPMODE_SFONLY UINT64_C(0x0000000000000010) +#define CMN_RHODES_PPU_PWPR_OPMODE_HAM UINT64_C(0x0000000000000020) +#define CMN_RHODES_PPU_PWPR_OPMODE_FAM UINT64_C(0x0000000000000030) +#define CMN_RHODES_PPU_PWPR_DYN_EN UINT64_C(0x0000000000000100) + +/* Mesh and Node ID mapping */ +#define CMN_RHODES_MESH_X_MAX 8 +#define CMN_RHODES_MESH_Y_MAX 8 + +#define CMN_RHODES_NODE_ID_PORT_POS 2 +#define CMN_RHODES_NODE_ID_PORT_MASK 0x1 +#define CMN_RHODES_NODE_ID_Y_POS 3 + +#define CMN_RHODES_MXP_PORT_CONNECT_INFO_DEVICE_TYPE_MASK UINT64_C(0x1F) + +#define CMN_RHODES_ROOT_NODE_OFFSET_PORT_POS 16 +#define CMN_RHODES_ROOT_NODE_OFFSET_Y_POS 22 + +/* + * Retrieve the number of child nodes of a given node + * + * \param node_base Pointer to the node descriptor + * \pre The node pointer must be valid + * + * \return Number of child nodes + */ +unsigned int get_node_child_count(void *node_base); + +/* + * Retrieve node type identifier + * + * \param node_base Pointer to the node descriptor + * \pre The node pointer must be valid + * + * \return Node's type identifier + */ +enum node_type get_node_type(void *node_base); + +/* + * Retrieve the physical identifier of a node from its hardware node descriptor. + * This identifier encodes the node's position in the mesh. + * + * Note: Multiple node descriptors can share the same identifier if they are + * related to the same device node in the mesh. + * + * \param node_base Pointer to the node descriptor + * \pre The node pointer must be valid + * + * \return Node's physical identifier + */ +unsigned int get_node_id(void *node_base); + +/* + * Retrieve the logical identifier of a node from its hardware node descriptor. + * This is an unique identifier (index) among nodes of the same type in the + * system. + * + * \param node_base Pointer to the node base address + * \pre The node pointer must be valid + * + * \return An integer representing the node's logical identifier + */ +unsigned int get_node_logical_id(void *node_base); + +/* + * Retrieve a child node given a node and child index + * + * \param node_base Pointer to the node descriptor + * \pre The node pointer must be valid + * \param child_index Child index + * \pre The child index must be valid + * + * \return Pointer to the child's node descriptor + */ +void *get_child_node(uintptr_t base, void *node_base, unsigned int child_index); + +/* + * Retrieve the physical identifier of a node using its child pointer in the + * parent's node hardware descriptor + * + * This function is used to extract a node's identifier without accessing the + * node descriptor. This is specially useful for external nodes that are in an + * unavailable power or clock domain. + * + * \param node_base Pointer to the parent node descriptor + * \pre The node pointer must be valid + * \param child_index Child index + * \pre The child index must be valid + * + * \return Physical child node identifier + */ +unsigned int get_child_node_id(void *node_base, unsigned int child_index); + +/* + * Verify if a child node (given a parent node base and child index) is an + * external node from the CMN RHODES instance point of view. + * + * \param node_base Pointer to the parent node descriptor + * \pre The node pointer must be valid + * \param child_index Child index + * \pre The child index must be valid + * + * \retval true if the node is external + * \retval false if the node is internal + */ +bool is_child_external(void *node_base, unsigned int child_index); + +/* + * Returns the port number from the child node id. + * + * \param child_node_id Child node id calculated from the child pointer. + * + * \retval port number (either 0 or 1). + */ +bool get_port_number(unsigned int child_node_id); + +/* + * Returns the device type from the MXP's port connect info register. + * + * \param mxp_base Pointer to the cross point node descriptor + * \pre The cross point node pointer must be valid + * \param port Port number + * \pre The port number should be either 0 or 1. + * + * \retval device type (por_mxp_por_mxp_device_port_connect_info_p[port] & 0x1F) + */ +unsigned int get_device_type(void *mxp_base, bool port); + +/* + * Convert a memory region size into a size format used by the CMN RHODES + * registers. The format is the binary logarithm of the memory region size + * represented as blocks multiple of the CMN RHODES's granularity: + * n = log2(size / SAM_GRANULARITY) + * + * \param size Memory region size to be converted + * \pre size must be a multiple of SAM_GRANULARITY + * + * \return log2(size / SAM_GRANULARITY) + */ +uint64_t sam_encode_region_size(uint64_t size); + +/* + * Configure a memory region + * + * \param reg Pointer to the region group descriptor to be configured + * \pre Must be a valid pointer + * \param region Region entry in the region group descriptor + * \param base Region base address + * \param size Region size + * \param node_type Type of the target node + * + * \return None + */ +void configure_region(volatile uint64_t *reg, uint64_t base, uint64_t size, + enum sam_node_type node_type); + +/* + * Retrieve the node type name + * + * \param node_type Node type + * + * \return Pointer to the node type name string + */ +const char *get_node_type_name(enum node_type node_type); + +/* + * Retrieve the node's position in the mesh along the X-axis + * + * \param node_base Pointer to the node descriptor + * + * \return Zero-indexed position along the X-axis + */ +unsigned int get_node_pos_x(void *node_base); + +/* + * Retrieve the node's position in the mesh along the Y-axis + * + * \param node_base Pointer to the node descriptor + * + * \return Zero-indexed position along the Y-axis + */ +unsigned int get_node_pos_y(void *node_base); + +/* + * Get the root node descriptor based on the peripheral base, HN-D node + * identifier and mesh size. + * + * \param base CMN RHODES peripheral base address + * \param hnd_node_id HN-D node identifier containing the global configuration + * \param mesh_size_x Size of the mesh along the x-axis + * \param mesh_size_y Size of the mesh along the x-axis + * + * \return Pointer to the root node descriptor + */ +struct cmn_rhodes_cfgm_reg *get_root_node(uintptr_t base, + unsigned int hnd_node_id, unsigned int mesh_size_x, + unsigned int mesh_size_y); + +#endif /* CMN_RHODES_H */ diff --git a/module/cmn_rhodes/src/mod_cmn_rhodes.c b/module/cmn_rhodes/src/mod_cmn_rhodes.c new file mode 100644 index 000000000..0c63f0df1 --- /dev/null +++ b/module/cmn_rhodes/src/mod_cmn_rhodes.c @@ -0,0 +1,588 @@ +/* + * Arm SCP/MCP Software + * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MOD_NAME "[CMN_RHODES] " + +static struct cmn_rhodes_ctx *ctx; + +static void process_node_hnf(struct cmn_rhodes_hnf_reg *hnf) +{ + unsigned int bit_pos; + unsigned int group; + unsigned int logical_id; + unsigned int node_id; + unsigned int region_idx; + unsigned int region_sub_count = 0; + static unsigned int cal_mode_factor = 1; + const struct mod_cmn_rhodes_mem_region_map *region; + const struct mod_cmn_rhodes_config *config = ctx->config; + + logical_id = get_node_logical_id(hnf); + node_id = get_node_id(hnf); + + /* + * If CAL mode is set, only even numbered hnf node should be added to the + * sys_cache_grp_hn_nodeid registers and hnf_count should be incremented + * only for the even numbered hnf nodes. + */ + if (config->hnf_cal_mode == true && (node_id % 2 == 1)) { + /* Factor to manipulate the group and bit_pos */ + cal_mode_factor = 2; + + /* + * Reduce the hnf_count as the current hnf node is not getting included + * in the sys_cache_grp_hn_nodeid register + */ + ctx->hnf_count--; + } + + assert(logical_id < config->snf_count); + + group = logical_id / + (CMN_RHODES_HNF_CACHE_GROUP_ENTRIES_PER_GROUP * cal_mode_factor); + bit_pos = (CMN_RHODES_HNF_CACHE_GROUP_ENTRY_BITS_WIDTH / cal_mode_factor) * + ((logical_id % + (CMN_RHODES_HNF_CACHE_GROUP_ENTRIES_PER_GROUP * + cal_mode_factor))); + + /* + * If CAL mode is set, add only even numbered hnd node to + * sys_cache_grp_hn_nodeid registers + */ + if (config->hnf_cal_mode == true) { + if (node_id % 2 == 0) + ctx->hnf_cache_group[group] += ((uint64_t)get_node_id(hnf)) << + bit_pos; + } else + ctx->hnf_cache_group[group] += ((uint64_t)get_node_id(hnf)) << bit_pos; + + /* Set target node */ + hnf->SAM_CONTROL = config->snf_table[logical_id]; + + /* + * Map sub-regions to this HN-F node + */ + for (region_idx = 0; region_idx < config->mmap_count; region_idx++) { + region = &config->mmap_table[region_idx]; + + /* Skip non sub-regions */ + if (region->type != MOD_CMN_RHODES_REGION_TYPE_SYSCACHE_SUB) + continue; + + /* Configure sub-region entry */ + hnf->SAM_MEMREGION[region_sub_count] = region->node_id | + (sam_encode_region_size(region->size) << + CMN_RHODES_HNF_SAM_MEMREGION_SIZE_POS) | + ((region->base / SAM_GRANULARITY) << + CMN_RHODES_HNF_SAM_MEMREGION_BASE_POS) | + CMN_RHODES_HNF_SAM_MEMREGION_VALID; + + region_sub_count++; + } + + /* Configure the system cache RAM PPU */ + hnf->PPU_PWPR = CMN_RHODES_PPU_PWPR_POLICY_ON | + CMN_RHODES_PPU_PWPR_OPMODE_FAM | + CMN_RHODES_PPU_PWPR_DYN_EN; +} + +/* + * Discover the topology of the interconnect and identify the number of: + * - External RN-SAM nodes + * - Internal RN-SAM nodes + * - HN-F nodes (cache) + */ +static int cmn_rhodes_discovery(void) +{ + unsigned int xp_count; + unsigned int xp_idx; + unsigned int node_count; + unsigned int node_idx; + bool xp_port; + struct cmn_rhodes_mxp_reg *xp; + struct node_header *node; + const struct mod_cmn_rhodes_config *config = ctx->config; + + ctx->log_api->log(MOD_LOG_GROUP_DEBUG, MOD_NAME "Starting discovery...\n"); + + assert(get_node_type(ctx->root) == NODE_TYPE_CFG); + + /* Traverse cross points (XP) */ + xp_count = get_node_child_count(ctx->root); + for (xp_idx = 0; xp_idx < xp_count; xp_idx++) { + xp = get_child_node(config->base, ctx->root, xp_idx); + assert(get_node_type(xp) == NODE_TYPE_XP); + + ctx->log_api->log(MOD_LOG_GROUP_DEBUG, MOD_NAME "\n"); + ctx->log_api->log(MOD_LOG_GROUP_DEBUG, + MOD_NAME "XP (%d, %d) ID:%d, LID:%d\n", + get_node_pos_x(xp), + get_node_pos_y(xp), + get_node_id(xp), + get_node_logical_id(xp)); + + /* Traverse nodes */ + node_count = get_node_child_count(xp); + for (node_idx = 0; node_idx < node_count; node_idx++) { + node = get_child_node(config->base, xp, node_idx); + if (is_child_external(xp, node_idx)) { /* External nodes */ + xp_port = get_port_number(get_child_node_id(xp, node_idx)); + + /* + * If the device type is CXRH, CXHA, or CXRA, then the external + * child node is CXLA as every CXRH, CXHA, or CXRA node has a + * corresponding external CXLA node. + */ + if ((get_device_type(xp, xp_port) == DEVICE_TYPE_CXRH) || + (get_device_type(xp, xp_port) == DEVICE_TYPE_CXHA) || + (get_device_type(xp, xp_port) == DEVICE_TYPE_CXRA)) { + ctx->log_api->log(MOD_LOG_GROUP_DEBUG, + MOD_NAME " Found CXLA at node ID: %d\n", + get_child_node_id(xp, node_idx)); + } else { /* External RN-SAM Node */ + ctx->external_rnsam_count++; + ctx->log_api->log(MOD_LOG_GROUP_DEBUG, + MOD_NAME " Found external node ID: %d\n", + get_child_node_id(xp, node_idx)); + } + } else { /* Internal nodes */ + switch (get_node_type(node)) { + case NODE_TYPE_HN_F: + if (ctx->hnf_count >= MAX_HNF_COUNT) { + ctx->log_api->log(MOD_LOG_GROUP_DEBUG, MOD_NAME + " hnf count %d >= max limit (%d)\n", + ctx->hnf_count, MAX_HNF_COUNT); + return FWK_E_DATA; + } + ctx->hnf_count++; + break; + + case NODE_TYPE_RN_SAM: + ctx->internal_rnsam_count++; + break; + + default: + /* Nothing to be done for other node types */ + break; + } + + ctx->log_api->log(MOD_LOG_GROUP_DEBUG, + MOD_NAME " %s ID:%d, LID:%d\n", + get_node_type_name(get_node_type(node)), + get_node_id(node), + get_node_logical_id(node)); + } + } + } + + /* When CAL is present, the number of HN-Fs must be even. */ + if ((ctx->hnf_count % 2 != 0) && (config->hnf_cal_mode == true)) { + ctx->log_api->log(MOD_LOG_GROUP_ERROR, MOD_NAME + "hnf count: %d should be even when CAL mode is set\n", + ctx->hnf_count); + return FWK_E_DATA; + } + + ctx->log_api->log(MOD_LOG_GROUP_DEBUG, + MOD_NAME "Total internal RN-SAM nodes: %d\n" + MOD_NAME "Total external RN-SAM nodes: %d\n" + MOD_NAME "Total HN-F nodes: %d\n", + ctx->internal_rnsam_count, + ctx->external_rnsam_count, + ctx->hnf_count); + + return FWK_SUCCESS; +} + +static void cmn_rhodes_configure(void) +{ + unsigned int node_count; + unsigned int node_idx; + unsigned int xp_count; + unsigned int xp_idx; + unsigned int xrnsam_entry; + unsigned int irnsam_entry; + bool xp_port; + void *node; + struct cmn_rhodes_mxp_reg *xp; + const struct mod_cmn_rhodes_config *config = ctx->config; + + assert(get_node_type(ctx->root) == NODE_TYPE_CFG); + + xrnsam_entry = 0; + irnsam_entry = 0; + + /* Traverse cross points (XP) */ + xp_count = get_node_child_count(ctx->root); + for (xp_idx = 0; xp_idx < xp_count; xp_idx++) { + xp = get_child_node(config->base, ctx->root, xp_idx); + assert(get_node_type(xp) == NODE_TYPE_XP); + + /* Traverse nodes */ + node_count = get_node_child_count(xp); + for (node_idx = 0; node_idx < node_count; node_idx++) { + node = get_child_node(config->base, xp, node_idx); + if (is_child_external(xp, node_idx)) { + unsigned int node_id = get_child_node_id(xp, node_idx); + xp_port = get_port_number(get_child_node_id(xp, node_idx)); + + /* Skip if the device type is CXG */ + if ((get_device_type(xp, xp_port) == DEVICE_TYPE_CXRH) || + (get_device_type(xp, xp_port) == DEVICE_TYPE_CXHA) || + (get_device_type(xp, xp_port) == DEVICE_TYPE_CXRA)) + continue; + + fwk_assert(xrnsam_entry < ctx->external_rnsam_count); + + ctx->external_rnsam_table[xrnsam_entry].node_id = node_id; + ctx->external_rnsam_table[xrnsam_entry].node = node; + + xrnsam_entry++; + } else { + enum node_type node_type = get_node_type(node); + + if (node_type == NODE_TYPE_RN_SAM) { + fwk_assert(irnsam_entry < ctx->internal_rnsam_count); + + ctx->internal_rnsam_table[irnsam_entry] = node; + + irnsam_entry++; + } else if (node_type == NODE_TYPE_HN_F) + process_node_hnf(node); + } + } + } +} + +static const char * const mmap_type_name[] = { + [MOD_CMN_RHODES_MEM_REGION_TYPE_IO] = "I/O", + [MOD_CMN_RHODES_MEM_REGION_TYPE_SYSCACHE] = "System Cache", + [MOD_CMN_RHODES_REGION_TYPE_SYSCACHE_SUB] = "Sub-System Cache", +}; + +static int cmn_rhodes_setup_sam(struct cmn_rhodes_rnsam_reg *rnsam) +{ + unsigned int bit_pos; + unsigned int group; + unsigned int group_count; + unsigned int region_idx; + unsigned int region_io_count = 0; + unsigned int region_sys_count = 0; + unsigned int scg_regions_enabled[MAX_SCG_COUNT] = {0, 0, 0, 0}; + const struct mod_cmn_rhodes_mem_region_map *region; + const struct mod_cmn_rhodes_config *config = ctx->config; + + ctx->log_api->log(MOD_LOG_GROUP_DEBUG, + MOD_NAME "Configuring SAM for node %d\n", + get_node_id(rnsam)); + + for (region_idx = 0; region_idx < config->mmap_count; region_idx++) { + region = &config->mmap_table[region_idx]; + + ctx->log_api->log(MOD_LOG_GROUP_DEBUG, + MOD_NAME " [0x%lx - 0x%lx] %s\n", + region->base, + region->base + region->size - 1, + mmap_type_name[region->type]); + + switch (region->type) { + case MOD_CMN_RHODES_MEM_REGION_TYPE_IO: + /* + * Configure memory region + */ + configure_region(&rnsam->NON_HASH_MEM_REGION[region_io_count], + region->base, + region->size, + SAM_NODE_TYPE_HN_I); + + /* + * Configure target node + */ + group = region_io_count / + CMN_RHODES_RNSAM_NON_HASH_TGT_NODEID_ENTRIES_PER_GROUP; + bit_pos = CMN_RHODES_RNSAM_NON_HASH_TGT_NODEID_ENTRY_BITS_WIDTH * + (region_io_count % + CMN_RHODES_RNSAM_NON_HASH_TGT_NODEID_ENTRIES_PER_GROUP); + + rnsam->NON_HASH_TGT_NODEID[group] &= + ~(CMN_RHODES_RNSAM_NON_HASH_TGT_NODEID_ENTRY_MASK << bit_pos); + rnsam->NON_HASH_TGT_NODEID[group] |= + (region->node_id & + CMN_RHODES_RNSAM_NON_HASH_TGT_NODEID_ENTRY_MASK) << bit_pos; + + region_io_count++; + break; + + case MOD_CMN_RHODES_MEM_REGION_TYPE_SYSCACHE: + /* + * Configure memory region + */ + configure_region(&rnsam->SYS_CACHE_GRP_REGION[region_sys_count], + region->base, + region->size, + SAM_NODE_TYPE_HN_F); + + /* Mark corresponding region as enabled */ + fwk_assert(region_sys_count < MAX_SCG_COUNT); + scg_regions_enabled[region_sys_count] = 1; + + region_sys_count++; + break; + + case MOD_CMN_RHODES_REGION_TYPE_SYSCACHE_SUB: + /* Do nothing. System cache sub-regions are handled by HN-Fs */ + break; + + default: + assert(false); + return FWK_E_DATA; + } + } + + group_count = ctx->hnf_count / CMN_RHODES_HNF_CACHE_GROUP_ENTRIES_PER_GROUP; + for (group = 0; group < group_count; group++) + rnsam->SYS_CACHE_GRP_HN_NODEID[group] = ctx->hnf_cache_group[group]; + + /* Program the number of HNFs */ + rnsam->SYS_CACHE_GRP_HN_COUNT = ctx->hnf_count; + + /* + * If CAL mode is enabled by the configuration program the SCG CAL Mode + * enable register. + */ + if (config->hnf_cal_mode) + for (region_idx = 0; region_idx < MAX_SCG_COUNT; region_idx++) + rnsam->SYS_CACHE_GRP_CAL_MODE = scg_regions_enabled[region_idx] * + (CMN_RHODES_RNSAM_SCG_HNF_CAL_MODE_EN << + (region_idx * CMN_RHODES_RNSAM_SCG_HNF_CAL_MODE_SHIFT)); + + /* Program the SYS_CACHE_GRP_SN_NODEID register for PrefetchTgt */ + if (config->hnf_cal_mode) + group_count = config->snf_count/ + (CMN_RHODES_RNSAM_SYS_CACHE_GRP_SN_NODEID_ENTRIES_PER_GROUP * 2); + else + group_count = config->snf_count/ + CMN_RHODES_RNSAM_SYS_CACHE_GRP_SN_NODEID_ENTRIES_PER_GROUP; + + for (group = 0; group < group_count; group++) + rnsam->SYS_CACHE_GRP_SN_NODEID[group] = ctx->sn_nodeid_group[group]; + + /* Enable RNSAM */ + rnsam->STATUS = ((uint64_t)config->hnd_node_id << + CMN_RHODES_RNSAM_STATUS_DEFAULT_NODEID_POS) | + CMN_RHODES_RNSAM_STATUS_UNSTALL; + __sync_synchronize(); + + return FWK_SUCCESS; +} + +static int cmn_rhodes_setup(void) +{ + unsigned int rnsam_idx; + int status = FWK_SUCCESS; + + if (!ctx->initialized) { + status = cmn_rhodes_discovery(); + if (status != FWK_SUCCESS) + return FWK_SUCCESS; + + /* + * Allocate resources based on the discovery + */ + + /* Pointers for the internal RN-SAM nodes */ + if (ctx->internal_rnsam_count != 0) { + ctx->internal_rnsam_table = fwk_mm_calloc( + ctx->internal_rnsam_count, sizeof(*ctx->internal_rnsam_table)); + if (ctx->internal_rnsam_table == NULL) + return FWK_E_NOMEM; + } + + /* Tuples for the external RN-RAM nodes (including their node IDs) */ + if (ctx->external_rnsam_count != 0) { + ctx->external_rnsam_table = fwk_mm_calloc( + ctx->external_rnsam_count, sizeof(*ctx->external_rnsam_table)); + if (ctx->external_rnsam_table == NULL) + return FWK_E_NOMEM; + } + + /* Cache groups */ + if (ctx->hnf_count != 0) { + /* + * Allocate enough group descriptors to accommodate all expected + * HN-F nodes in the system. + */ + ctx->hnf_cache_group = fwk_mm_calloc( + ctx->hnf_count / CMN_RHODES_HNF_CACHE_GROUP_ENTRIES_PER_GROUP, + sizeof(*ctx->hnf_cache_group)); + if (ctx->hnf_cache_group == NULL) + return FWK_E_NOMEM; + ctx->sn_nodeid_group = fwk_mm_calloc( + ctx->hnf_count / + CMN_RHODES_RNSAM_SYS_CACHE_GRP_SN_NODEID_ENTRIES_PER_GROUP, + sizeof(*ctx->sn_nodeid_group)); + if (ctx->sn_nodeid_group == NULL) + return FWK_E_NOMEM; + } + } + + cmn_rhodes_configure(); + + /* Setup internal RN-SAM nodes */ + for (rnsam_idx = 0; rnsam_idx < ctx->internal_rnsam_count; rnsam_idx++) + cmn_rhodes_setup_sam(ctx->internal_rnsam_table[rnsam_idx]); + + ctx->log_api->log(MOD_LOG_GROUP_DEBUG, MOD_NAME "Done\n"); + + ctx->initialized = true; + + return FWK_SUCCESS; +} + +static int cmn_rhodes_setup_rnsam(unsigned int node_id) +{ + unsigned int node_idx; + + for (node_idx = 0; node_idx < ctx->external_rnsam_count; node_idx++) { + if (ctx->external_rnsam_table[node_idx].node_id == node_id) { + cmn_rhodes_setup_sam(ctx->external_rnsam_table[node_idx].node); + return FWK_SUCCESS; + } + } + + return FWK_E_PARAM; +} + +/* + * PPUv1 State Observer API + */ + +static void post_ppu_on(void *data) +{ + assert(data != NULL); + cmn_rhodes_setup_rnsam(*(unsigned int *)data); +} + +static const struct mod_ppu_v1_power_state_observer_api +cmn_rhodes_observer_api = { + .post_ppu_on = post_ppu_on, +}; + +/* + * Framework handlers + */ + +static int cmn_rhodes_init(fwk_id_t module_id, unsigned int element_count, + const void *data) +{ + const struct mod_cmn_rhodes_config *config = data; + + /* No elements support */ + if (element_count > 0) + return FWK_E_DATA; + + /* Allocate space for the context */ + ctx = fwk_mm_calloc(1, sizeof(*ctx)); + if (ctx == NULL) + return FWK_E_NOMEM; + + if (config->base == 0) + return FWK_E_DATA; + + if ((config->mesh_size_x == 0) || + (config->mesh_size_x > CMN_RHODES_MESH_X_MAX)) + return FWK_E_DATA; + + if ((config->mesh_size_y == 0) || + (config->mesh_size_y > CMN_RHODES_MESH_Y_MAX)) + return FWK_E_DATA; + + if (config->snf_count > CMN_RHODES_HNF_CACHE_GROUP_ENTRIES_MAX) + return FWK_E_DATA; + + ctx->root = get_root_node(config->base, config->hnd_node_id, + config->mesh_size_x, config->mesh_size_y); + + ctx->config = config; + + return FWK_SUCCESS; +} + +static int cmn_rhodes_bind(fwk_id_t id, unsigned int round) +{ + int status; + + /* Use second round only (round numbering is zero-indexed) */ + if (round == 1) { + /* Bind to the log component */ + status = fwk_module_bind(FWK_ID_MODULE(FWK_MODULE_IDX_LOG), + FWK_ID_API(FWK_MODULE_IDX_LOG, 0), + &ctx->log_api); + if (status != FWK_SUCCESS) + return FWK_E_PANIC; + } + + return FWK_SUCCESS; +} + +static int cmn_rhodes_process_bind_request(fwk_id_t requester_id, + fwk_id_t target_id, fwk_id_t api_id, const void **api) +{ + *api = &cmn_rhodes_observer_api; + return FWK_SUCCESS; +} + +int cmn_rhodes_start(fwk_id_t id) +{ + if (fwk_id_is_equal(ctx->config->clock_id, FWK_ID_NONE)) { + cmn_rhodes_setup(); + return FWK_SUCCESS; + } + + /* Register the module for clock state notifications */ + return fwk_notification_subscribe(mod_clock_notification_id_state_changed, + ctx->config->clock_id, id); +} + +static int cmn_rhodes_process_notification( + const struct fwk_event *event, + struct fwk_event *resp_event) +{ + struct clock_notification_params *params; + + assert(fwk_id_is_equal(event->id, mod_clock_notification_id_state_changed)); + assert(fwk_id_is_type(event->target_id, FWK_ID_TYPE_MODULE)); + + params = (struct clock_notification_params *)event->params; + if (params->new_state == MOD_CLOCK_STATE_RUNNING) + cmn_rhodes_setup(); + + return FWK_SUCCESS; +} + +const struct fwk_module module_cmn_rhodes = { + .name = "CMN_RHODES", + .type = FWK_MODULE_TYPE_DRIVER, + .api_count = MOD_CMN_RHODES_API_COUNT, + .init = cmn_rhodes_init, + .bind = cmn_rhodes_bind, + .start = cmn_rhodes_start, + .process_bind_request = cmn_rhodes_process_bind_request, + .process_notification = cmn_rhodes_process_notification, +}; -- GitLab