xref: /kernel/linux/linux-6.6/drivers/cxl/cxl.h (revision 62306a36)
162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/* Copyright(c) 2020 Intel Corporation. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#ifndef __CXL_H__
562306a36Sopenharmony_ci#define __CXL_H__
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/libnvdimm.h>
862306a36Sopenharmony_ci#include <linux/bitfield.h>
962306a36Sopenharmony_ci#include <linux/bitops.h>
1062306a36Sopenharmony_ci#include <linux/log2.h>
1162306a36Sopenharmony_ci#include <linux/io.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/**
1462306a36Sopenharmony_ci * DOC: cxl objects
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * The CXL core objects like ports, decoders, and regions are shared
1762306a36Sopenharmony_ci * between the subsystem drivers cxl_acpi, cxl_pci, and core drivers
1862306a36Sopenharmony_ci * (port-driver, region-driver, nvdimm object-drivers... etc).
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/* CXL 2.0 8.2.4 CXL Component Register Layout and Definition */
2262306a36Sopenharmony_ci#define CXL_COMPONENT_REG_BLOCK_SIZE SZ_64K
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* CXL 2.0 8.2.5 CXL.cache and CXL.mem Registers*/
2562306a36Sopenharmony_ci#define CXL_CM_OFFSET 0x1000
2662306a36Sopenharmony_ci#define CXL_CM_CAP_HDR_OFFSET 0x0
2762306a36Sopenharmony_ci#define   CXL_CM_CAP_HDR_ID_MASK GENMASK(15, 0)
2862306a36Sopenharmony_ci#define     CM_CAP_HDR_CAP_ID 1
2962306a36Sopenharmony_ci#define   CXL_CM_CAP_HDR_VERSION_MASK GENMASK(19, 16)
3062306a36Sopenharmony_ci#define     CM_CAP_HDR_CAP_VERSION 1
3162306a36Sopenharmony_ci#define   CXL_CM_CAP_HDR_CACHE_MEM_VERSION_MASK GENMASK(23, 20)
3262306a36Sopenharmony_ci#define     CM_CAP_HDR_CACHE_MEM_VERSION 1
3362306a36Sopenharmony_ci#define   CXL_CM_CAP_HDR_ARRAY_SIZE_MASK GENMASK(31, 24)
3462306a36Sopenharmony_ci#define CXL_CM_CAP_PTR_MASK GENMASK(31, 20)
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci#define   CXL_CM_CAP_CAP_ID_RAS 0x2
3762306a36Sopenharmony_ci#define   CXL_CM_CAP_CAP_ID_HDM 0x5
3862306a36Sopenharmony_ci#define   CXL_CM_CAP_CAP_HDM_VERSION 1
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/* HDM decoders CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure */
4162306a36Sopenharmony_ci#define CXL_HDM_DECODER_CAP_OFFSET 0x0
4262306a36Sopenharmony_ci#define   CXL_HDM_DECODER_COUNT_MASK GENMASK(3, 0)
4362306a36Sopenharmony_ci#define   CXL_HDM_DECODER_TARGET_COUNT_MASK GENMASK(7, 4)
4462306a36Sopenharmony_ci#define   CXL_HDM_DECODER_INTERLEAVE_11_8 BIT(8)
4562306a36Sopenharmony_ci#define   CXL_HDM_DECODER_INTERLEAVE_14_12 BIT(9)
4662306a36Sopenharmony_ci#define CXL_HDM_DECODER_CTRL_OFFSET 0x4
4762306a36Sopenharmony_ci#define   CXL_HDM_DECODER_ENABLE BIT(1)
4862306a36Sopenharmony_ci#define CXL_HDM_DECODER0_BASE_LOW_OFFSET(i) (0x20 * (i) + 0x10)
4962306a36Sopenharmony_ci#define CXL_HDM_DECODER0_BASE_HIGH_OFFSET(i) (0x20 * (i) + 0x14)
5062306a36Sopenharmony_ci#define CXL_HDM_DECODER0_SIZE_LOW_OFFSET(i) (0x20 * (i) + 0x18)
5162306a36Sopenharmony_ci#define CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(i) (0x20 * (i) + 0x1c)
5262306a36Sopenharmony_ci#define CXL_HDM_DECODER0_CTRL_OFFSET(i) (0x20 * (i) + 0x20)
5362306a36Sopenharmony_ci#define   CXL_HDM_DECODER0_CTRL_IG_MASK GENMASK(3, 0)
5462306a36Sopenharmony_ci#define   CXL_HDM_DECODER0_CTRL_IW_MASK GENMASK(7, 4)
5562306a36Sopenharmony_ci#define   CXL_HDM_DECODER0_CTRL_LOCK BIT(8)
5662306a36Sopenharmony_ci#define   CXL_HDM_DECODER0_CTRL_COMMIT BIT(9)
5762306a36Sopenharmony_ci#define   CXL_HDM_DECODER0_CTRL_COMMITTED BIT(10)
5862306a36Sopenharmony_ci#define   CXL_HDM_DECODER0_CTRL_COMMIT_ERROR BIT(11)
5962306a36Sopenharmony_ci#define   CXL_HDM_DECODER0_CTRL_HOSTONLY BIT(12)
6062306a36Sopenharmony_ci#define CXL_HDM_DECODER0_TL_LOW(i) (0x20 * (i) + 0x24)
6162306a36Sopenharmony_ci#define CXL_HDM_DECODER0_TL_HIGH(i) (0x20 * (i) + 0x28)
6262306a36Sopenharmony_ci#define CXL_HDM_DECODER0_SKIP_LOW(i) CXL_HDM_DECODER0_TL_LOW(i)
6362306a36Sopenharmony_ci#define CXL_HDM_DECODER0_SKIP_HIGH(i) CXL_HDM_DECODER0_TL_HIGH(i)
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/* HDM decoder control register constants CXL 3.0 8.2.5.19.7 */
6662306a36Sopenharmony_ci#define CXL_DECODER_MIN_GRANULARITY 256
6762306a36Sopenharmony_ci#define CXL_DECODER_MAX_ENCODED_IG 6
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic inline int cxl_hdm_decoder_count(u32 cap_hdr)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	int val = FIELD_GET(CXL_HDM_DECODER_COUNT_MASK, cap_hdr);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	return val ? val * 2 : 1;
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/* Encode defined in CXL 2.0 8.2.5.12.7 HDM Decoder Control Register */
7762306a36Sopenharmony_cistatic inline int eig_to_granularity(u16 eig, unsigned int *granularity)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	if (eig > CXL_DECODER_MAX_ENCODED_IG)
8062306a36Sopenharmony_ci		return -EINVAL;
8162306a36Sopenharmony_ci	*granularity = CXL_DECODER_MIN_GRANULARITY << eig;
8262306a36Sopenharmony_ci	return 0;
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/* Encode defined in CXL ECN "3, 6, 12 and 16-way memory Interleaving" */
8662306a36Sopenharmony_cistatic inline int eiw_to_ways(u8 eiw, unsigned int *ways)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	switch (eiw) {
8962306a36Sopenharmony_ci	case 0 ... 4:
9062306a36Sopenharmony_ci		*ways = 1 << eiw;
9162306a36Sopenharmony_ci		break;
9262306a36Sopenharmony_ci	case 8 ... 10:
9362306a36Sopenharmony_ci		*ways = 3 << (eiw - 8);
9462306a36Sopenharmony_ci		break;
9562306a36Sopenharmony_ci	default:
9662306a36Sopenharmony_ci		return -EINVAL;
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	return 0;
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic inline int granularity_to_eig(int granularity, u16 *eig)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	if (granularity > SZ_16K || granularity < CXL_DECODER_MIN_GRANULARITY ||
10562306a36Sopenharmony_ci	    !is_power_of_2(granularity))
10662306a36Sopenharmony_ci		return -EINVAL;
10762306a36Sopenharmony_ci	*eig = ilog2(granularity) - 8;
10862306a36Sopenharmony_ci	return 0;
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic inline int ways_to_eiw(unsigned int ways, u8 *eiw)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	if (ways > 16)
11462306a36Sopenharmony_ci		return -EINVAL;
11562306a36Sopenharmony_ci	if (is_power_of_2(ways)) {
11662306a36Sopenharmony_ci		*eiw = ilog2(ways);
11762306a36Sopenharmony_ci		return 0;
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci	if (ways % 3)
12062306a36Sopenharmony_ci		return -EINVAL;
12162306a36Sopenharmony_ci	ways /= 3;
12262306a36Sopenharmony_ci	if (!is_power_of_2(ways))
12362306a36Sopenharmony_ci		return -EINVAL;
12462306a36Sopenharmony_ci	*eiw = ilog2(ways) + 8;
12562306a36Sopenharmony_ci	return 0;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci/* RAS Registers CXL 2.0 8.2.5.9 CXL RAS Capability Structure */
12962306a36Sopenharmony_ci#define CXL_RAS_UNCORRECTABLE_STATUS_OFFSET 0x0
13062306a36Sopenharmony_ci#define   CXL_RAS_UNCORRECTABLE_STATUS_MASK (GENMASK(16, 14) | GENMASK(11, 0))
13162306a36Sopenharmony_ci#define CXL_RAS_UNCORRECTABLE_MASK_OFFSET 0x4
13262306a36Sopenharmony_ci#define   CXL_RAS_UNCORRECTABLE_MASK_MASK (GENMASK(16, 14) | GENMASK(11, 0))
13362306a36Sopenharmony_ci#define   CXL_RAS_UNCORRECTABLE_MASK_F256B_MASK BIT(8)
13462306a36Sopenharmony_ci#define CXL_RAS_UNCORRECTABLE_SEVERITY_OFFSET 0x8
13562306a36Sopenharmony_ci#define   CXL_RAS_UNCORRECTABLE_SEVERITY_MASK (GENMASK(16, 14) | GENMASK(11, 0))
13662306a36Sopenharmony_ci#define CXL_RAS_CORRECTABLE_STATUS_OFFSET 0xC
13762306a36Sopenharmony_ci#define   CXL_RAS_CORRECTABLE_STATUS_MASK GENMASK(6, 0)
13862306a36Sopenharmony_ci#define CXL_RAS_CORRECTABLE_MASK_OFFSET 0x10
13962306a36Sopenharmony_ci#define   CXL_RAS_CORRECTABLE_MASK_MASK GENMASK(6, 0)
14062306a36Sopenharmony_ci#define CXL_RAS_CAP_CONTROL_OFFSET 0x14
14162306a36Sopenharmony_ci#define CXL_RAS_CAP_CONTROL_FE_MASK GENMASK(5, 0)
14262306a36Sopenharmony_ci#define CXL_RAS_HEADER_LOG_OFFSET 0x18
14362306a36Sopenharmony_ci#define CXL_RAS_CAPABILITY_LENGTH 0x58
14462306a36Sopenharmony_ci#define CXL_HEADERLOG_SIZE SZ_512
14562306a36Sopenharmony_ci#define CXL_HEADERLOG_SIZE_U32 SZ_512 / sizeof(u32)
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci/* CXL 2.0 8.2.8.1 Device Capabilities Array Register */
14862306a36Sopenharmony_ci#define CXLDEV_CAP_ARRAY_OFFSET 0x0
14962306a36Sopenharmony_ci#define   CXLDEV_CAP_ARRAY_CAP_ID 0
15062306a36Sopenharmony_ci#define   CXLDEV_CAP_ARRAY_ID_MASK GENMASK_ULL(15, 0)
15162306a36Sopenharmony_ci#define   CXLDEV_CAP_ARRAY_COUNT_MASK GENMASK_ULL(47, 32)
15262306a36Sopenharmony_ci/* CXL 2.0 8.2.8.2 CXL Device Capability Header Register */
15362306a36Sopenharmony_ci#define CXLDEV_CAP_HDR_CAP_ID_MASK GENMASK(15, 0)
15462306a36Sopenharmony_ci/* CXL 2.0 8.2.8.2.1 CXL Device Capabilities */
15562306a36Sopenharmony_ci#define CXLDEV_CAP_CAP_ID_DEVICE_STATUS 0x1
15662306a36Sopenharmony_ci#define CXLDEV_CAP_CAP_ID_PRIMARY_MAILBOX 0x2
15762306a36Sopenharmony_ci#define CXLDEV_CAP_CAP_ID_SECONDARY_MAILBOX 0x3
15862306a36Sopenharmony_ci#define CXLDEV_CAP_CAP_ID_MEMDEV 0x4000
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci/* CXL 3.0 8.2.8.3.1 Event Status Register */
16162306a36Sopenharmony_ci#define CXLDEV_DEV_EVENT_STATUS_OFFSET		0x00
16262306a36Sopenharmony_ci#define CXLDEV_EVENT_STATUS_INFO		BIT(0)
16362306a36Sopenharmony_ci#define CXLDEV_EVENT_STATUS_WARN		BIT(1)
16462306a36Sopenharmony_ci#define CXLDEV_EVENT_STATUS_FAIL		BIT(2)
16562306a36Sopenharmony_ci#define CXLDEV_EVENT_STATUS_FATAL		BIT(3)
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci#define CXLDEV_EVENT_STATUS_ALL (CXLDEV_EVENT_STATUS_INFO |	\
16862306a36Sopenharmony_ci				 CXLDEV_EVENT_STATUS_WARN |	\
16962306a36Sopenharmony_ci				 CXLDEV_EVENT_STATUS_FAIL |	\
17062306a36Sopenharmony_ci				 CXLDEV_EVENT_STATUS_FATAL)
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci/* CXL rev 3.0 section 8.2.9.2.4; Table 8-52 */
17362306a36Sopenharmony_ci#define CXLDEV_EVENT_INT_MODE_MASK	GENMASK(1, 0)
17462306a36Sopenharmony_ci#define CXLDEV_EVENT_INT_MSGNUM_MASK	GENMASK(7, 4)
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci/* CXL 2.0 8.2.8.4 Mailbox Registers */
17762306a36Sopenharmony_ci#define CXLDEV_MBOX_CAPS_OFFSET 0x00
17862306a36Sopenharmony_ci#define   CXLDEV_MBOX_CAP_PAYLOAD_SIZE_MASK GENMASK(4, 0)
17962306a36Sopenharmony_ci#define   CXLDEV_MBOX_CAP_BG_CMD_IRQ BIT(6)
18062306a36Sopenharmony_ci#define   CXLDEV_MBOX_CAP_IRQ_MSGNUM_MASK GENMASK(10, 7)
18162306a36Sopenharmony_ci#define CXLDEV_MBOX_CTRL_OFFSET 0x04
18262306a36Sopenharmony_ci#define   CXLDEV_MBOX_CTRL_DOORBELL BIT(0)
18362306a36Sopenharmony_ci#define   CXLDEV_MBOX_CTRL_BG_CMD_IRQ BIT(2)
18462306a36Sopenharmony_ci#define CXLDEV_MBOX_CMD_OFFSET 0x08
18562306a36Sopenharmony_ci#define   CXLDEV_MBOX_CMD_COMMAND_OPCODE_MASK GENMASK_ULL(15, 0)
18662306a36Sopenharmony_ci#define   CXLDEV_MBOX_CMD_PAYLOAD_LENGTH_MASK GENMASK_ULL(36, 16)
18762306a36Sopenharmony_ci#define CXLDEV_MBOX_STATUS_OFFSET 0x10
18862306a36Sopenharmony_ci#define   CXLDEV_MBOX_STATUS_BG_CMD BIT(0)
18962306a36Sopenharmony_ci#define   CXLDEV_MBOX_STATUS_RET_CODE_MASK GENMASK_ULL(47, 32)
19062306a36Sopenharmony_ci#define CXLDEV_MBOX_BG_CMD_STATUS_OFFSET 0x18
19162306a36Sopenharmony_ci#define   CXLDEV_MBOX_BG_CMD_COMMAND_OPCODE_MASK GENMASK_ULL(15, 0)
19262306a36Sopenharmony_ci#define   CXLDEV_MBOX_BG_CMD_COMMAND_PCT_MASK GENMASK_ULL(22, 16)
19362306a36Sopenharmony_ci#define   CXLDEV_MBOX_BG_CMD_COMMAND_RC_MASK GENMASK_ULL(47, 32)
19462306a36Sopenharmony_ci#define   CXLDEV_MBOX_BG_CMD_COMMAND_VENDOR_MASK GENMASK_ULL(63, 48)
19562306a36Sopenharmony_ci#define CXLDEV_MBOX_PAYLOAD_OFFSET 0x20
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci/*
19862306a36Sopenharmony_ci * Using struct_group() allows for per register-block-type helper routines,
19962306a36Sopenharmony_ci * without requiring block-type agnostic code to include the prefix.
20062306a36Sopenharmony_ci */
20162306a36Sopenharmony_cistruct cxl_regs {
20262306a36Sopenharmony_ci	/*
20362306a36Sopenharmony_ci	 * Common set of CXL Component register block base pointers
20462306a36Sopenharmony_ci	 * @hdm_decoder: CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure
20562306a36Sopenharmony_ci	 * @ras: CXL 2.0 8.2.5.9 CXL RAS Capability Structure
20662306a36Sopenharmony_ci	 */
20762306a36Sopenharmony_ci	struct_group_tagged(cxl_component_regs, component,
20862306a36Sopenharmony_ci		void __iomem *hdm_decoder;
20962306a36Sopenharmony_ci		void __iomem *ras;
21062306a36Sopenharmony_ci	);
21162306a36Sopenharmony_ci	/*
21262306a36Sopenharmony_ci	 * Common set of CXL Device register block base pointers
21362306a36Sopenharmony_ci	 * @status: CXL 2.0 8.2.8.3 Device Status Registers
21462306a36Sopenharmony_ci	 * @mbox: CXL 2.0 8.2.8.4 Mailbox Registers
21562306a36Sopenharmony_ci	 * @memdev: CXL 2.0 8.2.8.5 Memory Device Registers
21662306a36Sopenharmony_ci	 */
21762306a36Sopenharmony_ci	struct_group_tagged(cxl_device_regs, device_regs,
21862306a36Sopenharmony_ci		void __iomem *status, *mbox, *memdev;
21962306a36Sopenharmony_ci	);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	struct_group_tagged(cxl_pmu_regs, pmu_regs,
22262306a36Sopenharmony_ci		void __iomem *pmu;
22362306a36Sopenharmony_ci	);
22462306a36Sopenharmony_ci};
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistruct cxl_reg_map {
22762306a36Sopenharmony_ci	bool valid;
22862306a36Sopenharmony_ci	int id;
22962306a36Sopenharmony_ci	unsigned long offset;
23062306a36Sopenharmony_ci	unsigned long size;
23162306a36Sopenharmony_ci};
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistruct cxl_component_reg_map {
23462306a36Sopenharmony_ci	struct cxl_reg_map hdm_decoder;
23562306a36Sopenharmony_ci	struct cxl_reg_map ras;
23662306a36Sopenharmony_ci};
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistruct cxl_device_reg_map {
23962306a36Sopenharmony_ci	struct cxl_reg_map status;
24062306a36Sopenharmony_ci	struct cxl_reg_map mbox;
24162306a36Sopenharmony_ci	struct cxl_reg_map memdev;
24262306a36Sopenharmony_ci};
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistruct cxl_pmu_reg_map {
24562306a36Sopenharmony_ci	struct cxl_reg_map pmu;
24662306a36Sopenharmony_ci};
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci/**
24962306a36Sopenharmony_ci * struct cxl_register_map - DVSEC harvested register block mapping parameters
25062306a36Sopenharmony_ci * @host: device for devm operations and logging
25162306a36Sopenharmony_ci * @base: virtual base of the register-block-BAR + @block_offset
25262306a36Sopenharmony_ci * @resource: physical resource base of the register block
25362306a36Sopenharmony_ci * @max_size: maximum mapping size to perform register search
25462306a36Sopenharmony_ci * @reg_type: see enum cxl_regloc_type
25562306a36Sopenharmony_ci * @component_map: cxl_reg_map for component registers
25662306a36Sopenharmony_ci * @device_map: cxl_reg_maps for device registers
25762306a36Sopenharmony_ci * @pmu_map: cxl_reg_maps for CXL Performance Monitoring Units
25862306a36Sopenharmony_ci */
25962306a36Sopenharmony_cistruct cxl_register_map {
26062306a36Sopenharmony_ci	struct device *host;
26162306a36Sopenharmony_ci	void __iomem *base;
26262306a36Sopenharmony_ci	resource_size_t resource;
26362306a36Sopenharmony_ci	resource_size_t max_size;
26462306a36Sopenharmony_ci	u8 reg_type;
26562306a36Sopenharmony_ci	union {
26662306a36Sopenharmony_ci		struct cxl_component_reg_map component_map;
26762306a36Sopenharmony_ci		struct cxl_device_reg_map device_map;
26862306a36Sopenharmony_ci		struct cxl_pmu_reg_map pmu_map;
26962306a36Sopenharmony_ci	};
27062306a36Sopenharmony_ci};
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_civoid cxl_probe_component_regs(struct device *dev, void __iomem *base,
27362306a36Sopenharmony_ci			      struct cxl_component_reg_map *map);
27462306a36Sopenharmony_civoid cxl_probe_device_regs(struct device *dev, void __iomem *base,
27562306a36Sopenharmony_ci			   struct cxl_device_reg_map *map);
27662306a36Sopenharmony_ciint cxl_map_component_regs(const struct cxl_register_map *map,
27762306a36Sopenharmony_ci			   struct cxl_component_regs *regs,
27862306a36Sopenharmony_ci			   unsigned long map_mask);
27962306a36Sopenharmony_ciint cxl_map_device_regs(const struct cxl_register_map *map,
28062306a36Sopenharmony_ci			struct cxl_device_regs *regs);
28162306a36Sopenharmony_ciint cxl_map_pmu_regs(struct pci_dev *pdev, struct cxl_pmu_regs *regs,
28262306a36Sopenharmony_ci		     struct cxl_register_map *map);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cienum cxl_regloc_type;
28562306a36Sopenharmony_ciint cxl_count_regblock(struct pci_dev *pdev, enum cxl_regloc_type type);
28662306a36Sopenharmony_ciint cxl_find_regblock_instance(struct pci_dev *pdev, enum cxl_regloc_type type,
28762306a36Sopenharmony_ci			       struct cxl_register_map *map, int index);
28862306a36Sopenharmony_ciint cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type,
28962306a36Sopenharmony_ci		      struct cxl_register_map *map);
29062306a36Sopenharmony_ciint cxl_setup_regs(struct cxl_register_map *map);
29162306a36Sopenharmony_cistruct cxl_dport;
29262306a36Sopenharmony_ciresource_size_t cxl_rcd_component_reg_phys(struct device *dev,
29362306a36Sopenharmony_ci					   struct cxl_dport *dport);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci#define CXL_RESOURCE_NONE ((resource_size_t) -1)
29662306a36Sopenharmony_ci#define CXL_TARGET_STRLEN 20
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci/*
29962306a36Sopenharmony_ci * cxl_decoder flags that define the type of memory / devices this
30062306a36Sopenharmony_ci * decoder supports as well as configuration lock status See "CXL 2.0
30162306a36Sopenharmony_ci * 8.2.5.12.7 CXL HDM Decoder 0 Control Register" for details.
30262306a36Sopenharmony_ci * Additionally indicate whether decoder settings were autodetected,
30362306a36Sopenharmony_ci * user customized.
30462306a36Sopenharmony_ci */
30562306a36Sopenharmony_ci#define CXL_DECODER_F_RAM   BIT(0)
30662306a36Sopenharmony_ci#define CXL_DECODER_F_PMEM  BIT(1)
30762306a36Sopenharmony_ci#define CXL_DECODER_F_TYPE2 BIT(2)
30862306a36Sopenharmony_ci#define CXL_DECODER_F_TYPE3 BIT(3)
30962306a36Sopenharmony_ci#define CXL_DECODER_F_LOCK  BIT(4)
31062306a36Sopenharmony_ci#define CXL_DECODER_F_ENABLE    BIT(5)
31162306a36Sopenharmony_ci#define CXL_DECODER_F_MASK  GENMASK(5, 0)
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cienum cxl_decoder_type {
31462306a36Sopenharmony_ci	CXL_DECODER_DEVMEM = 2,
31562306a36Sopenharmony_ci	CXL_DECODER_HOSTONLYMEM = 3,
31662306a36Sopenharmony_ci};
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci/*
31962306a36Sopenharmony_ci * Current specification goes up to 8, double that seems a reasonable
32062306a36Sopenharmony_ci * software max for the foreseeable future
32162306a36Sopenharmony_ci */
32262306a36Sopenharmony_ci#define CXL_DECODER_MAX_INTERLEAVE 16
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci/**
32662306a36Sopenharmony_ci * struct cxl_decoder - Common CXL HDM Decoder Attributes
32762306a36Sopenharmony_ci * @dev: this decoder's device
32862306a36Sopenharmony_ci * @id: kernel device name id
32962306a36Sopenharmony_ci * @hpa_range: Host physical address range mapped by this decoder
33062306a36Sopenharmony_ci * @interleave_ways: number of cxl_dports in this decode
33162306a36Sopenharmony_ci * @interleave_granularity: data stride per dport
33262306a36Sopenharmony_ci * @target_type: accelerator vs expander (type2 vs type3) selector
33362306a36Sopenharmony_ci * @region: currently assigned region for this decoder
33462306a36Sopenharmony_ci * @flags: memory type capabilities and locking
33562306a36Sopenharmony_ci * @commit: device/decoder-type specific callback to commit settings to hw
33662306a36Sopenharmony_ci * @reset: device/decoder-type specific callback to reset hw settings
33762306a36Sopenharmony_ci*/
33862306a36Sopenharmony_cistruct cxl_decoder {
33962306a36Sopenharmony_ci	struct device dev;
34062306a36Sopenharmony_ci	int id;
34162306a36Sopenharmony_ci	struct range hpa_range;
34262306a36Sopenharmony_ci	int interleave_ways;
34362306a36Sopenharmony_ci	int interleave_granularity;
34462306a36Sopenharmony_ci	enum cxl_decoder_type target_type;
34562306a36Sopenharmony_ci	struct cxl_region *region;
34662306a36Sopenharmony_ci	unsigned long flags;
34762306a36Sopenharmony_ci	int (*commit)(struct cxl_decoder *cxld);
34862306a36Sopenharmony_ci	int (*reset)(struct cxl_decoder *cxld);
34962306a36Sopenharmony_ci};
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci/*
35262306a36Sopenharmony_ci * CXL_DECODER_DEAD prevents endpoints from being reattached to regions
35362306a36Sopenharmony_ci * while cxld_unregister() is running
35462306a36Sopenharmony_ci */
35562306a36Sopenharmony_cienum cxl_decoder_mode {
35662306a36Sopenharmony_ci	CXL_DECODER_NONE,
35762306a36Sopenharmony_ci	CXL_DECODER_RAM,
35862306a36Sopenharmony_ci	CXL_DECODER_PMEM,
35962306a36Sopenharmony_ci	CXL_DECODER_MIXED,
36062306a36Sopenharmony_ci	CXL_DECODER_DEAD,
36162306a36Sopenharmony_ci};
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic inline const char *cxl_decoder_mode_name(enum cxl_decoder_mode mode)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	static const char * const names[] = {
36662306a36Sopenharmony_ci		[CXL_DECODER_NONE] = "none",
36762306a36Sopenharmony_ci		[CXL_DECODER_RAM] = "ram",
36862306a36Sopenharmony_ci		[CXL_DECODER_PMEM] = "pmem",
36962306a36Sopenharmony_ci		[CXL_DECODER_MIXED] = "mixed",
37062306a36Sopenharmony_ci	};
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (mode >= CXL_DECODER_NONE && mode <= CXL_DECODER_MIXED)
37362306a36Sopenharmony_ci		return names[mode];
37462306a36Sopenharmony_ci	return "mixed";
37562306a36Sopenharmony_ci}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci/*
37862306a36Sopenharmony_ci * Track whether this decoder is reserved for region autodiscovery, or
37962306a36Sopenharmony_ci * free for userspace provisioning.
38062306a36Sopenharmony_ci */
38162306a36Sopenharmony_cienum cxl_decoder_state {
38262306a36Sopenharmony_ci	CXL_DECODER_STATE_MANUAL,
38362306a36Sopenharmony_ci	CXL_DECODER_STATE_AUTO,
38462306a36Sopenharmony_ci};
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci/**
38762306a36Sopenharmony_ci * struct cxl_endpoint_decoder - Endpoint  / SPA to DPA decoder
38862306a36Sopenharmony_ci * @cxld: base cxl_decoder_object
38962306a36Sopenharmony_ci * @dpa_res: actively claimed DPA span of this decoder
39062306a36Sopenharmony_ci * @skip: offset into @dpa_res where @cxld.hpa_range maps
39162306a36Sopenharmony_ci * @mode: which memory type / access-mode-partition this decoder targets
39262306a36Sopenharmony_ci * @state: autodiscovery state
39362306a36Sopenharmony_ci * @pos: interleave position in @cxld.region
39462306a36Sopenharmony_ci */
39562306a36Sopenharmony_cistruct cxl_endpoint_decoder {
39662306a36Sopenharmony_ci	struct cxl_decoder cxld;
39762306a36Sopenharmony_ci	struct resource *dpa_res;
39862306a36Sopenharmony_ci	resource_size_t skip;
39962306a36Sopenharmony_ci	enum cxl_decoder_mode mode;
40062306a36Sopenharmony_ci	enum cxl_decoder_state state;
40162306a36Sopenharmony_ci	int pos;
40262306a36Sopenharmony_ci};
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci/**
40562306a36Sopenharmony_ci * struct cxl_switch_decoder - Switch specific CXL HDM Decoder
40662306a36Sopenharmony_ci * @cxld: base cxl_decoder object
40762306a36Sopenharmony_ci * @nr_targets: number of elements in @target
40862306a36Sopenharmony_ci * @target: active ordered target list in current decoder configuration
40962306a36Sopenharmony_ci *
41062306a36Sopenharmony_ci * The 'switch' decoder type represents the decoder instances of cxl_port's that
41162306a36Sopenharmony_ci * route from the root of a CXL memory decode topology to the endpoints. They
41262306a36Sopenharmony_ci * come in two flavors, root-level decoders, statically defined by platform
41362306a36Sopenharmony_ci * firmware, and mid-level decoders, where interleave-granularity,
41462306a36Sopenharmony_ci * interleave-width, and the target list are mutable.
41562306a36Sopenharmony_ci */
41662306a36Sopenharmony_cistruct cxl_switch_decoder {
41762306a36Sopenharmony_ci	struct cxl_decoder cxld;
41862306a36Sopenharmony_ci	int nr_targets;
41962306a36Sopenharmony_ci	struct cxl_dport *target[];
42062306a36Sopenharmony_ci};
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistruct cxl_root_decoder;
42362306a36Sopenharmony_citypedef struct cxl_dport *(*cxl_calc_hb_fn)(struct cxl_root_decoder *cxlrd,
42462306a36Sopenharmony_ci					    int pos);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci/**
42762306a36Sopenharmony_ci * struct cxl_root_decoder - Static platform CXL address decoder
42862306a36Sopenharmony_ci * @res: host / parent resource for region allocations
42962306a36Sopenharmony_ci * @region_id: region id for next region provisioning event
43062306a36Sopenharmony_ci * @calc_hb: which host bridge covers the n'th position by granularity
43162306a36Sopenharmony_ci * @platform_data: platform specific configuration data
43262306a36Sopenharmony_ci * @range_lock: sync region autodiscovery by address range
43362306a36Sopenharmony_ci * @cxlsd: base cxl switch decoder
43462306a36Sopenharmony_ci */
43562306a36Sopenharmony_cistruct cxl_root_decoder {
43662306a36Sopenharmony_ci	struct resource *res;
43762306a36Sopenharmony_ci	atomic_t region_id;
43862306a36Sopenharmony_ci	cxl_calc_hb_fn calc_hb;
43962306a36Sopenharmony_ci	void *platform_data;
44062306a36Sopenharmony_ci	struct mutex range_lock;
44162306a36Sopenharmony_ci	struct cxl_switch_decoder cxlsd;
44262306a36Sopenharmony_ci};
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci/*
44562306a36Sopenharmony_ci * enum cxl_config_state - State machine for region configuration
44662306a36Sopenharmony_ci * @CXL_CONFIG_IDLE: Any sysfs attribute can be written freely
44762306a36Sopenharmony_ci * @CXL_CONFIG_INTERLEAVE_ACTIVE: region size has been set, no more
44862306a36Sopenharmony_ci * changes to interleave_ways or interleave_granularity
44962306a36Sopenharmony_ci * @CXL_CONFIG_ACTIVE: All targets have been added the region is now
45062306a36Sopenharmony_ci * active
45162306a36Sopenharmony_ci * @CXL_CONFIG_RESET_PENDING: see commit_store()
45262306a36Sopenharmony_ci * @CXL_CONFIG_COMMIT: Soft-config has been committed to hardware
45362306a36Sopenharmony_ci */
45462306a36Sopenharmony_cienum cxl_config_state {
45562306a36Sopenharmony_ci	CXL_CONFIG_IDLE,
45662306a36Sopenharmony_ci	CXL_CONFIG_INTERLEAVE_ACTIVE,
45762306a36Sopenharmony_ci	CXL_CONFIG_ACTIVE,
45862306a36Sopenharmony_ci	CXL_CONFIG_RESET_PENDING,
45962306a36Sopenharmony_ci	CXL_CONFIG_COMMIT,
46062306a36Sopenharmony_ci};
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci/**
46362306a36Sopenharmony_ci * struct cxl_region_params - region settings
46462306a36Sopenharmony_ci * @state: allow the driver to lockdown further parameter changes
46562306a36Sopenharmony_ci * @uuid: unique id for persistent regions
46662306a36Sopenharmony_ci * @interleave_ways: number of endpoints in the region
46762306a36Sopenharmony_ci * @interleave_granularity: capacity each endpoint contributes to a stripe
46862306a36Sopenharmony_ci * @res: allocated iomem capacity for this region
46962306a36Sopenharmony_ci * @targets: active ordered targets in current decoder configuration
47062306a36Sopenharmony_ci * @nr_targets: number of targets
47162306a36Sopenharmony_ci *
47262306a36Sopenharmony_ci * State transitions are protected by the cxl_region_rwsem
47362306a36Sopenharmony_ci */
47462306a36Sopenharmony_cistruct cxl_region_params {
47562306a36Sopenharmony_ci	enum cxl_config_state state;
47662306a36Sopenharmony_ci	uuid_t uuid;
47762306a36Sopenharmony_ci	int interleave_ways;
47862306a36Sopenharmony_ci	int interleave_granularity;
47962306a36Sopenharmony_ci	struct resource *res;
48062306a36Sopenharmony_ci	struct cxl_endpoint_decoder *targets[CXL_DECODER_MAX_INTERLEAVE];
48162306a36Sopenharmony_ci	int nr_targets;
48262306a36Sopenharmony_ci};
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci/*
48562306a36Sopenharmony_ci * Indicate whether this region has been assembled by autodetection or
48662306a36Sopenharmony_ci * userspace assembly. Prevent endpoint decoders outside of automatic
48762306a36Sopenharmony_ci * detection from being added to the region.
48862306a36Sopenharmony_ci */
48962306a36Sopenharmony_ci#define CXL_REGION_F_AUTO 0
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci/*
49262306a36Sopenharmony_ci * Require that a committed region successfully complete a teardown once
49362306a36Sopenharmony_ci * any of its associated decoders have been torn down. This maintains
49462306a36Sopenharmony_ci * the commit state for the region since there are committed decoders,
49562306a36Sopenharmony_ci * but blocks cxl_region_probe().
49662306a36Sopenharmony_ci */
49762306a36Sopenharmony_ci#define CXL_REGION_F_NEEDS_RESET 1
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci/**
50062306a36Sopenharmony_ci * struct cxl_region - CXL region
50162306a36Sopenharmony_ci * @dev: This region's device
50262306a36Sopenharmony_ci * @id: This region's id. Id is globally unique across all regions
50362306a36Sopenharmony_ci * @mode: Endpoint decoder allocation / access mode
50462306a36Sopenharmony_ci * @type: Endpoint decoder target type
50562306a36Sopenharmony_ci * @cxl_nvb: nvdimm bridge for coordinating @cxlr_pmem setup / shutdown
50662306a36Sopenharmony_ci * @cxlr_pmem: (for pmem regions) cached copy of the nvdimm bridge
50762306a36Sopenharmony_ci * @flags: Region state flags
50862306a36Sopenharmony_ci * @params: active + config params for the region
50962306a36Sopenharmony_ci */
51062306a36Sopenharmony_cistruct cxl_region {
51162306a36Sopenharmony_ci	struct device dev;
51262306a36Sopenharmony_ci	int id;
51362306a36Sopenharmony_ci	enum cxl_decoder_mode mode;
51462306a36Sopenharmony_ci	enum cxl_decoder_type type;
51562306a36Sopenharmony_ci	struct cxl_nvdimm_bridge *cxl_nvb;
51662306a36Sopenharmony_ci	struct cxl_pmem_region *cxlr_pmem;
51762306a36Sopenharmony_ci	unsigned long flags;
51862306a36Sopenharmony_ci	struct cxl_region_params params;
51962306a36Sopenharmony_ci};
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_cistruct cxl_nvdimm_bridge {
52262306a36Sopenharmony_ci	int id;
52362306a36Sopenharmony_ci	struct device dev;
52462306a36Sopenharmony_ci	struct cxl_port *port;
52562306a36Sopenharmony_ci	struct nvdimm_bus *nvdimm_bus;
52662306a36Sopenharmony_ci	struct nvdimm_bus_descriptor nd_desc;
52762306a36Sopenharmony_ci};
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci#define CXL_DEV_ID_LEN 19
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistruct cxl_nvdimm {
53262306a36Sopenharmony_ci	struct device dev;
53362306a36Sopenharmony_ci	struct cxl_memdev *cxlmd;
53462306a36Sopenharmony_ci	u8 dev_id[CXL_DEV_ID_LEN]; /* for nvdimm, string of 'serial' */
53562306a36Sopenharmony_ci};
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cistruct cxl_pmem_region_mapping {
53862306a36Sopenharmony_ci	struct cxl_memdev *cxlmd;
53962306a36Sopenharmony_ci	struct cxl_nvdimm *cxl_nvd;
54062306a36Sopenharmony_ci	u64 start;
54162306a36Sopenharmony_ci	u64 size;
54262306a36Sopenharmony_ci	int position;
54362306a36Sopenharmony_ci};
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_cistruct cxl_pmem_region {
54662306a36Sopenharmony_ci	struct device dev;
54762306a36Sopenharmony_ci	struct cxl_region *cxlr;
54862306a36Sopenharmony_ci	struct nd_region *nd_region;
54962306a36Sopenharmony_ci	struct range hpa_range;
55062306a36Sopenharmony_ci	int nr_mappings;
55162306a36Sopenharmony_ci	struct cxl_pmem_region_mapping mapping[];
55262306a36Sopenharmony_ci};
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_cistruct cxl_dax_region {
55562306a36Sopenharmony_ci	struct device dev;
55662306a36Sopenharmony_ci	struct cxl_region *cxlr;
55762306a36Sopenharmony_ci	struct range hpa_range;
55862306a36Sopenharmony_ci};
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci/**
56162306a36Sopenharmony_ci * struct cxl_port - logical collection of upstream port devices and
56262306a36Sopenharmony_ci *		     downstream port devices to construct a CXL memory
56362306a36Sopenharmony_ci *		     decode hierarchy.
56462306a36Sopenharmony_ci * @dev: this port's device
56562306a36Sopenharmony_ci * @uport_dev: PCI or platform device implementing the upstream port capability
56662306a36Sopenharmony_ci * @host_bridge: Shortcut to the platform attach point for this port
56762306a36Sopenharmony_ci * @id: id for port device-name
56862306a36Sopenharmony_ci * @dports: cxl_dport instances referenced by decoders
56962306a36Sopenharmony_ci * @endpoints: cxl_ep instances, endpoints that are a descendant of this port
57062306a36Sopenharmony_ci * @regions: cxl_region_ref instances, regions mapped by this port
57162306a36Sopenharmony_ci * @parent_dport: dport that points to this port in the parent
57262306a36Sopenharmony_ci * @decoder_ida: allocator for decoder ids
57362306a36Sopenharmony_ci * @comp_map: component register capability mappings
57462306a36Sopenharmony_ci * @nr_dports: number of entries in @dports
57562306a36Sopenharmony_ci * @hdm_end: track last allocated HDM decoder instance for allocation ordering
57662306a36Sopenharmony_ci * @commit_end: cursor to track highest committed decoder for commit ordering
57762306a36Sopenharmony_ci * @component_reg_phys: component register capability base address (optional)
57862306a36Sopenharmony_ci * @dead: last ep has been removed, force port re-creation
57962306a36Sopenharmony_ci * @depth: How deep this port is relative to the root. depth 0 is the root.
58062306a36Sopenharmony_ci * @cdat: Cached CDAT data
58162306a36Sopenharmony_ci * @cdat_available: Should a CDAT attribute be available in sysfs
58262306a36Sopenharmony_ci */
58362306a36Sopenharmony_cistruct cxl_port {
58462306a36Sopenharmony_ci	struct device dev;
58562306a36Sopenharmony_ci	struct device *uport_dev;
58662306a36Sopenharmony_ci	struct device *host_bridge;
58762306a36Sopenharmony_ci	int id;
58862306a36Sopenharmony_ci	struct xarray dports;
58962306a36Sopenharmony_ci	struct xarray endpoints;
59062306a36Sopenharmony_ci	struct xarray regions;
59162306a36Sopenharmony_ci	struct cxl_dport *parent_dport;
59262306a36Sopenharmony_ci	struct ida decoder_ida;
59362306a36Sopenharmony_ci	struct cxl_register_map comp_map;
59462306a36Sopenharmony_ci	int nr_dports;
59562306a36Sopenharmony_ci	int hdm_end;
59662306a36Sopenharmony_ci	int commit_end;
59762306a36Sopenharmony_ci	resource_size_t component_reg_phys;
59862306a36Sopenharmony_ci	bool dead;
59962306a36Sopenharmony_ci	unsigned int depth;
60062306a36Sopenharmony_ci	struct cxl_cdat {
60162306a36Sopenharmony_ci		void *table;
60262306a36Sopenharmony_ci		size_t length;
60362306a36Sopenharmony_ci	} cdat;
60462306a36Sopenharmony_ci	bool cdat_available;
60562306a36Sopenharmony_ci};
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic inline struct cxl_dport *
60862306a36Sopenharmony_cicxl_find_dport_by_dev(struct cxl_port *port, const struct device *dport_dev)
60962306a36Sopenharmony_ci{
61062306a36Sopenharmony_ci	return xa_load(&port->dports, (unsigned long)dport_dev);
61162306a36Sopenharmony_ci}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_cistruct cxl_rcrb_info {
61462306a36Sopenharmony_ci	resource_size_t base;
61562306a36Sopenharmony_ci	u16 aer_cap;
61662306a36Sopenharmony_ci};
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci/**
61962306a36Sopenharmony_ci * struct cxl_dport - CXL downstream port
62062306a36Sopenharmony_ci * @dport_dev: PCI bridge or firmware device representing the downstream link
62162306a36Sopenharmony_ci * @comp_map: component register capability mappings
62262306a36Sopenharmony_ci * @port_id: unique hardware identifier for dport in decoder target list
62362306a36Sopenharmony_ci * @rcrb: Data about the Root Complex Register Block layout
62462306a36Sopenharmony_ci * @rch: Indicate whether this dport was enumerated in RCH or VH mode
62562306a36Sopenharmony_ci * @port: reference to cxl_port that contains this downstream port
62662306a36Sopenharmony_ci */
62762306a36Sopenharmony_cistruct cxl_dport {
62862306a36Sopenharmony_ci	struct device *dport_dev;
62962306a36Sopenharmony_ci	struct cxl_register_map comp_map;
63062306a36Sopenharmony_ci	int port_id;
63162306a36Sopenharmony_ci	struct cxl_rcrb_info rcrb;
63262306a36Sopenharmony_ci	bool rch;
63362306a36Sopenharmony_ci	struct cxl_port *port;
63462306a36Sopenharmony_ci};
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci/**
63762306a36Sopenharmony_ci * struct cxl_ep - track an endpoint's interest in a port
63862306a36Sopenharmony_ci * @ep: device that hosts a generic CXL endpoint (expander or accelerator)
63962306a36Sopenharmony_ci * @dport: which dport routes to this endpoint on @port
64062306a36Sopenharmony_ci * @next: cxl switch port across the link attached to @dport NULL if
64162306a36Sopenharmony_ci *	  attached to an endpoint
64262306a36Sopenharmony_ci */
64362306a36Sopenharmony_cistruct cxl_ep {
64462306a36Sopenharmony_ci	struct device *ep;
64562306a36Sopenharmony_ci	struct cxl_dport *dport;
64662306a36Sopenharmony_ci	struct cxl_port *next;
64762306a36Sopenharmony_ci};
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci/**
65062306a36Sopenharmony_ci * struct cxl_region_ref - track a region's interest in a port
65162306a36Sopenharmony_ci * @port: point in topology to install this reference
65262306a36Sopenharmony_ci * @decoder: decoder assigned for @region in @port
65362306a36Sopenharmony_ci * @region: region for this reference
65462306a36Sopenharmony_ci * @endpoints: cxl_ep references for region members beneath @port
65562306a36Sopenharmony_ci * @nr_targets_set: track how many targets have been programmed during setup
65662306a36Sopenharmony_ci * @nr_eps: number of endpoints beneath @port
65762306a36Sopenharmony_ci * @nr_targets: number of distinct targets needed to reach @nr_eps
65862306a36Sopenharmony_ci */
65962306a36Sopenharmony_cistruct cxl_region_ref {
66062306a36Sopenharmony_ci	struct cxl_port *port;
66162306a36Sopenharmony_ci	struct cxl_decoder *decoder;
66262306a36Sopenharmony_ci	struct cxl_region *region;
66362306a36Sopenharmony_ci	struct xarray endpoints;
66462306a36Sopenharmony_ci	int nr_targets_set;
66562306a36Sopenharmony_ci	int nr_eps;
66662306a36Sopenharmony_ci	int nr_targets;
66762306a36Sopenharmony_ci};
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci/*
67062306a36Sopenharmony_ci * The platform firmware device hosting the root is also the top of the
67162306a36Sopenharmony_ci * CXL port topology. All other CXL ports have another CXL port as their
67262306a36Sopenharmony_ci * parent and their ->uport_dev / host device is out-of-line of the port
67362306a36Sopenharmony_ci * ancestry.
67462306a36Sopenharmony_ci */
67562306a36Sopenharmony_cistatic inline bool is_cxl_root(struct cxl_port *port)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	return port->uport_dev == port->dev.parent;
67862306a36Sopenharmony_ci}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ciint cxl_num_decoders_committed(struct cxl_port *port);
68162306a36Sopenharmony_cibool is_cxl_port(const struct device *dev);
68262306a36Sopenharmony_cistruct cxl_port *to_cxl_port(const struct device *dev);
68362306a36Sopenharmony_cistruct pci_bus;
68462306a36Sopenharmony_ciint devm_cxl_register_pci_bus(struct device *host, struct device *uport_dev,
68562306a36Sopenharmony_ci			      struct pci_bus *bus);
68662306a36Sopenharmony_cistruct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port);
68762306a36Sopenharmony_cistruct cxl_port *devm_cxl_add_port(struct device *host,
68862306a36Sopenharmony_ci				   struct device *uport_dev,
68962306a36Sopenharmony_ci				   resource_size_t component_reg_phys,
69062306a36Sopenharmony_ci				   struct cxl_dport *parent_dport);
69162306a36Sopenharmony_cistruct cxl_port *find_cxl_root(struct cxl_port *port);
69262306a36Sopenharmony_ciint devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd);
69362306a36Sopenharmony_civoid cxl_bus_rescan(void);
69462306a36Sopenharmony_civoid cxl_bus_drain(void);
69562306a36Sopenharmony_cistruct cxl_port *cxl_pci_find_port(struct pci_dev *pdev,
69662306a36Sopenharmony_ci				   struct cxl_dport **dport);
69762306a36Sopenharmony_cistruct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd,
69862306a36Sopenharmony_ci				   struct cxl_dport **dport);
69962306a36Sopenharmony_cibool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd);
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_cistruct cxl_dport *devm_cxl_add_dport(struct cxl_port *port,
70262306a36Sopenharmony_ci				     struct device *dport, int port_id,
70362306a36Sopenharmony_ci				     resource_size_t component_reg_phys);
70462306a36Sopenharmony_cistruct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port,
70562306a36Sopenharmony_ci					 struct device *dport_dev, int port_id,
70662306a36Sopenharmony_ci					 resource_size_t rcrb);
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_cistruct cxl_decoder *to_cxl_decoder(struct device *dev);
70962306a36Sopenharmony_cistruct cxl_root_decoder *to_cxl_root_decoder(struct device *dev);
71062306a36Sopenharmony_cistruct cxl_switch_decoder *to_cxl_switch_decoder(struct device *dev);
71162306a36Sopenharmony_cistruct cxl_endpoint_decoder *to_cxl_endpoint_decoder(struct device *dev);
71262306a36Sopenharmony_cibool is_root_decoder(struct device *dev);
71362306a36Sopenharmony_cibool is_switch_decoder(struct device *dev);
71462306a36Sopenharmony_cibool is_endpoint_decoder(struct device *dev);
71562306a36Sopenharmony_cistruct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
71662306a36Sopenharmony_ci						unsigned int nr_targets,
71762306a36Sopenharmony_ci						cxl_calc_hb_fn calc_hb);
71862306a36Sopenharmony_cistruct cxl_dport *cxl_hb_modulo(struct cxl_root_decoder *cxlrd, int pos);
71962306a36Sopenharmony_cistruct cxl_switch_decoder *cxl_switch_decoder_alloc(struct cxl_port *port,
72062306a36Sopenharmony_ci						    unsigned int nr_targets);
72162306a36Sopenharmony_ciint cxl_decoder_add(struct cxl_decoder *cxld, int *target_map);
72262306a36Sopenharmony_cistruct cxl_endpoint_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port);
72362306a36Sopenharmony_ciint cxl_decoder_add_locked(struct cxl_decoder *cxld, int *target_map);
72462306a36Sopenharmony_ciint cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld);
72562306a36Sopenharmony_ciint cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci/**
72862306a36Sopenharmony_ci * struct cxl_endpoint_dvsec_info - Cached DVSEC info
72962306a36Sopenharmony_ci * @mem_enabled: cached value of mem_enabled in the DVSEC at init time
73062306a36Sopenharmony_ci * @ranges: Number of active HDM ranges this device uses.
73162306a36Sopenharmony_ci * @port: endpoint port associated with this info instance
73262306a36Sopenharmony_ci * @dvsec_range: cached attributes of the ranges in the DVSEC, PCIE_DEVICE
73362306a36Sopenharmony_ci */
73462306a36Sopenharmony_cistruct cxl_endpoint_dvsec_info {
73562306a36Sopenharmony_ci	bool mem_enabled;
73662306a36Sopenharmony_ci	int ranges;
73762306a36Sopenharmony_ci	struct cxl_port *port;
73862306a36Sopenharmony_ci	struct range dvsec_range[2];
73962306a36Sopenharmony_ci};
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_cistruct cxl_hdm;
74262306a36Sopenharmony_cistruct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,
74362306a36Sopenharmony_ci				   struct cxl_endpoint_dvsec_info *info);
74462306a36Sopenharmony_ciint devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
74562306a36Sopenharmony_ci				struct cxl_endpoint_dvsec_info *info);
74662306a36Sopenharmony_ciint devm_cxl_add_passthrough_decoder(struct cxl_port *port);
74762306a36Sopenharmony_ciint cxl_dvsec_rr_decode(struct device *dev, int dvsec,
74862306a36Sopenharmony_ci			struct cxl_endpoint_dvsec_info *info);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_cibool is_cxl_region(struct device *dev);
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ciextern struct bus_type cxl_bus_type;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_cistruct cxl_driver {
75562306a36Sopenharmony_ci	const char *name;
75662306a36Sopenharmony_ci	int (*probe)(struct device *dev);
75762306a36Sopenharmony_ci	void (*remove)(struct device *dev);
75862306a36Sopenharmony_ci	struct device_driver drv;
75962306a36Sopenharmony_ci	int id;
76062306a36Sopenharmony_ci};
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_cistatic inline struct cxl_driver *to_cxl_drv(struct device_driver *drv)
76362306a36Sopenharmony_ci{
76462306a36Sopenharmony_ci	return container_of(drv, struct cxl_driver, drv);
76562306a36Sopenharmony_ci}
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ciint __cxl_driver_register(struct cxl_driver *cxl_drv, struct module *owner,
76862306a36Sopenharmony_ci			  const char *modname);
76962306a36Sopenharmony_ci#define cxl_driver_register(x) __cxl_driver_register(x, THIS_MODULE, KBUILD_MODNAME)
77062306a36Sopenharmony_civoid cxl_driver_unregister(struct cxl_driver *cxl_drv);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci#define module_cxl_driver(__cxl_driver) \
77362306a36Sopenharmony_ci	module_driver(__cxl_driver, cxl_driver_register, cxl_driver_unregister)
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci#define CXL_DEVICE_NVDIMM_BRIDGE	1
77662306a36Sopenharmony_ci#define CXL_DEVICE_NVDIMM		2
77762306a36Sopenharmony_ci#define CXL_DEVICE_PORT			3
77862306a36Sopenharmony_ci#define CXL_DEVICE_ROOT			4
77962306a36Sopenharmony_ci#define CXL_DEVICE_MEMORY_EXPANDER	5
78062306a36Sopenharmony_ci#define CXL_DEVICE_REGION		6
78162306a36Sopenharmony_ci#define CXL_DEVICE_PMEM_REGION		7
78262306a36Sopenharmony_ci#define CXL_DEVICE_DAX_REGION		8
78362306a36Sopenharmony_ci#define CXL_DEVICE_PMU			9
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci#define MODULE_ALIAS_CXL(type) MODULE_ALIAS("cxl:t" __stringify(type) "*")
78662306a36Sopenharmony_ci#define CXL_MODALIAS_FMT "cxl:t%d"
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_cistruct cxl_nvdimm_bridge *to_cxl_nvdimm_bridge(struct device *dev);
78962306a36Sopenharmony_cistruct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host,
79062306a36Sopenharmony_ci						     struct cxl_port *port);
79162306a36Sopenharmony_cistruct cxl_nvdimm *to_cxl_nvdimm(struct device *dev);
79262306a36Sopenharmony_cibool is_cxl_nvdimm(struct device *dev);
79362306a36Sopenharmony_cibool is_cxl_nvdimm_bridge(struct device *dev);
79462306a36Sopenharmony_ciint devm_cxl_add_nvdimm(struct cxl_memdev *cxlmd);
79562306a36Sopenharmony_cistruct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_memdev *cxlmd);
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci#ifdef CONFIG_CXL_REGION
79862306a36Sopenharmony_cibool is_cxl_pmem_region(struct device *dev);
79962306a36Sopenharmony_cistruct cxl_pmem_region *to_cxl_pmem_region(struct device *dev);
80062306a36Sopenharmony_ciint cxl_add_to_region(struct cxl_port *root,
80162306a36Sopenharmony_ci		      struct cxl_endpoint_decoder *cxled);
80262306a36Sopenharmony_cistruct cxl_dax_region *to_cxl_dax_region(struct device *dev);
80362306a36Sopenharmony_ci#else
80462306a36Sopenharmony_cistatic inline bool is_cxl_pmem_region(struct device *dev)
80562306a36Sopenharmony_ci{
80662306a36Sopenharmony_ci	return false;
80762306a36Sopenharmony_ci}
80862306a36Sopenharmony_cistatic inline struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev)
80962306a36Sopenharmony_ci{
81062306a36Sopenharmony_ci	return NULL;
81162306a36Sopenharmony_ci}
81262306a36Sopenharmony_cistatic inline int cxl_add_to_region(struct cxl_port *root,
81362306a36Sopenharmony_ci				    struct cxl_endpoint_decoder *cxled)
81462306a36Sopenharmony_ci{
81562306a36Sopenharmony_ci	return 0;
81662306a36Sopenharmony_ci}
81762306a36Sopenharmony_cistatic inline struct cxl_dax_region *to_cxl_dax_region(struct device *dev)
81862306a36Sopenharmony_ci{
81962306a36Sopenharmony_ci	return NULL;
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci#endif
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci/*
82462306a36Sopenharmony_ci * Unit test builds overrides this to __weak, find the 'strong' version
82562306a36Sopenharmony_ci * of these symbols in tools/testing/cxl/.
82662306a36Sopenharmony_ci */
82762306a36Sopenharmony_ci#ifndef __mock
82862306a36Sopenharmony_ci#define __mock static
82962306a36Sopenharmony_ci#endif
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci#endif /* __CXL_H__ */
832