hw/cxl: Support type3 HDM-DB
Add basic plumbing for memory expander devices that support Back Invalidation. This introduces a 'hdm-db=on|off' parameter and exposes the relevant BI RT/Decoder component cachemem registers. Some noteworthy properties: - Devices require enabling Flit mode across the CXL topology. - Explicit BI-ID commit is required. - HDM decoder support both host and dev coherency models. Tested-by: Dongjoo Seo <dongjoo.seo1@samsung.com> 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-7-Jonathan.Cameron@huawei.com>
Davidlohr Bueso committed
Feb 4, 2026 at 17:09 UTC
88ac457c88c237e1e025e88f71d8d1a2ff729aed
9 files changed
+225
-15
docs/system/devices/cxl.rst
+23
@@ -384,6 +384,29 @@ An example of 4 devices below a switch suitable for 1, 2 or 4 way interleave::
384
-device cxl-type3,bus=swport3,persistent-memdev=cxl-mem3,lsa=cxl-lsa3,id=cxl-pmem3,sn=0x4 \
385
-M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=4k
386
387
+An example of 4 type3 devices with volatile memory below a switch. Two of the devices
388
+use HDM-DB for coherence, which requires operating in Flit mode::
389
+
390
+ qemu-system-x86_64 -M q35,cxl=on -m 4G,maxmem=8G,slots=8 -smp 4 \
391
+ ...
392
+ -object memory-backend-ram,id=cxl-mem0,share=on,size=256M \
393
+ -object memory-backend-ram,id=cxl-mem1,share=on,size=256M \
394
+ -object memory-backend-ram,id=cxl-mem2,share=on,size=256M \
395
+ -object memory-backend-ram,id=cxl-mem3,share=on,size=256M \
396
+ -device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1 \
397
+ -device cxl-rp,port=0,bus=cxl.1,id=root_port0,chassis=0,slot=0 \
398
+ -device cxl-rp,port=1,bus=cxl.1,id=root_port1,chassis=0,slot=1 \
399
+ -device cxl-upstream,bus=root_port0,id=us0,x-256b-flit=on \
400
+ -device cxl-downstream,port=0,bus=us0,id=swport0,chassis=0,slot=4 \
401
+ -device cxl-type3,bus=swport0,volatile-memdev=cxl-mem0,id=cxl-mem0,sn=0x1,x-256b-flit=on,hdm-db=on \
402
+ -device cxl-downstream,port=1,bus=us0,id=swport1,chassis=0,slot=5 \
403
+ -device cxl-type3,bus=swport1,volatile-memdev=cxl-mem1,id=cxl-mem1,sn=0x2,x-256b-flit=on,hdm-db=on \
404
+ -device cxl-downstream,port=2,bus=us0,id=swport2,chassis=0,slot=6 \
405
+ -device cxl-type3,bus=swport2,volatile-memdev=cxl-mem2,id=cxl-mem2,sn=0x3 \
406
+ -device cxl-downstream,port=3,bus=us0,id=swport3,chassis=0,slot=7 \
407
+ -device cxl-type3,bus=swport3,volatile-memdev=cxl-mem3,id=cxl-mem3,sn=0x4 \
408
+ -M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=4k
409
+
410
A simple arm/virt example featuring a single direct connected CXL Type 3
411
Volatile Memory device::
412
hw/cxl/cxl-component-utils.c
+135
-7
@@ -71,10 +71,40 @@ static uint64_t cxl_cache_mem_read_reg(void *opaque, hwaddr offset,
71
case 4:
72
if (cregs->special_ops && cregs->special_ops->read) {
73
return cregs->special_ops->read(cxl_cstate, offset, 4);
74
- } else {
75
- QEMU_BUILD_BUG_ON(sizeof(*cregs->cache_mem_registers) != 4);
76
- return cregs->cache_mem_registers[offset / 4];
74
}
75
+
76
+ QEMU_BUILD_BUG_ON(sizeof(*cregs->cache_mem_registers) != 4);
77
+
78
+ if (offset == A_CXL_BI_RT_STATUS ||
79
+ offset == A_CXL_BI_DECODER_STATUS) {
80
+ int type;
81
+ uint64_t started;
82
+
83
+ type = (offset == A_CXL_BI_RT_STATUS) ?
84
+ CXL_BISTATE_RT : CXL_BISTATE_DECODER;
85
+ started = cxl_cstate->bi_state[type].last_commit;
86
+
87
+ if (started) {
88
+ uint32_t *cache_mem = cregs->cache_mem_registers;
89
+ uint32_t val = cache_mem[offset / 4];
90
+ uint64_t now;
91
+ int set;
92
+
93
+ now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
94
+ /* arbitrary 100 ms to do the commit */
95
+ set = !!(now >= started + 100);
96
+
97
+ if (offset == A_CXL_BI_RT_STATUS) {
98
+ val = FIELD_DP32(val, CXL_BI_RT_STATUS, COMMITTED, set);
99
+ } else {
100
+ val = FIELD_DP32(val, CXL_BI_DECODER_STATUS, COMMITTED,
101
+ set);
102
+ }
103
+ stl_le_p((uint8_t *)cache_mem + offset, val);
104
+ }
105
+ }
106
+
107
+ return cregs->cache_mem_registers[offset / 4];
108
case 8:
109
qemu_log_mask(LOG_UNIMP,
110
"CXL 8 byte cache mem registers not implemented\n");
@@ -118,6 +148,47 @@ static void dumb_hdm_handler(CXLComponentState *cxl_cstate, hwaddr offset,
148
stl_le_p((uint8_t *)cache_mem + offset, value);
149
}
150
151
+static void bi_handler(CXLComponentState *cxl_cstate, hwaddr offset,
152
+ uint32_t value)
153
+{
154
+ ComponentRegisters *cregs = &cxl_cstate->crb;
155
+ uint32_t sts, *cache_mem = cregs->cache_mem_registers;
156
+ bool to_commit = false;
157
+ int type = 0; /* Unused value - work around for compiler warning */
158
+
159
+ switch (offset) {
160
+ case A_CXL_BI_RT_CTRL:
161
+ to_commit = FIELD_EX32(value, CXL_BI_RT_CTRL, COMMIT);
162
+ if (to_commit) {
163
+ sts = cxl_cache_mem_read_reg(cxl_cstate,
164
+ R_CXL_BI_RT_STATUS, 4);
165
+ sts = FIELD_DP32(sts, CXL_BI_RT_STATUS, COMMITTED, 0);
166
+ stl_le_p((uint8_t *)cache_mem + R_CXL_BI_RT_STATUS, sts);
167
+ type = CXL_BISTATE_RT;
168
+ }
169
+ break;
170
+ case A_CXL_BI_DECODER_CTRL:
171
+ to_commit = FIELD_EX32(value, CXL_BI_DECODER_CTRL, COMMIT);
172
+ if (to_commit) {
173
+ sts = cxl_cache_mem_read_reg(cxl_cstate,
174
+ R_CXL_BI_DECODER_STATUS, 4);
175
+ sts = FIELD_DP32(sts, CXL_BI_DECODER_STATUS, COMMITTED, 0);
176
+ stl_le_p((uint8_t *)cache_mem + R_CXL_BI_DECODER_STATUS, sts);
177
+ type = CXL_BISTATE_DECODER;
178
+ }
179
+ break;
180
+ default:
181
+ break;
182
+ }
183
+
184
+ if (to_commit) {
185
+ cxl_cstate->bi_state[type].last_commit =
186
+ qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
187
+ }
188
+
189
+ stl_le_p((uint8_t *)cache_mem + offset, value);
190
+}
191
+
192
static void cxl_cache_mem_write_reg(void *opaque, hwaddr offset, uint64_t value,
193
unsigned size)
194
{
@@ -141,6 +212,9 @@ static void cxl_cache_mem_write_reg(void *opaque, hwaddr offset, uint64_t value,
212
if (offset >= A_CXL_HDM_DECODER_CAPABILITY &&
213
offset <= A_CXL_HDM_DECODER3_TARGET_LIST_HI) {
214
dumb_hdm_handler(cxl_cstate, offset, value);
215
+ } else if (offset == A_CXL_BI_RT_CTRL ||
216
+ offset == A_CXL_BI_DECODER_CTRL) {
217
+ bi_handler(cxl_cstate, offset, value);
218
} else {
219
cregs->cache_mem_registers[offset / 4] = value;
220
}
@@ -230,7 +304,7 @@ static void ras_init_common(uint32_t *reg_state, uint32_t *write_msk)
304
}
305
306
static void hdm_init_common(uint32_t *reg_state, uint32_t *write_msk,
233
- enum reg_type type)
307
+ enum reg_type type, bool bi)
308
{
309
int decoder_count = CXL_HDM_DECODER_COUNT;
310
int hdm_inc = R_CXL_HDM_DECODER1_BASE_LO - R_CXL_HDM_DECODER0_BASE_LO;
@@ -255,7 +329,9 @@ static void hdm_init_common(uint32_t *reg_state, uint32_t *write_msk,
329
UIO_DECODER_COUNT, 0);
330
ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, MEMDATA_NXM_CAP, 0);
331
ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY,
258
- SUPPORTED_COHERENCY_MODEL, 0); /* Unknown */
332
+ SUPPORTED_COHERENCY_MODEL,
333
+ /* host+dev or Unknown */
334
+ type == CXL2_TYPE3_DEVICE && bi ? 3 : 0);
335
ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_GLOBAL_CONTROL,
336
HDM_DECODER_ENABLE, 0);
337
write_msk[R_CXL_HDM_DECODER_GLOBAL_CONTROL] = 0x3;
@@ -278,9 +354,43 @@ static void hdm_init_common(uint32_t *reg_state, uint32_t *write_msk,
354
}
355
}
356
357
+static void bi_rt_init_common(uint32_t *reg_state, uint32_t *write_msk)
358
+{
359
+ /* switch usp must commit the new BI-ID, timeout of 2secs */
360
+ ARRAY_FIELD_DP32(reg_state, CXL_BI_RT_CAPABILITY, EXPLICIT_COMMIT, 1);
361
+
362
+ ARRAY_FIELD_DP32(reg_state, CXL_BI_RT_CTRL, COMMIT, 0);
363
+ write_msk[R_CXL_BI_RT_CTRL] = 0x1;
364
+
365
+ ARRAY_FIELD_DP32(reg_state, CXL_BI_RT_STATUS, COMMITTED, 0);
366
+ ARRAY_FIELD_DP32(reg_state, CXL_BI_RT_STATUS, ERR_NOT_COMMITTED, 0);
367
+ ARRAY_FIELD_DP32(reg_state, CXL_BI_RT_STATUS, COMMIT_TMO_SCALE, 0x6);
368
+ ARRAY_FIELD_DP32(reg_state, CXL_BI_RT_STATUS, COMMIT_TMO_BASE, 0x2);
369
+}
370
+
371
+static void bi_decoder_init_common(uint32_t *reg_state, uint32_t *write_msk,
372
+ enum reg_type type)
373
+{
374
+ ARRAY_FIELD_DP32(reg_state, CXL_BI_DECODER_CAPABILITY, HDM_D, 0);
375
+ /* switch dsp must commit the new BI-ID, timeout of 2secs */
376
+ ARRAY_FIELD_DP32(reg_state, CXL_BI_DECODER_CAPABILITY, EXPLICIT_COMMIT,
377
+ (type != CXL2_ROOT_PORT && type != CXL2_TYPE3_DEVICE));
378
+
379
+ ARRAY_FIELD_DP32(reg_state, CXL_BI_DECODER_CTRL, BI_FW, 0);
380
+ ARRAY_FIELD_DP32(reg_state, CXL_BI_DECODER_CTRL, BI_ENABLE, 0);
381
+ ARRAY_FIELD_DP32(reg_state, CXL_BI_DECODER_CTRL, COMMIT, 0);
382
+ write_msk[R_CXL_BI_DECODER_CTRL] = 0x7;
383
+
384
+ ARRAY_FIELD_DP32(reg_state, CXL_BI_DECODER_STATUS, COMMITTED, 0);
385
+ ARRAY_FIELD_DP32(reg_state, CXL_BI_DECODER_STATUS, ERR_NOT_COMMITTED, 0);
386
+ ARRAY_FIELD_DP32(reg_state, CXL_BI_DECODER_STATUS, COMMIT_TMO_SCALE, 0x6);
387
+ ARRAY_FIELD_DP32(reg_state, CXL_BI_DECODER_STATUS, COMMIT_TMO_BASE, 0x2);
388
+}
389
+
390
void cxl_component_register_init_common(uint32_t *reg_state,
391
uint32_t *write_msk,
283
- enum reg_type type)
392
+ enum reg_type type,
393
+ bool bi)
394
{
395
int caps = 0;
396
@@ -320,7 +430,7 @@ void cxl_component_register_init_common(uint32_t *reg_state,
430
case CXL2_LOGICAL_DEVICE:
431
/* + HDM */
432
init_cap_reg(HDM, 5, 1);
323
- hdm_init_common(reg_state, write_msk, type);
433
+ hdm_init_common(reg_state, write_msk, type, bi);
434
/* fallthrough */
435
case CXL2_DOWNSTREAM_PORT:
436
case CXL2_DEVICE:
@@ -335,6 +445,24 @@ void cxl_component_register_init_common(uint32_t *reg_state,
445
abort();
446
}
447
448
+ /* back invalidate */
449
+ if (bi) {
450
+ switch (type) {
451
+ case CXL2_UPSTREAM_PORT:
452
+ init_cap_reg(BI_RT, 11, CXL_BI_RT_CAP_VERSION);
453
+ bi_rt_init_common(reg_state, write_msk);
454
+ break;
455
+ case CXL2_ROOT_PORT:
456
+ case CXL2_DOWNSTREAM_PORT:
457
+ case CXL2_TYPE3_DEVICE:
458
+ init_cap_reg(BI_DECODER, 12, CXL_BI_DECODER_CAP_VERSION);
459
+ bi_decoder_init_common(reg_state, write_msk, type);
460
+ break;
461
+ default:
462
+ break;
463
+ }
464
+ }
465
+
466
ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, ARRAY_SIZE, caps);
467
#undef init_cap_reg
468
}
hw/mem/cxl_type3.c
+8
-1
@@ -748,6 +748,11 @@ static bool cxl_setup_memory(CXLType3Dev *ct3d, Error **errp)
748
return false;
749
}
750
751
+ if (!ct3d->flitmode && ct3d->hdmdb) {
752
+ error_setg(errp, "hdm-db requires operating in 256b flit");
753
+ return false;
754
+ }
755
+
756
if (ct3d->hostvmem) {
757
MemoryRegion *vmr;
758
char *v_name;
@@ -1317,7 +1322,8 @@ static void ct3d_reset(DeviceState *dev)
1322
1323
pcie_cap_fill_link_ep_usp(PCI_DEVICE(dev), ct3d->width, ct3d->speed,
1324
ct3d->flitmode);
1320
- cxl_component_register_init_common(reg_state, write_msk, CXL2_TYPE3_DEVICE);
1325
+ cxl_component_register_init_common(reg_state, write_msk,
1326
+ CXL2_TYPE3_DEVICE, ct3d->hdmdb);
1327
cxl_device_register_init_t3(ct3d, CXL_T3_MSIX_MBOX);
1328
1329
/*
@@ -1356,6 +1362,7 @@ static const Property ct3_props[] = {
1362
DEFINE_PROP_PCIE_LINK_WIDTH("x-width", CXLType3Dev,
1363
width, PCIE_LINK_WIDTH_16),
1364
DEFINE_PROP_BOOL("x-256b-flit", CXLType3Dev, flitmode, false),
1365
+ DEFINE_PROP_BOOL("hdm-db", CXLType3Dev, hdmdb, false),
1366
};
1367
1368
static uint64_t get_lsa_size(CXLType3Dev *ct3d)
hw/pci-bridge/cxl_downstream.c
+1
-1
@@ -39,7 +39,7 @@ static void latch_registers(CXLDownstreamPort *dsp)
39
uint32_t *write_msk = dsp->cxl_cstate.crb.cache_mem_regs_write_mask;
40
41
cxl_component_register_init_common(reg_state, write_msk,
42
- CXL2_DOWNSTREAM_PORT);
42
+ CXL2_DOWNSTREAM_PORT, true);
43
}
44
45
/* TODO: Look at sharing this code across all CXL port types */
hw/pci-bridge/cxl_root_port.c
+2
-1
@@ -101,7 +101,8 @@ static void latch_registers(CXLRootPort *crp)
101
uint32_t *reg_state = crp->cxl_cstate.crb.cache_mem_registers;
102
uint32_t *write_msk = crp->cxl_cstate.crb.cache_mem_regs_write_mask;
103
104
- cxl_component_register_init_common(reg_state, write_msk, CXL2_ROOT_PORT);
104
+ cxl_component_register_init_common(reg_state, write_msk, CXL2_ROOT_PORT,
105
+ true);
106
}
107
108
static void build_dvsecs(PCIDevice *d, CXLComponentState *cxl)
hw/pci-bridge/cxl_upstream.c
+1
-1
@@ -90,7 +90,7 @@ static void latch_registers(CXLUpstreamPort *usp)
90
uint32_t *write_msk = usp->cxl_cstate.crb.cache_mem_regs_write_mask;
91
92
cxl_component_register_init_common(reg_state, write_msk,
93
- CXL2_UPSTREAM_PORT);
93
+ CXL2_UPSTREAM_PORT, usp->flitmode);
94
ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, TARGET_COUNT, 8);
95
}
96
hw/pci-bridge/pci_expander_bridge.c
+1
-1
@@ -300,7 +300,7 @@ static void pxb_cxl_dev_reset(DeviceState *dev)
300
uint32_t *write_msk = cxl_cstate->crb.cache_mem_regs_write_mask;
301
int dsp_count = 0;
302
303
- cxl_component_register_init_common(reg_state, write_msk, CXL2_RC);
303
+ cxl_component_register_init_common(reg_state, write_msk, CXL2_RC, false);
304
/*
305
* The CXL specification allows for host bridges with no HDM decoders
306
* if they only have a single root port.
include/hw/cxl/cxl_component.h
+51
-3
@@ -67,6 +67,8 @@ CXLx_CAPABILITY_HEADER(LINK, 2)
67
CXLx_CAPABILITY_HEADER(HDM, 3)
68
CXLx_CAPABILITY_HEADER(EXTSEC, 4)
69
CXLx_CAPABILITY_HEADER(SNOOP, 5)
70
+CXLx_CAPABILITY_HEADER(BI_RT, 6)
71
+CXLx_CAPABILITY_HEADER(BI_DECODER, 7)
72
73
/*
74
* Capability structures contain the actual registers that the CXL component
@@ -211,10 +213,55 @@ HDM_DECODER_INIT(3);
213
(CXL_IDE_REGISTERS_OFFSET + CXL_IDE_REGISTERS_SIZE)
214
#define CXL_SNOOP_REGISTERS_SIZE 0x8
215
214
-QEMU_BUILD_BUG_MSG((CXL_SNOOP_REGISTERS_OFFSET +
215
- CXL_SNOOP_REGISTERS_SIZE) >= 0x1000,
216
+#define CXL_BI_RT_CAP_VERSION 1
217
+#define CXL_BI_RT_REGISTERS_OFFSET \
218
+ (CXL_SNOOP_REGISTERS_OFFSET + CXL_SNOOP_REGISTERS_SIZE)
219
+#define CXL_BI_RT_REGISTERS_SIZE 0xC
220
+
221
+REG32(CXL_BI_RT_CAPABILITY, CXL_BI_RT_REGISTERS_OFFSET)
222
+ FIELD(CXL_BI_RT_CAPABILITY, EXPLICIT_COMMIT, 0, 1)
223
+REG32(CXL_BI_RT_CTRL, CXL_BI_RT_REGISTERS_OFFSET + 0x4)
224
+ FIELD(CXL_BI_RT_CTRL, COMMIT, 0, 1)
225
+REG32(CXL_BI_RT_STATUS, CXL_BI_RT_REGISTERS_OFFSET + 0x8)
226
+ FIELD(CXL_BI_RT_STATUS, COMMITTED, 0, 1)
227
+ FIELD(CXL_BI_RT_STATUS, ERR_NOT_COMMITTED, 1, 1)
228
+ FIELD(CXL_BI_RT_STATUS, COMMIT_TMO_SCALE, 8, 4)
229
+ FIELD(CXL_BI_RT_STATUS, COMMIT_TMO_BASE, 12, 4)
230
+
231
+/* CXL r3.2 8.2.4.27 - CXL BI Decoder Capability Structure */
232
+#define CXL_BI_DECODER_CAP_VERSION 1
233
+#define CXL_BI_DECODER_REGISTERS_OFFSET \
234
+ (CXL_BI_RT_REGISTERS_OFFSET + CXL_BI_RT_REGISTERS_SIZE)
235
+#define CXL_BI_DECODER_REGISTERS_SIZE 0xC
236
+
237
+REG32(CXL_BI_DECODER_CAPABILITY, CXL_BI_DECODER_REGISTERS_OFFSET)
238
+ FIELD(CXL_BI_DECODER_CAPABILITY, HDM_D, 0, 1)
239
+ FIELD(CXL_BI_DECODER_CAPABILITY, EXPLICIT_COMMIT, 1, 1)
240
+REG32(CXL_BI_DECODER_CTRL, CXL_BI_DECODER_REGISTERS_OFFSET + 0x4)
241
+ FIELD(CXL_BI_DECODER_CTRL, BI_FW, 0, 1)
242
+ FIELD(CXL_BI_DECODER_CTRL, BI_ENABLE, 1, 1)
243
+ FIELD(CXL_BI_DECODER_CTRL, COMMIT, 2, 1)
244
+REG32(CXL_BI_DECODER_STATUS, CXL_BI_DECODER_REGISTERS_OFFSET + 0x8)
245
+ FIELD(CXL_BI_DECODER_STATUS, COMMITTED, 0, 1)
246
+ FIELD(CXL_BI_DECODER_STATUS, ERR_NOT_COMMITTED, 1, 1)
247
+ FIELD(CXL_BI_DECODER_STATUS, COMMIT_TMO_SCALE, 8, 4)
248
+ FIELD(CXL_BI_DECODER_STATUS, COMMIT_TMO_BASE, 12, 4)
249
+
250
+QEMU_BUILD_BUG_MSG((CXL_BI_DECODER_REGISTERS_OFFSET +
251
+ CXL_BI_DECODER_REGISTERS_SIZE) >= 0x1000,
252
"No space for registers");
253
254
+/* track BI explicit commit handling for route table and decoder */
255
+enum {
256
+ CXL_BISTATE_RT = 0,
257
+ CXL_BISTATE_DECODER,
258
+ CXL_BISTATE_MAX
259
+};
260
+
261
+typedef struct bi_state {
262
+ uint64_t last_commit; /* last 0->1 transition */
263
+} BIState;
264
+
265
typedef struct component_registers {
266
/*
267
* Main memory region to be registered with QEMU core.
@@ -259,6 +306,7 @@ typedef struct cxl_component {
306
};
307
308
CDATObject cdat;
309
+ BIState bi_state[CXL_BISTATE_MAX];
310
} CXLComponentState;
311
312
void cxl_component_register_block_init(Object *obj,
@@ -266,7 +314,7 @@ void cxl_component_register_block_init(Object *obj,
314
const char *type);
315
void cxl_component_register_init_common(uint32_t *reg_state,
316
uint32_t *write_msk,
269
- enum reg_type type);
317
+ enum reg_type type, bool bi);
318
319
void cxl_component_create_dvsec(CXLComponentState *cxl_cstate,
320
enum reg_type cxl_dev_type, uint16_t length,
include/hw/cxl/cxl_device.h
+3
@@ -770,6 +770,9 @@ struct CXLType3Dev {
770
CXLMemSparingReadAttrs rank_sparing_attrs;
771
CXLMemSparingWriteAttrs rank_sparing_wr_attrs;
772
773
+ /* BI flows */
774
+ bool hdmdb;
775
+
776
struct dynamic_capacity {
777
HostMemoryBackend *host_dc;
778
AddressSpace host_dc_as;