qemu
304 строки · 9.6 Кб
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/sysbus.h"28#include "qapi/error.h"29#include "hw/cxl/cxl.h"30
31#define CXL_ROOT_PORT_DID 0x707532
33#define CXL_RP_MSI_OFFSET 0x6034#define CXL_RP_MSI_SUPPORTED_FLAGS PCI_MSI_FLAGS_MASKBIT35#define CXL_RP_MSI_NR_VECTOR 236
37/* Copied from the gen root port which we derive */
38#define GEN_PCIE_ROOT_PORT_AER_OFFSET 0x10039#define GEN_PCIE_ROOT_PORT_ACS_OFFSET \40(GEN_PCIE_ROOT_PORT_AER_OFFSET + PCI_ERR_SIZEOF)41#define CXL_ROOT_PORT_DVSEC_OFFSET \42(GEN_PCIE_ROOT_PORT_ACS_OFFSET + PCI_ACS_SIZEOF)43
44typedef struct CXLRootPort {45/*< private >*/46PCIESlot parent_obj;47
48CXLComponentState cxl_cstate;49PCIResReserve res_reserve;50} CXLRootPort;51
52#define TYPE_CXL_ROOT_PORT "cxl-rp"53DECLARE_INSTANCE_CHECKER(CXLRootPort, CXL_ROOT_PORT, TYPE_CXL_ROOT_PORT)54
55/*
56* If two MSI vector are allocated, Advanced Error Interrupt Message Number
57* is 1. otherwise 0.
58* 17.12.5.10 RPERRSTS, 32:27 bit Advanced Error Interrupt Message Number.
59*/
60static uint8_t cxl_rp_aer_vector(const PCIDevice *d)61{
62switch (msi_nr_vectors_allocated(d)) {63case 1:64return 0;65case 2:66return 1;67case 4:68case 8:69case 16:70case 32:71default:72break;73}74abort();75return 0;76}
77
78static int cxl_rp_interrupts_init(PCIDevice *d, Error **errp)79{
80int rc;81
82rc = msi_init(d, CXL_RP_MSI_OFFSET, CXL_RP_MSI_NR_VECTOR,83CXL_RP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_64BIT,84CXL_RP_MSI_SUPPORTED_FLAGS & PCI_MSI_FLAGS_MASKBIT,85errp);86if (rc < 0) {87assert(rc == -ENOTSUP);88}89
90return rc;91}
92
93static void cxl_rp_interrupts_uninit(PCIDevice *d)94{
95msi_uninit(d);96}
97
98static void latch_registers(CXLRootPort *crp)99{
100uint32_t *reg_state = crp->cxl_cstate.crb.cache_mem_registers;101uint32_t *write_msk = crp->cxl_cstate.crb.cache_mem_regs_write_mask;102
103cxl_component_register_init_common(reg_state, write_msk, CXL2_ROOT_PORT);104}
105
106static void build_dvsecs(CXLComponentState *cxl)107{
108uint8_t *dvsec;109
110dvsec = (uint8_t *)&(CXLDVSECPortExt){ 0 };111cxl_component_create_dvsec(cxl, CXL2_ROOT_PORT,112EXTENSIONS_PORT_DVSEC_LENGTH,113EXTENSIONS_PORT_DVSEC,114EXTENSIONS_PORT_DVSEC_REVID, dvsec);115
116dvsec = (uint8_t *)&(CXLDVSECPortGPF){117.rsvd = 0,118.phase1_ctrl = 1, /* 1μs timeout */119.phase2_ctrl = 1, /* 1μs timeout */120};121cxl_component_create_dvsec(cxl, CXL2_ROOT_PORT,122GPF_PORT_DVSEC_LENGTH, GPF_PORT_DVSEC,123GPF_PORT_DVSEC_REVID, dvsec);124
125dvsec = (uint8_t *)&(CXLDVSECPortFlexBus){126.cap = 0x26, /* IO, Mem, non-MLD */127.ctrl = 0x2,128.status = 0x26, /* same */129.rcvd_mod_ts_data_phase1 = 0xef,130};131cxl_component_create_dvsec(cxl, CXL2_ROOT_PORT,132PCIE_CXL3_FLEXBUS_PORT_DVSEC_LENGTH,133PCIE_FLEXBUS_PORT_DVSEC,134PCIE_CXL3_FLEXBUS_PORT_DVSEC_REVID, dvsec);135
136dvsec = (uint8_t *)&(CXLDVSECRegisterLocator){137.rsvd = 0,138.reg0_base_lo = RBI_COMPONENT_REG | CXL_COMPONENT_REG_BAR_IDX,139.reg0_base_hi = 0,140};141cxl_component_create_dvsec(cxl, CXL2_ROOT_PORT,142REG_LOC_DVSEC_LENGTH, REG_LOC_DVSEC,143REG_LOC_DVSEC_REVID, dvsec);144}
145
146static void cxl_rp_realize(DeviceState *dev, Error **errp)147{
148PCIDevice *pci_dev = PCI_DEVICE(dev);149PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(dev);150CXLRootPort *crp = CXL_ROOT_PORT(dev);151CXLComponentState *cxl_cstate = &crp->cxl_cstate;152ComponentRegisters *cregs = &cxl_cstate->crb;153MemoryRegion *component_bar = &cregs->component_registers;154Error *local_err = NULL;155
156rpc->parent_realize(dev, &local_err);157if (local_err) {158error_propagate(errp, local_err);159return;160}161
162int rc =163pci_bridge_qemu_reserve_cap_init(pci_dev, 0, crp->res_reserve, errp);164if (rc < 0) {165rpc->parent_class.exit(pci_dev);166return;167}168
169if (!crp->res_reserve.io || crp->res_reserve.io == -1) {170pci_word_test_and_clear_mask(pci_dev->wmask + PCI_COMMAND,171PCI_COMMAND_IO);172pci_dev->wmask[PCI_IO_BASE] = 0;173pci_dev->wmask[PCI_IO_LIMIT] = 0;174}175
176cxl_cstate->dvsec_offset = CXL_ROOT_PORT_DVSEC_OFFSET;177cxl_cstate->pdev = pci_dev;178build_dvsecs(cxl_cstate);179
180cxl_component_register_block_init(OBJECT(pci_dev), cxl_cstate,181TYPE_CXL_ROOT_PORT);182
183pci_register_bar(pci_dev, CXL_COMPONENT_REG_BAR_IDX,184PCI_BASE_ADDRESS_SPACE_MEMORY |185PCI_BASE_ADDRESS_MEM_TYPE_64,186component_bar);187}
188
189static void cxl_rp_reset_hold(Object *obj, ResetType type)190{
191PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(obj);192CXLRootPort *crp = CXL_ROOT_PORT(obj);193
194if (rpc->parent_phases.hold) {195rpc->parent_phases.hold(obj, type);196}197
198latch_registers(crp);199}
200
201static Property gen_rp_props[] = {202DEFINE_PROP_UINT32("bus-reserve", CXLRootPort, res_reserve.bus, -1),203DEFINE_PROP_SIZE("io-reserve", CXLRootPort, res_reserve.io, -1),204DEFINE_PROP_SIZE("mem-reserve", CXLRootPort, res_reserve.mem_non_pref, -1),205DEFINE_PROP_SIZE("pref32-reserve", CXLRootPort, res_reserve.mem_pref_32,206-1),207DEFINE_PROP_SIZE("pref64-reserve", CXLRootPort, res_reserve.mem_pref_64,208-1),209DEFINE_PROP_END_OF_LIST()210};211
212static void cxl_rp_dvsec_write_config(PCIDevice *dev, uint32_t addr,213uint32_t val, int len)214{
215CXLRootPort *crp = CXL_ROOT_PORT(dev);216
217if (range_contains(&crp->cxl_cstate.dvsecs[EXTENSIONS_PORT_DVSEC], addr)) {218uint8_t *reg = &dev->config[addr];219addr -= crp->cxl_cstate.dvsecs[EXTENSIONS_PORT_DVSEC].lob;220if (addr == PORT_CONTROL_OFFSET) {221if (pci_get_word(reg) & PORT_CONTROL_UNMASK_SBR) {222/* unmask SBR */223qemu_log_mask(LOG_UNIMP, "SBR mask control is not supported\n");224}225if (pci_get_word(reg) & PORT_CONTROL_ALT_MEMID_EN) {226/* Alt Memory & ID Space Enable */227qemu_log_mask(LOG_UNIMP,228"Alt Memory & ID space is not supported\n");229}230}231}232}
233
234static void cxl_rp_aer_vector_update(PCIDevice *d)235{
236PCIERootPortClass *rpc = PCIE_ROOT_PORT_GET_CLASS(d);237
238if (rpc->aer_vector) {239pcie_aer_root_set_vector(d, rpc->aer_vector(d));240}241}
242
243static void cxl_rp_write_config(PCIDevice *d, uint32_t address, uint32_t val,244int len)245{
246uint16_t slt_ctl, slt_sta;247uint32_t root_cmd =248pci_get_long(d->config + d->exp.aer_cap + PCI_ERR_ROOT_COMMAND);249
250pcie_cap_slot_get(d, &slt_ctl, &slt_sta);251pci_bridge_write_config(d, address, val, len);252cxl_rp_aer_vector_update(d);253pcie_cap_flr_write_config(d, address, val, len);254pcie_cap_slot_write_config(d, slt_ctl, slt_sta, address, val, len);255pcie_aer_write_config(d, address, val, len);256pcie_aer_root_write_config(d, address, val, len, root_cmd);257
258cxl_rp_dvsec_write_config(d, address, val, len);259}
260
261static void cxl_root_port_class_init(ObjectClass *oc, void *data)262{
263DeviceClass *dc = DEVICE_CLASS(oc);264PCIDeviceClass *k = PCI_DEVICE_CLASS(oc);265ResettableClass *rc = RESETTABLE_CLASS(oc);266PCIERootPortClass *rpc = PCIE_ROOT_PORT_CLASS(oc);267
268k->vendor_id = PCI_VENDOR_ID_INTEL;269k->device_id = CXL_ROOT_PORT_DID;270dc->desc = "CXL Root Port";271k->revision = 0;272device_class_set_props(dc, gen_rp_props);273k->config_write = cxl_rp_write_config;274
275device_class_set_parent_realize(dc, cxl_rp_realize, &rpc->parent_realize);276resettable_class_set_parent_phases(rc, NULL, cxl_rp_reset_hold, NULL,277&rpc->parent_phases);278
279rpc->aer_offset = GEN_PCIE_ROOT_PORT_AER_OFFSET;280rpc->acs_offset = GEN_PCIE_ROOT_PORT_ACS_OFFSET;281rpc->aer_vector = cxl_rp_aer_vector;282rpc->interrupts_init = cxl_rp_interrupts_init;283rpc->interrupts_uninit = cxl_rp_interrupts_uninit;284
285dc->hotpluggable = false;286}
287
288static const TypeInfo cxl_root_port_info = {289.name = TYPE_CXL_ROOT_PORT,290.parent = TYPE_PCIE_ROOT_PORT,291.instance_size = sizeof(CXLRootPort),292.class_init = cxl_root_port_class_init,293.interfaces = (InterfaceInfo[]) {294{ INTERFACE_CXL_DEVICE },295{ }296},297};298
299static void cxl_register(void)300{
301type_register_static(&cxl_root_port_info);302}
303
304type_init(cxl_register);305