regs.c 15 KB

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