diff --git a/hw/cxl/cxl-component-utils.c b/hw/cxl/cxl-component-utils.c index 473895948b..91770f103a 100644 --- a/hw/cxl/cxl-component-utils.c +++ b/hw/cxl/cxl-component-utils.c @@ -284,32 +284,6 @@ void cxl_component_register_init_common(uint32_t *reg_state, { int caps = 0; - /* - * In CXL 2.0 the capabilities required for each CXL component are such - * that, with the ordering chosen here, a single number can be used to - * define which capabilities should be provided. - */ - switch (type) { - case CXL2_DOWNSTREAM_PORT: - case CXL2_DEVICE: - /* RAS, Link */ - caps = 2; - break; - case CXL2_UPSTREAM_PORT: - case CXL2_TYPE3_DEVICE: - case CXL2_LOGICAL_DEVICE: - /* + HDM */ - caps = 3; - break; - case CXL2_ROOT_PORT: - case CXL2_RC: - /* + Extended Security, + Snoop */ - caps = 5; - break; - default: - abort(); - } - memset(reg_state, 0, CXL2_COMPONENT_CM_REGION_SIZE); /* CXL Capability Header Register */ @@ -317,11 +291,12 @@ void cxl_component_register_init_common(uint32_t *reg_state, ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, VERSION, CXL_CAPABILITY_VERSION); ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, CACHE_MEM_VERSION, 1); - ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, ARRAY_SIZE, caps); #define init_cap_reg(reg, id, version) \ do { \ - int which = R_CXL_##reg##_CAPABILITY_HEADER; \ + int which = CXL_##reg##_CAP_HDR_IDX; \ + if (CXL_##reg##_CAP_HDR_IDX > caps) \ + caps = CXL_##reg##_CAP_HDR_IDX; \ reg_state[which] = FIELD_DP32(reg_state[which], \ CXL_##reg##_CAPABILITY_HEADER, ID, id); \ reg_state[which] = \ @@ -332,37 +307,35 @@ void cxl_component_register_init_common(uint32_t *reg_state, CXL_##reg##_REGISTERS_OFFSET); \ } while (0) + /* CXL r3.2 8.2.4 Table 8-22 */ switch (type) { - case CXL2_DEVICE: - case CXL2_TYPE3_DEVICE: - case CXL2_LOGICAL_DEVICE: case CXL2_ROOT_PORT: + case CXL2_RC: + /* + Extended Security, + Snoop */ + init_cap_reg(EXTSEC, 6, 1); + init_cap_reg(SNOOP, 8, 1); + /* fallthrough */ case CXL2_UPSTREAM_PORT: + case CXL2_TYPE3_DEVICE: + case CXL2_LOGICAL_DEVICE: + /* + HDM */ + init_cap_reg(HDM, 5, 1); + hdm_init_common(reg_state, write_msk, type); + /* fallthrough */ case CXL2_DOWNSTREAM_PORT: - init_cap_reg(RAS, 2, CXL_RAS_CAPABILITY_VERSION); - ras_init_common(reg_state, write_msk); + case CXL2_DEVICE: + /* RAS, Link */ + if (type != CXL2_RC) { + init_cap_reg(RAS, 2, 2); + ras_init_common(reg_state, write_msk); + } + init_cap_reg(LINK, 4, 2); break; default: - break; - } - - init_cap_reg(LINK, 4, CXL_LINK_CAPABILITY_VERSION); - - if (caps < 3) { - return; - } - - if (type != CXL2_ROOT_PORT) { - init_cap_reg(HDM, 5, CXL_HDM_CAPABILITY_VERSION); - hdm_init_common(reg_state, write_msk, type); - } - if (caps < 5) { - return; + abort(); } - init_cap_reg(EXTSEC, 6, CXL_EXTSEC_CAP_VERSION); - init_cap_reg(SNOOP, 8, CXL_SNOOP_CAP_VERSION); - + ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, ARRAY_SIZE, caps); #undef init_cap_reg } diff --git a/include/hw/cxl/cxl_component.h b/include/hw/cxl/cxl_component.h index b0f2aa7914..1f167d3ef7 100644 --- a/include/hw/cxl/cxl_component.h +++ b/include/hw/cxl/cxl_component.h @@ -32,10 +32,20 @@ enum reg_type { }; /* - * Capability registers are defined at the top of the CXL.cache/mem region and - * are packed. For our purposes we will always define the caps in the same - * order. - * CXL r3.1 Table 8-22: CXL_CAPABILITY_ID Assignment for details. + * CXL r3.2 - 8.2.4 Table 8-22 and 8-23 + * + * Capability registers are defined at the top of the CXL.cache/mem region. + * They are defined to be packed and at variable offsets. However, NULL + * capabilities can be added to the packed array. To facilitate easier access + * within the QEMU code, define these at specified offsets. Then NULL out any + * capabilities for devices which don't (or can't) have a particular capability + * (see cxl_component_register_init_common). NULL capabilities are to be + * ignored by software. + * + * 'offsets' are based on index's which can then be used to report the array + * size in CXL Capability Header Register (index/offset 0). + * + * See CXL r3.2 Table 8-25 for an example of allowing a 'NULL' header. */ /* CXL r3.1 Section 8.2.4.1: CXL Capability Header Register */ @@ -46,16 +56,17 @@ REG32(CXL_CAPABILITY_HEADER, 0) FIELD(CXL_CAPABILITY_HEADER, CACHE_MEM_VERSION, 20, 4) FIELD(CXL_CAPABILITY_HEADER, ARRAY_SIZE, 24, 8) -#define CXLx_CAPABILITY_HEADER(type, offset) \ - REG32(CXL_##type##_CAPABILITY_HEADER, offset) \ +#define CXLx_CAPABILITY_HEADER(type, idx) \ + enum { CXL_##type##_CAP_HDR_IDX = idx }; \ + REG32(CXL_##type##_CAPABILITY_HEADER, (idx * 0x4)) \ FIELD(CXL_##type##_CAPABILITY_HEADER, ID, 0, 16) \ FIELD(CXL_##type##_CAPABILITY_HEADER, VERSION, 16, 4) \ FIELD(CXL_##type##_CAPABILITY_HEADER, PTR, 20, 12) -CXLx_CAPABILITY_HEADER(RAS, 0x4) -CXLx_CAPABILITY_HEADER(LINK, 0x8) -CXLx_CAPABILITY_HEADER(HDM, 0xc) -CXLx_CAPABILITY_HEADER(EXTSEC, 0x10) -CXLx_CAPABILITY_HEADER(SNOOP, 0x14) +CXLx_CAPABILITY_HEADER(RAS, 1) +CXLx_CAPABILITY_HEADER(LINK, 2) +CXLx_CAPABILITY_HEADER(HDM, 3) +CXLx_CAPABILITY_HEADER(EXTSEC, 4) +CXLx_CAPABILITY_HEADER(SNOOP, 5) /* * Capability structures contain the actual registers that the CXL component