@samitouri / QOSamiQemu / commits / 5729c01a60

hw/cxl: Refactor component register initialization

CXL 3.2 8.2.4 Table 8-22 defines which capabilities are mandatory, not permitted, or optional for each type of device. cxl_component_register_init_common() uses a rather odd 'fall through' mechanism to define each component register set. This assumes that any device or capability being added builds on the previous devices capabilities. This is not true as there are mutually exclusive capabilities defined. For example, downstream ports can not have snoop but it can have Back Invalidate capable decoders. Refactor this code to make it easier to add individual capabilities as defined by a device type. Any capability which is not specified by the type is left NULL'ed out which complies with the packed nature of the register array. Update all spec references to 3.2. No functional changes should be seen with this patch. Signed-off-by: Ira Weiny <ira.weiny@intel.com> Tested-by: Dongjoo Seo <dongjoo.seo1@samsung.com> [rebased, no RAS for HBs, r3.2 references] Signed-off-by: Davidlohr Bueso <dave@stgolabs.net> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Message-Id: <20260204170936.43959-3-Jonathan.Cameron@huawei.com>

Ira Weiny committed Feb 4, 2026 at 17:09 UTC 5729c01a600d62c19202936481b06e84a14236ba
2 files changed +46 -62
hw/cxl/cxl-component-utils.c
+24 -51
@@ -284,32 +284,6 @@ void cxl_component_register_init_common(uint32_t *reg_state,
284 {
285 int caps = 0;
286
287 - /*
288 - * In CXL 2.0 the capabilities required for each CXL component are such
289 - * that, with the ordering chosen here, a single number can be used to
290 - * define which capabilities should be provided.
291 - */
292 - switch (type) {
293 - case CXL2_DOWNSTREAM_PORT:
294 - case CXL2_DEVICE:
295 - /* RAS, Link */
296 - caps = 2;
297 - break;
298 - case CXL2_UPSTREAM_PORT:
299 - case CXL2_TYPE3_DEVICE:
300 - case CXL2_LOGICAL_DEVICE:
301 - /* + HDM */
302 - caps = 3;
303 - break;
304 - case CXL2_ROOT_PORT:
305 - case CXL2_RC:
306 - /* + Extended Security, + Snoop */
307 - caps = 5;
308 - break;
309 - default:
310 - abort();
311 - }
312 -
287 memset(reg_state, 0, CXL2_COMPONENT_CM_REGION_SIZE);
288
289 /* CXL Capability Header Register */
@@ -317,11 +291,12 @@ void cxl_component_register_init_common(uint32_t *reg_state,
291 ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, VERSION,
292 CXL_CAPABILITY_VERSION);
293 ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, CACHE_MEM_VERSION, 1);
320 - ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, ARRAY_SIZE, caps);
294
295 #define init_cap_reg(reg, id, version) \
296 do { \
324 - int which = R_CXL_##reg##_CAPABILITY_HEADER; \
297 + int which = CXL_##reg##_CAP_HDR_IDX; \
298 + if (CXL_##reg##_CAP_HDR_IDX > caps) \
299 + caps = CXL_##reg##_CAP_HDR_IDX; \
300 reg_state[which] = FIELD_DP32(reg_state[which], \
301 CXL_##reg##_CAPABILITY_HEADER, ID, id); \
302 reg_state[which] = \
@@ -332,37 +307,35 @@ void cxl_component_register_init_common(uint32_t *reg_state,
307 CXL_##reg##_REGISTERS_OFFSET); \
308 } while (0)
309
310 + /* CXL r3.2 8.2.4 Table 8-22 */
311 switch (type) {
336 - case CXL2_DEVICE:
337 - case CXL2_TYPE3_DEVICE:
338 - case CXL2_LOGICAL_DEVICE:
312 case CXL2_ROOT_PORT:
313 + case CXL2_RC:
314 + /* + Extended Security, + Snoop */
315 + init_cap_reg(EXTSEC, 6, 1);
316 + init_cap_reg(SNOOP, 8, 1);
317 + /* fallthrough */
318 case CXL2_UPSTREAM_PORT:
319 + case CXL2_TYPE3_DEVICE:
320 + case CXL2_LOGICAL_DEVICE:
321 + /* + HDM */
322 + init_cap_reg(HDM, 5, 1);
323 + hdm_init_common(reg_state, write_msk, type);
324 + /* fallthrough */
325 case CXL2_DOWNSTREAM_PORT:
342 - init_cap_reg(RAS, 2, CXL_RAS_CAPABILITY_VERSION);
343 - ras_init_common(reg_state, write_msk);
326 + case CXL2_DEVICE:
327 + /* RAS, Link */
328 + if (type != CXL2_RC) {
329 + init_cap_reg(RAS, 2, 2);
330 + ras_init_common(reg_state, write_msk);
331 + }
332 + init_cap_reg(LINK, 4, 2);
333 break;
334 default:
346 - break;
347 - }
348 -
349 - init_cap_reg(LINK, 4, CXL_LINK_CAPABILITY_VERSION);
350 -
351 - if (caps < 3) {
352 - return;
353 - }
354 -
355 - if (type != CXL2_ROOT_PORT) {
356 - init_cap_reg(HDM, 5, CXL_HDM_CAPABILITY_VERSION);
357 - hdm_init_common(reg_state, write_msk, type);
358 - }
359 - if (caps < 5) {
360 - return;
335 + abort();
336 }
337
363 - init_cap_reg(EXTSEC, 6, CXL_EXTSEC_CAP_VERSION);
364 - init_cap_reg(SNOOP, 8, CXL_SNOOP_CAP_VERSION);
365 -
338 + ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, ARRAY_SIZE, caps);
339 #undef init_cap_reg
340 }
341
include/hw/cxl/cxl_component.h
+22 -11
@@ -32,10 +32,20 @@ enum reg_type {
32 };
33
34 /*
35 - * Capability registers are defined at the top of the CXL.cache/mem region and
36 - * are packed. For our purposes we will always define the caps in the same
37 - * order.
38 - * CXL r3.1 Table 8-22: CXL_CAPABILITY_ID Assignment for details.
35 + * CXL r3.2 - 8.2.4 Table 8-22 and 8-23
36 + *
37 + * Capability registers are defined at the top of the CXL.cache/mem region.
38 + * They are defined to be packed and at variable offsets. However, NULL
39 + * capabilities can be added to the packed array. To facilitate easier access
40 + * within the QEMU code, define these at specified offsets. Then NULL out any
41 + * capabilities for devices which don't (or can't) have a particular capability
42 + * (see cxl_component_register_init_common). NULL capabilities are to be
43 + * ignored by software.
44 + *
45 + * 'offsets' are based on index's which can then be used to report the array
46 + * size in CXL Capability Header Register (index/offset 0).
47 + *
48 + * See CXL r3.2 Table 8-25 for an example of allowing a 'NULL' header.
49 */
50
51 /* CXL r3.1 Section 8.2.4.1: CXL Capability Header Register */
@@ -46,16 +56,17 @@ REG32(CXL_CAPABILITY_HEADER, 0)
56 FIELD(CXL_CAPABILITY_HEADER, CACHE_MEM_VERSION, 20, 4)
57 FIELD(CXL_CAPABILITY_HEADER, ARRAY_SIZE, 24, 8)
58
49 -#define CXLx_CAPABILITY_HEADER(type, offset) \
50 - REG32(CXL_##type##_CAPABILITY_HEADER, offset) \
59 +#define CXLx_CAPABILITY_HEADER(type, idx) \
60 + enum { CXL_##type##_CAP_HDR_IDX = idx }; \
61 + REG32(CXL_##type##_CAPABILITY_HEADER, (idx * 0x4)) \
62 FIELD(CXL_##type##_CAPABILITY_HEADER, ID, 0, 16) \
63 FIELD(CXL_##type##_CAPABILITY_HEADER, VERSION, 16, 4) \
64 FIELD(CXL_##type##_CAPABILITY_HEADER, PTR, 20, 12)
54 -CXLx_CAPABILITY_HEADER(RAS, 0x4)
55 -CXLx_CAPABILITY_HEADER(LINK, 0x8)
56 -CXLx_CAPABILITY_HEADER(HDM, 0xc)
57 -CXLx_CAPABILITY_HEADER(EXTSEC, 0x10)
58 -CXLx_CAPABILITY_HEADER(SNOOP, 0x14)
65 +CXLx_CAPABILITY_HEADER(RAS, 1)
66 +CXLx_CAPABILITY_HEADER(LINK, 2)
67 +CXLx_CAPABILITY_HEADER(HDM, 3)
68 +CXLx_CAPABILITY_HEADER(EXTSEC, 4)
69 +CXLx_CAPABILITY_HEADER(SNOOP, 5)
70
71 /*
72 * Capability structures contain the actual registers that the CXL component