diff options
Diffstat (limited to 'hw/cxl')
-rw-r--r-- | hw/cxl/cxl-host.c | 43 |
1 files changed, 41 insertions, 2 deletions
diff --git a/hw/cxl/cxl-host.c b/hw/cxl/cxl-host.c index efa14908d8..483d8eb13f 100644 --- a/hw/cxl/cxl-host.c +++ b/hw/cxl/cxl-host.c @@ -129,8 +129,9 @@ static bool cxl_hdm_find_target(uint32_t *cache_mem, hwaddr addr, static PCIDevice *cxl_cfmws_find_device(CXLFixedWindow *fw, hwaddr addr) { - CXLComponentState *hb_cstate; + CXLComponentState *hb_cstate, *usp_cstate; PCIHostState *hb; + CXLUpstreamPort *usp; int rb_index; uint32_t *cache_mem; uint8_t target; @@ -164,8 +165,46 @@ static PCIDevice *cxl_cfmws_find_device(CXLFixedWindow *fw, hwaddr addr) } d = pci_bridge_get_sec_bus(PCI_BRIDGE(rp))->devices[0]; + if (!d) { + return NULL; + } + + if (object_dynamic_cast(OBJECT(d), TYPE_CXL_TYPE3)) { + return d; + } + + /* + * Could also be a switch. Note only one level of switching currently + * supported. + */ + if (!object_dynamic_cast(OBJECT(d), TYPE_CXL_USP)) { + return NULL; + } + usp = CXL_USP(d); + + usp_cstate = cxl_usp_to_cstate(usp); + if (!usp_cstate) { + return NULL; + } + + cache_mem = usp_cstate->crb.cache_mem_registers; + + target_found = cxl_hdm_find_target(cache_mem, addr, &target); + if (!target_found) { + return NULL; + } + + d = pcie_find_port_by_pn(&PCI_BRIDGE(d)->sec_bus, target); + if (!d) { + return NULL; + } + + d = pci_bridge_get_sec_bus(PCI_BRIDGE(d))->devices[0]; + if (!d) { + return NULL; + } - if (!d || !object_dynamic_cast(OBJECT(d), TYPE_CXL_TYPE3)) { + if (!object_dynamic_cast(OBJECT(d), TYPE_CXL_TYPE3)) { return NULL; } |