1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright(c) 2020 Intel Corporation. */ 3 #include <linux/io-64-nonatomic-lo-hi.h> 4 #include <linux/device.h> 5 #include <linux/slab.h> 6 #include <linux/pci.h> 7 #include <cxlmem.h> 8 #include <cxlpci.h> 9 #include <pmu.h> 10 11 #include "core.h" 12 13 /** 14 * DOC: cxl registers 15 * 16 * CXL device capabilities are enumerated by PCI DVSEC (Designated 17 * Vendor-specific) and / or descriptors provided by platform firmware. 18 * They can be defined as a set like the device and component registers 19 * mandated by CXL Section 8.1.12.2 Memory Device PCIe Capabilities and 20 * Extended Capabilities, or they can be individual capabilities 21 * appended to bridged and endpoint devices. 22 * 23 * Provide common infrastructure for enumerating and mapping these 24 * discrete capabilities. 25 */ 26 27 /** 28 * cxl_probe_component_regs() - Detect CXL Component register blocks 29 * @dev: Host device of the @base mapping 30 * @base: Mapping containing the HDM Decoder Capability Header 31 * @map: Map object describing the register block information found 32 * 33 * See CXL 2.0 8.2.4 Component Register Layout and Definition 34 * See CXL 2.0 8.2.5.5 CXL Device Register Interface 35 * 36 * Probe for component register information and return it in map object. 37 */ 38 void cxl_probe_component_regs(struct device *dev, void __iomem *base, 39 struct cxl_component_reg_map *map) 40 { 41 int cap, cap_count; 42 u32 cap_array; 43 44 *map = (struct cxl_component_reg_map) { 0 }; 45 46 /* 47 * CXL.cache and CXL.mem registers are at offset 0x1000 as defined in 48 * CXL 2.0 8.2.4 Table 141. 49 */ 50 base += CXL_CM_OFFSET; 51 52 cap_array = readl(base + CXL_CM_CAP_HDR_OFFSET); 53 54 if (FIELD_GET(CXL_CM_CAP_HDR_ID_MASK, cap_array) != CM_CAP_HDR_CAP_ID) { 55 dev_err(dev, 56 "Couldn't locate the CXL.cache and CXL.mem capability array header.\n"); 57 return; 58 } 59 60 /* It's assumed that future versions will be backward compatible */ 61 cap_count = FIELD_GET(CXL_CM_CAP_HDR_ARRAY_SIZE_MASK, cap_array); 62 63 for (cap = 1; cap <= cap_count; cap++) { 64 void __iomem *register_block; 65 struct cxl_reg_map *rmap; 66 u16 cap_id, offset; 67 u32 length, hdr; 68 69 hdr = readl(base + cap * 0x4); 70 71 cap_id = FIELD_GET(CXL_CM_CAP_HDR_ID_MASK, hdr); 72 offset = FIELD_GET(CXL_CM_CAP_PTR_MASK, hdr); 73 register_block = base + offset; 74 hdr = readl(register_block); 75 76 rmap = NULL; 77 switch (cap_id) { 78 case CXL_CM_CAP_CAP_ID_HDM: { 79 int decoder_cnt; 80 81 dev_dbg(dev, "found HDM decoder capability (0x%x)\n", 82 offset); 83 84 decoder_cnt = cxl_hdm_decoder_count(hdr); 85 length = 0x20 * decoder_cnt + 0x10; 86 rmap = &map->hdm_decoder; 87 break; 88 } 89 case CXL_CM_CAP_CAP_ID_RAS: 90 dev_dbg(dev, "found RAS capability (0x%x)\n", 91 offset); 92 length = CXL_RAS_CAPABILITY_LENGTH; 93 rmap = &map->ras; 94 break; 95 default: 96 dev_dbg(dev, "Unknown CM cap ID: %d (0x%x)\n", cap_id, 97 offset); 98 break; 99 } 100 101 if (!rmap) 102 continue; 103 rmap->valid = true; 104 rmap->id = cap_id; 105 rmap->offset = CXL_CM_OFFSET + offset; 106 rmap->size = length; 107 } 108 } 109 EXPORT_SYMBOL_NS_GPL(cxl_probe_component_regs, CXL); 110 111 /** 112 * cxl_probe_device_regs() - Detect CXL Device register blocks 113 * @dev: Host device of the @base mapping 114 * @base: Mapping of CXL 2.0 8.2.8 CXL Device Register Interface 115 * @map: Map object describing the register block information found 116 * 117 * Probe for device register information and return it in map object. 118 */ 119 void cxl_probe_device_regs(struct device *dev, void __iomem *base, 120 struct cxl_device_reg_map *map) 121 { 122 int cap, cap_count; 123 u64 cap_array; 124 125 *map = (struct cxl_device_reg_map){ 0 }; 126 127 cap_array = readq(base + CXLDEV_CAP_ARRAY_OFFSET); 128 if (FIELD_GET(CXLDEV_CAP_ARRAY_ID_MASK, cap_array) != 129 CXLDEV_CAP_ARRAY_CAP_ID) 130 return; 131 132 cap_count = FIELD_GET(CXLDEV_CAP_ARRAY_COUNT_MASK, cap_array); 133 134 for (cap = 1; cap <= cap_count; cap++) { 135 struct cxl_reg_map *rmap; 136 u32 offset, length; 137 u16 cap_id; 138 139 cap_id = FIELD_GET(CXLDEV_CAP_HDR_CAP_ID_MASK, 140 readl(base + cap * 0x10)); 141 offset = readl(base + cap * 0x10 + 0x4); 142 length = readl(base + cap * 0x10 + 0x8); 143 144 rmap = NULL; 145 switch (cap_id) { 146 case CXLDEV_CAP_CAP_ID_DEVICE_STATUS: 147 dev_dbg(dev, "found Status capability (0x%x)\n", offset); 148 rmap = &map->status; 149 break; 150 case CXLDEV_CAP_CAP_ID_PRIMARY_MAILBOX: 151 dev_dbg(dev, "found Mailbox capability (0x%x)\n", offset); 152 rmap = &map->mbox; 153 break; 154 case CXLDEV_CAP_CAP_ID_SECONDARY_MAILBOX: 155 dev_dbg(dev, "found Secondary Mailbox capability (0x%x)\n", offset); 156 break; 157 case CXLDEV_CAP_CAP_ID_MEMDEV: 158 dev_dbg(dev, "found Memory Device capability (0x%x)\n", offset); 159 rmap = &map->memdev; 160 break; 161 default: 162 if (cap_id >= 0x8000) 163 dev_dbg(dev, "Vendor cap ID: %#x offset: %#x\n", cap_id, offset); 164 else 165 dev_dbg(dev, "Unknown cap ID: %#x offset: %#x\n", cap_id, offset); 166 break; 167 } 168 169 if (!rmap) 170 continue; 171 rmap->valid = true; 172 rmap->id = cap_id; 173 rmap->offset = offset; 174 rmap->size = length; 175 } 176 } 177 EXPORT_SYMBOL_NS_GPL(cxl_probe_device_regs, CXL); 178 179 void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr, 180 resource_size_t length) 181 { 182 void __iomem *ret_val; 183 struct resource *res; 184 185 if (WARN_ON_ONCE(addr == CXL_RESOURCE_NONE)) 186 return NULL; 187 188 res = devm_request_mem_region(dev, addr, length, dev_name(dev)); 189 if (!res) { 190 resource_size_t end = addr + length - 1; 191 192 dev_err(dev, "Failed to request region %pa-%pa\n", &addr, &end); 193 return NULL; 194 } 195 196 ret_val = devm_ioremap(dev, addr, length); 197 if (!ret_val) 198 dev_err(dev, "Failed to map region %pr\n", res); 199 200 return ret_val; 201 } 202 203 int cxl_map_component_regs(struct device *dev, struct cxl_component_regs *regs, 204 const struct cxl_register_map *map, unsigned long map_mask) 205 { 206 struct mapinfo { 207 const struct cxl_reg_map *rmap; 208 void __iomem **addr; 209 } mapinfo[] = { 210 { &map->component_map.hdm_decoder, ®s->hdm_decoder }, 211 { &map->component_map.ras, ®s->ras }, 212 }; 213 int i; 214 215 for (i = 0; i < ARRAY_SIZE(mapinfo); i++) { 216 struct mapinfo *mi = &mapinfo[i]; 217 resource_size_t phys_addr; 218 resource_size_t length; 219 220 if (!mi->rmap->valid) 221 continue; 222 if (!test_bit(mi->rmap->id, &map_mask)) 223 continue; 224 phys_addr = map->resource + mi->rmap->offset; 225 length = mi->rmap->size; 226 *(mi->addr) = devm_cxl_iomap_block(dev, phys_addr, length); 227 if (!*(mi->addr)) 228 return -ENOMEM; 229 } 230 231 return 0; 232 } 233 EXPORT_SYMBOL_NS_GPL(cxl_map_component_regs, CXL); 234 235 int cxl_map_device_regs(struct device *dev, 236 struct cxl_device_regs *regs, 237 const struct cxl_register_map *map) 238 { 239 resource_size_t phys_addr = map->resource; 240 struct mapinfo { 241 const struct cxl_reg_map *rmap; 242 void __iomem **addr; 243 } mapinfo[] = { 244 { &map->device_map.status, ®s->status, }, 245 { &map->device_map.mbox, ®s->mbox, }, 246 { &map->device_map.memdev, ®s->memdev, }, 247 }; 248 int i; 249 250 for (i = 0; i < ARRAY_SIZE(mapinfo); i++) { 251 struct mapinfo *mi = &mapinfo[i]; 252 resource_size_t length; 253 resource_size_t addr; 254 255 if (!mi->rmap->valid) 256 continue; 257 258 addr = phys_addr + mi->rmap->offset; 259 length = mi->rmap->size; 260 *(mi->addr) = devm_cxl_iomap_block(dev, addr, length); 261 if (!*(mi->addr)) 262 return -ENOMEM; 263 } 264 265 return 0; 266 } 267 EXPORT_SYMBOL_NS_GPL(cxl_map_device_regs, CXL); 268 269 static bool cxl_decode_regblock(struct pci_dev *pdev, u32 reg_lo, u32 reg_hi, 270 struct cxl_register_map *map) 271 { 272 int bar = FIELD_GET(CXL_DVSEC_REG_LOCATOR_BIR_MASK, reg_lo); 273 u64 offset = ((u64)reg_hi << 32) | 274 (reg_lo & CXL_DVSEC_REG_LOCATOR_BLOCK_OFF_LOW_MASK); 275 276 if (offset > pci_resource_len(pdev, bar)) { 277 dev_warn(&pdev->dev, 278 "BAR%d: %pr: too small (offset: %pa, type: %d)\n", bar, 279 &pdev->resource[bar], &offset, map->reg_type); 280 return false; 281 } 282 283 map->reg_type = FIELD_GET(CXL_DVSEC_REG_LOCATOR_BLOCK_ID_MASK, reg_lo); 284 map->resource = pci_resource_start(pdev, bar) + offset; 285 map->max_size = pci_resource_len(pdev, bar) - offset; 286 return true; 287 } 288 289 /** 290 * cxl_find_regblock_instance() - Locate a register block by type / index 291 * @pdev: The CXL PCI device to enumerate. 292 * @type: Register Block Indicator id 293 * @map: Enumeration output, clobbered on error 294 * @index: Index into which particular instance of a regblock wanted in the 295 * order found in register locator DVSEC. 296 * 297 * Return: 0 if register block enumerated, negative error code otherwise 298 * 299 * A CXL DVSEC may point to one or more register blocks, search for them 300 * by @type and @index. 301 */ 302 int cxl_find_regblock_instance(struct pci_dev *pdev, enum cxl_regloc_type type, 303 struct cxl_register_map *map, int index) 304 { 305 u32 regloc_size, regblocks; 306 int instance = 0; 307 int regloc, i; 308 309 map->resource = CXL_RESOURCE_NONE; 310 regloc = pci_find_dvsec_capability(pdev, PCI_DVSEC_VENDOR_ID_CXL, 311 CXL_DVSEC_REG_LOCATOR); 312 if (!regloc) 313 return -ENXIO; 314 315 pci_read_config_dword(pdev, regloc + PCI_DVSEC_HEADER1, ®loc_size); 316 regloc_size = FIELD_GET(PCI_DVSEC_HEADER1_LENGTH_MASK, regloc_size); 317 318 regloc += CXL_DVSEC_REG_LOCATOR_BLOCK1_OFFSET; 319 regblocks = (regloc_size - CXL_DVSEC_REG_LOCATOR_BLOCK1_OFFSET) / 8; 320 321 for (i = 0; i < regblocks; i++, regloc += 8) { 322 u32 reg_lo, reg_hi; 323 324 pci_read_config_dword(pdev, regloc, ®_lo); 325 pci_read_config_dword(pdev, regloc + 4, ®_hi); 326 327 if (!cxl_decode_regblock(pdev, reg_lo, reg_hi, map)) 328 continue; 329 330 if (map->reg_type == type) { 331 if (index == instance) 332 return 0; 333 instance++; 334 } 335 } 336 337 map->resource = CXL_RESOURCE_NONE; 338 return -ENODEV; 339 } 340 EXPORT_SYMBOL_NS_GPL(cxl_find_regblock_instance, CXL); 341 342 /** 343 * cxl_find_regblock() - Locate register blocks by type 344 * @pdev: The CXL PCI device to enumerate. 345 * @type: Register Block Indicator id 346 * @map: Enumeration output, clobbered on error 347 * 348 * Return: 0 if register block enumerated, negative error code otherwise 349 * 350 * A CXL DVSEC may point to one or more register blocks, search for them 351 * by @type. 352 */ 353 int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type, 354 struct cxl_register_map *map) 355 { 356 return cxl_find_regblock_instance(pdev, type, map, 0); 357 } 358 EXPORT_SYMBOL_NS_GPL(cxl_find_regblock, CXL); 359 360 /** 361 * cxl_count_regblock() - Count instances of a given regblock type. 362 * @pdev: The CXL PCI device to enumerate. 363 * @type: Register Block Indicator id 364 * 365 * Some regblocks may be repeated. Count how many instances. 366 * 367 * Return: count of matching regblocks. 368 */ 369 int cxl_count_regblock(struct pci_dev *pdev, enum cxl_regloc_type type) 370 { 371 struct cxl_register_map map; 372 int rc, count = 0; 373 374 while (1) { 375 rc = cxl_find_regblock_instance(pdev, type, &map, count); 376 if (rc) 377 return count; 378 count++; 379 } 380 } 381 EXPORT_SYMBOL_NS_GPL(cxl_count_regblock, CXL); 382 383 int cxl_map_pmu_regs(struct pci_dev *pdev, struct cxl_pmu_regs *regs, 384 struct cxl_register_map *map) 385 { 386 struct device *dev = &pdev->dev; 387 resource_size_t phys_addr; 388 389 phys_addr = map->resource; 390 regs->pmu = devm_cxl_iomap_block(dev, phys_addr, CXL_PMU_REGMAP_SIZE); 391 if (!regs->pmu) 392 return -ENOMEM; 393 394 return 0; 395 } 396 EXPORT_SYMBOL_NS_GPL(cxl_map_pmu_regs, CXL); 397 398 resource_size_t cxl_rcrb_to_component(struct device *dev, 399 resource_size_t rcrb, 400 enum cxl_rcrb which) 401 { 402 resource_size_t component_reg_phys; 403 void __iomem *addr; 404 u32 bar0, bar1; 405 u16 cmd; 406 u32 id; 407 408 if (which == CXL_RCRB_UPSTREAM) 409 rcrb += SZ_4K; 410 411 /* 412 * RCRB's BAR[0..1] point to component block containing CXL 413 * subsystem component registers. MEMBAR extraction follows 414 * the PCI Base spec here, esp. 64 bit extraction and memory 415 * ranges alignment (6.0, 7.5.1.2.1). 416 */ 417 if (!request_mem_region(rcrb, SZ_4K, "CXL RCRB")) 418 return CXL_RESOURCE_NONE; 419 addr = ioremap(rcrb, SZ_4K); 420 if (!addr) { 421 dev_err(dev, "Failed to map region %pr\n", addr); 422 release_mem_region(rcrb, SZ_4K); 423 return CXL_RESOURCE_NONE; 424 } 425 426 id = readl(addr + PCI_VENDOR_ID); 427 cmd = readw(addr + PCI_COMMAND); 428 bar0 = readl(addr + PCI_BASE_ADDRESS_0); 429 bar1 = readl(addr + PCI_BASE_ADDRESS_1); 430 iounmap(addr); 431 release_mem_region(rcrb, SZ_4K); 432 433 /* 434 * Sanity check, see CXL 3.0 Figure 9-8 CXL Device that Does Not 435 * Remap Upstream Port and Component Registers 436 */ 437 if (id == U32_MAX) { 438 if (which == CXL_RCRB_DOWNSTREAM) 439 dev_err(dev, "Failed to access Downstream Port RCRB\n"); 440 return CXL_RESOURCE_NONE; 441 } 442 if (!(cmd & PCI_COMMAND_MEMORY)) 443 return CXL_RESOURCE_NONE; 444 /* The RCRB is a Memory Window, and the MEM_TYPE_1M bit is obsolete */ 445 if (bar0 & (PCI_BASE_ADDRESS_MEM_TYPE_1M | PCI_BASE_ADDRESS_SPACE_IO)) 446 return CXL_RESOURCE_NONE; 447 448 component_reg_phys = bar0 & PCI_BASE_ADDRESS_MEM_MASK; 449 if (bar0 & PCI_BASE_ADDRESS_MEM_TYPE_64) 450 component_reg_phys |= ((u64)bar1) << 32; 451 452 if (!component_reg_phys) 453 return CXL_RESOURCE_NONE; 454 455 /* MEMBAR is block size (64k) aligned. */ 456 if (!IS_ALIGNED(component_reg_phys, CXL_COMPONENT_REG_BLOCK_SIZE)) 457 return CXL_RESOURCE_NONE; 458 459 return component_reg_phys; 460 } 461 EXPORT_SYMBOL_NS_GPL(cxl_rcrb_to_component, CXL); 462