1aadfe320SJonathan Cameron /*
2aadfe320SJonathan Cameron * CXL host parameter parsing routines
3aadfe320SJonathan Cameron *
4aadfe320SJonathan Cameron * Copyright (c) 2022 Huawei
5aadfe320SJonathan Cameron * Modeled loosely on the NUMA options handling in hw/core/numa.c
6aadfe320SJonathan Cameron */
7aadfe320SJonathan Cameron
8aadfe320SJonathan Cameron #include "qemu/osdep.h"
9aadfe320SJonathan Cameron #include "qemu/units.h"
10aadfe320SJonathan Cameron #include "qemu/bitmap.h"
11aadfe320SJonathan Cameron #include "qemu/error-report.h"
12aadfe320SJonathan Cameron #include "qapi/error.h"
13aadfe320SJonathan Cameron #include "sysemu/qtest.h"
14aadfe320SJonathan Cameron #include "hw/boards.h"
15aadfe320SJonathan Cameron
16aadfe320SJonathan Cameron #include "qapi/qapi-visit-machine.h"
17aadfe320SJonathan Cameron #include "hw/cxl/cxl.h"
1803b39fcfSJonathan Cameron #include "hw/cxl/cxl_host.h"
19eb19d907SJonathan Cameron #include "hw/pci/pci_bus.h"
20eb19d907SJonathan Cameron #include "hw/pci/pci_bridge.h"
21eb19d907SJonathan Cameron #include "hw/pci/pci_host.h"
22eb19d907SJonathan Cameron #include "hw/pci/pcie_port.h"
237bd1900bSJonathan Cameron #include "hw/pci-bridge/pci_expander_bridge.h"
24aadfe320SJonathan Cameron
cxl_fixed_memory_window_config(CXLState * cxl_state,CXLFixedMemoryWindowOptions * object,Error ** errp)2503b39fcfSJonathan Cameron static void cxl_fixed_memory_window_config(CXLState *cxl_state,
26aadfe320SJonathan Cameron CXLFixedMemoryWindowOptions *object,
27aadfe320SJonathan Cameron Error **errp)
28aadfe320SJonathan Cameron {
295c7eedf5SZhao Liu ERRP_GUARD();
30a99fbb00SJonathan Cameron g_autofree CXLFixedWindow *fw = g_malloc0(sizeof(*fw));
31aadfe320SJonathan Cameron strList *target;
32aadfe320SJonathan Cameron int i;
33aadfe320SJonathan Cameron
34aadfe320SJonathan Cameron for (target = object->targets; target; target = target->next) {
35aadfe320SJonathan Cameron fw->num_targets++;
36aadfe320SJonathan Cameron }
37aadfe320SJonathan Cameron
38aadfe320SJonathan Cameron fw->enc_int_ways = cxl_interleave_ways_enc(fw->num_targets, errp);
39aadfe320SJonathan Cameron if (*errp) {
40aadfe320SJonathan Cameron return;
41aadfe320SJonathan Cameron }
42aadfe320SJonathan Cameron
43aadfe320SJonathan Cameron if (object->size % (256 * MiB)) {
44aadfe320SJonathan Cameron error_setg(errp,
45f99ad11cSHoa Nguyen "Size of a CXL fixed memory window must be a multiple of 256MiB");
46aadfe320SJonathan Cameron return;
47aadfe320SJonathan Cameron }
48aadfe320SJonathan Cameron fw->size = object->size;
49aadfe320SJonathan Cameron
50aadfe320SJonathan Cameron if (object->has_interleave_granularity) {
51aadfe320SJonathan Cameron fw->enc_int_gran =
52aadfe320SJonathan Cameron cxl_interleave_granularity_enc(object->interleave_granularity,
53aadfe320SJonathan Cameron errp);
54aadfe320SJonathan Cameron if (*errp) {
55aadfe320SJonathan Cameron return;
56aadfe320SJonathan Cameron }
57aadfe320SJonathan Cameron } else {
58aadfe320SJonathan Cameron /* Default to 256 byte interleave */
59aadfe320SJonathan Cameron fw->enc_int_gran = 0;
60aadfe320SJonathan Cameron }
61aadfe320SJonathan Cameron
627b165fa1SLi Zhijian fw->targets = g_malloc0_n(fw->num_targets, sizeof(*fw->targets));
637b165fa1SLi Zhijian for (i = 0, target = object->targets; target; i++, target = target->next) {
647b165fa1SLi Zhijian /* This link cannot be resolved yet, so stash the name for now */
657b165fa1SLi Zhijian fw->targets[i] = g_strdup(target->value);
667b165fa1SLi Zhijian }
677b165fa1SLi Zhijian
68a99fbb00SJonathan Cameron cxl_state->fixed_windows = g_list_append(cxl_state->fixed_windows,
69a99fbb00SJonathan Cameron g_steal_pointer(&fw));
70aadfe320SJonathan Cameron
71aadfe320SJonathan Cameron return;
72aadfe320SJonathan Cameron }
73aadfe320SJonathan Cameron
cxl_fmws_link_targets(CXLState * cxl_state,Error ** errp)74dab390ffSJonathan Cameron void cxl_fmws_link_targets(CXLState *cxl_state, Error **errp)
75aadfe320SJonathan Cameron {
76dab390ffSJonathan Cameron if (cxl_state && cxl_state->fixed_windows) {
77aadfe320SJonathan Cameron GList *it;
78aadfe320SJonathan Cameron
79dab390ffSJonathan Cameron for (it = cxl_state->fixed_windows; it; it = it->next) {
80aadfe320SJonathan Cameron CXLFixedWindow *fw = it->data;
81aadfe320SJonathan Cameron int i;
82aadfe320SJonathan Cameron
83aadfe320SJonathan Cameron for (i = 0; i < fw->num_targets; i++) {
84aadfe320SJonathan Cameron Object *o;
85aadfe320SJonathan Cameron bool ambig;
86aadfe320SJonathan Cameron
87aadfe320SJonathan Cameron o = object_resolve_path_type(fw->targets[i],
88c28db9e0SJonathan Cameron TYPE_PXB_CXL_DEV,
89aadfe320SJonathan Cameron &ambig);
90aadfe320SJonathan Cameron if (!o) {
91aadfe320SJonathan Cameron error_setg(errp, "Could not resolve CXLFM target %s",
92aadfe320SJonathan Cameron fw->targets[i]);
93aadfe320SJonathan Cameron return;
94aadfe320SJonathan Cameron }
95aadfe320SJonathan Cameron fw->target_hbs[i] = PXB_CXL_DEV(o);
96aadfe320SJonathan Cameron }
97aadfe320SJonathan Cameron }
98aadfe320SJonathan Cameron }
99aadfe320SJonathan Cameron }
100eb19d907SJonathan Cameron
cxl_hdm_find_target(uint32_t * cache_mem,hwaddr addr,uint8_t * target)101eb19d907SJonathan Cameron static bool cxl_hdm_find_target(uint32_t *cache_mem, hwaddr addr,
102eb19d907SJonathan Cameron uint8_t *target)
103eb19d907SJonathan Cameron {
10461c44bcfSJonathan Cameron int hdm_inc = R_CXL_HDM_DECODER1_BASE_LO - R_CXL_HDM_DECODER0_BASE_LO;
105e967413fSJonathan Cameron unsigned int hdm_count;
106e967413fSJonathan Cameron bool found = false;
107e967413fSJonathan Cameron int i;
108e967413fSJonathan Cameron uint32_t cap;
109eb19d907SJonathan Cameron
110e967413fSJonathan Cameron cap = ldl_le_p(cache_mem + R_CXL_HDM_DECODER_CAPABILITY);
111e967413fSJonathan Cameron hdm_count = cxl_decoder_count_dec(FIELD_EX32(cap,
112e967413fSJonathan Cameron CXL_HDM_DECODER_CAPABILITY,
113e967413fSJonathan Cameron DECODER_COUNT));
114e967413fSJonathan Cameron for (i = 0; i < hdm_count; i++) {
115e967413fSJonathan Cameron uint32_t ctrl, ig_enc, iw_enc, target_idx;
116e967413fSJonathan Cameron uint32_t low, high;
117e967413fSJonathan Cameron uint64_t base, size;
118e967413fSJonathan Cameron
119e967413fSJonathan Cameron low = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_BASE_LO + i * hdm_inc);
120e967413fSJonathan Cameron high = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_BASE_HI + i * hdm_inc);
121e967413fSJonathan Cameron base = (low & 0xf0000000) | ((uint64_t)high << 32);
122e967413fSJonathan Cameron low = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_SIZE_LO + i * hdm_inc);
123e967413fSJonathan Cameron high = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_SIZE_HI + i * hdm_inc);
124e967413fSJonathan Cameron size = (low & 0xf0000000) | ((uint64_t)high << 32);
125e967413fSJonathan Cameron if (addr < base || addr >= base + size) {
126e967413fSJonathan Cameron continue;
127e967413fSJonathan Cameron }
128e967413fSJonathan Cameron
129e967413fSJonathan Cameron ctrl = ldl_le_p(cache_mem + R_CXL_HDM_DECODER0_CTRL + i * hdm_inc);
130eb19d907SJonathan Cameron if (!FIELD_EX32(ctrl, CXL_HDM_DECODER0_CTRL, COMMITTED)) {
131eb19d907SJonathan Cameron return false;
132eb19d907SJonathan Cameron }
133e967413fSJonathan Cameron found = true;
134eb19d907SJonathan Cameron ig_enc = FIELD_EX32(ctrl, CXL_HDM_DECODER0_CTRL, IG);
135eb19d907SJonathan Cameron iw_enc = FIELD_EX32(ctrl, CXL_HDM_DECODER0_CTRL, IW);
136eb19d907SJonathan Cameron target_idx = (addr / cxl_decode_ig(ig_enc)) % (1 << iw_enc);
137eb19d907SJonathan Cameron
138d2289b52SJonathan Cameron if (target_idx < 4) {
139e967413fSJonathan Cameron uint32_t val = ldl_le_p(cache_mem +
140e967413fSJonathan Cameron R_CXL_HDM_DECODER0_TARGET_LIST_LO +
141e967413fSJonathan Cameron i * hdm_inc);
142e967413fSJonathan Cameron *target = extract32(val, target_idx * 8, 8);
143eb19d907SJonathan Cameron } else {
144e967413fSJonathan Cameron uint32_t val = ldl_le_p(cache_mem +
145e967413fSJonathan Cameron R_CXL_HDM_DECODER0_TARGET_LIST_HI +
146e967413fSJonathan Cameron i * hdm_inc);
147e967413fSJonathan Cameron *target = extract32(val, (target_idx - 4) * 8, 8);
148e967413fSJonathan Cameron }
149e967413fSJonathan Cameron break;
150eb19d907SJonathan Cameron }
151eb19d907SJonathan Cameron
152e967413fSJonathan Cameron return found;
153eb19d907SJonathan Cameron }
154eb19d907SJonathan Cameron
cxl_cfmws_find_device(CXLFixedWindow * fw,hwaddr addr)155eb19d907SJonathan Cameron static PCIDevice *cxl_cfmws_find_device(CXLFixedWindow *fw, hwaddr addr)
156eb19d907SJonathan Cameron {
15718cef1c6SJonathan Cameron CXLComponentState *hb_cstate, *usp_cstate;
158eb19d907SJonathan Cameron PCIHostState *hb;
15918cef1c6SJonathan Cameron CXLUpstreamPort *usp;
160eb19d907SJonathan Cameron int rb_index;
161eb19d907SJonathan Cameron uint32_t *cache_mem;
162eb19d907SJonathan Cameron uint8_t target;
163eb19d907SJonathan Cameron bool target_found;
164eb19d907SJonathan Cameron PCIDevice *rp, *d;
165eb19d907SJonathan Cameron
166eb19d907SJonathan Cameron /* Address is relative to memory region. Convert to HPA */
167eb19d907SJonathan Cameron addr += fw->base;
168eb19d907SJonathan Cameron
169eb19d907SJonathan Cameron rb_index = (addr / cxl_decode_ig(fw->enc_int_gran)) % fw->num_targets;
170c28db9e0SJonathan Cameron hb = PCI_HOST_BRIDGE(fw->target_hbs[rb_index]->cxl_host_bridge);
171eb19d907SJonathan Cameron if (!hb || !hb->bus || !pci_bus_is_cxl(hb->bus)) {
172eb19d907SJonathan Cameron return NULL;
173eb19d907SJonathan Cameron }
174eb19d907SJonathan Cameron
175154070eaSJonathan Cameron if (cxl_get_hb_passthrough(hb)) {
176154070eaSJonathan Cameron rp = pcie_find_port_first(hb->bus);
177154070eaSJonathan Cameron if (!rp) {
178154070eaSJonathan Cameron return NULL;
179154070eaSJonathan Cameron }
180154070eaSJonathan Cameron } else {
181eb19d907SJonathan Cameron hb_cstate = cxl_get_hb_cstate(hb);
182eb19d907SJonathan Cameron if (!hb_cstate) {
183eb19d907SJonathan Cameron return NULL;
184eb19d907SJonathan Cameron }
185eb19d907SJonathan Cameron
186eb19d907SJonathan Cameron cache_mem = hb_cstate->crb.cache_mem_registers;
187eb19d907SJonathan Cameron
188eb19d907SJonathan Cameron target_found = cxl_hdm_find_target(cache_mem, addr, &target);
189eb19d907SJonathan Cameron if (!target_found) {
190eb19d907SJonathan Cameron return NULL;
191eb19d907SJonathan Cameron }
192eb19d907SJonathan Cameron
193eb19d907SJonathan Cameron rp = pcie_find_port_by_pn(hb->bus, target);
194eb19d907SJonathan Cameron if (!rp) {
195eb19d907SJonathan Cameron return NULL;
196eb19d907SJonathan Cameron }
197154070eaSJonathan Cameron }
198eb19d907SJonathan Cameron
199eb19d907SJonathan Cameron d = pci_bridge_get_sec_bus(PCI_BRIDGE(rp))->devices[0];
20018cef1c6SJonathan Cameron if (!d) {
20118cef1c6SJonathan Cameron return NULL;
20218cef1c6SJonathan Cameron }
203eb19d907SJonathan Cameron
20418cef1c6SJonathan Cameron if (object_dynamic_cast(OBJECT(d), TYPE_CXL_TYPE3)) {
20518cef1c6SJonathan Cameron return d;
20618cef1c6SJonathan Cameron }
20718cef1c6SJonathan Cameron
20818cef1c6SJonathan Cameron /*
20918cef1c6SJonathan Cameron * Could also be a switch. Note only one level of switching currently
21018cef1c6SJonathan Cameron * supported.
21118cef1c6SJonathan Cameron */
21218cef1c6SJonathan Cameron if (!object_dynamic_cast(OBJECT(d), TYPE_CXL_USP)) {
21318cef1c6SJonathan Cameron return NULL;
21418cef1c6SJonathan Cameron }
21518cef1c6SJonathan Cameron usp = CXL_USP(d);
21618cef1c6SJonathan Cameron
21718cef1c6SJonathan Cameron usp_cstate = cxl_usp_to_cstate(usp);
21818cef1c6SJonathan Cameron if (!usp_cstate) {
21918cef1c6SJonathan Cameron return NULL;
22018cef1c6SJonathan Cameron }
22118cef1c6SJonathan Cameron
22218cef1c6SJonathan Cameron cache_mem = usp_cstate->crb.cache_mem_registers;
22318cef1c6SJonathan Cameron
22418cef1c6SJonathan Cameron target_found = cxl_hdm_find_target(cache_mem, addr, &target);
22518cef1c6SJonathan Cameron if (!target_found) {
22618cef1c6SJonathan Cameron return NULL;
22718cef1c6SJonathan Cameron }
22818cef1c6SJonathan Cameron
22918cef1c6SJonathan Cameron d = pcie_find_port_by_pn(&PCI_BRIDGE(d)->sec_bus, target);
23018cef1c6SJonathan Cameron if (!d) {
23118cef1c6SJonathan Cameron return NULL;
23218cef1c6SJonathan Cameron }
23318cef1c6SJonathan Cameron
23418cef1c6SJonathan Cameron d = pci_bridge_get_sec_bus(PCI_BRIDGE(d))->devices[0];
23518cef1c6SJonathan Cameron if (!d) {
23618cef1c6SJonathan Cameron return NULL;
23718cef1c6SJonathan Cameron }
23818cef1c6SJonathan Cameron
23918cef1c6SJonathan Cameron if (!object_dynamic_cast(OBJECT(d), TYPE_CXL_TYPE3)) {
240eb19d907SJonathan Cameron return NULL;
241eb19d907SJonathan Cameron }
242eb19d907SJonathan Cameron
243eb19d907SJonathan Cameron return d;
244eb19d907SJonathan Cameron }
245eb19d907SJonathan Cameron
cxl_read_cfmws(void * opaque,hwaddr addr,uint64_t * data,unsigned size,MemTxAttrs attrs)246eb19d907SJonathan Cameron static MemTxResult cxl_read_cfmws(void *opaque, hwaddr addr, uint64_t *data,
247eb19d907SJonathan Cameron unsigned size, MemTxAttrs attrs)
248eb19d907SJonathan Cameron {
249eb19d907SJonathan Cameron CXLFixedWindow *fw = opaque;
250eb19d907SJonathan Cameron PCIDevice *d;
251eb19d907SJonathan Cameron
252eb19d907SJonathan Cameron d = cxl_cfmws_find_device(fw, addr);
253eb19d907SJonathan Cameron if (d == NULL) {
254eb19d907SJonathan Cameron *data = 0;
255eb19d907SJonathan Cameron /* Reads to invalid address return poison */
256eb19d907SJonathan Cameron return MEMTX_ERROR;
257eb19d907SJonathan Cameron }
258eb19d907SJonathan Cameron
259eb19d907SJonathan Cameron return cxl_type3_read(d, addr + fw->base, data, size, attrs);
260eb19d907SJonathan Cameron }
261eb19d907SJonathan Cameron
cxl_write_cfmws(void * opaque,hwaddr addr,uint64_t data,unsigned size,MemTxAttrs attrs)262eb19d907SJonathan Cameron static MemTxResult cxl_write_cfmws(void *opaque, hwaddr addr,
263eb19d907SJonathan Cameron uint64_t data, unsigned size,
264eb19d907SJonathan Cameron MemTxAttrs attrs)
265eb19d907SJonathan Cameron {
266eb19d907SJonathan Cameron CXLFixedWindow *fw = opaque;
267eb19d907SJonathan Cameron PCIDevice *d;
268eb19d907SJonathan Cameron
269eb19d907SJonathan Cameron d = cxl_cfmws_find_device(fw, addr);
270eb19d907SJonathan Cameron if (d == NULL) {
271eb19d907SJonathan Cameron /* Writes to invalid address are silent */
272eb19d907SJonathan Cameron return MEMTX_OK;
273eb19d907SJonathan Cameron }
274eb19d907SJonathan Cameron
275eb19d907SJonathan Cameron return cxl_type3_write(d, addr + fw->base, data, size, attrs);
276eb19d907SJonathan Cameron }
277eb19d907SJonathan Cameron
278eb19d907SJonathan Cameron const MemoryRegionOps cfmws_ops = {
279eb19d907SJonathan Cameron .read_with_attrs = cxl_read_cfmws,
280eb19d907SJonathan Cameron .write_with_attrs = cxl_write_cfmws,
281eb19d907SJonathan Cameron .endianness = DEVICE_LITTLE_ENDIAN,
282eb19d907SJonathan Cameron .valid = {
283eb19d907SJonathan Cameron .min_access_size = 1,
284eb19d907SJonathan Cameron .max_access_size = 8,
285eb19d907SJonathan Cameron .unaligned = true,
286eb19d907SJonathan Cameron },
287eb19d907SJonathan Cameron .impl = {
288eb19d907SJonathan Cameron .min_access_size = 1,
289eb19d907SJonathan Cameron .max_access_size = 8,
290eb19d907SJonathan Cameron .unaligned = true,
291eb19d907SJonathan Cameron },
292eb19d907SJonathan Cameron };
29303b39fcfSJonathan Cameron
machine_get_cxl(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)29403b39fcfSJonathan Cameron static void machine_get_cxl(Object *obj, Visitor *v, const char *name,
29503b39fcfSJonathan Cameron void *opaque, Error **errp)
29603b39fcfSJonathan Cameron {
29703b39fcfSJonathan Cameron CXLState *cxl_state = opaque;
29803b39fcfSJonathan Cameron bool value = cxl_state->is_enabled;
29903b39fcfSJonathan Cameron
30003b39fcfSJonathan Cameron visit_type_bool(v, name, &value, errp);
30103b39fcfSJonathan Cameron }
30203b39fcfSJonathan Cameron
machine_set_cxl(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)30303b39fcfSJonathan Cameron static void machine_set_cxl(Object *obj, Visitor *v, const char *name,
30403b39fcfSJonathan Cameron void *opaque, Error **errp)
30503b39fcfSJonathan Cameron {
30603b39fcfSJonathan Cameron CXLState *cxl_state = opaque;
30703b39fcfSJonathan Cameron bool value;
30803b39fcfSJonathan Cameron
30903b39fcfSJonathan Cameron if (!visit_type_bool(v, name, &value, errp)) {
31003b39fcfSJonathan Cameron return;
31103b39fcfSJonathan Cameron }
31203b39fcfSJonathan Cameron cxl_state->is_enabled = value;
31303b39fcfSJonathan Cameron }
31403b39fcfSJonathan Cameron
machine_get_cfmw(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)31503b39fcfSJonathan Cameron static void machine_get_cfmw(Object *obj, Visitor *v, const char *name,
31603b39fcfSJonathan Cameron void *opaque, Error **errp)
31703b39fcfSJonathan Cameron {
318*a207d5f8SZhao Liu CXLState *state = opaque;
319*a207d5f8SZhao Liu CXLFixedMemoryWindowOptionsList **list = &state->cfmw_list;
32003b39fcfSJonathan Cameron
32103b39fcfSJonathan Cameron visit_type_CXLFixedMemoryWindowOptionsList(v, name, list, errp);
32203b39fcfSJonathan Cameron }
32303b39fcfSJonathan Cameron
machine_set_cfmw(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)32403b39fcfSJonathan Cameron static void machine_set_cfmw(Object *obj, Visitor *v, const char *name,
32503b39fcfSJonathan Cameron void *opaque, Error **errp)
32603b39fcfSJonathan Cameron {
32703b39fcfSJonathan Cameron CXLState *state = opaque;
32803b39fcfSJonathan Cameron CXLFixedMemoryWindowOptionsList *cfmw_list = NULL;
32903b39fcfSJonathan Cameron CXLFixedMemoryWindowOptionsList *it;
33003b39fcfSJonathan Cameron
33103b39fcfSJonathan Cameron visit_type_CXLFixedMemoryWindowOptionsList(v, name, &cfmw_list, errp);
33203b39fcfSJonathan Cameron if (!cfmw_list) {
33303b39fcfSJonathan Cameron return;
33403b39fcfSJonathan Cameron }
33503b39fcfSJonathan Cameron
33603b39fcfSJonathan Cameron for (it = cfmw_list; it; it = it->next) {
33703b39fcfSJonathan Cameron cxl_fixed_memory_window_config(state, it->value, errp);
33803b39fcfSJonathan Cameron }
33903b39fcfSJonathan Cameron state->cfmw_list = cfmw_list;
34003b39fcfSJonathan Cameron }
34103b39fcfSJonathan Cameron
cxl_machine_init(Object * obj,CXLState * state)34203b39fcfSJonathan Cameron void cxl_machine_init(Object *obj, CXLState *state)
34303b39fcfSJonathan Cameron {
34403b39fcfSJonathan Cameron object_property_add(obj, "cxl", "bool", machine_get_cxl,
34503b39fcfSJonathan Cameron machine_set_cxl, NULL, state);
34603b39fcfSJonathan Cameron object_property_set_description(obj, "cxl",
34703b39fcfSJonathan Cameron "Set on/off to enable/disable "
34803b39fcfSJonathan Cameron "CXL instantiation");
34903b39fcfSJonathan Cameron
35003b39fcfSJonathan Cameron object_property_add(obj, "cxl-fmw", "CXLFixedMemoryWindow",
35103b39fcfSJonathan Cameron machine_get_cfmw, machine_set_cfmw,
35203b39fcfSJonathan Cameron NULL, state);
35303b39fcfSJonathan Cameron object_property_set_description(obj, "cxl-fmw",
35403b39fcfSJonathan Cameron "CXL Fixed Memory Windows (array)");
35503b39fcfSJonathan Cameron }
3567bd1900bSJonathan Cameron
cxl_hook_up_pxb_registers(PCIBus * bus,CXLState * state,Error ** errp)3577bd1900bSJonathan Cameron void cxl_hook_up_pxb_registers(PCIBus *bus, CXLState *state, Error **errp)
3587bd1900bSJonathan Cameron {
3597bd1900bSJonathan Cameron /* Walk the pci busses looking for pxb busses to hook up */
3607bd1900bSJonathan Cameron if (bus) {
3617bd1900bSJonathan Cameron QLIST_FOREACH(bus, &bus->child, sibling) {
3627bd1900bSJonathan Cameron if (!pci_bus_is_root(bus)) {
3637bd1900bSJonathan Cameron continue;
3647bd1900bSJonathan Cameron }
3657bd1900bSJonathan Cameron if (pci_bus_is_cxl(bus)) {
3667bd1900bSJonathan Cameron if (!state->is_enabled) {
3677bd1900bSJonathan Cameron error_setg(errp, "CXL host bridges present, but cxl=off");
3687bd1900bSJonathan Cameron return;
3697bd1900bSJonathan Cameron }
3707bd1900bSJonathan Cameron pxb_cxl_hook_up_registers(state, bus, errp);
3717bd1900bSJonathan Cameron }
3727bd1900bSJonathan Cameron }
3737bd1900bSJonathan Cameron }
3747bd1900bSJonathan Cameron }
375