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 1687de174aSJonathan 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) { 2087de174aSJonathan Cameron case 1: return 0x0; 2187de174aSJonathan Cameron case 2: return 0x1; 2287de174aSJonathan Cameron case 4: return 0x2; 2387de174aSJonathan Cameron case 6: return 0x3; 2487de174aSJonathan Cameron case 8: return 0x4; 2587de174aSJonathan Cameron case 10: return 0x5; 2687de174aSJonathan Cameron /* Switches and Host Bridges may have more than 10 decoders */ 2787de174aSJonathan Cameron case 12: return 0x6; 2887de174aSJonathan Cameron case 14: return 0x7; 2987de174aSJonathan Cameron case 16: return 0x8; 3087de174aSJonathan Cameron case 20: return 0x9; 3187de174aSJonathan Cameron case 24: return 0xa; 3287de174aSJonathan Cameron case 28: return 0xb; 3387de174aSJonathan Cameron case 32: return 0xc; 3487de174aSJonathan Cameron } 3587de174aSJonathan Cameron return 0; 3687de174aSJonathan Cameron } 3787de174aSJonathan Cameron 3887de174aSJonathan Cameron int cxl_decoder_count_dec(int enc_cnt) 3987de174aSJonathan Cameron { 4087de174aSJonathan Cameron switch (enc_cnt) { 4187de174aSJonathan Cameron case 0x0: return 1; 4287de174aSJonathan Cameron case 0x1: return 2; 4387de174aSJonathan Cameron case 0x2: return 4; 4487de174aSJonathan Cameron case 0x3: return 6; 4587de174aSJonathan Cameron case 0x4: return 8; 4687de174aSJonathan Cameron case 0x5: return 10; 4787de174aSJonathan Cameron /* Switches and Host Bridges may have more than 10 decoders */ 4887de174aSJonathan Cameron case 0x6: return 12; 4987de174aSJonathan Cameron case 0x7: return 14; 5087de174aSJonathan Cameron case 0x8: return 16; 5187de174aSJonathan Cameron case 0x9: return 20; 5287de174aSJonathan Cameron case 0xa: return 24; 5387de174aSJonathan Cameron case 0xb: return 28; 5487de174aSJonathan 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 70388d6b57SJonathan Cameron switch (size) { 71388d6b57SJonathan Cameron case 4: 72388d6b57SJonathan Cameron if (cregs->special_ops && cregs->special_ops->read) { 73388d6b57SJonathan Cameron return cregs->special_ops->read(cxl_cstate, offset, 4); 74388d6b57SJonathan Cameron } else { 75388d6b57SJonathan Cameron QEMU_BUILD_BUG_ON(sizeof(*cregs->cache_mem_registers) != 4); 76388d6b57SJonathan Cameron return cregs->cache_mem_registers[offset / 4]; 77388d6b57SJonathan Cameron } 78388d6b57SJonathan Cameron case 8: 799e58f52dSBen Widawsky qemu_log_mask(LOG_UNIMP, 809e58f52dSBen Widawsky "CXL 8 byte cache mem registers not implemented\n"); 819e58f52dSBen Widawsky return 0; 82388d6b57SJonathan Cameron default: 83388d6b57SJonathan Cameron /* 84487152faSMichael Tokarev * In line with specification limitaions on access sizes, this 85388d6b57SJonathan Cameron * routine is not called with other sizes. 86388d6b57SJonathan Cameron */ 87388d6b57SJonathan Cameron g_assert_not_reached(); 889e58f52dSBen Widawsky } 899e58f52dSBen Widawsky } 909e58f52dSBen Widawsky 913540bf56SBen Widawsky static void dumb_hdm_handler(CXLComponentState *cxl_cstate, hwaddr offset, 923540bf56SBen Widawsky uint32_t value) 933540bf56SBen Widawsky { 943540bf56SBen Widawsky ComponentRegisters *cregs = &cxl_cstate->crb; 953540bf56SBen Widawsky uint32_t *cache_mem = cregs->cache_mem_registers; 963540bf56SBen Widawsky bool should_commit = false; 97823371a6SJonathan Cameron bool should_uncommit = false; 983540bf56SBen Widawsky 993540bf56SBen Widawsky switch (offset) { 1003540bf56SBen Widawsky case A_CXL_HDM_DECODER0_CTRL: 101e967413fSJonathan Cameron case A_CXL_HDM_DECODER1_CTRL: 102e967413fSJonathan Cameron case A_CXL_HDM_DECODER2_CTRL: 103e967413fSJonathan Cameron case A_CXL_HDM_DECODER3_CTRL: 1043540bf56SBen Widawsky should_commit = FIELD_EX32(value, CXL_HDM_DECODER0_CTRL, COMMIT); 105823371a6SJonathan Cameron should_uncommit = !should_commit; 1063540bf56SBen Widawsky break; 1073540bf56SBen Widawsky default: 1083540bf56SBen Widawsky break; 1093540bf56SBen Widawsky } 1103540bf56SBen Widawsky 1113540bf56SBen Widawsky if (should_commit) { 11292ff7cabSJonathan Cameron value = FIELD_DP32(value, CXL_HDM_DECODER0_CTRL, ERR, 0); 11392ff7cabSJonathan Cameron value = FIELD_DP32(value, CXL_HDM_DECODER0_CTRL, COMMITTED, 1); 114823371a6SJonathan Cameron } else if (should_uncommit) { 115823371a6SJonathan Cameron value = FIELD_DP32(value, CXL_HDM_DECODER0_CTRL, ERR, 0); 116823371a6SJonathan Cameron value = FIELD_DP32(value, CXL_HDM_DECODER0_CTRL, COMMITTED, 0); 1173540bf56SBen Widawsky } 11892ff7cabSJonathan Cameron stl_le_p((uint8_t *)cache_mem + offset, value); 1193540bf56SBen Widawsky } 1203540bf56SBen Widawsky 1219e58f52dSBen Widawsky static void cxl_cache_mem_write_reg(void *opaque, hwaddr offset, uint64_t value, 1229e58f52dSBen Widawsky unsigned size) 1239e58f52dSBen Widawsky { 1249e58f52dSBen Widawsky CXLComponentState *cxl_cstate = opaque; 1259e58f52dSBen Widawsky ComponentRegisters *cregs = &cxl_cstate->crb; 1269e58f52dSBen Widawsky uint32_t mask; 1279e58f52dSBen Widawsky 128388d6b57SJonathan Cameron switch (size) { 129388d6b57SJonathan Cameron case 4: { 130388d6b57SJonathan Cameron QEMU_BUILD_BUG_ON(sizeof(*cregs->cache_mem_regs_write_mask) != 4); 131388d6b57SJonathan Cameron QEMU_BUILD_BUG_ON(sizeof(*cregs->cache_mem_registers) != 4); 132388d6b57SJonathan Cameron mask = cregs->cache_mem_regs_write_mask[offset / 4]; 1339e58f52dSBen Widawsky value &= mask; 1349e58f52dSBen Widawsky /* RO bits should remain constant. Done by reading existing value */ 135388d6b57SJonathan Cameron value |= ~mask & cregs->cache_mem_registers[offset / 4]; 1369e58f52dSBen Widawsky if (cregs->special_ops && cregs->special_ops->write) { 1379e58f52dSBen Widawsky cregs->special_ops->write(cxl_cstate, offset, value, size); 1383540bf56SBen Widawsky return; 1393540bf56SBen Widawsky } 1403540bf56SBen Widawsky 1413540bf56SBen Widawsky if (offset >= A_CXL_HDM_DECODER_CAPABILITY && 142e967413fSJonathan Cameron offset <= A_CXL_HDM_DECODER3_TARGET_LIST_HI) { 1433540bf56SBen Widawsky dumb_hdm_handler(cxl_cstate, offset, value); 1449e58f52dSBen Widawsky } else { 145388d6b57SJonathan Cameron cregs->cache_mem_registers[offset / 4] = value; 146388d6b57SJonathan Cameron } 147388d6b57SJonathan Cameron return; 148388d6b57SJonathan Cameron } 149388d6b57SJonathan Cameron case 8: 150388d6b57SJonathan Cameron qemu_log_mask(LOG_UNIMP, 151388d6b57SJonathan Cameron "CXL 8 byte cache mem registers not implemented\n"); 152388d6b57SJonathan Cameron return; 153388d6b57SJonathan Cameron default: 154388d6b57SJonathan Cameron /* 155487152faSMichael Tokarev * In line with specification limitaions on access sizes, this 156388d6b57SJonathan Cameron * routine is not called with other sizes. 157388d6b57SJonathan Cameron */ 158388d6b57SJonathan Cameron g_assert_not_reached(); 1599e58f52dSBen Widawsky } 1609e58f52dSBen Widawsky } 1619e58f52dSBen Widawsky 1629e58f52dSBen Widawsky /* 1639e58f52dSBen Widawsky * 8.2.3 1649e58f52dSBen Widawsky * The access restrictions specified in Section 8.2.2 also apply to CXL 2.0 1659e58f52dSBen Widawsky * Component Registers. 1669e58f52dSBen Widawsky * 1679e58f52dSBen Widawsky * 8.2.2 1689e58f52dSBen Widawsky * • A 32 bit register shall be accessed as a 4 Bytes quantity. Partial 1699e58f52dSBen Widawsky * reads are not permitted. 1709e58f52dSBen Widawsky * • A 64 bit register shall be accessed as a 8 Bytes quantity. Partial 1719e58f52dSBen Widawsky * reads are not permitted. 1729e58f52dSBen Widawsky * 1739e58f52dSBen Widawsky * As of the spec defined today, only 4 byte registers exist. 1749e58f52dSBen Widawsky */ 1759e58f52dSBen Widawsky static const MemoryRegionOps cache_mem_ops = { 1769e58f52dSBen Widawsky .read = cxl_cache_mem_read_reg, 1779e58f52dSBen Widawsky .write = cxl_cache_mem_write_reg, 1789e58f52dSBen Widawsky .endianness = DEVICE_LITTLE_ENDIAN, 1799e58f52dSBen Widawsky .valid = { 1809e58f52dSBen Widawsky .min_access_size = 4, 1819e58f52dSBen Widawsky .max_access_size = 8, 1829e58f52dSBen Widawsky .unaligned = false, 1839e58f52dSBen Widawsky }, 1849e58f52dSBen Widawsky .impl = { 1859e58f52dSBen Widawsky .min_access_size = 4, 1869e58f52dSBen Widawsky .max_access_size = 8, 1879e58f52dSBen Widawsky }, 1889e58f52dSBen Widawsky }; 1899e58f52dSBen Widawsky 1909e58f52dSBen Widawsky void cxl_component_register_block_init(Object *obj, 1919e58f52dSBen Widawsky CXLComponentState *cxl_cstate, 1929e58f52dSBen Widawsky const char *type) 1939e58f52dSBen Widawsky { 1949e58f52dSBen Widawsky ComponentRegisters *cregs = &cxl_cstate->crb; 1959e58f52dSBen Widawsky 1969e58f52dSBen Widawsky memory_region_init(&cregs->component_registers, obj, type, 1979e58f52dSBen Widawsky CXL2_COMPONENT_BLOCK_SIZE); 1989e58f52dSBen Widawsky 1999e58f52dSBen Widawsky /* io registers controls link which we don't care about in QEMU */ 200f8b02dd6SLi Zhijian memory_region_init_io(&cregs->io, obj, NULL, NULL, ".io", 2019e58f52dSBen Widawsky CXL2_COMPONENT_IO_REGION_SIZE); 202729d45a6SLi Zhijian memory_region_init_io(&cregs->cache_mem, obj, &cache_mem_ops, cxl_cstate, 2039e58f52dSBen Widawsky ".cache_mem", CXL2_COMPONENT_CM_REGION_SIZE); 2049e58f52dSBen Widawsky 2059e58f52dSBen Widawsky memory_region_add_subregion(&cregs->component_registers, 0, &cregs->io); 2069e58f52dSBen Widawsky memory_region_add_subregion(&cregs->component_registers, 2079e58f52dSBen Widawsky CXL2_COMPONENT_IO_REGION_SIZE, 2089e58f52dSBen Widawsky &cregs->cache_mem); 2099e58f52dSBen Widawsky } 2109e58f52dSBen Widawsky 2119e58f52dSBen Widawsky static void ras_init_common(uint32_t *reg_state, uint32_t *write_msk) 2129e58f52dSBen Widawsky { 2139e58f52dSBen Widawsky /* 2149e58f52dSBen Widawsky * Error status is RW1C but given bits are not yet set, it can 2159e58f52dSBen Widawsky * be handled as RO. 2169e58f52dSBen Widawsky */ 217cb4e642cSJonathan Cameron stl_le_p(reg_state + R_CXL_RAS_UNC_ERR_STATUS, 0); 218415442a1SJonathan Cameron stl_le_p(write_msk + R_CXL_RAS_UNC_ERR_STATUS, 0x1cfff); 2199e58f52dSBen Widawsky /* Bits 12-13 and 17-31 reserved in CXL 2.0 */ 220cb4e642cSJonathan Cameron stl_le_p(reg_state + R_CXL_RAS_UNC_ERR_MASK, 0x1cfff); 221cb4e642cSJonathan Cameron stl_le_p(write_msk + R_CXL_RAS_UNC_ERR_MASK, 0x1cfff); 222cb4e642cSJonathan Cameron stl_le_p(reg_state + R_CXL_RAS_UNC_ERR_SEVERITY, 0x1cfff); 223cb4e642cSJonathan Cameron stl_le_p(write_msk + R_CXL_RAS_UNC_ERR_SEVERITY, 0x1cfff); 224cb4e642cSJonathan Cameron stl_le_p(reg_state + R_CXL_RAS_COR_ERR_STATUS, 0); 225415442a1SJonathan Cameron stl_le_p(write_msk + R_CXL_RAS_COR_ERR_STATUS, 0x7f); 226cb4e642cSJonathan Cameron stl_le_p(reg_state + R_CXL_RAS_COR_ERR_MASK, 0x7f); 227cb4e642cSJonathan Cameron stl_le_p(write_msk + R_CXL_RAS_COR_ERR_MASK, 0x7f); 2289e58f52dSBen Widawsky /* CXL switches and devices must set */ 229415442a1SJonathan Cameron stl_le_p(reg_state + R_CXL_RAS_ERR_CAP_CTRL, 0x200); 2309e58f52dSBen Widawsky } 2319e58f52dSBen Widawsky 232f824f529SJonathan Cameron static void hdm_init_common(uint32_t *reg_state, uint32_t *write_msk, 233f824f529SJonathan Cameron enum reg_type type) 2349e58f52dSBen Widawsky { 235e967413fSJonathan Cameron int decoder_count = CXL_HDM_DECODER_COUNT; 23661c44bcfSJonathan Cameron int hdm_inc = R_CXL_HDM_DECODER1_BASE_LO - R_CXL_HDM_DECODER0_BASE_LO; 2379e58f52dSBen Widawsky int i; 2389e58f52dSBen Widawsky 2399e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, DECODER_COUNT, 2409e58f52dSBen Widawsky cxl_decoder_count_enc(decoder_count)); 2419e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, TARGET_COUNT, 1); 2429e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, INTERLEAVE_256B, 1); 2439e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, INTERLEAVE_4K, 1); 244b342489aSJonathan Cameron ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, 245b342489aSJonathan Cameron POISON_ON_ERR_CAP, 0); 246ae243dbfSJonathan Cameron ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, 3_6_12_WAY, 0); 247ae243dbfSJonathan Cameron ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, 16_WAY, 0); 248ae243dbfSJonathan Cameron ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, UIO, 0); 249ae243dbfSJonathan Cameron ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, 250ae243dbfSJonathan Cameron UIO_DECODER_COUNT, 0); 251ae243dbfSJonathan Cameron ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, MEMDATA_NXM_CAP, 0); 252ae243dbfSJonathan Cameron ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_CAPABILITY, 253ae243dbfSJonathan Cameron SUPPORTED_COHERENCY_MODEL, 0); /* Unknown */ 2549e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_HDM_DECODER_GLOBAL_CONTROL, 2559e58f52dSBen Widawsky HDM_DECODER_ENABLE, 0); 2569e58f52dSBen Widawsky write_msk[R_CXL_HDM_DECODER_GLOBAL_CONTROL] = 0x3; 2579e58f52dSBen Widawsky for (i = 0; i < decoder_count; i++) { 25861c44bcfSJonathan Cameron write_msk[R_CXL_HDM_DECODER0_BASE_LO + i * hdm_inc] = 0xf0000000; 25961c44bcfSJonathan Cameron write_msk[R_CXL_HDM_DECODER0_BASE_HI + i * hdm_inc] = 0xffffffff; 26061c44bcfSJonathan Cameron write_msk[R_CXL_HDM_DECODER0_SIZE_LO + i * hdm_inc] = 0xf0000000; 26161c44bcfSJonathan Cameron write_msk[R_CXL_HDM_DECODER0_SIZE_HI + i * hdm_inc] = 0xffffffff; 26261c44bcfSJonathan Cameron write_msk[R_CXL_HDM_DECODER0_CTRL + i * hdm_inc] = 0x13ff; 263f824f529SJonathan Cameron if (type == CXL2_DEVICE || 264f824f529SJonathan Cameron type == CXL2_TYPE3_DEVICE || 265f824f529SJonathan Cameron type == CXL2_LOGICAL_DEVICE) { 26661c44bcfSJonathan Cameron write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_LO + i * hdm_inc] = 26761c44bcfSJonathan Cameron 0xf0000000; 268f824f529SJonathan Cameron } else { 26961c44bcfSJonathan Cameron write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_LO + i * hdm_inc] = 27061c44bcfSJonathan Cameron 0xffffffff; 271f824f529SJonathan Cameron } 27261c44bcfSJonathan Cameron write_msk[R_CXL_HDM_DECODER0_TARGET_LIST_HI + i * hdm_inc] = 0xffffffff; 2739e58f52dSBen Widawsky } 2749e58f52dSBen Widawsky } 2759e58f52dSBen Widawsky 276b342489aSJonathan Cameron void cxl_component_register_init_common(uint32_t *reg_state, 277b342489aSJonathan Cameron uint32_t *write_msk, 2789e58f52dSBen Widawsky enum reg_type type) 2799e58f52dSBen Widawsky { 2809e58f52dSBen Widawsky int caps = 0; 2819e58f52dSBen Widawsky 2829e58f52dSBen Widawsky /* 283b342489aSJonathan Cameron * In CXL 2.0 the capabilities required for each CXL component are such 284b342489aSJonathan Cameron * that, with the ordering chosen here, a single number can be used to 285b342489aSJonathan Cameron * define which capabilities should be provided. 2869e58f52dSBen Widawsky */ 2879e58f52dSBen Widawsky switch (type) { 2889e58f52dSBen Widawsky case CXL2_DOWNSTREAM_PORT: 2899e58f52dSBen Widawsky case CXL2_DEVICE: 2909e58f52dSBen Widawsky /* RAS, Link */ 2919e58f52dSBen Widawsky caps = 2; 2929e58f52dSBen Widawsky break; 2939e58f52dSBen Widawsky case CXL2_UPSTREAM_PORT: 2949e58f52dSBen Widawsky case CXL2_TYPE3_DEVICE: 2959e58f52dSBen Widawsky case CXL2_LOGICAL_DEVICE: 2969e58f52dSBen Widawsky /* + HDM */ 2979e58f52dSBen Widawsky caps = 3; 2989e58f52dSBen Widawsky break; 2999e58f52dSBen Widawsky case CXL2_ROOT_PORT: 3009e58f52dSBen Widawsky /* + Extended Security, + Snoop */ 3019e58f52dSBen Widawsky caps = 5; 3029e58f52dSBen Widawsky break; 3039e58f52dSBen Widawsky default: 3049e58f52dSBen Widawsky abort(); 3059e58f52dSBen Widawsky } 3069e58f52dSBen Widawsky 3079e58f52dSBen Widawsky memset(reg_state, 0, CXL2_COMPONENT_CM_REGION_SIZE); 3089e58f52dSBen Widawsky 3099e58f52dSBen Widawsky /* CXL Capability Header Register */ 3109e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, ID, 1); 3119e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, VERSION, 1); 3129e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, CACHE_MEM_VERSION, 1); 3139e58f52dSBen Widawsky ARRAY_FIELD_DP32(reg_state, CXL_CAPABILITY_HEADER, ARRAY_SIZE, caps); 3149e58f52dSBen Widawsky 3159e58f52dSBen Widawsky #define init_cap_reg(reg, id, version) \ 3169e58f52dSBen Widawsky do { \ 3179e58f52dSBen Widawsky int which = R_CXL_##reg##_CAPABILITY_HEADER; \ 3189e58f52dSBen Widawsky reg_state[which] = FIELD_DP32(reg_state[which], \ 3199e58f52dSBen Widawsky CXL_##reg##_CAPABILITY_HEADER, ID, id); \ 3209e58f52dSBen Widawsky reg_state[which] = \ 3219e58f52dSBen Widawsky FIELD_DP32(reg_state[which], CXL_##reg##_CAPABILITY_HEADER, \ 3229e58f52dSBen Widawsky VERSION, version); \ 3239e58f52dSBen Widawsky reg_state[which] = \ 3249e58f52dSBen Widawsky FIELD_DP32(reg_state[which], CXL_##reg##_CAPABILITY_HEADER, PTR, \ 3259e58f52dSBen Widawsky CXL_##reg##_REGISTERS_OFFSET); \ 3269e58f52dSBen Widawsky } while (0) 3279e58f52dSBen Widawsky 328*a185ff05SJonathan Cameron init_cap_reg(RAS, 2, CXL_RAS_CAPABILITY_VERSION); 3299e58f52dSBen Widawsky ras_init_common(reg_state, write_msk); 3309e58f52dSBen Widawsky 3319e58f52dSBen Widawsky init_cap_reg(LINK, 4, 2); 3329e58f52dSBen Widawsky 3339e58f52dSBen Widawsky if (caps < 3) { 3349e58f52dSBen Widawsky return; 3359e58f52dSBen Widawsky } 3369e58f52dSBen Widawsky 337ae243dbfSJonathan Cameron init_cap_reg(HDM, 5, CXL_HDM_CAPABILITY_VERSION); 338f824f529SJonathan Cameron hdm_init_common(reg_state, write_msk, type); 3399e58f52dSBen Widawsky 3409e58f52dSBen Widawsky if (caps < 5) { 3419e58f52dSBen Widawsky return; 3429e58f52dSBen Widawsky } 3439e58f52dSBen Widawsky 3449e58f52dSBen Widawsky init_cap_reg(EXTSEC, 6, 1); 3459e58f52dSBen Widawsky init_cap_reg(SNOOP, 8, 1); 3469e58f52dSBen Widawsky 3479e58f52dSBen Widawsky #undef init_cap_reg 3489e58f52dSBen Widawsky } 3499e58f52dSBen Widawsky 3509e58f52dSBen Widawsky /* 3519e58f52dSBen Widawsky * Helper to creates a DVSEC header for a CXL entity. The caller is responsible 3529e58f52dSBen Widawsky * for tracking the valid offset. 3539e58f52dSBen Widawsky * 3549e58f52dSBen Widawsky * This function will build the DVSEC header on behalf of the caller and then 3559e58f52dSBen Widawsky * copy in the remaining data for the vendor specific bits. 3569e58f52dSBen Widawsky * It will also set up appropriate write masks. 3579e58f52dSBen Widawsky */ 3589e58f52dSBen Widawsky void cxl_component_create_dvsec(CXLComponentState *cxl, 3599e58f52dSBen Widawsky enum reg_type cxl_dev_type, uint16_t length, 3609e58f52dSBen Widawsky uint16_t type, uint8_t rev, uint8_t *body) 3619e58f52dSBen Widawsky { 3629e58f52dSBen Widawsky PCIDevice *pdev = cxl->pdev; 3639e58f52dSBen Widawsky uint16_t offset = cxl->dvsec_offset; 3649e58f52dSBen Widawsky uint8_t *wmask = pdev->wmask; 3659e58f52dSBen Widawsky 3669e58f52dSBen Widawsky assert(offset >= PCI_CFG_SPACE_SIZE && 3679e58f52dSBen Widawsky ((offset + length) < PCI_CFG_SPACE_EXP_SIZE)); 3689e58f52dSBen Widawsky assert((length & 0xf000) == 0); 3699e58f52dSBen Widawsky assert((rev & ~0xf) == 0); 3709e58f52dSBen Widawsky 3719e58f52dSBen Widawsky /* Create the DVSEC in the MCFG space */ 3729e58f52dSBen Widawsky pcie_add_capability(pdev, PCI_EXT_CAP_ID_DVSEC, 1, offset, length); 3739e58f52dSBen Widawsky pci_set_long(pdev->config + offset + PCIE_DVSEC_HEADER1_OFFSET, 3749e58f52dSBen Widawsky (length << 20) | (rev << 16) | CXL_VENDOR_ID); 3759e58f52dSBen Widawsky pci_set_word(pdev->config + offset + PCIE_DVSEC_ID_OFFSET, type); 3769e58f52dSBen Widawsky memcpy(pdev->config + offset + sizeof(DVSECHeader), 3779e58f52dSBen Widawsky body + sizeof(DVSECHeader), 3789e58f52dSBen Widawsky length - sizeof(DVSECHeader)); 3799e58f52dSBen Widawsky 3809e58f52dSBen Widawsky /* Configure write masks */ 3819e58f52dSBen Widawsky switch (type) { 3829e58f52dSBen Widawsky case PCIE_CXL_DEVICE_DVSEC: 383e1706ea8SBen Widawsky /* Cntrl RW Lock - so needs explicit blocking when lock is set */ 384e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, ctrl)] = 0xFD; 385e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, ctrl) + 1] = 0x4F; 386e1706ea8SBen Widawsky /* Status is RW1CS */ 387e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, ctrl2)] = 0x0F; 388e1706ea8SBen Widawsky /* Lock is RW Once */ 389e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, lock)] = 0x01; 390e1706ea8SBen Widawsky /* range1/2_base_high/low is RW Lock */ 391e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi)] = 0xFF; 392e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi) + 1] = 0xFF; 393e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi) + 2] = 0xFF; 394e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range1_base_hi) + 3] = 0xFF; 395e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range1_base_lo) + 3] = 0xF0; 396e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi)] = 0xFF; 397e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi) + 1] = 0xFF; 398e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi) + 2] = 0xFF; 399e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range2_base_hi) + 3] = 0xFF; 400e1706ea8SBen Widawsky wmask[offset + offsetof(CXLDVSECDevice, range2_base_lo) + 3] = 0xF0; 4019e58f52dSBen Widawsky break; 4029e58f52dSBen Widawsky case NON_CXL_FUNCTION_MAP_DVSEC: 4039e58f52dSBen Widawsky break; /* Not yet implemented */ 4049e58f52dSBen Widawsky case EXTENSIONS_PORT_DVSEC: 405b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, control)] = 0x0F; 406b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, control) + 1] = 0x40; 407b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, alt_bus_base)] = 0xFF; 408b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, alt_bus_limit)] = 0xFF; 409b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, alt_memory_base)] = 0xF0; 410b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, alt_memory_base) + 1] = 0xFF; 411b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, alt_memory_limit)] = 0xF0; 412b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, alt_memory_limit) + 1] = 0xFF; 413b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, alt_prefetch_base)] = 0xF0; 414b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, alt_prefetch_base) + 1] = 0xFF; 415b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, alt_prefetch_limit)] = 0xF0; 416b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, alt_prefetch_limit) + 1] = 417b34ae3c9SJonathan Cameron 0xFF; 418b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, alt_prefetch_base_high)] = 419b34ae3c9SJonathan Cameron 0xFF; 420b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, alt_prefetch_base_high) + 1] = 421b34ae3c9SJonathan Cameron 0xFF; 422b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, alt_prefetch_base_high) + 2] = 423b34ae3c9SJonathan Cameron 0xFF; 424b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, alt_prefetch_base_high) + 3] = 425b34ae3c9SJonathan Cameron 0xFF; 426b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, alt_prefetch_limit_high)] = 427b34ae3c9SJonathan Cameron 0xFF; 428b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, alt_prefetch_limit_high) + 1] = 429b34ae3c9SJonathan Cameron 0xFF; 430b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, alt_prefetch_limit_high) + 2] = 431b34ae3c9SJonathan Cameron 0xFF; 432b34ae3c9SJonathan Cameron wmask[offset + offsetof(CXLDVSECPortExt, alt_prefetch_limit_high) + 3] = 433b34ae3c9SJonathan Cameron 0xFF; 4349e58f52dSBen Widawsky break; 4359e58f52dSBen Widawsky case GPF_PORT_DVSEC: 4369e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortGPF, phase1_ctrl)] = 0x0F; 4379e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortGPF, phase1_ctrl) + 1] = 0x0F; 4389e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortGPF, phase2_ctrl)] = 0x0F; 4399e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortGPF, phase2_ctrl) + 1] = 0x0F; 4409e58f52dSBen Widawsky break; 4419e58f52dSBen Widawsky case GPF_DEVICE_DVSEC: 4429e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_duration)] = 0x0F; 4439e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_duration) + 1] = 0x0F; 4449e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power)] = 0xFF; 4459e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power) + 1] = 0xFF; 4469e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power) + 2] = 0xFF; 4479e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECDeviceGPF, phase2_power) + 3] = 0xFF; 4489e58f52dSBen Widawsky break; 4499e58f52dSBen Widawsky case PCIE_FLEXBUS_PORT_DVSEC: 4509e58f52dSBen Widawsky switch (cxl_dev_type) { 4519e58f52dSBen Widawsky case CXL2_ROOT_PORT: 4529e58f52dSBen Widawsky /* No MLD */ 4539e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortFlexBus, ctrl)] = 0xbd; 4549e58f52dSBen Widawsky break; 4559e58f52dSBen Widawsky case CXL2_DOWNSTREAM_PORT: 4569e58f52dSBen Widawsky wmask[offset + offsetof(CXLDVSECPortFlexBus, ctrl)] = 0xfd; 4579e58f52dSBen Widawsky break; 4589e58f52dSBen Widawsky default: /* Registers are RO for other component types */ 4599e58f52dSBen Widawsky break; 4609e58f52dSBen Widawsky } 461b342489aSJonathan Cameron /* There are rw1cs bits in the status register but never set */ 4629e58f52dSBen Widawsky break; 4639e58f52dSBen Widawsky } 4649e58f52dSBen Widawsky 4659e58f52dSBen Widawsky /* Update state for future DVSEC additions */ 4669e58f52dSBen Widawsky range_init_nofail(&cxl->dvsecs[type], cxl->dvsec_offset, length); 4679e58f52dSBen Widawsky cxl->dvsec_offset += length; 4689e58f52dSBen Widawsky } 469829de299SJonathan Cameron 47087de174aSJonathan Cameron /* CXL r3.0 Section 8.2.4.19.7 CXL HDM Decoder n Control Register */ 471829de299SJonathan Cameron uint8_t cxl_interleave_ways_enc(int iw, Error **errp) 472829de299SJonathan Cameron { 473829de299SJonathan Cameron switch (iw) { 474829de299SJonathan Cameron case 1: return 0x0; 475829de299SJonathan Cameron case 2: return 0x1; 476829de299SJonathan Cameron case 4: return 0x2; 477829de299SJonathan Cameron case 8: return 0x3; 478829de299SJonathan Cameron case 16: return 0x4; 479829de299SJonathan Cameron case 3: return 0x8; 480829de299SJonathan Cameron case 6: return 0x9; 481829de299SJonathan Cameron case 12: return 0xa; 482829de299SJonathan Cameron default: 483829de299SJonathan Cameron error_setg(errp, "Interleave ways: %d not supported", iw); 484829de299SJonathan Cameron return 0; 485829de299SJonathan Cameron } 486829de299SJonathan Cameron } 487829de299SJonathan Cameron 48887de174aSJonathan Cameron int cxl_interleave_ways_dec(uint8_t iw_enc, Error **errp) 48987de174aSJonathan Cameron { 49087de174aSJonathan Cameron switch (iw_enc) { 49187de174aSJonathan Cameron case 0x0: return 1; 49287de174aSJonathan Cameron case 0x1: return 2; 49387de174aSJonathan Cameron case 0x2: return 4; 49487de174aSJonathan Cameron case 0x3: return 8; 49587de174aSJonathan Cameron case 0x4: return 16; 49687de174aSJonathan Cameron case 0x8: return 3; 49787de174aSJonathan Cameron case 0x9: return 6; 49887de174aSJonathan Cameron case 0xa: return 12; 49987de174aSJonathan Cameron default: 50087de174aSJonathan Cameron error_setg(errp, "Encoded interleave ways: %d not supported", iw_enc); 50187de174aSJonathan Cameron return 0; 50287de174aSJonathan Cameron } 50387de174aSJonathan Cameron } 50487de174aSJonathan Cameron 505829de299SJonathan Cameron uint8_t cxl_interleave_granularity_enc(uint64_t gran, Error **errp) 506829de299SJonathan Cameron { 507829de299SJonathan Cameron switch (gran) { 508829de299SJonathan Cameron case 256: return 0; 509829de299SJonathan Cameron case 512: return 1; 510829de299SJonathan Cameron case 1024: return 2; 511829de299SJonathan Cameron case 2048: return 3; 512829de299SJonathan Cameron case 4096: return 4; 513829de299SJonathan Cameron case 8192: return 5; 514829de299SJonathan Cameron case 16384: return 6; 515829de299SJonathan Cameron default: 516829de299SJonathan Cameron error_setg(errp, "Interleave granularity: %" PRIu64 " invalid", gran); 517829de299SJonathan Cameron return 0; 518829de299SJonathan Cameron } 519829de299SJonathan Cameron } 520