2 * Emulated CXL Switch Downstream Port
4 * Copyright (c) 2022 Huawei Technologies.
6 * Based on xio3130_downstream.c
8 * SPDX-License-Identifier: GPL-2.0-or-later
11 #include "qemu/osdep.h"
13 #include "hw/pci/msi.h"
14 #include "hw/pci/pcie.h"
15 #include "hw/pci/pcie_port.h"
16 #include "qapi/error.h"
18 typedef struct CXLDownstreamPort
{
23 CXLComponentState cxl_cstate
;
26 #define TYPE_CXL_DSP "cxl-downstream"
27 DECLARE_INSTANCE_CHECKER(CXLDownstreamPort
, CXL_DSP
, TYPE_CXL_DSP
)
29 #define CXL_DOWNSTREAM_PORT_MSI_OFFSET 0x70
30 #define CXL_DOWNSTREAM_PORT_MSI_NR_VECTOR 1
31 #define CXL_DOWNSTREAM_PORT_EXP_OFFSET 0x90
32 #define CXL_DOWNSTREAM_PORT_AER_OFFSET 0x100
33 #define CXL_DOWNSTREAM_PORT_DVSEC_OFFSET \
34 (CXL_DOWNSTREAM_PORT_AER_OFFSET + PCI_ERR_SIZEOF)
36 static void latch_registers(CXLDownstreamPort
*dsp
)
38 uint32_t *reg_state
= dsp
->cxl_cstate
.crb
.cache_mem_registers
;
39 uint32_t *write_msk
= dsp
->cxl_cstate
.crb
.cache_mem_regs_write_mask
;
41 cxl_component_register_init_common(reg_state
, write_msk
,
42 CXL2_DOWNSTREAM_PORT
);
45 /* TODO: Look at sharing this code acorss all CXL port types */
46 static void cxl_dsp_dvsec_write_config(PCIDevice
*dev
, uint32_t addr
,
47 uint32_t val
, int len
)
49 CXLDownstreamPort
*dsp
= CXL_DSP(dev
);
50 CXLComponentState
*cxl_cstate
= &dsp
->cxl_cstate
;
52 if (range_contains(&cxl_cstate
->dvsecs
[EXTENSIONS_PORT_DVSEC
], addr
)) {
53 uint8_t *reg
= &dev
->config
[addr
];
54 addr
-= cxl_cstate
->dvsecs
[EXTENSIONS_PORT_DVSEC
].lob
;
55 if (addr
== PORT_CONTROL_OFFSET
) {
56 if (pci_get_word(reg
) & PORT_CONTROL_UNMASK_SBR
) {
58 qemu_log_mask(LOG_UNIMP
, "SBR mask control is not supported\n");
60 if (pci_get_word(reg
) & PORT_CONTROL_ALT_MEMID_EN
) {
61 /* Alt Memory & ID Space Enable */
62 qemu_log_mask(LOG_UNIMP
,
63 "Alt Memory & ID space is not supported\n");
70 static void cxl_dsp_config_write(PCIDevice
*d
, uint32_t address
,
71 uint32_t val
, int len
)
73 uint16_t slt_ctl
, slt_sta
;
75 pcie_cap_slot_get(d
, &slt_ctl
, &slt_sta
);
76 pci_bridge_write_config(d
, address
, val
, len
);
77 pcie_cap_flr_write_config(d
, address
, val
, len
);
78 pcie_cap_slot_write_config(d
, slt_ctl
, slt_sta
, address
, val
, len
);
79 pcie_aer_write_config(d
, address
, val
, len
);
81 cxl_dsp_dvsec_write_config(d
, address
, val
, len
);
84 static void cxl_dsp_reset(DeviceState
*qdev
)
86 PCIDevice
*d
= PCI_DEVICE(qdev
);
87 CXLDownstreamPort
*dsp
= CXL_DSP(qdev
);
89 pcie_cap_deverr_reset(d
);
90 pcie_cap_slot_reset(d
);
91 pcie_cap_arifwd_reset(d
);
92 pci_bridge_reset(qdev
);
97 static void build_dvsecs(CXLComponentState
*cxl
)
101 dvsec
= (uint8_t *)&(CXLDVSECPortExtensions
){ 0 };
102 cxl_component_create_dvsec(cxl
, CXL2_DOWNSTREAM_PORT
,
103 EXTENSIONS_PORT_DVSEC_LENGTH
,
104 EXTENSIONS_PORT_DVSEC
,
105 EXTENSIONS_PORT_DVSEC_REVID
, dvsec
);
107 dvsec
= (uint8_t *)&(CXLDVSECPortFlexBus
){
108 .cap
= 0x27, /* Cache, IO, Mem, non-MLD */
109 .ctrl
= 0x02, /* IO always enabled */
110 .status
= 0x26, /* same */
111 .rcvd_mod_ts_data_phase1
= 0xef, /* WTF? */
113 cxl_component_create_dvsec(cxl
, CXL2_DOWNSTREAM_PORT
,
114 PCIE_FLEXBUS_PORT_DVSEC_LENGTH_2_0
,
115 PCIE_FLEXBUS_PORT_DVSEC
,
116 PCIE_FLEXBUS_PORT_DVSEC_REVID_2_0
, dvsec
);
118 dvsec
= (uint8_t *)&(CXLDVSECPortGPF
){
120 .phase1_ctrl
= 1, /* 1μs timeout */
121 .phase2_ctrl
= 1, /* 1μs timeout */
123 cxl_component_create_dvsec(cxl
, CXL2_DOWNSTREAM_PORT
,
124 GPF_PORT_DVSEC_LENGTH
, GPF_PORT_DVSEC
,
125 GPF_PORT_DVSEC_REVID
, dvsec
);
127 dvsec
= (uint8_t *)&(CXLDVSECRegisterLocator
){
129 .reg0_base_lo
= RBI_COMPONENT_REG
| CXL_COMPONENT_REG_BAR_IDX
,
132 cxl_component_create_dvsec(cxl
, CXL2_DOWNSTREAM_PORT
,
133 REG_LOC_DVSEC_LENGTH
, REG_LOC_DVSEC
,
134 REG_LOC_DVSEC_REVID
, dvsec
);
137 static void cxl_dsp_realize(PCIDevice
*d
, Error
**errp
)
139 PCIEPort
*p
= PCIE_PORT(d
);
140 PCIESlot
*s
= PCIE_SLOT(d
);
141 CXLDownstreamPort
*dsp
= CXL_DSP(d
);
142 CXLComponentState
*cxl_cstate
= &dsp
->cxl_cstate
;
143 ComponentRegisters
*cregs
= &cxl_cstate
->crb
;
144 MemoryRegion
*component_bar
= &cregs
->component_registers
;
147 pci_bridge_initfn(d
, TYPE_PCIE_BUS
);
148 pcie_port_init_reg(d
);
150 rc
= msi_init(d
, CXL_DOWNSTREAM_PORT_MSI_OFFSET
,
151 CXL_DOWNSTREAM_PORT_MSI_NR_VECTOR
,
154 assert(rc
== -ENOTSUP
);
158 rc
= pcie_cap_init(d
, CXL_DOWNSTREAM_PORT_EXP_OFFSET
,
159 PCI_EXP_TYPE_DOWNSTREAM
, p
->port
,
165 pcie_cap_flr_init(d
);
166 pcie_cap_deverr_init(d
);
167 pcie_cap_slot_init(d
, s
);
168 pcie_cap_arifwd_init(d
);
170 pcie_chassis_create(s
->chassis
);
171 rc
= pcie_chassis_add_slot(s
);
173 error_setg(errp
, "Can't add chassis slot, error %d", rc
);
177 rc
= pcie_aer_init(d
, PCI_ERR_VER
, CXL_DOWNSTREAM_PORT_AER_OFFSET
,
178 PCI_ERR_SIZEOF
, errp
);
183 cxl_cstate
->dvsec_offset
= CXL_DOWNSTREAM_PORT_DVSEC_OFFSET
;
184 cxl_cstate
->pdev
= d
;
185 build_dvsecs(cxl_cstate
);
186 cxl_component_register_block_init(OBJECT(d
), cxl_cstate
, TYPE_CXL_DSP
);
187 pci_register_bar(d
, CXL_COMPONENT_REG_BAR_IDX
,
188 PCI_BASE_ADDRESS_SPACE_MEMORY
|
189 PCI_BASE_ADDRESS_MEM_TYPE_64
,
195 pcie_chassis_del_slot(s
);
201 pci_bridge_exitfn(d
);
204 static void cxl_dsp_exitfn(PCIDevice
*d
)
206 PCIESlot
*s
= PCIE_SLOT(d
);
209 pcie_chassis_del_slot(s
);
212 pci_bridge_exitfn(d
);
215 static void cxl_dsp_class_init(ObjectClass
*oc
, void *data
)
217 DeviceClass
*dc
= DEVICE_CLASS(oc
);
218 PCIDeviceClass
*k
= PCI_DEVICE_CLASS(oc
);
220 k
->config_write
= cxl_dsp_config_write
;
221 k
->realize
= cxl_dsp_realize
;
222 k
->exit
= cxl_dsp_exitfn
;
223 k
->vendor_id
= 0x19e5; /* Huawei */
224 k
->device_id
= 0xa129; /* Emulated CXL Switch Downstream Port */
226 set_bit(DEVICE_CATEGORY_BRIDGE
, dc
->categories
);
227 dc
->desc
= "CXL Switch Downstream Port";
228 dc
->reset
= cxl_dsp_reset
;
231 static const TypeInfo cxl_dsp_info
= {
232 .name
= TYPE_CXL_DSP
,
233 .instance_size
= sizeof(CXLDownstreamPort
),
234 .parent
= TYPE_PCIE_SLOT
,
235 .class_init
= cxl_dsp_class_init
,
236 .interfaces
= (InterfaceInfo
[]) {
237 { INTERFACE_PCIE_DEVICE
},
238 { INTERFACE_CXL_DEVICE
},
243 static void cxl_dsp_register_type(void)
245 type_register_static(&cxl_dsp_info
);
248 type_init(cxl_dsp_register_type
);