cxl_downstream.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /*
  2. * Emulated CXL Switch Downstream Port
  3. *
  4. * Copyright (c) 2022 Huawei Technologies.
  5. *
  6. * Based on xio3130_downstream.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/pci/msi.h"
  13. #include "hw/pci/pcie.h"
  14. #include "hw/pci/pcie_port.h"
  15. #include "qapi/error.h"
  16. typedef struct CXLDownstreamPort {
  17. /*< private >*/
  18. PCIESlot parent_obj;
  19. /*< public >*/
  20. CXLComponentState cxl_cstate;
  21. } CXLDownstreamPort;
  22. #define TYPE_CXL_DSP "cxl-downstream"
  23. DECLARE_INSTANCE_CHECKER(CXLDownstreamPort, CXL_DSP, TYPE_CXL_DSP)
  24. #define CXL_DOWNSTREAM_PORT_MSI_OFFSET 0x70
  25. #define CXL_DOWNSTREAM_PORT_MSI_NR_VECTOR 1
  26. #define CXL_DOWNSTREAM_PORT_EXP_OFFSET 0x90
  27. #define CXL_DOWNSTREAM_PORT_AER_OFFSET 0x100
  28. #define CXL_DOWNSTREAM_PORT_DVSEC_OFFSET \
  29. (CXL_DOWNSTREAM_PORT_AER_OFFSET + PCI_ERR_SIZEOF)
  30. static void latch_registers(CXLDownstreamPort *dsp)
  31. {
  32. uint32_t *reg_state = dsp->cxl_cstate.crb.cache_mem_registers;
  33. uint32_t *write_msk = dsp->cxl_cstate.crb.cache_mem_regs_write_mask;
  34. cxl_component_register_init_common(reg_state, write_msk,
  35. CXL2_DOWNSTREAM_PORT);
  36. }
  37. /* TODO: Look at sharing this code acorss all CXL port types */
  38. static void cxl_dsp_dvsec_write_config(PCIDevice *dev, uint32_t addr,
  39. uint32_t val, int len)
  40. {
  41. CXLDownstreamPort *dsp = CXL_DSP(dev);
  42. CXLComponentState *cxl_cstate = &dsp->cxl_cstate;
  43. if (range_contains(&cxl_cstate->dvsecs[EXTENSIONS_PORT_DVSEC], addr)) {
  44. uint8_t *reg = &dev->config[addr];
  45. addr -= cxl_cstate->dvsecs[EXTENSIONS_PORT_DVSEC].lob;
  46. if (addr == PORT_CONTROL_OFFSET) {
  47. if (pci_get_word(reg) & PORT_CONTROL_UNMASK_SBR) {
  48. /* unmask SBR */
  49. qemu_log_mask(LOG_UNIMP, "SBR mask control is not supported\n");
  50. }
  51. if (pci_get_word(reg) & PORT_CONTROL_ALT_MEMID_EN) {
  52. /* Alt Memory & ID Space Enable */
  53. qemu_log_mask(LOG_UNIMP,
  54. "Alt Memory & ID space is not supported\n");
  55. }
  56. }
  57. }
  58. }
  59. static void cxl_dsp_config_write(PCIDevice *d, uint32_t address,
  60. uint32_t val, int len)
  61. {
  62. uint16_t slt_ctl, slt_sta;
  63. pcie_cap_slot_get(d, &slt_ctl, &slt_sta);
  64. pci_bridge_write_config(d, address, val, len);
  65. pcie_cap_flr_write_config(d, address, val, len);
  66. pcie_cap_slot_write_config(d, slt_ctl, slt_sta, address, val, len);
  67. pcie_aer_write_config(d, address, val, len);
  68. cxl_dsp_dvsec_write_config(d, address, val, len);
  69. }
  70. static void cxl_dsp_reset(DeviceState *qdev)
  71. {
  72. PCIDevice *d = PCI_DEVICE(qdev);
  73. CXLDownstreamPort *dsp = CXL_DSP(qdev);
  74. pcie_cap_deverr_reset(d);
  75. pcie_cap_slot_reset(d);
  76. pcie_cap_arifwd_reset(d);
  77. pci_bridge_reset(qdev);
  78. latch_registers(dsp);
  79. }
  80. static void build_dvsecs(CXLComponentState *cxl)
  81. {
  82. uint8_t *dvsec;
  83. dvsec = (uint8_t *)&(CXLDVSECPortExtensions){ 0 };
  84. cxl_component_create_dvsec(cxl, CXL2_DOWNSTREAM_PORT,
  85. EXTENSIONS_PORT_DVSEC_LENGTH,
  86. EXTENSIONS_PORT_DVSEC,
  87. EXTENSIONS_PORT_DVSEC_REVID, dvsec);
  88. dvsec = (uint8_t *)&(CXLDVSECPortFlexBus){
  89. .cap = 0x27, /* Cache, IO, Mem, non-MLD */
  90. .ctrl = 0x02, /* IO always enabled */
  91. .status = 0x26, /* same */
  92. .rcvd_mod_ts_data_phase1 = 0xef, /* WTF? */
  93. };
  94. cxl_component_create_dvsec(cxl, CXL2_DOWNSTREAM_PORT,
  95. PCIE_FLEXBUS_PORT_DVSEC_LENGTH_2_0,
  96. PCIE_FLEXBUS_PORT_DVSEC,
  97. PCIE_FLEXBUS_PORT_DVSEC_REVID_2_0, dvsec);
  98. dvsec = (uint8_t *)&(CXLDVSECPortGPF){
  99. .rsvd = 0,
  100. .phase1_ctrl = 1, /* 1μs timeout */
  101. .phase2_ctrl = 1, /* 1μs timeout */
  102. };
  103. cxl_component_create_dvsec(cxl, CXL2_DOWNSTREAM_PORT,
  104. GPF_PORT_DVSEC_LENGTH, GPF_PORT_DVSEC,
  105. GPF_PORT_DVSEC_REVID, dvsec);
  106. dvsec = (uint8_t *)&(CXLDVSECRegisterLocator){
  107. .rsvd = 0,
  108. .reg0_base_lo = RBI_COMPONENT_REG | CXL_COMPONENT_REG_BAR_IDX,
  109. .reg0_base_hi = 0,
  110. };
  111. cxl_component_create_dvsec(cxl, CXL2_DOWNSTREAM_PORT,
  112. REG_LOC_DVSEC_LENGTH, REG_LOC_DVSEC,
  113. REG_LOC_DVSEC_REVID, dvsec);
  114. }
  115. static void cxl_dsp_realize(PCIDevice *d, Error **errp)
  116. {
  117. PCIEPort *p = PCIE_PORT(d);
  118. PCIESlot *s = PCIE_SLOT(d);
  119. CXLDownstreamPort *dsp = CXL_DSP(d);
  120. CXLComponentState *cxl_cstate = &dsp->cxl_cstate;
  121. ComponentRegisters *cregs = &cxl_cstate->crb;
  122. MemoryRegion *component_bar = &cregs->component_registers;
  123. int rc;
  124. pci_bridge_initfn(d, TYPE_PCIE_BUS);
  125. pcie_port_init_reg(d);
  126. rc = msi_init(d, CXL_DOWNSTREAM_PORT_MSI_OFFSET,
  127. CXL_DOWNSTREAM_PORT_MSI_NR_VECTOR,
  128. true, true, errp);
  129. if (rc) {
  130. assert(rc == -ENOTSUP);
  131. goto err_bridge;
  132. }
  133. rc = pcie_cap_init(d, CXL_DOWNSTREAM_PORT_EXP_OFFSET,
  134. PCI_EXP_TYPE_DOWNSTREAM, p->port,
  135. errp);
  136. if (rc < 0) {
  137. goto err_msi;
  138. }
  139. pcie_cap_flr_init(d);
  140. pcie_cap_deverr_init(d);
  141. pcie_cap_slot_init(d, s);
  142. pcie_cap_arifwd_init(d);
  143. pcie_chassis_create(s->chassis);
  144. rc = pcie_chassis_add_slot(s);
  145. if (rc < 0) {
  146. error_setg(errp, "Can't add chassis slot, error %d", rc);
  147. goto err_pcie_cap;
  148. }
  149. rc = pcie_aer_init(d, PCI_ERR_VER, CXL_DOWNSTREAM_PORT_AER_OFFSET,
  150. PCI_ERR_SIZEOF, errp);
  151. if (rc < 0) {
  152. goto err_chassis;
  153. }
  154. cxl_cstate->dvsec_offset = CXL_DOWNSTREAM_PORT_DVSEC_OFFSET;
  155. cxl_cstate->pdev = d;
  156. build_dvsecs(cxl_cstate);
  157. cxl_component_register_block_init(OBJECT(d), cxl_cstate, TYPE_CXL_DSP);
  158. pci_register_bar(d, CXL_COMPONENT_REG_BAR_IDX,
  159. PCI_BASE_ADDRESS_SPACE_MEMORY |
  160. PCI_BASE_ADDRESS_MEM_TYPE_64,
  161. component_bar);
  162. return;
  163. err_chassis:
  164. pcie_chassis_del_slot(s);
  165. err_pcie_cap:
  166. pcie_cap_exit(d);
  167. err_msi:
  168. msi_uninit(d);
  169. err_bridge:
  170. pci_bridge_exitfn(d);
  171. }
  172. static void cxl_dsp_exitfn(PCIDevice *d)
  173. {
  174. PCIESlot *s = PCIE_SLOT(d);
  175. pcie_aer_exit(d);
  176. pcie_chassis_del_slot(s);
  177. pcie_cap_exit(d);
  178. msi_uninit(d);
  179. pci_bridge_exitfn(d);
  180. }
  181. static void cxl_dsp_class_init(ObjectClass *oc, void *data)
  182. {
  183. DeviceClass *dc = DEVICE_CLASS(oc);
  184. PCIDeviceClass *k = PCI_DEVICE_CLASS(oc);
  185. k->config_write = cxl_dsp_config_write;
  186. k->realize = cxl_dsp_realize;
  187. k->exit = cxl_dsp_exitfn;
  188. k->vendor_id = 0x19e5; /* Huawei */
  189. k->device_id = 0xa129; /* Emulated CXL Switch Downstream Port */
  190. k->revision = 0;
  191. set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
  192. dc->desc = "CXL Switch Downstream Port";
  193. dc->reset = cxl_dsp_reset;
  194. }
  195. static const TypeInfo cxl_dsp_info = {
  196. .name = TYPE_CXL_DSP,
  197. .instance_size = sizeof(CXLDownstreamPort),
  198. .parent = TYPE_PCIE_SLOT,
  199. .class_init = cxl_dsp_class_init,
  200. .interfaces = (InterfaceInfo[]) {
  201. { INTERFACE_PCIE_DEVICE },
  202. { INTERFACE_CXL_DEVICE },
  203. { }
  204. },
  205. };
  206. static void cxl_dsp_register_type(void)
  207. {
  208. type_register_static(&cxl_dsp_info);
  209. }
  210. type_init(cxl_dsp_register_type);