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*87de174aSJonathan Cameron /* CXL r3.0 Section 8.2.4.19.1 CXL HDM Decoder Capability Register */ 17f5a4e1a6SJonathan Cameron int cxl_decoder_count_enc(int count) 18f5a4e1a6SJonathan Cameron { 19f5a4e1a6SJonathan Cameron switch (count) { 20*87de174aSJonathan Cameron case 1: return 0x0; 21*87de174aSJonathan Cameron case 2: return 0x1; 22*87de174aSJonathan Cameron case 4: return 0x2; 23*87de174aSJonathan Cameron case 6: return 0x3; 24*87de174aSJonathan Cameron case 8: return 0x4; 25*87de174aSJonathan Cameron case 10: return 0x5; 26*87de174aSJonathan Cameron /* Switches and Host Bridges may have more than 10 decoders */ 27*87de174aSJonathan Cameron case 12: return 0x6; 28*87de174aSJonathan Cameron case 14: return 0x7; 29*87de174aSJonathan Cameron case 16: return 0x8; 30*87de174aSJonathan Cameron case 20: return 0x9; 31*87de174aSJonathan Cameron case 24: return 0xa; 32*87de174aSJonathan Cameron case 28: return 0xb; 33*87de174aSJonathan Cameron case 32: return 0xc; 34*87de174aSJonathan Cameron } 35*87de174aSJonathan Cameron return 0; 36*87de174aSJonathan Cameron } 37*87de174aSJonathan Cameron 38*87de174aSJonathan Cameron int cxl_decoder_count_dec(int enc_cnt) 39*87de174aSJonathan Cameron { 40*87de174aSJonathan Cameron switch (enc_cnt) { 41*87de174aSJonathan Cameron case 0x0: return 1; 42*87de174aSJonathan Cameron case 0x1: return 2; 43*87de174aSJonathan Cameron case 0x2: return 4; 44*87de174aSJonathan Cameron case 0x3: return 6; 45*87de174aSJonathan Cameron case 0x4: return 8; 46*87de174aSJonathan Cameron case 0x5: return 10; 47*87de174aSJonathan Cameron /* Switches and Host Bridges may have more than 10 decoders */ 48*87de174aSJonathan Cameron case 0x6: return 12; 49*87de174aSJonathan Cameron case 0x7: return 14; 50*87de174aSJonathan Cameron case 0x8: return 16; 51*87de174aSJonathan Cameron case 0x9: return 20; 52*87de174aSJonathan Cameron case 0xa: return 24; 53*87de174aSJonathan Cameron case 0xb: return 28; 54*87de174aSJonathan Cameron case 0xc: return 32; 55f5a4e1a6SJonathan Cameron } 56f5a4e1a6SJonathan Cameron return 0; 57f5a4e1a6SJonathan Cameron } 58f5a4e1a6SJonathan Cameron 59f5a4e1a6SJonathan Cameron hwaddr cxl_decode_ig(int ig) 60f5a4e1a6SJonathan Cameron { 61f5a4e1a6SJonathan Cameron return 1ULL << (ig + 8); 62f5a4e1a6SJonathan Cameron } 63f5a4e1a6SJonathan Cameron 649e58f52dSBen Widawsky static uint64_t cxl_cache_mem_read_reg(void *opaque, hwaddr offset, 659e58f52dSBen Widawsky unsigned size) 669e58f52dSBen Widawsky { 679e58f52dSBen Widawsky CXLComponentState *cxl_cstate = opaque; 689e58f52dSBen Widawsky ComponentRegisters *cregs = &cxl_cstate->crb; 699e58f52dSBen Widawsky 709e58f52dSBen Widawsky if (size == 8) { 719e58f52dSBen Widawsky qemu_log_mask(LOG_UNIMP, 729e58f52dSBen Widawsky "CXL 8 byte cache mem registers not implemented\n"); 739e58f52dSBen Widawsky return 0; 749e58f52dSBen Widawsky } 759e58f52dSBen Widawsky 769e58f52dSBen Widawsky if (cregs->special_ops && cregs->special_ops->read) { 779e58f52dSBen Widawsky return cregs->special_ops->read(cxl_cstate, offset, size); 789e58f52dSBen Widawsky } else { 799e58f52dSBen Widawsky return cregs->cache_mem_registers[offset / sizeof(*cregs->cache_mem_registers)]; 809e58f52dSBen Widawsky } 819e58f52dSBen Widawsky } 829e58f52dSBen Widawsky 833540bf56SBen Widawsky static void dumb_hdm_handler(CXLComponentState *cxl_cstate, hwaddr offset, 843540bf56SBen Widawsky uint32_t value) 853540bf56SBen Widawsky { 863540bf56SBen Widawsky ComponentRegisters *cregs = &cxl_cstate->crb; 873540bf56SBen Widawsky uint32_t *cache_mem = cregs->cache_mem_registers; 883540bf56SBen Widawsky bool should_commit = false; 89823371a6SJonathan Cameron bool should_uncommit = false; 903540bf56SBen Widawsky 913540bf56SBen Widawsky switch (offset) { 923540bf56SBen Widawsky case A_CXL_HDM_DECODER0_CTRL: 933540bf56SBen Widawsky should_commit = FIELD_EX32(value, CXL_HDM_DECODER0_CTRL, COMMIT); 94823371a6SJonathan Cameron should_uncommit = !should_commit; 953540bf56SBen Widawsky break; 963540bf56SBen Widawsky default: 973540bf56SBen Widawsky break; 983540bf56SBen Widawsky } 993540bf56SBen Widawsky 1003540bf56SBen Widawsky if (should_commit) { 10192ff7cabSJonathan Cameron value = FIELD_DP32(value, CXL_HDM_DECODER0_CTRL, ERR, 0); 10292ff7cabSJonathan Cameron value = FIELD_DP32(value, CXL_HDM_DECODER0_CTRL, COMMITTED, 1); 103823371a6SJonathan Cameron } else if (should_uncommit) { 104823371a6SJonathan Cameron value = FIELD_DP32(value, CXL_HDM_DECODER0_CTRL, ERR, 0); 105823371a6SJonathan Cameron value = FIELD_DP32(value, CXL_HDM_DECODER0_CTRL, COMMITTED, 0); 1063540bf56SBen Widawsky } 10792ff7cabSJonathan Cameron stl_le_p((uint8_t *)cache_mem + offset, value); 1083540bf56SBen Widawsky } 1093540bf56SBen Widawsky 1109e58f52dSBen Widawsky static void cxl_cache_mem_write_reg(void *opaque, hwaddr offset, uint64_t value, 1119e58f52dSBen Widawsky unsigned size) 1129e58f52dSBen Widawsky { 1139e58f52dSBen Widawsky CXLComponentState *cxl_cstate = opaque; 1149e58f52dSBen Widawsky ComponentRegisters *cregs = &cxl_cstate->crb; 1159e58f52dSBen Widawsky uint32_t mask; 1169e58f52dSBen Widawsky 1179e58f52dSBen Widawsky if (size == 8) { 1189e58f52dSBen Widawsky qemu_log_mask(LOG_UNIMP, 1199e58f52dSBen Widawsky "CXL 8 byte cache mem registers not implemented\n"); 1209e58f52dSBen Widawsky return; 1219e58f52dSBen Widawsky } 1229e58f52dSBen Widawsky mask = cregs->cache_mem_regs_write_mask[offset / sizeof(*cregs->cache_mem_regs_write_mask)]; 1239e58f52dSBen Widawsky value &= mask; 1249e58f52dSBen Widawsky /* RO bits should remain constant. Done by reading existing value */ 1259e58f52dSBen Widawsky value |= ~mask & cregs->cache_mem_registers[offset / sizeof(*cregs->cache_mem_registers)]; 1269e58f52dSBen Widawsky if (cregs->special_ops && cregs->special_ops->write) { 1279e58f52dSBen Widawsky cregs->special_ops->write(cxl_cstate, offset, value, size); 1283540bf56SBen Widawsky return; 1293540bf56SBen Widawsky } 1303540bf56SBen Widawsky 1313540bf56SBen Widawsky if (offset >= A_CXL_HDM_DECODER_CAPABILITY && 1323540bf56SBen Widawsky offset <= A_CXL_HDM_DECODER0_TARGET_LIST_HI) { 1333540bf56SBen Widawsky dumb_hdm_handler(cxl_cstate, offset, value); 1349e58f52dSBen Widawsky } else { 1359e58f52dSBen Widawsky cregs->cache_mem_registers[offset / sizeof(*cregs->cache_mem_registers)] = value; 1369e58f52dSBen Widawsky } 1379e58f52dSBen Widawsky } 1389e58f52dSBen Widawsky 1399e58f52dSBen Widawsky /* 1409e58f52dSBen Widawsky * 8.2.3 1419e58f52dSBen Widawsky * The access restrictions specified in Section 8.2.2 also apply to CXL 2.0 1429e58f52dSBen Widawsky * Component Registers. 1439e58f52dSBen Widawsky * 1449e58f52dSBen Widawsky * 8.2.2 1459e58f52dSBen Widawsky * • A 32 bit register shall be accessed as a 4 Bytes quantity. Partial 1469e58f52dSBen Widawsky * reads are not permitted. 1479e58f52dSBen Widawsky * • A 64 bit register shall be accessed as a 8 Bytes quantity. Partial 1489e58f52dSBen Widawsky * reads are not permitted. 1499e58f52dSBen Widawsky * 1509e58f52dSBen Widawsky * As of the spec defined today, only 4 byte registers exist. 1519e58f52dSBen Widawsky */ 1529e58f52dSBen Widawsky static const MemoryRegionOps cache_mem_ops = { 1539e58f52dSBen Widawsky .read = cxl_cache_mem_read_reg, 1549e58f52dSBen Widawsky .write = cxl_cache_mem_write_reg, 1559e58f52dSBen Widawsky .endianness = DEVICE_LITTLE_ENDIAN, 1569e58f52dSBen Widawsky .valid = { 1579e58f52dSBen Widawsky .min_access_size = 4, 1589e58f52dSBen Widawsky .max_access_size = 8, 1599e58f52dSBen Widawsky .unaligned = false, 1609e58f52dSBen Widawsky }, 1619e58f52dSBen Widawsky .impl = { 1629e58f52dSBen Widawsky .min_access_size = 4, 1639e58f52dSBen Widawsky .max_access_size = 8, 1649e58f52dSBen Widawsky }, 1659e58f52dSBen Widawsky }; 1669e58f52dSBen Widawsky 1679e58f52dSBen Widawsky void cxl_component_register_block_init(Object *obj, 1689e58f52dSBen Widawsky CXLComponentState *cxl_cstate, 1699e58f52dSBen Widawsky const char *type) 1709e58f52dSBen Widawsky { 1719e58f52dSBen Widawsky ComponentRegisters *cregs = &cxl_cstate->crb; 1729e58f52dSBen Widawsky 1739e58f52dSBen Widawsky memory_region_init(&cregs->component_registers, obj, type, 1749e58f52dSBen Widawsky CXL2_COMPONENT_BLOCK_SIZE); 1759e58f52dSBen Widawsky 1769e58f52dSBen Widawsky /* io registers controls link which we don't care about in QEMU */ 1779e58f52dSBen Widawsky memory_region_init_io(&cregs->io, obj, NULL, cregs, ".io", 1789e58f52dSBen Widawsky CXL2_COMPONENT_IO_REGION_SIZE); 1799e58f52dSBen Widawsky memory_region_init_io(&cregs->cache_mem, obj, &cache_mem_ops, cregs, 1809e58f52dSBen Widawsky ".cache_mem", CXL2_COMPONENT_CM_REGION_SIZE); 1819e58f52dSBen Widawsky 1829e58f52dSBen Widawsky memory_region_add_subregion(&cregs->component_registers, 0, &cregs->io); 1839e58f52dSBen Widawsky memory_region_add_subregion(&cregs->component_registers, 1849e58f52dSBen Widawsky CXL2_COMPONENT_IO_REGION_SIZE, 1859e58f52dSBen Widawsky &cregs->cache_mem); 1869e58f52dSBen Widawsky } 1879e58f52dSBen Widawsky 1889e58f52dSBen Widawsky static void ras_init_common(uint32_t *reg_state, uint32_t *write_msk) 1899e58f52dSBen Widawsky { 1909e58f52dSBen Widawsky /* 1919e58f52dSBen Widawsky * Error status is RW1C but given bits are not yet set, it can 1929e58f52dSBen Widawsky * be handled as RO. 1939e58f52dSBen Widawsky */ 194cb4e642cSJonathan Cameron stl_le_p(reg_state + R_CXL_RAS_UNC_ERR_STATUS, 0); 195415442a1SJonathan Cameron stl_le_p(write_msk + R_CXL_RAS_UNC_ERR_STATUS, 0x1cfff); 1969e58f52dSBen Widawsky /* Bits 12-13 and 17-31 reserved in CXL 2.0 */ 197cb4e642cSJonathan Cameron stl_le_p(reg_state + R_CXL_RAS_UNC_ERR_MASK, 0x1cfff); 198cb4e642cSJonathan Cameron stl_le_p(write_msk + R_CXL_RAS_UNC_ERR_MASK, 0x1cfff); 199cb4e642cSJonathan Cameron stl_le_p(reg_state + R_CXL_RAS_UNC_ERR_SEVERITY, 0x1cfff); 200cb4e642cSJonathan Cameron stl_le_p(write_msk + R_CXL_RAS_UNC_ERR_SEVERITY, 0x1cfff); 201cb4e642cSJonathan Cameron stl_le_p(reg_state + R_CXL_RAS_COR_ERR_STATUS, 0); 202415442a1SJonathan Cameron stl_le_p(write_msk + R_CXL_RAS_COR_ERR_STATUS, 0x7f); 203cb4e642cSJonathan Cameron stl_le_p(reg_state + R_CXL_RAS_COR_ERR_MASK, 0x7f); 204cb4e642cSJonathan Cameron stl_le_p(write_msk + R_CXL_RAS_COR_ERR_MASK, 0x7f); 2059e58f52dSBen Widawsky /* CXL switches and devices must set */ 206415442a1SJonathan Cameron stl_le_p(reg_state + R_CXL_RAS_ERR_CAP_CTRL, 0x200); 2079e58f52dSBen Widawsky } 2089e58f52dSBen Widawsky 209f824f529SJonathan Cameron static void hdm_init_common(uint32_t *reg_state, uint32_t *write_msk, 210f824f529SJonathan Cameron enum reg_type type) 2119e58f52dSBen Widawsky { 2129e58f52dSBen Widawsky int decoder_count = 1; 2139e58f52dSBen Widawsky int i; 2149e58f52dSBen Widawsky 2159e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, DECODER_COUNT, 2169e58f52dSBen Widawsky cxl_decoder_count_enc(decoder_count)); 2179e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, TARGET_COUNT, 1); 2189e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, INTERLEAVE_256B, 1); 2199e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, INTERLEAVE_4K, 1); 2209e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, POISON_ON_ERR_CAP, 0); 2219e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_GLOBAL_CONTROL, 2229e58f52dSBen Widawsky HDM_DECODER_ENABLE, 0); 2239e58f52dSBen Widawsky write_msk[R_CXL_HDM_DECODER_GLOBAL_CONTROL] = 0x3; 2249e58f52dSBen Widawsky for (i = 0; i < decoder_count; i++) { 2259e58f52dSBen Widawsky write_msk[R_CXL_HDM_DECODER0_BASE_LO + i * 0x20] = 0xf0000000; 2269e58f52dSBen Widawsky write_msk[R_CXL_HDM_DECODER0_BASE_HI + i * 0x20] = 0xffffffff; 2279e58f52dSBen Widawsky write_msk[R_CXL_HDM_DECODER0_SIZE_LO + i * 0x20] = 0xf0000000; 2289e58f52dSBen Widawsky write_msk[R_CXL_HDM_DECODER0_SIZE_HI + i * 0x20] = 0xffffffff; 2299e58f52dSBen Widawsky write_msk[R_CXL_HDM_DECODER0_CTRL + i * 0x20] = 0x13ff; 230f824f529SJonathan Cameron if (type == CXL2_DEVICE || 231f824f529SJonathan Cameron type == CXL2_TYPE3_DEVICE || 232f824f529SJonathan Cameron type == CXL2_LOGICAL_DEVICE) { 233f824f529SJonathan Cameron write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_LO + i * 0x20] = 0xf0000000; 234f824f529SJonathan Cameron } else { 235f824f529SJonathan Cameron write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_LO + i * 0x20] = 0xffffffff; 236f824f529SJonathan Cameron } 237f824f529SJonathan Cameron write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_HI + i * 0x20] = 0xffffffff; 2389e58f52dSBen Widawsky } 2399e58f52dSBen Widawsky } 2409e58f52dSBen Widawsky 2419e58f52dSBen Widawsky void cxl_component_register_init_common(uint32_t *reg_state, uint32_t *write_msk, 2429e58f52dSBen Widawsky enum reg_type type) 2439e58f52dSBen Widawsky { 2449e58f52dSBen Widawsky int caps = 0; 2459e58f52dSBen Widawsky 2469e58f52dSBen Widawsky /* 2479e58f52dSBen Widawsky * In CXL 2.0 the capabilities required for each CXL component are such that, 2489e58f52dSBen Widawsky * with the ordering chosen here, a single number can be used to define 2499e58f52dSBen Widawsky * which capabilities should be provided. 2509e58f52dSBen Widawsky */ 2519e58f52dSBen Widawsky switch (type) { 2529e58f52dSBen Widawsky case CXL2_DOWNSTREAM_PORT: 2539e58f52dSBen Widawsky case CXL2_DEVICE: 2549e58f52dSBen Widawsky /* RAS, Link */ 2559e58f52dSBen Widawsky caps = 2; 2569e58f52dSBen Widawsky break; 2579e58f52dSBen Widawsky case CXL2_UPSTREAM_PORT: 2589e58f52dSBen Widawsky case CXL2_TYPE3_DEVICE: 2599e58f52dSBen Widawsky case CXL2_LOGICAL_DEVICE: 2609e58f52dSBen Widawsky /* + HDM */ 2619e58f52dSBen Widawsky caps = 3; 2629e58f52dSBen Widawsky break; 2639e58f52dSBen Widawsky case CXL2_ROOT_PORT: 2649e58f52dSBen Widawsky /* + Extended Security, + Snoop */ 2659e58f52dSBen Widawsky caps = 5; 2669e58f52dSBen Widawsky break; 2679e58f52dSBen Widawsky default: 2689e58f52dSBen Widawsky abort(); 2699e58f52dSBen Widawsky } 2709e58f52dSBen Widawsky 2719e58f52dSBen Widawsky memset(reg_state, 0, CXL2_COMPONENT_CM_REGION_SIZE); 2729e58f52dSBen Widawsky 2739e58f52dSBen Widawsky /* CXL Capability Header Register */ 2749e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, ID, 1); 2759e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, VERSION, 1); 2769e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, CACHE_MEM_VERSION, 1); 2779e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, ARRAY_SIZE, caps); 2789e58f52dSBen Widawsky 2799e58f52dSBen Widawsky #define init_cap_reg(reg, id, version) \ 2809e58f52dSBen Widawsky QEMU_BUILD_BUG_ON(CXL_##reg##_REGISTERS_OFFSET == 0); \ 2819e58f52dSBen Widawsky do { \ 2829e58f52dSBen Widawsky int which = R_CXL_##reg##_CAPABILITY_HEADER; \ 2839e58f52dSBen Widawsky reg_state[which] = FIELD_DP32(reg_state[which], \ 2849e58f52dSBen Widawsky CXL_##reg##_CAPABILITY_HEADER, ID, id); \ 2859e58f52dSBen Widawsky reg_state[which] = \ 2869e58f52dSBen Widawsky FIELD_DP32(reg_state[which], CXL_##reg##_CAPABILITY_HEADER, \ 2879e58f52dSBen Widawsky VERSION, version); \ 2889e58f52dSBen Widawsky reg_state[which] = \ 2899e58f52dSBen Widawsky FIELD_DP32(reg_state[which], CXL_##reg##_CAPABILITY_HEADER, PTR, \ 2909e58f52dSBen Widawsky CXL_##reg##_REGISTERS_OFFSET); \ 2919e58f52dSBen Widawsky } while (0) 2929e58f52dSBen Widawsky 2939e58f52dSBen Widawsky init_cap_reg(RAS, 2, 2); 2949e58f52dSBen Widawsky ras_init_common(reg_state, write_msk); 2959e58f52dSBen Widawsky 2969e58f52dSBen Widawsky init_cap_reg(LINK, 4, 2); 2979e58f52dSBen Widawsky 2989e58f52dSBen Widawsky if (caps < 3) { 2999e58f52dSBen Widawsky return; 3009e58f52dSBen Widawsky } 3019e58f52dSBen Widawsky 3029e58f52dSBen Widawsky init_cap_reg(HDM, 5, 1); 303f824f529SJonathan Cameron hdm_init_common(reg_state, write_msk, type); 3049e58f52dSBen Widawsky 3059e58f52dSBen Widawsky if (caps < 5) { 3069e58f52dSBen Widawsky return; 3079e58f52dSBen Widawsky } 3089e58f52dSBen Widawsky 3099e58f52dSBen Widawsky init_cap_reg(EXTSEC, 6, 1); 3109e58f52dSBen Widawsky init_cap_reg(SNOOP, 8, 1); 3119e58f52dSBen Widawsky 3129e58f52dSBen Widawsky #undef init_cap_reg 3139e58f52dSBen Widawsky } 3149e58f52dSBen Widawsky 3159e58f52dSBen Widawsky /* 3169e58f52dSBen Widawsky * Helper to creates a DVSEC header for a CXL entity. The caller is responsible 3179e58f52dSBen Widawsky * for tracking the valid offset. 3189e58f52dSBen Widawsky * 3199e58f52dSBen Widawsky * This function will build the DVSEC header on behalf of the caller and then 3209e58f52dSBen Widawsky * copy in the remaining data for the vendor specific bits. 3219e58f52dSBen Widawsky * It will also set up appropriate write masks. 3229e58f52dSBen Widawsky */ 3239e58f52dSBen Widawsky void cxl_component_create_dvsec(CXLComponentState *cxl, 3249e58f52dSBen Widawsky enum reg_type cxl_dev_type, uint16_t length, 3259e58f52dSBen Widawsky uint16_t type, uint8_t rev, uint8_t *body) 3269e58f52dSBen Widawsky { 3279e58f52dSBen Widawsky PCIDevice *pdev = cxl->pdev; 3289e58f52dSBen Widawsky uint16_t offset = cxl->dvsec_offset; 3299e58f52dSBen Widawsky uint8_t *wmask = pdev->wmask; 3309e58f52dSBen Widawsky 3319e58f52dSBen Widawsky assert(offset >= PCI_CFG_SPACE_SIZE && 3329e58f52dSBen Widawsky ((offset + length) < PCI_CFG_SPACE_EXP_SIZE)); 3339e58f52dSBen Widawsky assert((length & 0xf000) == 0); 3349e58f52dSBen Widawsky assert((rev & ~0xf) == 0); 3359e58f52dSBen Widawsky 3369e58f52dSBen Widawsky /* Create the DVSEC in the MCFG space */ 3379e58f52dSBen Widawsky pcie_add_capability(pdev, PCI_EXT_CAP_ID_DVSEC, 1, offset, length); 3389e58f52dSBen Widawsky pci_set_long(pdev->config + offset + PCIE_DVSEC_HEADER1_OFFSET, 3399e58f52dSBen Widawsky (length << 20) | (rev << 16) | CXL_VENDOR_ID); 3409e58f52dSBen Widawsky pci_set_word(pdev->config + offset + PCIE_DVSEC_ID_OFFSET, type); 3419e58f52dSBen Widawsky memcpy(pdev->config + offset + sizeof(DVSECHeader), 3429e58f52dSBen Widawsky body + sizeof(DVSECHeader), 3439e58f52dSBen Widawsky length - sizeof(DVSECHeader)); 3449e58f52dSBen Widawsky 3459e58f52dSBen Widawsky /* Configure write masks */ 3469e58f52dSBen Widawsky switch (type) { 3479e58f52dSBen Widawsky case PCIE_CXL_DEVICE_DVSEC: 348e1706ea8SBen Widawsky /* Cntrl RW Lock - so needs explicit blocking when lock is set */ 349e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, ctrl)] = 0xFD; 350e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, ctrl) + 1] = 0x4F; 351e1706ea8SBen Widawsky /* Status is RW1CS */ 352e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, ctrl2)] = 0x0F; 353e1706ea8SBen Widawsky /* Lock is RW Once */ 354e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, lock)] = 0x01; 355e1706ea8SBen Widawsky /* range1/2_base_high/low is RW Lock */ 356e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi)] = 0xFF; 357e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi) + 1] = 0xFF; 358e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi) + 2] = 0xFF; 359e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi) + 3] = 0xFF; 360e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range1_base_lo) + 3] = 0xF0; 361e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi)] = 0xFF; 362e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi) + 1] = 0xFF; 363e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi) + 2] = 0xFF; 364e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi) + 3] = 0xFF; 365e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range2_base_lo) + 3] = 0xF0; 3669e58f52dSBen Widawsky break; 3679e58f52dSBen Widawsky case NON_CXL_FUNCTION_MAP_DVSEC: 3689e58f52dSBen Widawsky break; /* Not yet implemented */ 3699e58f52dSBen Widawsky case EXTENSIONS_PORT_DVSEC: 3709e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, control)] = 0x0F; 3719e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, control) + 1] = 0x40; 3729e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_bus_base)] = 0xFF; 3739e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_bus_limit)] = 0xFF; 3749e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_memory_base)] = 0xF0; 3759e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_memory_base) + 1] = 0xFF; 3769e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_memory_limit)] = 0xF0; 3779e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_memory_limit) + 1] = 0xFF; 3789e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base)] = 0xF0; 3799e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base) + 1] = 0xFF; 3809e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit)] = 0xF0; 3819e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit) + 1] = 0xFF; 3829e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base_high)] = 0xFF; 3839e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base_high) + 1] = 0xFF; 3849e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base_high) + 2] = 0xFF; 3859e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_base_high) + 3] = 0xFF; 3869e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit_high)] = 0xFF; 3879e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit_high) + 1] = 0xFF; 3889e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit_high) + 2] = 0xFF; 3899e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortExtensions, alt_prefetch_limit_high) + 3] = 0xFF; 3909e58f52dSBen Widawsky break; 3919e58f52dSBen Widawsky case GPF_PORT_DVSEC: 3929e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortGPF, phase1_ctrl)] = 0x0F; 3939e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortGPF, phase1_ctrl) + 1] = 0x0F; 3949e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortGPF, phase2_ctrl)] = 0x0F; 3959e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortGPF, phase2_ctrl) + 1] = 0x0F; 3969e58f52dSBen Widawsky break; 3979e58f52dSBen Widawsky case GPF_DEVICE_DVSEC: 3989e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_duration)] = 0x0F; 3999e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_duration) + 1] = 0x0F; 4009e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power)] = 0xFF; 4019e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power) + 1] = 0xFF; 4029e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power) + 2] = 0xFF; 4039e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power) + 3] = 0xFF; 4049e58f52dSBen Widawsky break; 4059e58f52dSBen Widawsky case PCIE_FLEXBUS_PORT_DVSEC: 4069e58f52dSBen Widawsky switch (cxl_dev_type) { 4079e58f52dSBen Widawsky case CXL2_ROOT_PORT: 4089e58f52dSBen Widawsky /* No MLD */ 4099e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortFlexBus, ctrl)] = 0xbd; 4109e58f52dSBen Widawsky break; 4119e58f52dSBen Widawsky case CXL2_DOWNSTREAM_PORT: 4129e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortFlexBus, ctrl)] = 0xfd; 4139e58f52dSBen Widawsky break; 4149e58f52dSBen Widawsky default: /* Registers are RO for other component types */ 4159e58f52dSBen Widawsky break; 4169e58f52dSBen Widawsky } 4179e58f52dSBen Widawsky /* There are rw1cs bits in the status register but never set currently */ 4189e58f52dSBen Widawsky break; 4199e58f52dSBen Widawsky } 4209e58f52dSBen Widawsky 4219e58f52dSBen Widawsky /* Update state for future DVSEC additions */ 4229e58f52dSBen Widawsky range_init_nofail(&cxl->dvsecs[type], cxl->dvsec_offset, length); 4239e58f52dSBen Widawsky cxl->dvsec_offset += length; 4249e58f52dSBen Widawsky } 425829de299SJonathan Cameron 426*87de174aSJonathan Cameron /* CXL r3.0 Section 8.2.4.19.7 CXL HDM Decoder n Control Register */ 427829de299SJonathan Cameron uint8_t cxl_interleave_ways_enc(int iw, Error **errp) 428829de299SJonathan Cameron { 429829de299SJonathan Cameron switch (iw) { 430829de299SJonathan Cameron case 1: return 0x0; 431829de299SJonathan Cameron case 2: return 0x1; 432829de299SJonathan Cameron case 4: return 0x2; 433829de299SJonathan Cameron case 8: return 0x3; 434829de299SJonathan Cameron case 16: return 0x4; 435829de299SJonathan Cameron case 3: return 0x8; 436829de299SJonathan Cameron case 6: return 0x9; 437829de299SJonathan Cameron case 12: return 0xa; 438829de299SJonathan Cameron default: 439829de299SJonathan Cameron error_setg(errp, "Interleave ways: %d not supported", iw); 440829de299SJonathan Cameron return 0; 441829de299SJonathan Cameron } 442829de299SJonathan Cameron } 443829de299SJonathan Cameron 444*87de174aSJonathan Cameron int cxl_interleave_ways_dec(uint8_t iw_enc, Error **errp) 445*87de174aSJonathan Cameron { 446*87de174aSJonathan Cameron switch (iw_enc) { 447*87de174aSJonathan Cameron case 0x0: return 1; 448*87de174aSJonathan Cameron case 0x1: return 2; 449*87de174aSJonathan Cameron case 0x2: return 4; 450*87de174aSJonathan Cameron case 0x3: return 8; 451*87de174aSJonathan Cameron case 0x4: return 16; 452*87de174aSJonathan Cameron case 0x8: return 3; 453*87de174aSJonathan Cameron case 0x9: return 6; 454*87de174aSJonathan Cameron case 0xa: return 12; 455*87de174aSJonathan Cameron default: 456*87de174aSJonathan Cameron error_setg(errp, "Encoded interleave ways: %d not supported", iw_enc); 457*87de174aSJonathan Cameron return 0; 458*87de174aSJonathan Cameron } 459*87de174aSJonathan Cameron } 460*87de174aSJonathan Cameron 461829de299SJonathan Cameron uint8_t cxl_interleave_granularity_enc(uint64_t gran, Error **errp) 462829de299SJonathan Cameron { 463829de299SJonathan Cameron switch (gran) { 464829de299SJonathan Cameron case 256: return 0; 465829de299SJonathan Cameron case 512: return 1; 466829de299SJonathan Cameron case 1024: return 2; 467829de299SJonathan Cameron case 2048: return 3; 468829de299SJonathan Cameron case 4096: return 4; 469829de299SJonathan Cameron case 8192: return 5; 470829de299SJonathan Cameron case 16384: return 6; 471829de299SJonathan Cameron default: 472829de299SJonathan Cameron error_setg(errp, "Interleave granularity: %" PRIu64 " invalid", gran); 473829de299SJonathan Cameron return 0; 474829de299SJonathan Cameron } 475829de299SJonathan Cameron } 476