cxl_upstream.c 12 KB

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