qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

cxl_downstream.c (7605B)


      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 
     11 #include "qemu/osdep.h"
     12 #include "qemu/log.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"
     17 
     18 typedef struct CXLDownStreamPort {
     19     /*< private >*/
     20     PCIESlot parent_obj;
     21 
     22     /*< public >*/
     23     CXLComponentState cxl_cstate;
     24 } CXLDownstreamPort;
     25 
     26 #define TYPE_CXL_DSP "cxl-downstream"
     27 DECLARE_INSTANCE_CHECKER(CXLDownstreamPort, CXL_DSP, TYPE_CXL_DSP)
     28 
     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)
     35 
     36 static void latch_registers(CXLDownstreamPort *dsp)
     37 {
     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;
     40 
     41     cxl_component_register_init_common(reg_state, write_msk,
     42                                        CXL2_DOWNSTREAM_PORT);
     43 }
     44 
     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)
     48 {
     49     CXLDownstreamPort *dsp = CXL_DSP(dev);
     50     CXLComponentState *cxl_cstate = &dsp->cxl_cstate;
     51 
     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) {
     57                 /* unmask SBR */
     58                 qemu_log_mask(LOG_UNIMP, "SBR mask control is not supported\n");
     59             }
     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");
     64 
     65             }
     66         }
     67     }
     68 }
     69 
     70 static void cxl_dsp_config_write(PCIDevice *d, uint32_t address,
     71                                  uint32_t val, int len)
     72 {
     73     uint16_t slt_ctl, slt_sta;
     74 
     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);
     80 
     81     cxl_dsp_dvsec_write_config(d, address, val, len);
     82 }
     83 
     84 static void cxl_dsp_reset(DeviceState *qdev)
     85 {
     86     PCIDevice *d = PCI_DEVICE(qdev);
     87     CXLDownstreamPort *dsp = CXL_DSP(qdev);
     88 
     89     pcie_cap_deverr_reset(d);
     90     pcie_cap_slot_reset(d);
     91     pcie_cap_arifwd_reset(d);
     92     pci_bridge_reset(qdev);
     93 
     94     latch_registers(dsp);
     95 }
     96 
     97 static void build_dvsecs(CXLComponentState *cxl)
     98 {
     99     uint8_t *dvsec;
    100 
    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);
    106 
    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? */
    112     };
    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);
    117 
    118     dvsec = (uint8_t *)&(CXLDVSECPortGPF){
    119         .rsvd        = 0,
    120         .phase1_ctrl = 1, /* 1μs timeout */
    121         .phase2_ctrl = 1, /* 1μs timeout */
    122     };
    123     cxl_component_create_dvsec(cxl, CXL2_DOWNSTREAM_PORT,
    124                                GPF_PORT_DVSEC_LENGTH, GPF_PORT_DVSEC,
    125                                GPF_PORT_DVSEC_REVID, dvsec);
    126 
    127     dvsec = (uint8_t *)&(CXLDVSECRegisterLocator){
    128         .rsvd         = 0,
    129         .reg0_base_lo = RBI_COMPONENT_REG | CXL_COMPONENT_REG_BAR_IDX,
    130         .reg0_base_hi = 0,
    131     };
    132     cxl_component_create_dvsec(cxl, CXL2_DOWNSTREAM_PORT,
    133                                REG_LOC_DVSEC_LENGTH, REG_LOC_DVSEC,
    134                                REG_LOC_DVSEC_REVID, dvsec);
    135 }
    136 
    137 static void cxl_dsp_realize(PCIDevice *d, Error **errp)
    138 {
    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;
    145     int rc;
    146 
    147     pci_bridge_initfn(d, TYPE_PCIE_BUS);
    148     pcie_port_init_reg(d);
    149 
    150     rc = msi_init(d, CXL_DOWNSTREAM_PORT_MSI_OFFSET,
    151                   CXL_DOWNSTREAM_PORT_MSI_NR_VECTOR,
    152                   true, true, errp);
    153     if (rc) {
    154         assert(rc == -ENOTSUP);
    155         goto err_bridge;
    156     }
    157 
    158     rc = pcie_cap_init(d, CXL_DOWNSTREAM_PORT_EXP_OFFSET,
    159                        PCI_EXP_TYPE_DOWNSTREAM, p->port,
    160                        errp);
    161     if (rc < 0) {
    162         goto err_msi;
    163     }
    164 
    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);
    169 
    170     pcie_chassis_create(s->chassis);
    171     rc = pcie_chassis_add_slot(s);
    172     if (rc < 0) {
    173         error_setg(errp, "Can't add chassis slot, error %d", rc);
    174         goto err_pcie_cap;
    175     }
    176 
    177     rc = pcie_aer_init(d, PCI_ERR_VER, CXL_DOWNSTREAM_PORT_AER_OFFSET,
    178                        PCI_ERR_SIZEOF, errp);
    179     if (rc < 0) {
    180         goto err_chassis;
    181     }
    182 
    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,
    190                      component_bar);
    191 
    192     return;
    193 
    194  err_chassis:
    195     pcie_chassis_del_slot(s);
    196  err_pcie_cap:
    197     pcie_cap_exit(d);
    198  err_msi:
    199     msi_uninit(d);
    200  err_bridge:
    201     pci_bridge_exitfn(d);
    202 }
    203 
    204 static void cxl_dsp_exitfn(PCIDevice *d)
    205 {
    206     PCIESlot *s = PCIE_SLOT(d);
    207 
    208     pcie_aer_exit(d);
    209     pcie_chassis_del_slot(s);
    210     pcie_cap_exit(d);
    211     msi_uninit(d);
    212     pci_bridge_exitfn(d);
    213 }
    214 
    215 static void cxl_dsp_class_init(ObjectClass *oc, void *data)
    216 {
    217     DeviceClass *dc = DEVICE_CLASS(oc);
    218     PCIDeviceClass *k = PCI_DEVICE_CLASS(oc);
    219 
    220     k->is_bridge = true;
    221     k->config_write = cxl_dsp_config_write;
    222     k->realize = cxl_dsp_realize;
    223     k->exit = cxl_dsp_exitfn;
    224     k->vendor_id = 0x19e5; /* Huawei */
    225     k->device_id = 0xa129; /* Emulated CXL Switch Downstream Port */
    226     k->revision = 0;
    227     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
    228     dc->desc = "CXL Switch Downstream Port";
    229     dc->reset = cxl_dsp_reset;
    230 }
    231 
    232 static const TypeInfo cxl_dsp_info = {
    233     .name = TYPE_CXL_DSP,
    234     .instance_size = sizeof(CXLDownstreamPort),
    235     .parent = TYPE_PCIE_SLOT,
    236     .class_init = cxl_dsp_class_init,
    237     .interfaces = (InterfaceInfo[]) {
    238         { INTERFACE_PCIE_DEVICE },
    239         { INTERFACE_CXL_DEVICE },
    240         { }
    241     },
    242 };
    243 
    244 static void cxl_dsp_register_type(void)
    245 {
    246     type_register_static(&cxl_dsp_info);
    247 }
    248 
    249 type_init(cxl_dsp_register_type);