19e58f52dSBen Widawsky /* 29e58f52dSBen Widawsky * CXL Utility library for components 39e58f52dSBen Widawsky * 49e58f52dSBen Widawsky * Copyright(C) 2020 Intel Corporation. 59e58f52dSBen Widawsky * 69e58f52dSBen Widawsky * This work is licensed under the terms of the GNU GPL, version 2. See the 79e58f52dSBen Widawsky * COPYING file in the top-level directory. 89e58f52dSBen Widawsky */ 99e58f52dSBen Widawsky 109e58f52dSBen Widawsky #include "qemu/osdep.h" 119e58f52dSBen Widawsky #include "qemu/log.h" 12829de299SJonathan Cameron #include "qapi/error.h" 139e58f52dSBen Widawsky #include "hw/pci/pci.h" 149e58f52dSBen Widawsky #include "hw/cxl/cxl.h" 159e58f52dSBen Widawsky 16*f5a4e1a6SJonathan Cameron int cxl_decoder_count_enc(int count) 17*f5a4e1a6SJonathan Cameron { 18*f5a4e1a6SJonathan Cameron switch (count) { 19*f5a4e1a6SJonathan Cameron case 1: return 0; 20*f5a4e1a6SJonathan Cameron case 2: return 1; 21*f5a4e1a6SJonathan Cameron case 4: return 2; 22*f5a4e1a6SJonathan Cameron case 6: return 3; 23*f5a4e1a6SJonathan Cameron case 8: return 4; 24*f5a4e1a6SJonathan Cameron case 10: return 5; 25*f5a4e1a6SJonathan Cameron } 26*f5a4e1a6SJonathan Cameron return 0; 27*f5a4e1a6SJonathan Cameron } 28*f5a4e1a6SJonathan Cameron 29*f5a4e1a6SJonathan Cameron hwaddr cxl_decode_ig(int ig) 30*f5a4e1a6SJonathan Cameron { 31*f5a4e1a6SJonathan Cameron return 1ULL << (ig + 8); 32*f5a4e1a6SJonathan Cameron } 33*f5a4e1a6SJonathan Cameron 349e58f52dSBen Widawsky static uint64_t cxl_cache_mem_read_reg(void *opaque, hwaddr offset, 359e58f52dSBen Widawsky unsigned size) 369e58f52dSBen Widawsky { 379e58f52dSBen Widawsky CXLComponentState *cxl_cstate = opaque; 389e58f52dSBen Widawsky ComponentRegisters *cregs = &cxl_cstate->crb; 399e58f52dSBen Widawsky 409e58f52dSBen Widawsky if (size == 8) { 419e58f52dSBen Widawsky qemu_log_mask(LOG_UNIMP, 429e58f52dSBen Widawsky "CXL 8 byte cache mem registers not implemented\n"); 439e58f52dSBen Widawsky return 0; 449e58f52dSBen Widawsky } 459e58f52dSBen Widawsky 469e58f52dSBen Widawsky if (cregs->special_ops && cregs->special_ops->read) { 479e58f52dSBen Widawsky return cregs->special_ops->read(cxl_cstate, offset, size); 489e58f52dSBen Widawsky } else { 499e58f52dSBen Widawsky return cregs->cache_mem_registers[offset / sizeof(*cregs->cache_mem_registers)]; 509e58f52dSBen Widawsky } 519e58f52dSBen Widawsky } 529e58f52dSBen Widawsky 533540bf56SBen Widawsky static void dumb_hdm_handler(CXLComponentState *cxl_cstate, hwaddr offset, 543540bf56SBen Widawsky uint32_t value) 553540bf56SBen Widawsky { 563540bf56SBen Widawsky ComponentRegisters *cregs = &cxl_cstate->crb; 573540bf56SBen Widawsky uint32_t *cache_mem = cregs->cache_mem_registers; 583540bf56SBen Widawsky bool should_commit = false; 59823371a6SJonathan Cameron bool should_uncommit = false; 603540bf56SBen Widawsky 613540bf56SBen Widawsky switch (offset) { 623540bf56SBen Widawsky case A_CXL_HDM_DECODER0_CTRL: 633540bf56SBen Widawsky should_commit = FIELD_EX32(value, CXL_HDM_DECODER0_CTRL, COMMIT); 64823371a6SJonathan Cameron should_uncommit = !should_commit; 653540bf56SBen Widawsky break; 663540bf56SBen Widawsky default: 673540bf56SBen Widawsky break; 683540bf56SBen Widawsky } 693540bf56SBen Widawsky 703540bf56SBen Widawsky if (should_commit) { 7192ff7cabSJonathan Cameron value = FIELD_DP32(value, CXL_HDM_DECODER0_CTRL, ERR, 0); 7292ff7cabSJonathan Cameron value = FIELD_DP32(value, CXL_HDM_DECODER0_CTRL, COMMITTED, 1); 73823371a6SJonathan Cameron } else if (should_uncommit) { 74823371a6SJonathan Cameron value = FIELD_DP32(value, CXL_HDM_DECODER0_CTRL, ERR, 0); 75823371a6SJonathan Cameron value = FIELD_DP32(value, CXL_HDM_DECODER0_CTRL, COMMITTED, 0); 763540bf56SBen Widawsky } 7792ff7cabSJonathan Cameron stl_le_p((uint8_t *)cache_mem + offset, value); 783540bf56SBen Widawsky } 793540bf56SBen Widawsky 809e58f52dSBen Widawsky static void cxl_cache_mem_write_reg(void *opaque, hwaddr offset, uint64_t value, 819e58f52dSBen Widawsky unsigned size) 829e58f52dSBen Widawsky { 839e58f52dSBen Widawsky CXLComponentState *cxl_cstate = opaque; 849e58f52dSBen Widawsky ComponentRegisters *cregs = &cxl_cstate->crb; 859e58f52dSBen Widawsky uint32_t mask; 869e58f52dSBen Widawsky 879e58f52dSBen Widawsky if (size == 8) { 889e58f52dSBen Widawsky qemu_log_mask(LOG_UNIMP, 899e58f52dSBen Widawsky "CXL 8 byte cache mem registers not implemented\n"); 909e58f52dSBen Widawsky return; 919e58f52dSBen Widawsky } 929e58f52dSBen Widawsky mask = cregs->cache_mem_regs_write_mask[offset / sizeof(*cregs->cache_mem_regs_write_mask)]; 939e58f52dSBen Widawsky value &= mask; 949e58f52dSBen Widawsky /* RO bits should remain constant. Done by reading existing value */ 959e58f52dSBen Widawsky value |= ~mask & cregs->cache_mem_registers[offset / sizeof(*cregs->cache_mem_registers)]; 969e58f52dSBen Widawsky if (cregs->special_ops && cregs->special_ops->write) { 979e58f52dSBen Widawsky cregs->special_ops->write(cxl_cstate, offset, value, size); 983540bf56SBen Widawsky return; 993540bf56SBen Widawsky } 1003540bf56SBen Widawsky 1013540bf56SBen Widawsky if (offset >= A_CXL_HDM_DECODER_CAPABILITY && 1023540bf56SBen Widawsky offset <= A_CXL_HDM_DECODER0_TARGET_LIST_HI) { 1033540bf56SBen Widawsky dumb_hdm_handler(cxl_cstate, offset, value); 1049e58f52dSBen Widawsky } else { 1059e58f52dSBen Widawsky cregs->cache_mem_registers[offset / sizeof(*cregs->cache_mem_registers)] = value; 1069e58f52dSBen Widawsky } 1079e58f52dSBen Widawsky } 1089e58f52dSBen Widawsky 1099e58f52dSBen Widawsky /* 1109e58f52dSBen Widawsky * 8.2.3 1119e58f52dSBen Widawsky * The access restrictions specified in Section 8.2.2 also apply to CXL 2.0 1129e58f52dSBen Widawsky * Component Registers. 1139e58f52dSBen Widawsky * 1149e58f52dSBen Widawsky * 8.2.2 1159e58f52dSBen Widawsky * • A 32 bit register shall be accessed as a 4 Bytes quantity. Partial 1169e58f52dSBen Widawsky * reads are not permitted. 1179e58f52dSBen Widawsky * • A 64 bit register shall be accessed as a 8 Bytes quantity. Partial 1189e58f52dSBen Widawsky * reads are not permitted. 1199e58f52dSBen Widawsky * 1209e58f52dSBen Widawsky * As of the spec defined today, only 4 byte registers exist. 1219e58f52dSBen Widawsky */ 1229e58f52dSBen Widawsky static const MemoryRegionOps cache_mem_ops = { 1239e58f52dSBen Widawsky .read = cxl_cache_mem_read_reg, 1249e58f52dSBen Widawsky .write = cxl_cache_mem_write_reg, 1259e58f52dSBen Widawsky .endianness = DEVICE_LITTLE_ENDIAN, 1269e58f52dSBen Widawsky .valid = { 1279e58f52dSBen Widawsky .min_access_size = 4, 1289e58f52dSBen Widawsky .max_access_size = 8, 1299e58f52dSBen Widawsky .unaligned = false, 1309e58f52dSBen Widawsky }, 1319e58f52dSBen Widawsky .impl = { 1329e58f52dSBen Widawsky .min_access_size = 4, 1339e58f52dSBen Widawsky .max_access_size = 8, 1349e58f52dSBen Widawsky }, 1359e58f52dSBen Widawsky }; 1369e58f52dSBen Widawsky 1379e58f52dSBen Widawsky void cxl_component_register_block_init(Object *obj, 1389e58f52dSBen Widawsky CXLComponentState *cxl_cstate, 1399e58f52dSBen Widawsky const char *type) 1409e58f52dSBen Widawsky { 1419e58f52dSBen Widawsky ComponentRegisters *cregs = &cxl_cstate->crb; 1429e58f52dSBen Widawsky 1439e58f52dSBen Widawsky memory_region_init(&cregs->component_registers, obj, type, 1449e58f52dSBen Widawsky CXL2_COMPONENT_BLOCK_SIZE); 1459e58f52dSBen Widawsky 1469e58f52dSBen Widawsky /* io registers controls link which we don't care about in QEMU */ 1479e58f52dSBen Widawsky memory_region_init_io(&cregs->io, obj, NULL, cregs, ".io", 1489e58f52dSBen Widawsky CXL2_COMPONENT_IO_REGION_SIZE); 1499e58f52dSBen Widawsky memory_region_init_io(&cregs->cache_mem, obj, &cache_mem_ops, cregs, 1509e58f52dSBen Widawsky ".cache_mem", CXL2_COMPONENT_CM_REGION_SIZE); 1519e58f52dSBen Widawsky 1529e58f52dSBen Widawsky memory_region_add_subregion(&cregs->component_registers, 0, &cregs->io); 1539e58f52dSBen Widawsky memory_region_add_subregion(&cregs->component_registers, 1549e58f52dSBen Widawsky CXL2_COMPONENT_IO_REGION_SIZE, 1559e58f52dSBen Widawsky &cregs->cache_mem); 1569e58f52dSBen Widawsky } 1579e58f52dSBen Widawsky 1589e58f52dSBen Widawsky static void ras_init_common(uint32_t *reg_state, uint32_t *write_msk) 1599e58f52dSBen Widawsky { 1609e58f52dSBen Widawsky /* 1619e58f52dSBen Widawsky * Error status is RW1C but given bits are not yet set, it can 1629e58f52dSBen Widawsky * be handled as RO. 1639e58f52dSBen Widawsky */ 164cb4e642cSJonathan Cameron stl_le_p(reg_state + R_CXL_RAS_UNC_ERR_STATUS, 0); 165415442a1SJonathan Cameron stl_le_p(write_msk + R_CXL_RAS_UNC_ERR_STATUS, 0x1cfff); 1669e58f52dSBen Widawsky /* Bits 12-13 and 17-31 reserved in CXL 2.0 */ 167cb4e642cSJonathan Cameron stl_le_p(reg_state + R_CXL_RAS_UNC_ERR_MASK, 0x1cfff); 168cb4e642cSJonathan Cameron stl_le_p(write_msk + R_CXL_RAS_UNC_ERR_MASK, 0x1cfff); 169cb4e642cSJonathan Cameron stl_le_p(reg_state + R_CXL_RAS_UNC_ERR_SEVERITY, 0x1cfff); 170cb4e642cSJonathan Cameron stl_le_p(write_msk + R_CXL_RAS_UNC_ERR_SEVERITY, 0x1cfff); 171cb4e642cSJonathan Cameron stl_le_p(reg_state + R_CXL_RAS_COR_ERR_STATUS, 0); 172415442a1SJonathan Cameron stl_le_p(write_msk + R_CXL_RAS_COR_ERR_STATUS, 0x7f); 173cb4e642cSJonathan Cameron stl_le_p(reg_state + R_CXL_RAS_COR_ERR_MASK, 0x7f); 174cb4e642cSJonathan Cameron stl_le_p(write_msk + R_CXL_RAS_COR_ERR_MASK, 0x7f); 1759e58f52dSBen Widawsky /* CXL switches and devices must set */ 176415442a1SJonathan Cameron stl_le_p(reg_state + R_CXL_RAS_ERR_CAP_CTRL, 0x200); 1779e58f52dSBen Widawsky } 1789e58f52dSBen Widawsky 179f824f529SJonathan Cameron static void hdm_init_common(uint32_t *reg_state, uint32_t *write_msk, 180f824f529SJonathan Cameron enum reg_type type) 1819e58f52dSBen Widawsky { 1829e58f52dSBen Widawsky int decoder_count = 1; 1839e58f52dSBen Widawsky int i; 1849e58f52dSBen Widawsky 1859e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, DECODER_COUNT, 1869e58f52dSBen Widawsky cxl_decoder_count_enc(decoder_count)); 1879e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, TARGET_COUNT, 1); 1889e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, INTERLEAVE_256B, 1); 1899e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, INTERLEAVE_4K, 1); 1909e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, POISON_ON_ERR_CAP, 0); 1919e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_GLOBAL_CONTROL, 1929e58f52dSBen Widawsky HDM_DECODER_ENABLE, 0); 1939e58f52dSBen Widawsky write_msk[R_CXL_HDM_DECODER_GLOBAL_CONTROL] = 0x3; 1949e58f52dSBen Widawsky for (i = 0; i < decoder_count; i++) { 1959e58f52dSBen Widawsky write_msk[R_CXL_HDM_DECODER0_BASE_LO + i * 0x20] = 0xf0000000; 1969e58f52dSBen Widawsky write_msk[R_CXL_HDM_DECODER0_BASE_HI + i * 0x20] = 0xffffffff; 1979e58f52dSBen Widawsky write_msk[R_CXL_HDM_DECODER0_SIZE_LO + i * 0x20] = 0xf0000000; 1989e58f52dSBen Widawsky write_msk[R_CXL_HDM_DECODER0_SIZE_HI + i * 0x20] = 0xffffffff; 1999e58f52dSBen Widawsky write_msk[R_CXL_HDM_DECODER0_CTRL + i * 0x20] = 0x13ff; 200f824f529SJonathan Cameron if (type == CXL2_DEVICE || 201f824f529SJonathan Cameron type == CXL2_TYPE3_DEVICE || 202f824f529SJonathan Cameron type == CXL2_LOGICAL_DEVICE) { 203f824f529SJonathan Cameron write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_LO + i * 0x20] = 0xf0000000; 204f824f529SJonathan Cameron } else { 205f824f529SJonathan Cameron write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_LO + i * 0x20] = 0xffffffff; 206f824f529SJonathan Cameron } 207f824f529SJonathan Cameron write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_HI + i * 0x20] = 0xffffffff; 2089e58f52dSBen Widawsky } 2099e58f52dSBen Widawsky } 2109e58f52dSBen Widawsky 2119e58f52dSBen Widawsky void cxl_component_register_init_common(uint32_t *reg_state, uint32_t *write_msk, 2129e58f52dSBen Widawsky enum reg_type type) 2139e58f52dSBen Widawsky { 2149e58f52dSBen Widawsky int caps = 0; 2159e58f52dSBen Widawsky 2169e58f52dSBen Widawsky /* 2179e58f52dSBen Widawsky * In CXL 2.0 the capabilities required for each CXL component are such that, 2189e58f52dSBen Widawsky * with the ordering chosen here, a single number can be used to define 2199e58f52dSBen Widawsky * which capabilities should be provided. 2209e58f52dSBen Widawsky */ 2219e58f52dSBen Widawsky switch (type) { 2229e58f52dSBen Widawsky case CXL2_DOWNSTREAM_PORT: 2239e58f52dSBen Widawsky case CXL2_DEVICE: 2249e58f52dSBen Widawsky /* RAS, Link */ 2259e58f52dSBen Widawsky caps = 2; 2269e58f52dSBen Widawsky break; 2279e58f52dSBen Widawsky case CXL2_UPSTREAM_PORT: 2289e58f52dSBen Widawsky case CXL2_TYPE3_DEVICE: 2299e58f52dSBen Widawsky case CXL2_LOGICAL_DEVICE: 2309e58f52dSBen Widawsky /* + HDM */ 2319e58f52dSBen Widawsky caps = 3; 2329e58f52dSBen Widawsky break; 2339e58f52dSBen Widawsky case CXL2_ROOT_PORT: 2349e58f52dSBen Widawsky /* + Extended Security, + Snoop */ 2359e58f52dSBen Widawsky caps = 5; 2369e58f52dSBen Widawsky break; 2379e58f52dSBen Widawsky default: 2389e58f52dSBen Widawsky abort(); 2399e58f52dSBen Widawsky } 2409e58f52dSBen Widawsky 2419e58f52dSBen Widawsky memset(reg_state, 0, CXL2_COMPONENT_CM_REGION_SIZE); 2429e58f52dSBen Widawsky 2439e58f52dSBen Widawsky /* CXL Capability Header Register */ 2449e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, ID, 1); 2459e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, VERSION, 1); 2469e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, CACHE_MEM_VERSION, 1); 2479e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, ARRAY_SIZE, caps); 2489e58f52dSBen Widawsky 2499e58f52dSBen Widawsky #define init_cap_reg(reg, id, version) \ 2509e58f52dSBen Widawsky QEMU_BUILD_BUG_ON(CXL_##reg##_REGISTERS_OFFSET == 0); \ 2519e58f52dSBen Widawsky do { \ 2529e58f52dSBen Widawsky int which = R_CXL_##reg##_CAPABILITY_HEADER; \ 2539e58f52dSBen Widawsky reg_state[which] = FIELD_DP32(reg_state[which], \ 2549e58f52dSBen Widawsky CXL_##reg##_CAPABILITY_HEADER, ID, id); \ 2559e58f52dSBen Widawsky reg_state[which] = \ 2569e58f52dSBen Widawsky FIELD_DP32(reg_state[which], CXL_##reg##_CAPABILITY_HEADER, \ 2579e58f52dSBen Widawsky VERSION, version); \ 2589e58f52dSBen Widawsky reg_state[which] = \ 2599e58f52dSBen Widawsky FIELD_DP32(reg_state[which], CXL_##reg##_CAPABILITY_HEADER, PTR, \ 2609e58f52dSBen Widawsky CXL_##reg##_REGISTERS_OFFSET); \ 2619e58f52dSBen Widawsky } while (0) 2629e58f52dSBen Widawsky 2639e58f52dSBen Widawsky init_cap_reg(RAS, 2, 2); 2649e58f52dSBen Widawsky ras_init_common(reg_state, write_msk); 2659e58f52dSBen Widawsky 2669e58f52dSBen Widawsky init_cap_reg(LINK, 4, 2); 2679e58f52dSBen Widawsky 2689e58f52dSBen Widawsky if (caps < 3) { 2699e58f52dSBen Widawsky return; 2709e58f52dSBen Widawsky } 2719e58f52dSBen Widawsky 2729e58f52dSBen Widawsky init_cap_reg(HDM, 5, 1); 273f824f529SJonathan Cameron hdm_init_common(reg_state, write_msk, type); 2749e58f52dSBen Widawsky 2759e58f52dSBen Widawsky if (caps < 5) { 2769e58f52dSBen Widawsky return; 2779e58f52dSBen Widawsky } 2789e58f52dSBen Widawsky 2799e58f52dSBen Widawsky init_cap_reg(EXTSEC, 6, 1); 2809e58f52dSBen Widawsky init_cap_reg(SNOOP, 8, 1); 2819e58f52dSBen Widawsky 2829e58f52dSBen Widawsky #undef init_cap_reg 2839e58f52dSBen Widawsky } 2849e58f52dSBen Widawsky 2859e58f52dSBen Widawsky /* 2869e58f52dSBen Widawsky * Helper to creates a DVSEC header for a CXL entity. The caller is responsible 2879e58f52dSBen Widawsky * for tracking the valid offset. 2889e58f52dSBen Widawsky * 2899e58f52dSBen Widawsky * This function will build the DVSEC header on behalf of the caller and then 2909e58f52dSBen Widawsky * copy in the remaining data for the vendor specific bits. 2919e58f52dSBen Widawsky * It will also set up appropriate write masks. 2929e58f52dSBen Widawsky */ 2939e58f52dSBen Widawsky void cxl_component_create_dvsec(CXLComponentState *cxl, 2949e58f52dSBen Widawsky enum reg_type cxl_dev_type, uint16_t length, 2959e58f52dSBen Widawsky uint16_t type, uint8_t rev, uint8_t *body) 2969e58f52dSBen Widawsky { 2979e58f52dSBen Widawsky PCIDevice *pdev = cxl->pdev; 2989e58f52dSBen Widawsky uint16_t offset = cxl->dvsec_offset; 2999e58f52dSBen Widawsky uint8_t *wmask = pdev->wmask; 3009e58f52dSBen Widawsky 3019e58f52dSBen Widawsky assert(offset >= PCI_CFG_SPACE_SIZE && 3029e58f52dSBen Widawsky ((offset + length) < PCI_CFG_SPACE_EXP_SIZE)); 3039e58f52dSBen Widawsky assert((length & 0xf000) == 0); 3049e58f52dSBen Widawsky assert((rev & ~0xf) == 0); 3059e58f52dSBen Widawsky 3069e58f52dSBen Widawsky /* Create the DVSEC in the MCFG space */ 3079e58f52dSBen Widawsky pcie_add_capability(pdev, PCI_EXT_CAP_ID_DVSEC, 1, offset, length); 3089e58f52dSBen Widawsky pci_set_long(pdev->config + offset + PCIE_DVSEC_HEADER1_OFFSET, 3099e58f52dSBen Widawsky (length << 20) | (rev << 16) | CXL_VENDOR_ID); 3109e58f52dSBen Widawsky pci_set_word(pdev->config + offset + PCIE_DVSEC_ID_OFFSET, type); 3119e58f52dSBen Widawsky memcpy(pdev->config + offset + sizeof(DVSECHeader), 3129e58f52dSBen Widawsky body + sizeof(DVSECHeader), 3139e58f52dSBen Widawsky length - sizeof(DVSECHeader)); 3149e58f52dSBen Widawsky 3159e58f52dSBen Widawsky /* Configure write masks */ 3169e58f52dSBen Widawsky switch (type) { 3179e58f52dSBen Widawsky case PCIE_CXL_DEVICE_DVSEC: 318e1706ea8SBen Widawsky /* Cntrl RW Lock - so needs explicit blocking when lock is set */ 319e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, ctrl)] = 0xFD; 320e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, ctrl) + 1] = 0x4F; 321e1706ea8SBen Widawsky /* Status is RW1CS */ 322e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, ctrl2)] = 0x0F; 323e1706ea8SBen Widawsky /* Lock is RW Once */ 324e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, lock)] = 0x01; 325e1706ea8SBen Widawsky /* range1/2_base_high/low is RW Lock */ 326e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi)] = 0xFF; 327e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi) + 1] = 0xFF; 328e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi) + 2] = 0xFF; 329e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi) + 3] = 0xFF; 330e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range1_base_lo) + 3] = 0xF0; 331e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi)] = 0xFF; 332e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi) + 1] = 0xFF; 333e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi) + 2] = 0xFF; 334e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi) + 3] = 0xFF; 335e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range2_base_lo) + 3] = 0xF0; 3369e58f52dSBen Widawsky break; 3379e58f52dSBen Widawsky case NON_CXL_FUNCTION_MAP_DVSEC: 3389e58f52dSBen Widawsky break; /* Not yet implemented */ 3399e58f52dSBen Widawsky case EXTENSIONS_PORT_DVSEC: 3409e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, control)] = 0x0F; 3419e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, control) + 1] = 0x40; 3429e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_bus_base)] = 0xFF; 3439e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_bus_limit)] = 0xFF; 3449e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_memory_base)] = 0xF0; 3459e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_memory_base) + 1] = 0xFF; 3469e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_memory_limit)] = 0xF0; 3479e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_memory_limit) + 1] = 0xFF; 3489e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base)] = 0xF0; 3499e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base) + 1] = 0xFF; 3509e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit)] = 0xF0; 3519e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit) + 1] = 0xFF; 3529e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base_high)] = 0xFF; 3539e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base_high) + 1] = 0xFF; 3549e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base_high) + 2] = 0xFF; 3559e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base_high) + 3] = 0xFF; 3569e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit_high)] = 0xFF; 3579e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit_high) + 1] = 0xFF; 3589e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit_high) + 2] = 0xFF; 3599e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit_high) + 3] = 0xFF; 3609e58f52dSBen Widawsky break; 3619e58f52dSBen Widawsky case GPF_PORT_DVSEC: 3629e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortGPF, phase1_ctrl)] = 0x0F; 3639e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortGPF, phase1_ctrl) + 1] = 0x0F; 3649e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortGPF, phase2_ctrl)] = 0x0F; 3659e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortGPF, phase2_ctrl) + 1] = 0x0F; 3669e58f52dSBen Widawsky break; 3679e58f52dSBen Widawsky case GPF_DEVICE_DVSEC: 3689e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_duration)] = 0x0F; 3699e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_duration) + 1] = 0x0F; 3709e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power)] = 0xFF; 3719e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power) + 1] = 0xFF; 3729e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power) + 2] = 0xFF; 3739e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power) + 3] = 0xFF; 3749e58f52dSBen Widawsky break; 3759e58f52dSBen Widawsky case PCIE_FLEXBUS_PORT_DVSEC: 3769e58f52dSBen Widawsky switch (cxl_dev_type) { 3779e58f52dSBen Widawsky case CXL2_ROOT_PORT: 3789e58f52dSBen Widawsky /* No MLD */ 3799e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortFlexBus, ctrl)] = 0xbd; 3809e58f52dSBen Widawsky break; 3819e58f52dSBen Widawsky case CXL2_DOWNSTREAM_PORT: 3829e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortFlexBus, ctrl)] = 0xfd; 3839e58f52dSBen Widawsky break; 3849e58f52dSBen Widawsky default: /* Registers are RO for other component types */ 3859e58f52dSBen Widawsky break; 3869e58f52dSBen Widawsky } 3879e58f52dSBen Widawsky /* There are rw1cs bits in the status register but never set currently */ 3889e58f52dSBen Widawsky break; 3899e58f52dSBen Widawsky } 3909e58f52dSBen Widawsky 3919e58f52dSBen Widawsky /* Update state for future DVSEC additions */ 3929e58f52dSBen Widawsky range_init_nofail(&cxl->dvsecs[type], cxl->dvsec_offset, length); 3939e58f52dSBen Widawsky cxl->dvsec_offset += length; 3949e58f52dSBen Widawsky } 395829de299SJonathan Cameron 396829de299SJonathan Cameron uint8_t cxl_interleave_ways_enc(int iw, Error **errp) 397829de299SJonathan Cameron { 398829de299SJonathan Cameron switch (iw) { 399829de299SJonathan Cameron case 1: return 0x0; 400829de299SJonathan Cameron case 2: return 0x1; 401829de299SJonathan Cameron case 4: return 0x2; 402829de299SJonathan Cameron case 8: return 0x3; 403829de299SJonathan Cameron case 16: return 0x4; 404829de299SJonathan Cameron case 3: return 0x8; 405829de299SJonathan Cameron case 6: return 0x9; 406829de299SJonathan Cameron case 12: return 0xa; 407829de299SJonathan Cameron default: 408829de299SJonathan Cameron error_setg(errp, "Interleave ways: %d not supported", iw); 409829de299SJonathan Cameron return 0; 410829de299SJonathan Cameron } 411829de299SJonathan Cameron } 412829de299SJonathan Cameron 413829de299SJonathan Cameron uint8_t cxl_interleave_granularity_enc(uint64_t gran, Error **errp) 414829de299SJonathan Cameron { 415829de299SJonathan Cameron switch (gran) { 416829de299SJonathan Cameron case 256: return 0; 417829de299SJonathan Cameron case 512: return 1; 418829de299SJonathan Cameron case 1024: return 2; 419829de299SJonathan Cameron case 2048: return 3; 420829de299SJonathan Cameron case 4096: return 4; 421829de299SJonathan Cameron case 8192: return 5; 422829de299SJonathan Cameron case 16384: return 6; 423829de299SJonathan Cameron default: 424829de299SJonathan Cameron error_setg(errp, "Interleave granularity: %" PRIu64 " invalid", gran); 425829de299SJonathan Cameron return 0; 426829de299SJonathan Cameron } 427829de299SJonathan Cameron } 428