xref: /openbmc/qemu/hw/pci-bridge/cxl_upstream.c (revision ab1b2ba9)
1 /*
2  * Emulated CXL Switch Upstream Port
3  *
4  * Copyright (c) 2022 Huawei Technologies.
5  *
6  * Based on xio3130_upstream.c
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10 
11 #include "qemu/osdep.h"
12 #include "qemu/log.h"
13 #include "hw/qdev-properties.h"
14 #include "hw/pci/msi.h"
15 #include "hw/pci/pcie.h"
16 #include "hw/pci/pcie_port.h"
17 
18 #define CXL_UPSTREAM_PORT_MSI_NR_VECTOR 2
19 
20 #define CXL_UPSTREAM_PORT_MSI_OFFSET 0x70
21 #define CXL_UPSTREAM_PORT_PCIE_CAP_OFFSET 0x90
22 #define CXL_UPSTREAM_PORT_AER_OFFSET 0x100
23 #define CXL_UPSTREAM_PORT_DVSEC_OFFSET \
24     (CXL_UPSTREAM_PORT_AER_OFFSET + PCI_ERR_SIZEOF)
25 
26 typedef struct CXLUpstreamPort {
27     /*< private >*/
28     PCIEPort parent_obj;
29 
30     /*< public >*/
31     CXLComponentState cxl_cstate;
32     DOECap doe_cdat;
33 } CXLUpstreamPort;
34 
35 CXLComponentState *cxl_usp_to_cstate(CXLUpstreamPort *usp)
36 {
37     return &usp->cxl_cstate;
38 }
39 
40 static void cxl_usp_dvsec_write_config(PCIDevice *dev, uint32_t addr,
41                                        uint32_t val, int len)
42 {
43     CXLUpstreamPort *usp = CXL_USP(dev);
44 
45     if (range_contains(&usp->cxl_cstate.dvsecs[EXTENSIONS_PORT_DVSEC], addr)) {
46         uint8_t *reg = &dev->config[addr];
47         addr -= usp->cxl_cstate.dvsecs[EXTENSIONS_PORT_DVSEC].lob;
48         if (addr == PORT_CONTROL_OFFSET) {
49             if (pci_get_word(reg) & PORT_CONTROL_UNMASK_SBR) {
50                 /* unmask SBR */
51                 qemu_log_mask(LOG_UNIMP, "SBR mask control is not supported\n");
52             }
53             if (pci_get_word(reg) & PORT_CONTROL_ALT_MEMID_EN) {
54                 /* Alt Memory & ID Space Enable */
55                 qemu_log_mask(LOG_UNIMP,
56                               "Alt Memory & ID space is not supported\n");
57             }
58         }
59     }
60 }
61 
62 static void cxl_usp_write_config(PCIDevice *d, uint32_t address,
63                                  uint32_t val, int len)
64 {
65     CXLUpstreamPort *usp = CXL_USP(d);
66 
67     pcie_doe_write_config(&usp->doe_cdat, address, val, len);
68     pci_bridge_write_config(d, address, val, len);
69     pcie_cap_flr_write_config(d, address, val, len);
70     pcie_aer_write_config(d, address, val, len);
71 
72     cxl_usp_dvsec_write_config(d, address, val, len);
73 }
74 
75 static uint32_t cxl_usp_read_config(PCIDevice *d, uint32_t address, int len)
76 {
77     CXLUpstreamPort *usp = CXL_USP(d);
78     uint32_t val;
79 
80     if (pcie_doe_read_config(&usp->doe_cdat, address, len, &val)) {
81         return val;
82     }
83 
84     return pci_default_read_config(d, address, len);
85 }
86 
87 static void latch_registers(CXLUpstreamPort *usp)
88 {
89     uint32_t *reg_state = usp->cxl_cstate.crb.cache_mem_registers;
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);
94     ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, TARGET_COUNT, 8);
95 }
96 
97 static void cxl_usp_reset(DeviceState *qdev)
98 {
99     PCIDevice *d = PCI_DEVICE(qdev);
100     CXLUpstreamPort *usp = CXL_USP(qdev);
101 
102     pci_bridge_reset(qdev);
103     pcie_cap_deverr_reset(d);
104     latch_registers(usp);
105 }
106 
107 static void build_dvsecs(CXLComponentState *cxl)
108 {
109     uint8_t *dvsec;
110 
111     dvsec = (uint8_t *)&(CXLDVSECPortExtensions){
112         .status = 0x1, /* Port Power Management Init Complete */
113     };
114     cxl_component_create_dvsec(cxl, CXL2_UPSTREAM_PORT,
115                                EXTENSIONS_PORT_DVSEC_LENGTH,
116                                EXTENSIONS_PORT_DVSEC,
117                                EXTENSIONS_PORT_DVSEC_REVID, dvsec);
118     dvsec = (uint8_t *)&(CXLDVSECPortFlexBus){
119         .cap                     = 0x27, /* Cache, IO, Mem, non-MLD */
120         .ctrl                    = 0x27, /* Cache, IO, Mem */
121         .status                  = 0x26, /* same */
122         .rcvd_mod_ts_data_phase1 = 0xef, /* WTF? */
123     };
124     cxl_component_create_dvsec(cxl, CXL2_UPSTREAM_PORT,
125                                PCIE_FLEXBUS_PORT_DVSEC_LENGTH_2_0,
126                                PCIE_FLEXBUS_PORT_DVSEC,
127                                PCIE_FLEXBUS_PORT_DVSEC_REVID_2_0, dvsec);
128 
129     dvsec = (uint8_t *)&(CXLDVSECRegisterLocator){
130         .rsvd         = 0,
131         .reg0_base_lo = RBI_COMPONENT_REG | CXL_COMPONENT_REG_BAR_IDX,
132         .reg0_base_hi = 0,
133     };
134     cxl_component_create_dvsec(cxl, CXL2_UPSTREAM_PORT,
135                                REG_LOC_DVSEC_LENGTH, REG_LOC_DVSEC,
136                                REG_LOC_DVSEC_REVID, dvsec);
137 }
138 
139 static bool cxl_doe_cdat_rsp(DOECap *doe_cap)
140 {
141     CDATObject *cdat = &CXL_USP(doe_cap->pdev)->cxl_cstate.cdat;
142     uint16_t ent;
143     void *base;
144     uint32_t len;
145     CDATReq *req = pcie_doe_get_write_mbox_ptr(doe_cap);
146     CDATRsp rsp;
147 
148     cxl_doe_cdat_update(&CXL_USP(doe_cap->pdev)->cxl_cstate, &error_fatal);
149     assert(cdat->entry_len);
150 
151     /* Discard if request length mismatched */
152     if (pcie_doe_get_obj_len(req) <
153         DIV_ROUND_UP(sizeof(CDATReq), sizeof(uint32_t))) {
154         return false;
155     }
156 
157     ent = req->entry_handle;
158     base = cdat->entry[ent].base;
159     len = cdat->entry[ent].length;
160 
161     rsp = (CDATRsp) {
162         .header = {
163             .vendor_id = CXL_VENDOR_ID,
164             .data_obj_type = CXL_DOE_TABLE_ACCESS,
165             .reserved = 0x0,
166             .length = DIV_ROUND_UP((sizeof(rsp) + len), sizeof(uint32_t)),
167         },
168         .rsp_code = CXL_DOE_TAB_RSP,
169         .table_type = CXL_DOE_TAB_TYPE_CDAT,
170         .entry_handle = (ent < cdat->entry_len - 1) ?
171                         ent + 1 : CXL_DOE_TAB_ENT_MAX,
172     };
173 
174     memcpy(doe_cap->read_mbox, &rsp, sizeof(rsp));
175         memcpy(doe_cap->read_mbox + DIV_ROUND_UP(sizeof(rsp), sizeof(uint32_t)),
176            base, len);
177 
178     doe_cap->read_mbox_len += rsp.header.length;
179 
180     return true;
181 }
182 
183 static DOEProtocol doe_cdat_prot[] = {
184     { CXL_VENDOR_ID, CXL_DOE_TABLE_ACCESS, cxl_doe_cdat_rsp },
185     { }
186 };
187 
188 enum {
189     CXL_USP_CDAT_SSLBIS_LAT,
190     CXL_USP_CDAT_SSLBIS_BW,
191     CXL_USP_CDAT_NUM_ENTRIES
192 };
193 
194 static int build_cdat_table(CDATSubHeader ***cdat_table, void *priv)
195 {
196     g_autofree CDATSslbis *sslbis_latency = NULL;
197     g_autofree CDATSslbis *sslbis_bandwidth = NULL;
198     CXLUpstreamPort *us = CXL_USP(priv);
199     PCIBus *bus = &PCI_BRIDGE(us)->sec_bus;
200     int devfn, sslbis_size, i;
201     int count = 0;
202     uint16_t port_ids[256];
203 
204     for (devfn = 0; devfn < ARRAY_SIZE(bus->devices); devfn++) {
205         PCIDevice *d = bus->devices[devfn];
206         PCIEPort *port;
207 
208         if (!d || !pci_is_express(d) || !d->exp.exp_cap) {
209             continue;
210         }
211 
212         /*
213          * Whilst the PCI express spec doesn't allow anything other than
214          * downstream ports on this bus, let us be a little paranoid
215          */
216         if (!object_dynamic_cast(OBJECT(d), TYPE_PCIE_PORT)) {
217             continue;
218         }
219 
220         port = PCIE_PORT(d);
221         port_ids[count] = port->port;
222         count++;
223     }
224 
225     /* May not yet have any ports - try again later */
226     if (count == 0) {
227         return 0;
228     }
229 
230     sslbis_size = sizeof(CDATSslbis) + sizeof(*sslbis_latency->sslbe) * count;
231     sslbis_latency = g_malloc(sslbis_size);
232     if (!sslbis_latency) {
233         return -ENOMEM;
234     }
235     *sslbis_latency = (CDATSslbis) {
236         .sslbis_header = {
237             .header = {
238                 .type = CDAT_TYPE_SSLBIS,
239                 .length = sslbis_size,
240             },
241             .data_type = HMATLB_DATA_TYPE_ACCESS_LATENCY,
242             .entry_base_unit = 10000,
243         },
244     };
245 
246     for (i = 0; i < count; i++) {
247         sslbis_latency->sslbe[i] = (CDATSslbe) {
248             .port_x_id = CDAT_PORT_ID_USP,
249             .port_y_id = port_ids[i],
250             .latency_bandwidth = 15, /* 150ns */
251         };
252     }
253 
254     sslbis_bandwidth = g_malloc(sslbis_size);
255     if (!sslbis_bandwidth) {
256         return 0;
257     }
258     *sslbis_bandwidth = (CDATSslbis) {
259         .sslbis_header = {
260             .header = {
261                 .type = CDAT_TYPE_SSLBIS,
262                 .length = sslbis_size,
263             },
264             .data_type = HMATLB_DATA_TYPE_ACCESS_BANDWIDTH,
265             .entry_base_unit = 1000,
266         },
267     };
268 
269     for (i = 0; i < count; i++) {
270         sslbis_bandwidth->sslbe[i] = (CDATSslbe) {
271             .port_x_id = CDAT_PORT_ID_USP,
272             .port_y_id = port_ids[i],
273             .latency_bandwidth = 16, /* 16 GB/s */
274         };
275     }
276 
277     *cdat_table = g_malloc0(sizeof(*cdat_table) * CXL_USP_CDAT_NUM_ENTRIES);
278     if (!*cdat_table) {
279         return -ENOMEM;
280     }
281 
282     /* Header always at start of structure */
283     (*cdat_table)[CXL_USP_CDAT_SSLBIS_LAT] = g_steal_pointer(&sslbis_latency);
284     (*cdat_table)[CXL_USP_CDAT_SSLBIS_BW] = g_steal_pointer(&sslbis_bandwidth);
285 
286     return CXL_USP_CDAT_NUM_ENTRIES;
287 }
288 
289 static void free_default_cdat_table(CDATSubHeader **cdat_table, int num,
290                                     void *priv)
291 {
292     int i;
293 
294     for (i = 0; i < num; i++) {
295         g_free(cdat_table[i]);
296     }
297     g_free(cdat_table);
298 }
299 
300 static void cxl_usp_realize(PCIDevice *d, Error **errp)
301 {
302     PCIEPort *p = PCIE_PORT(d);
303     CXLUpstreamPort *usp = CXL_USP(d);
304     CXLComponentState *cxl_cstate = &usp->cxl_cstate;
305     ComponentRegisters *cregs = &cxl_cstate->crb;
306     MemoryRegion *component_bar = &cregs->component_registers;
307     int rc;
308 
309     pci_bridge_initfn(d, TYPE_PCIE_BUS);
310     pcie_port_init_reg(d);
311 
312     rc = msi_init(d, CXL_UPSTREAM_PORT_MSI_OFFSET,
313                   CXL_UPSTREAM_PORT_MSI_NR_VECTOR, true, true, errp);
314     if (rc) {
315         assert(rc == -ENOTSUP);
316         goto err_bridge;
317     }
318 
319     rc = pcie_cap_init(d, CXL_UPSTREAM_PORT_PCIE_CAP_OFFSET,
320                        PCI_EXP_TYPE_UPSTREAM, p->port, errp);
321     if (rc < 0) {
322         goto err_msi;
323     }
324 
325     pcie_cap_flr_init(d);
326     pcie_cap_deverr_init(d);
327     rc = pcie_aer_init(d, PCI_ERR_VER, CXL_UPSTREAM_PORT_AER_OFFSET,
328                        PCI_ERR_SIZEOF, errp);
329     if (rc) {
330         goto err_cap;
331     }
332 
333     cxl_cstate->dvsec_offset = CXL_UPSTREAM_PORT_DVSEC_OFFSET;
334     cxl_cstate->pdev = d;
335     build_dvsecs(cxl_cstate);
336     cxl_component_register_block_init(OBJECT(d), cxl_cstate, TYPE_CXL_USP);
337     pci_register_bar(d, CXL_COMPONENT_REG_BAR_IDX,
338                      PCI_BASE_ADDRESS_SPACE_MEMORY |
339                      PCI_BASE_ADDRESS_MEM_TYPE_64,
340                      component_bar);
341 
342     pcie_doe_init(d, &usp->doe_cdat, cxl_cstate->dvsec_offset, doe_cdat_prot,
343                   true, 1);
344 
345     cxl_cstate->cdat.build_cdat_table = build_cdat_table;
346     cxl_cstate->cdat.free_cdat_table = free_default_cdat_table;
347     cxl_cstate->cdat.private = d;
348     cxl_doe_cdat_init(cxl_cstate, errp);
349 
350     return;
351 
352 err_cap:
353     pcie_cap_exit(d);
354 err_msi:
355     msi_uninit(d);
356 err_bridge:
357     pci_bridge_exitfn(d);
358 }
359 
360 static void cxl_usp_exitfn(PCIDevice *d)
361 {
362     pcie_aer_exit(d);
363     pcie_cap_exit(d);
364     msi_uninit(d);
365     pci_bridge_exitfn(d);
366 }
367 
368 static Property cxl_upstream_props[] = {
369     DEFINE_PROP_STRING("cdat", CXLUpstreamPort, cxl_cstate.cdat.filename),
370     DEFINE_PROP_END_OF_LIST()
371 };
372 
373 static void cxl_upstream_class_init(ObjectClass *oc, void *data)
374 {
375     DeviceClass *dc = DEVICE_CLASS(oc);
376     PCIDeviceClass *k = PCI_DEVICE_CLASS(oc);
377 
378     k->is_bridge = true;
379     k->config_write = cxl_usp_write_config;
380     k->config_read = cxl_usp_read_config;
381     k->realize = cxl_usp_realize;
382     k->exit = cxl_usp_exitfn;
383     k->vendor_id = 0x19e5; /* Huawei */
384     k->device_id = 0xa128; /* Emulated CXL Switch Upstream Port */
385     k->revision = 0;
386     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
387     dc->desc = "CXL Switch Upstream Port";
388     dc->reset = cxl_usp_reset;
389     device_class_set_props(dc, cxl_upstream_props);
390 }
391 
392 static const TypeInfo cxl_usp_info = {
393     .name = TYPE_CXL_USP,
394     .parent = TYPE_PCIE_PORT,
395     .instance_size = sizeof(CXLUpstreamPort),
396     .class_init = cxl_upstream_class_init,
397     .interfaces = (InterfaceInfo[]) {
398         { INTERFACE_PCIE_DEVICE },
399         { INTERFACE_CXL_DEVICE },
400         { }
401     },
402 };
403 
404 static void cxl_usp_register_type(void)
405 {
406     type_register_static(&cxl_usp_info);
407 }
408 
409 type_init(cxl_usp_register_type);
410