xref: /qemu/hw/pci-bridge/cxl_root_port.c (revision 720a0e417ef0814d90aa884096a643b02ee854dc)
1  /*
2   * CXL 2.0 Root Port Implementation
3   *
4   * Copyright(C) 2020 Intel Corporation.
5   *
6   * This library is free software; you can redistribute it and/or
7   * modify it under the terms of the GNU Lesser General Public
8   * License as published by the Free Software Foundation; either
9   * version 2 of the License, or (at your option) any later version.
10   *
11   * This library is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   * Lesser General Public License for more details.
15   *
16   * You should have received a copy of the GNU Lesser General Public
17   * License along with this library; if not, see <http://www.gnu.org/licenses/>
18   */
19  
20  #include "qemu/osdep.h"
21  #include "qemu/log.h"
22  #include "qemu/range.h"
23  #include "hw/pci/pci_bridge.h"
24  #include "hw/pci/pcie_port.h"
25  #include "hw/pci/msi.h"
26  #include "hw/qdev-properties.h"
27  #include "hw/qdev-properties-system.h"
28  #include "hw/sysbus.h"
29  #include "qapi/error.h"
30  #include "hw/cxl/cxl.h"
31  
32  #define CXL_ROOT_PORT_DID 0x7075
33  
34  #define CXL_RP_MSI_OFFSET               0x60
35  #define CXL_RP_MSI_SUPPORTED_FLAGS      PCI_MSI_FLAGS_MASKBIT
36  #define CXL_RP_MSI_NR_VECTOR            2
37  
38  /* Copied from the gen root port which we derive */
39  #define GEN_PCIE_ROOT_PORT_AER_OFFSET 0x100
40  #define GEN_PCIE_ROOT_PORT_ACS_OFFSET \
41      (GEN_PCIE_ROOT_PORT_AER_OFFSET + PCI_ERR_SIZEOF)
42  #define CXL_ROOT_PORT_DVSEC_OFFSET \
43      (GEN_PCIE_ROOT_PORT_ACS_OFFSET + PCI_ACS_SIZEOF)
44  
45  typedef struct CXLRootPort {
46      /*< private >*/
47      PCIESlot parent_obj;
48  
49      CXLComponentState cxl_cstate;
50      PCIResReserve res_reserve;
51  } CXLRootPort;
52  
53  #define TYPE_CXL_ROOT_PORT "cxl-rp"
54  DECLARE_INSTANCE_CHECKER(CXLRootPort, CXL_ROOT_PORT, TYPE_CXL_ROOT_PORT)
55  
56  /*
57   * If two MSI vector are allocated, Advanced Error Interrupt Message Number
58   * is 1. otherwise 0.
59   * 17.12.5.10 RPERRSTS,  32:27 bit Advanced Error Interrupt Message Number.
60   */
61  static uint8_t cxl_rp_aer_vector(const PCIDevice *d)
62  {
63      switch (msi_nr_vectors_allocated(d)) {
64      case 1:
65          return 0;
66      case 2:
67          return 1;
68      case 4:
69      case 8:
70      case 16:
71      case 32:
72      default:
73          break;
74      }
75      abort();
76      return 0;
77  }
78  
79  static int cxl_rp_interrupts_init(PCIDevice *d, Error **errp)
80  {
81      int rc;
82  
83      rc = msi_init(d, CXL_RP_MSI_OFFSET, CXL_RP_MSI_NR_VECTOR,
84                    CXL_RP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,
85                    CXL_RP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT,
86                    errp);
87      if (rc < 0) {
88          assert(rc == -ENOTSUP);
89      }
90  
91      return rc;
92  }
93  
94  static void cxl_rp_interrupts_uninit(PCIDevice *d)
95  {
96      msi_uninit(d);
97  }
98  
99  static void latch_registers(CXLRootPort *crp)
100  {
101      uint32_t *reg_state = crp->cxl_cstate.crb.cache_mem_registers;
102      uint32_t *write_msk = crp->cxl_cstate.crb.cache_mem_regs_write_mask;
103  
104      cxl_component_register_init_common(reg_state, write_msk, CXL2_ROOT_PORT);
105  }
106  
107  static void build_dvsecs(CXLComponentState *cxl)
108  {
109      uint8_t *dvsec;
110  
111      dvsec = (uint8_t *)&(CXLDVSECPortExt){ 0 };
112      cxl_component_create_dvsec(cxl, CXL2_ROOT_PORT,
113                                 EXTENSIONS_PORT_DVSEC_LENGTH,
114                                 EXTENSIONS_PORT_DVSEC,
115                                 EXTENSIONS_PORT_DVSEC_REVID, dvsec);
116  
117      dvsec = (uint8_t *)&(CXLDVSECPortGPF){
118          .rsvd        = 0,
119          .phase1_ctrl = 1, /* 1μs timeout */
120          .phase2_ctrl = 1, /* 1μs timeout */
121      };
122      cxl_component_create_dvsec(cxl, CXL2_ROOT_PORT,
123                                 GPF_PORT_DVSEC_LENGTH, GPF_PORT_DVSEC,
124                                 GPF_PORT_DVSEC_REVID, dvsec);
125  
126      dvsec = (uint8_t *)&(CXLDVSECPortFlexBus){
127          .cap                     = 0x26, /* IO, Mem, non-MLD */
128          .ctrl                    = 0x2,
129          .status                  = 0x26, /* same */
130          .rcvd_mod_ts_data_phase1 = 0xef,
131      };
132      cxl_component_create_dvsec(cxl, CXL2_ROOT_PORT,
133                                 PCIE_CXL3_FLEXBUS_PORT_DVSEC_LENGTH,
134                                 PCIE_FLEXBUS_PORT_DVSEC,
135                                 PCIE_CXL3_FLEXBUS_PORT_DVSEC_REVID, dvsec);
136  
137      dvsec = (uint8_t *)&(CXLDVSECRegisterLocator){
138          .rsvd         = 0,
139          .reg0_base_lo = RBI_COMPONENT_REG | CXL_COMPONENT_REG_BAR_IDX,
140          .reg0_base_hi = 0,
141      };
142      cxl_component_create_dvsec(cxl, CXL2_ROOT_PORT,
143                                 REG_LOC_DVSEC_LENGTH, REG_LOC_DVSEC,
144                                 REG_LOC_DVSEC_REVID, dvsec);
145  }
146  
147  static void cxl_rp_realize(DeviceState *dev, Error **errp)
148  {
149      PCIDevice *pci_dev     = PCI_DEVICE(dev);
150      PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);
151      CXLRootPort *crp       = CXL_ROOT_PORT(dev);
152      CXLComponentState *cxl_cstate = &crp->cxl_cstate;
153      ComponentRegisters *cregs = &cxl_cstate->crb;
154      MemoryRegion *component_bar = &cregs->component_registers;
155      Error *local_err = NULL;
156  
157      rpc->parent_realize(dev, &local_err);
158      if (local_err) {
159          error_propagate(errp, local_err);
160          return;
161      }
162  
163      int rc =
164          pci_bridge_qemu_reserve_cap_init(pci_dev, 0, crp->res_reserve, errp);
165      if (rc < 0) {
166          rpc->parent_class.exit(pci_dev);
167          return;
168      }
169  
170      if (!crp->res_reserve.io || crp->res_reserve.io == -1) {
171          pci_word_test_and_clear_mask(pci_dev->wmask + PCI_COMMAND,
172                                       PCI_COMMAND_IO);
173          pci_dev->wmask[PCI_IO_BASE]  = 0;
174          pci_dev->wmask[PCI_IO_LIMIT] = 0;
175      }
176  
177      cxl_cstate->dvsec_offset = CXL_ROOT_PORT_DVSEC_OFFSET;
178      cxl_cstate->pdev = pci_dev;
179      build_dvsecs(cxl_cstate);
180  
181      cxl_component_register_block_init(OBJECT(pci_dev), cxl_cstate,
182                                        TYPE_CXL_ROOT_PORT);
183  
184      pci_register_bar(pci_dev, CXL_COMPONENT_REG_BAR_IDX,
185                       PCI_BASE_ADDRESS_SPACE_MEMORY |
186                           PCI_BASE_ADDRESS_MEM_TYPE_64,
187                       component_bar);
188  }
189  
190  static void cxl_rp_reset_hold(Object *obj, ResetType type)
191  {
192      PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(obj);
193      CXLRootPort *crp = CXL_ROOT_PORT(obj);
194  
195      if (rpc->parent_phases.hold) {
196          rpc->parent_phases.hold(obj, type);
197      }
198  
199      latch_registers(crp);
200  }
201  
202  static const Property gen_rp_props[] = {
203      DEFINE_PROP_UINT32("bus-reserve", CXLRootPort, res_reserve.bus, -1),
204      DEFINE_PROP_SIZE("io-reserve", CXLRootPort, res_reserve.io, -1),
205      DEFINE_PROP_SIZE("mem-reserve", CXLRootPort, res_reserve.mem_non_pref, -1),
206      DEFINE_PROP_SIZE("pref32-reserve", CXLRootPort, res_reserve.mem_pref_32,
207                       -1),
208      DEFINE_PROP_SIZE("pref64-reserve", CXLRootPort, res_reserve.mem_pref_64,
209                       -1),
210      DEFINE_PROP_PCIE_LINK_SPEED("x-speed", PCIESlot,
211                                  speed, PCIE_LINK_SPEED_64),
212      DEFINE_PROP_PCIE_LINK_WIDTH("x-width", PCIESlot,
213                                  width, PCIE_LINK_WIDTH_32),
214  };
215  
216  static void cxl_rp_dvsec_write_config(PCIDevice *dev, uint32_t addr,
217                                        uint32_t val, int len)
218  {
219      CXLRootPort *crp = CXL_ROOT_PORT(dev);
220  
221      if (range_contains(&crp->cxl_cstate.dvsecs[EXTENSIONS_PORT_DVSEC], addr)) {
222          uint8_t *reg = &dev->config[addr];
223          addr -= crp->cxl_cstate.dvsecs[EXTENSIONS_PORT_DVSEC].lob;
224          if (addr == PORT_CONTROL_OFFSET) {
225              if (pci_get_word(reg) & PORT_CONTROL_UNMASK_SBR) {
226                  /* unmask SBR */
227                  qemu_log_mask(LOG_UNIMP, "SBR mask control is not supported\n");
228              }
229              if (pci_get_word(reg) & PORT_CONTROL_ALT_MEMID_EN) {
230                  /* Alt Memory & ID Space Enable */
231                  qemu_log_mask(LOG_UNIMP,
232                                "Alt Memory & ID space is not supported\n");
233              }
234          }
235      }
236  }
237  
238  static void cxl_rp_aer_vector_update(PCIDevice *d)
239  {
240      PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d);
241  
242      if (rpc->aer_vector) {
243          pcie_aer_root_set_vector(d, rpc->aer_vector(d));
244      }
245  }
246  
247  static void cxl_rp_write_config(PCIDevice *d, uint32_t address, uint32_t val,
248                                  int len)
249  {
250      uint16_t slt_ctl, slt_sta;
251      uint32_t root_cmd =
252          pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND);
253  
254      pcie_cap_slot_get(d, &slt_ctl, &slt_sta);
255      pci_bridge_write_config(d, address, val, len);
256      cxl_rp_aer_vector_update(d);
257      pcie_cap_flr_write_config(d, address, val, len);
258      pcie_cap_slot_write_config(d, slt_ctl, slt_sta, address, val, len);
259      pcie_aer_write_config(d, address, val, len);
260      pcie_aer_root_write_config(d, address, val, len, root_cmd);
261  
262      cxl_rp_dvsec_write_config(d, address, val, len);
263  }
264  
265  static void cxl_root_port_class_init(ObjectClass *oc, void *data)
266  {
267      DeviceClass *dc        = DEVICE_CLASS(oc);
268      PCIDeviceClass *k      = PCI_DEVICE_CLASS(oc);
269      ResettableClass *rc    = RESETTABLE_CLASS(oc);
270      PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(oc);
271  
272      k->vendor_id = PCI_VENDOR_ID_INTEL;
273      k->device_id = CXL_ROOT_PORT_DID;
274      dc->desc     = "CXL Root Port";
275      k->revision  = 0;
276      device_class_set_props(dc, gen_rp_props);
277      k->config_write = cxl_rp_write_config;
278  
279      device_class_set_parent_realize(dc, cxl_rp_realize, &rpc->parent_realize);
280      resettable_class_set_parent_phases(rc, NULL, cxl_rp_reset_hold, NULL,
281                                         &rpc->parent_phases);
282  
283      rpc->aer_offset = GEN_PCIE_ROOT_PORT_AER_OFFSET;
284      rpc->acs_offset = GEN_PCIE_ROOT_PORT_ACS_OFFSET;
285      rpc->aer_vector = cxl_rp_aer_vector;
286      rpc->interrupts_init = cxl_rp_interrupts_init;
287      rpc->interrupts_uninit = cxl_rp_interrupts_uninit;
288  
289      dc->hotpluggable = false;
290  }
291  
292  static const TypeInfo cxl_root_port_info = {
293      .name = TYPE_CXL_ROOT_PORT,
294      .parent = TYPE_PCIE_ROOT_PORT,
295      .instance_size = sizeof(CXLRootPort),
296      .class_init = cxl_root_port_class_init,
297      .interfaces = (InterfaceInfo[]) {
298          { INTERFACE_CXL_DEVICE },
299          { }
300      },
301  };
302  
303  static void cxl_register(void)
304  {
305      type_register_static(&cxl_root_port_info);
306  }
307  
308  type_init(cxl_register);
309