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   */
cxl_probe_component_regs(struct device * dev,void __iomem * base,struct cxl_component_reg_map * map)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   */
cxl_probe_device_regs(struct device * dev,void __iomem * base,struct cxl_device_reg_map * map)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  
devm_cxl_iomap_block(struct device * dev,resource_size_t addr,resource_size_t length)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  
cxl_map_component_regs(const struct cxl_register_map * map,struct cxl_component_regs * regs,unsigned long map_mask)203  int cxl_map_component_regs(const struct cxl_register_map *map,
204  			   struct cxl_component_regs *regs,
205  			   unsigned long map_mask)
206  {
207  	struct device *host = map->host;
208  	struct mapinfo {
209  		const struct cxl_reg_map *rmap;
210  		void __iomem **addr;
211  	} mapinfo[] = {
212  		{ &map->component_map.hdm_decoder, &regs->hdm_decoder },
213  		{ &map->component_map.ras, &regs->ras },
214  	};
215  	int i;
216  
217  	for (i = 0; i < ARRAY_SIZE(mapinfo); i++) {
218  		struct mapinfo *mi = &mapinfo[i];
219  		resource_size_t addr;
220  		resource_size_t length;
221  
222  		if (!mi->rmap->valid)
223  			continue;
224  		if (!test_bit(mi->rmap->id, &map_mask))
225  			continue;
226  		addr = map->resource + mi->rmap->offset;
227  		length = mi->rmap->size;
228  		*(mi->addr) = devm_cxl_iomap_block(host, addr, length);
229  		if (!*(mi->addr))
230  			return -ENOMEM;
231  	}
232  
233  	return 0;
234  }
235  EXPORT_SYMBOL_NS_GPL(cxl_map_component_regs, CXL);
236  
cxl_map_device_regs(const struct cxl_register_map * map,struct cxl_device_regs * regs)237  int cxl_map_device_regs(const struct cxl_register_map *map,
238  			struct cxl_device_regs *regs)
239  {
240  	struct device *host = map->host;
241  	resource_size_t phys_addr = map->resource;
242  	struct mapinfo {
243  		const struct cxl_reg_map *rmap;
244  		void __iomem **addr;
245  	} mapinfo[] = {
246  		{ &map->device_map.status, &regs->status, },
247  		{ &map->device_map.mbox, &regs->mbox, },
248  		{ &map->device_map.memdev, &regs->memdev, },
249  	};
250  	int i;
251  
252  	for (i = 0; i < ARRAY_SIZE(mapinfo); i++) {
253  		struct mapinfo *mi = &mapinfo[i];
254  		resource_size_t length;
255  		resource_size_t addr;
256  
257  		if (!mi->rmap->valid)
258  			continue;
259  
260  		addr = phys_addr + mi->rmap->offset;
261  		length = mi->rmap->size;
262  		*(mi->addr) = devm_cxl_iomap_block(host, addr, length);
263  		if (!*(mi->addr))
264  			return -ENOMEM;
265  	}
266  
267  	return 0;
268  }
269  EXPORT_SYMBOL_NS_GPL(cxl_map_device_regs, CXL);
270  
cxl_decode_regblock(struct pci_dev * pdev,u32 reg_lo,u32 reg_hi,struct cxl_register_map * map)271  static bool cxl_decode_regblock(struct pci_dev *pdev, u32 reg_lo, u32 reg_hi,
272  				struct cxl_register_map *map)
273  {
274  	u8 reg_type = FIELD_GET(CXL_DVSEC_REG_LOCATOR_BLOCK_ID_MASK, reg_lo);
275  	int bar = FIELD_GET(CXL_DVSEC_REG_LOCATOR_BIR_MASK, reg_lo);
276  	u64 offset = ((u64)reg_hi << 32) |
277  		     (reg_lo & CXL_DVSEC_REG_LOCATOR_BLOCK_OFF_LOW_MASK);
278  
279  	if (offset > pci_resource_len(pdev, bar)) {
280  		dev_warn(&pdev->dev,
281  			 "BAR%d: %pr: too small (offset: %pa, type: %d)\n", bar,
282  			 &pdev->resource[bar], &offset, reg_type);
283  		return false;
284  	}
285  
286  	map->reg_type = reg_type;
287  	map->resource = pci_resource_start(pdev, bar) + offset;
288  	map->max_size = pci_resource_len(pdev, bar) - offset;
289  	return true;
290  }
291  
292  /**
293   * cxl_find_regblock_instance() - Locate a register block by type / index
294   * @pdev: The CXL PCI device to enumerate.
295   * @type: Register Block Indicator id
296   * @map: Enumeration output, clobbered on error
297   * @index: Index into which particular instance of a regblock wanted in the
298   *	   order found in register locator DVSEC.
299   *
300   * Return: 0 if register block enumerated, negative error code otherwise
301   *
302   * A CXL DVSEC may point to one or more register blocks, search for them
303   * by @type and @index.
304   */
cxl_find_regblock_instance(struct pci_dev * pdev,enum cxl_regloc_type type,struct cxl_register_map * map,int index)305  int cxl_find_regblock_instance(struct pci_dev *pdev, enum cxl_regloc_type type,
306  			       struct cxl_register_map *map, int index)
307  {
308  	u32 regloc_size, regblocks;
309  	int instance = 0;
310  	int regloc, i;
311  
312  	*map = (struct cxl_register_map) {
313  		.host = &pdev->dev,
314  		.resource = CXL_RESOURCE_NONE,
315  	};
316  
317  	regloc = pci_find_dvsec_capability(pdev, PCI_VENDOR_ID_CXL,
318  					   CXL_DVSEC_REG_LOCATOR);
319  	if (!regloc)
320  		return -ENXIO;
321  
322  	pci_read_config_dword(pdev, regloc + PCI_DVSEC_HEADER1, &regloc_size);
323  	regloc_size = FIELD_GET(PCI_DVSEC_HEADER1_LENGTH_MASK, regloc_size);
324  
325  	regloc += CXL_DVSEC_REG_LOCATOR_BLOCK1_OFFSET;
326  	regblocks = (regloc_size - CXL_DVSEC_REG_LOCATOR_BLOCK1_OFFSET) / 8;
327  
328  	for (i = 0; i < regblocks; i++, regloc += 8) {
329  		u32 reg_lo, reg_hi;
330  
331  		pci_read_config_dword(pdev, regloc, &reg_lo);
332  		pci_read_config_dword(pdev, regloc + 4, &reg_hi);
333  
334  		if (!cxl_decode_regblock(pdev, reg_lo, reg_hi, map))
335  			continue;
336  
337  		if (map->reg_type == type) {
338  			if (index == instance)
339  				return 0;
340  			instance++;
341  		}
342  	}
343  
344  	map->resource = CXL_RESOURCE_NONE;
345  	return -ENODEV;
346  }
347  EXPORT_SYMBOL_NS_GPL(cxl_find_regblock_instance, CXL);
348  
349  /**
350   * cxl_find_regblock() - Locate register blocks by type
351   * @pdev: The CXL PCI device to enumerate.
352   * @type: Register Block Indicator id
353   * @map: Enumeration output, clobbered on error
354   *
355   * Return: 0 if register block enumerated, negative error code otherwise
356   *
357   * A CXL DVSEC may point to one or more register blocks, search for them
358   * by @type.
359   */
cxl_find_regblock(struct pci_dev * pdev,enum cxl_regloc_type type,struct cxl_register_map * map)360  int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type,
361  		      struct cxl_register_map *map)
362  {
363  	return cxl_find_regblock_instance(pdev, type, map, 0);
364  }
365  EXPORT_SYMBOL_NS_GPL(cxl_find_regblock, CXL);
366  
367  /**
368   * cxl_count_regblock() - Count instances of a given regblock type.
369   * @pdev: The CXL PCI device to enumerate.
370   * @type: Register Block Indicator id
371   *
372   * Some regblocks may be repeated. Count how many instances.
373   *
374   * Return: count of matching regblocks.
375   */
cxl_count_regblock(struct pci_dev * pdev,enum cxl_regloc_type type)376  int cxl_count_regblock(struct pci_dev *pdev, enum cxl_regloc_type type)
377  {
378  	struct cxl_register_map map;
379  	int rc, count = 0;
380  
381  	while (1) {
382  		rc = cxl_find_regblock_instance(pdev, type, &map, count);
383  		if (rc)
384  			return count;
385  		count++;
386  	}
387  }
388  EXPORT_SYMBOL_NS_GPL(cxl_count_regblock, CXL);
389  
cxl_map_pmu_regs(struct cxl_register_map * map,struct cxl_pmu_regs * regs)390  int cxl_map_pmu_regs(struct cxl_register_map *map, struct cxl_pmu_regs *regs)
391  {
392  	struct device *dev = map->host;
393  	resource_size_t phys_addr;
394  
395  	phys_addr = map->resource;
396  	regs->pmu = devm_cxl_iomap_block(dev, phys_addr, CXL_PMU_REGMAP_SIZE);
397  	if (!regs->pmu)
398  		return -ENOMEM;
399  
400  	return 0;
401  }
402  EXPORT_SYMBOL_NS_GPL(cxl_map_pmu_regs, CXL);
403  
cxl_map_regblock(struct cxl_register_map * map)404  static int cxl_map_regblock(struct cxl_register_map *map)
405  {
406  	struct device *host = map->host;
407  
408  	map->base = ioremap(map->resource, map->max_size);
409  	if (!map->base) {
410  		dev_err(host, "failed to map registers\n");
411  		return -ENOMEM;
412  	}
413  
414  	dev_dbg(host, "Mapped CXL Memory Device resource %pa\n", &map->resource);
415  	return 0;
416  }
417  
cxl_unmap_regblock(struct cxl_register_map * map)418  static void cxl_unmap_regblock(struct cxl_register_map *map)
419  {
420  	iounmap(map->base);
421  	map->base = NULL;
422  }
423  
cxl_probe_regs(struct cxl_register_map * map)424  static int cxl_probe_regs(struct cxl_register_map *map)
425  {
426  	struct cxl_component_reg_map *comp_map;
427  	struct cxl_device_reg_map *dev_map;
428  	struct device *host = map->host;
429  	void __iomem *base = map->base;
430  
431  	switch (map->reg_type) {
432  	case CXL_REGLOC_RBI_COMPONENT:
433  		comp_map = &map->component_map;
434  		cxl_probe_component_regs(host, base, comp_map);
435  		dev_dbg(host, "Set up component registers\n");
436  		break;
437  	case CXL_REGLOC_RBI_MEMDEV:
438  		dev_map = &map->device_map;
439  		cxl_probe_device_regs(host, base, dev_map);
440  		if (!dev_map->status.valid || !dev_map->mbox.valid ||
441  		    !dev_map->memdev.valid) {
442  			dev_err(host, "registers not found: %s%s%s\n",
443  				!dev_map->status.valid ? "status " : "",
444  				!dev_map->mbox.valid ? "mbox " : "",
445  				!dev_map->memdev.valid ? "memdev " : "");
446  			return -ENXIO;
447  		}
448  
449  		dev_dbg(host, "Probing device registers...\n");
450  		break;
451  	default:
452  		break;
453  	}
454  
455  	return 0;
456  }
457  
cxl_setup_regs(struct cxl_register_map * map)458  int cxl_setup_regs(struct cxl_register_map *map)
459  {
460  	int rc;
461  
462  	rc = cxl_map_regblock(map);
463  	if (rc)
464  		return rc;
465  
466  	rc = cxl_probe_regs(map);
467  	cxl_unmap_regblock(map);
468  
469  	return rc;
470  }
471  EXPORT_SYMBOL_NS_GPL(cxl_setup_regs, CXL);
472  
cxl_rcrb_to_aer(struct device * dev,resource_size_t rcrb)473  u16 cxl_rcrb_to_aer(struct device *dev, resource_size_t rcrb)
474  {
475  	void __iomem *addr;
476  	u16 offset = 0;
477  	u32 cap_hdr;
478  
479  	if (WARN_ON_ONCE(rcrb == CXL_RESOURCE_NONE))
480  		return 0;
481  
482  	if (!request_mem_region(rcrb, SZ_4K, dev_name(dev)))
483  		return 0;
484  
485  	addr = ioremap(rcrb, SZ_4K);
486  	if (!addr)
487  		goto out;
488  
489  	cap_hdr = readl(addr + offset);
490  	while (PCI_EXT_CAP_ID(cap_hdr) != PCI_EXT_CAP_ID_ERR) {
491  		offset = PCI_EXT_CAP_NEXT(cap_hdr);
492  
493  		/* Offset 0 terminates capability list. */
494  		if (!offset)
495  			break;
496  		cap_hdr = readl(addr + offset);
497  	}
498  
499  	if (offset)
500  		dev_dbg(dev, "found AER extended capability (0x%x)\n", offset);
501  
502  	iounmap(addr);
503  out:
504  	release_mem_region(rcrb, SZ_4K);
505  
506  	return offset;
507  }
508  
__rcrb_to_component(struct device * dev,struct cxl_rcrb_info * ri,enum cxl_rcrb which)509  resource_size_t __rcrb_to_component(struct device *dev, struct cxl_rcrb_info *ri,
510  				    enum cxl_rcrb which)
511  {
512  	resource_size_t component_reg_phys;
513  	resource_size_t rcrb = ri->base;
514  	void __iomem *addr;
515  	u32 bar0, bar1;
516  	u16 cmd;
517  	u32 id;
518  
519  	if (which == CXL_RCRB_UPSTREAM)
520  		rcrb += SZ_4K;
521  
522  	/*
523  	 * RCRB's BAR[0..1] point to component block containing CXL
524  	 * subsystem component registers. MEMBAR extraction follows
525  	 * the PCI Base spec here, esp. 64 bit extraction and memory
526  	 * ranges alignment (6.0, 7.5.1.2.1).
527  	 */
528  	if (!request_mem_region(rcrb, SZ_4K, "CXL RCRB"))
529  		return CXL_RESOURCE_NONE;
530  	addr = ioremap(rcrb, SZ_4K);
531  	if (!addr) {
532  		dev_err(dev, "Failed to map region %pr\n", addr);
533  		release_mem_region(rcrb, SZ_4K);
534  		return CXL_RESOURCE_NONE;
535  	}
536  
537  	id = readl(addr + PCI_VENDOR_ID);
538  	cmd = readw(addr + PCI_COMMAND);
539  	bar0 = readl(addr + PCI_BASE_ADDRESS_0);
540  	bar1 = readl(addr + PCI_BASE_ADDRESS_1);
541  	iounmap(addr);
542  	release_mem_region(rcrb, SZ_4K);
543  
544  	/*
545  	 * Sanity check, see CXL 3.0 Figure 9-8 CXL Device that Does Not
546  	 * Remap Upstream Port and Component Registers
547  	 */
548  	if (id == U32_MAX) {
549  		if (which == CXL_RCRB_DOWNSTREAM)
550  			dev_err(dev, "Failed to access Downstream Port RCRB\n");
551  		return CXL_RESOURCE_NONE;
552  	}
553  	if (!(cmd & PCI_COMMAND_MEMORY))
554  		return CXL_RESOURCE_NONE;
555  	/* The RCRB is a Memory Window, and the MEM_TYPE_1M bit is obsolete */
556  	if (bar0 & (PCI_BASE_ADDRESS_MEM_TYPE_1M | PCI_BASE_ADDRESS_SPACE_IO))
557  		return CXL_RESOURCE_NONE;
558  
559  	component_reg_phys = bar0 & PCI_BASE_ADDRESS_MEM_MASK;
560  	if (bar0 & PCI_BASE_ADDRESS_MEM_TYPE_64)
561  		component_reg_phys |= ((u64)bar1) << 32;
562  
563  	if (!component_reg_phys)
564  		return CXL_RESOURCE_NONE;
565  
566  	/* MEMBAR is block size (64k) aligned. */
567  	if (!IS_ALIGNED(component_reg_phys, CXL_COMPONENT_REG_BLOCK_SIZE))
568  		return CXL_RESOURCE_NONE;
569  
570  	return component_reg_phys;
571  }
572  
cxl_rcd_component_reg_phys(struct device * dev,struct cxl_dport * dport)573  resource_size_t cxl_rcd_component_reg_phys(struct device *dev,
574  					   struct cxl_dport *dport)
575  {
576  	if (!dport->rch)
577  		return CXL_RESOURCE_NONE;
578  	return __rcrb_to_component(dev, &dport->rcrb, CXL_RCRB_UPSTREAM);
579  }
580  EXPORT_SYMBOL_NS_GPL(cxl_rcd_component_reg_phys, CXL);
581