Commit | Line | Data |
---|---|---|
8adaf747 BW |
1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* Copyright(c) 2020 Intel Corporation. */ | |
3 | ||
4 | #ifndef __CXL_H__ | |
5 | #define __CXL_H__ | |
6 | ||
8fdcb170 | 7 | #include <linux/libnvdimm.h> |
8adaf747 BW |
8 | #include <linux/bitfield.h> |
9 | #include <linux/bitops.h> | |
80d10a6c | 10 | #include <linux/log2.h> |
8adaf747 BW |
11 | #include <linux/io.h> |
12 | ||
4812be97 DW |
13 | /** |
14 | * DOC: cxl objects | |
15 | * | |
16 | * The CXL core objects like ports, decoders, and regions are shared | |
17 | * between the subsystem drivers cxl_acpi, cxl_pci, and core drivers | |
18 | * (port-driver, region-driver, nvdimm object-drivers... etc). | |
19 | */ | |
20 | ||
d17d0540 DW |
21 | /* CXL 2.0 8.2.4 CXL Component Register Layout and Definition */ |
22 | #define CXL_COMPONENT_REG_BLOCK_SIZE SZ_64K | |
23 | ||
08422378 BW |
24 | /* CXL 2.0 8.2.5 CXL.cache and CXL.mem Registers*/ |
25 | #define CXL_CM_OFFSET 0x1000 | |
26 | #define CXL_CM_CAP_HDR_OFFSET 0x0 | |
27 | #define CXL_CM_CAP_HDR_ID_MASK GENMASK(15, 0) | |
28 | #define CM_CAP_HDR_CAP_ID 1 | |
29 | #define CXL_CM_CAP_HDR_VERSION_MASK GENMASK(19, 16) | |
30 | #define CM_CAP_HDR_CAP_VERSION 1 | |
31 | #define CXL_CM_CAP_HDR_CACHE_MEM_VERSION_MASK GENMASK(23, 20) | |
32 | #define CM_CAP_HDR_CACHE_MEM_VERSION 1 | |
33 | #define CXL_CM_CAP_HDR_ARRAY_SIZE_MASK GENMASK(31, 24) | |
34 | #define CXL_CM_CAP_PTR_MASK GENMASK(31, 20) | |
35 | ||
36 | #define CXL_CM_CAP_CAP_ID_HDM 0x5 | |
37 | #define CXL_CM_CAP_CAP_HDM_VERSION 1 | |
38 | ||
39 | /* HDM decoders CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure */ | |
40 | #define CXL_HDM_DECODER_CAP_OFFSET 0x0 | |
41 | #define CXL_HDM_DECODER_COUNT_MASK GENMASK(3, 0) | |
42 | #define CXL_HDM_DECODER_TARGET_COUNT_MASK GENMASK(7, 4) | |
d17d0540 DW |
43 | #define CXL_HDM_DECODER_INTERLEAVE_11_8 BIT(8) |
44 | #define CXL_HDM_DECODER_INTERLEAVE_14_12 BIT(9) | |
45 | #define CXL_HDM_DECODER_CTRL_OFFSET 0x4 | |
46 | #define CXL_HDM_DECODER_ENABLE BIT(1) | |
47 | #define CXL_HDM_DECODER0_BASE_LOW_OFFSET(i) (0x20 * (i) + 0x10) | |
48 | #define CXL_HDM_DECODER0_BASE_HIGH_OFFSET(i) (0x20 * (i) + 0x14) | |
49 | #define CXL_HDM_DECODER0_SIZE_LOW_OFFSET(i) (0x20 * (i) + 0x18) | |
50 | #define CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(i) (0x20 * (i) + 0x1c) | |
51 | #define CXL_HDM_DECODER0_CTRL_OFFSET(i) (0x20 * (i) + 0x20) | |
52 | #define CXL_HDM_DECODER0_CTRL_IG_MASK GENMASK(3, 0) | |
53 | #define CXL_HDM_DECODER0_CTRL_IW_MASK GENMASK(7, 4) | |
54 | #define CXL_HDM_DECODER0_CTRL_LOCK BIT(8) | |
55 | #define CXL_HDM_DECODER0_CTRL_COMMIT BIT(9) | |
56 | #define CXL_HDM_DECODER0_CTRL_COMMITTED BIT(10) | |
57 | #define CXL_HDM_DECODER0_CTRL_TYPE BIT(12) | |
58 | #define CXL_HDM_DECODER0_TL_LOW(i) (0x20 * (i) + 0x24) | |
59 | #define CXL_HDM_DECODER0_TL_HIGH(i) (0x20 * (i) + 0x28) | |
9c57cde0 DW |
60 | #define CXL_HDM_DECODER0_SKIP_LOW(i) CXL_HDM_DECODER0_TL_LOW(i) |
61 | #define CXL_HDM_DECODER0_SKIP_HIGH(i) CXL_HDM_DECODER0_TL_HIGH(i) | |
08422378 | 62 | |
6423035f BW |
63 | static inline int cxl_hdm_decoder_count(u32 cap_hdr) |
64 | { | |
65 | int val = FIELD_GET(CXL_HDM_DECODER_COUNT_MASK, cap_hdr); | |
66 | ||
67 | return val ? val * 2 : 1; | |
68 | } | |
69 | ||
419af595 DW |
70 | /* Encode defined in CXL 2.0 8.2.5.12.7 HDM Decoder Control Register */ |
71 | static inline int cxl_to_granularity(u16 ig, unsigned int *val) | |
72 | { | |
73 | if (ig > 6) | |
74 | return -EINVAL; | |
75 | *val = 256 << ig; | |
76 | return 0; | |
77 | } | |
78 | ||
79 | /* Encode defined in CXL ECN "3, 6, 12 and 16-way memory Interleaving" */ | |
80 | static inline int cxl_to_ways(u8 eniw, unsigned int *val) | |
81 | { | |
82 | switch (eniw) { | |
83 | case 0 ... 4: | |
84 | *val = 1 << eniw; | |
85 | break; | |
86 | case 8 ... 10: | |
87 | *val = 3 << (eniw - 8); | |
88 | break; | |
89 | default: | |
90 | return -EINVAL; | |
91 | } | |
92 | ||
93 | return 0; | |
94 | } | |
95 | ||
80d10a6c BW |
96 | static inline int granularity_to_cxl(int g, u16 *ig) |
97 | { | |
98 | if (g > SZ_16K || g < 256 || !is_power_of_2(g)) | |
99 | return -EINVAL; | |
100 | *ig = ilog2(g) - 8; | |
101 | return 0; | |
102 | } | |
103 | ||
104 | static inline int ways_to_cxl(int ways, u8 *iw) | |
105 | { | |
106 | if (ways > 16) | |
107 | return -EINVAL; | |
108 | if (is_power_of_2(ways)) { | |
109 | *iw = ilog2(ways); | |
110 | return 0; | |
111 | } | |
112 | if (ways % 3) | |
113 | return -EINVAL; | |
114 | ways /= 3; | |
115 | if (!is_power_of_2(ways)) | |
116 | return -EINVAL; | |
117 | *iw = ilog2(ways) + 8; | |
118 | return 0; | |
119 | } | |
120 | ||
8adaf747 BW |
121 | /* CXL 2.0 8.2.8.1 Device Capabilities Array Register */ |
122 | #define CXLDEV_CAP_ARRAY_OFFSET 0x0 | |
123 | #define CXLDEV_CAP_ARRAY_CAP_ID 0 | |
124 | #define CXLDEV_CAP_ARRAY_ID_MASK GENMASK_ULL(15, 0) | |
125 | #define CXLDEV_CAP_ARRAY_COUNT_MASK GENMASK_ULL(47, 32) | |
126 | /* CXL 2.0 8.2.8.2 CXL Device Capability Header Register */ | |
127 | #define CXLDEV_CAP_HDR_CAP_ID_MASK GENMASK(15, 0) | |
128 | /* CXL 2.0 8.2.8.2.1 CXL Device Capabilities */ | |
129 | #define CXLDEV_CAP_CAP_ID_DEVICE_STATUS 0x1 | |
130 | #define CXLDEV_CAP_CAP_ID_PRIMARY_MAILBOX 0x2 | |
131 | #define CXLDEV_CAP_CAP_ID_SECONDARY_MAILBOX 0x3 | |
132 | #define CXLDEV_CAP_CAP_ID_MEMDEV 0x4000 | |
133 | ||
134 | /* CXL 2.0 8.2.8.4 Mailbox Registers */ | |
135 | #define CXLDEV_MBOX_CAPS_OFFSET 0x00 | |
136 | #define CXLDEV_MBOX_CAP_PAYLOAD_SIZE_MASK GENMASK(4, 0) | |
137 | #define CXLDEV_MBOX_CTRL_OFFSET 0x04 | |
138 | #define CXLDEV_MBOX_CTRL_DOORBELL BIT(0) | |
139 | #define CXLDEV_MBOX_CMD_OFFSET 0x08 | |
140 | #define CXLDEV_MBOX_CMD_COMMAND_OPCODE_MASK GENMASK_ULL(15, 0) | |
141 | #define CXLDEV_MBOX_CMD_PAYLOAD_LENGTH_MASK GENMASK_ULL(36, 16) | |
142 | #define CXLDEV_MBOX_STATUS_OFFSET 0x10 | |
143 | #define CXLDEV_MBOX_STATUS_RET_CODE_MASK GENMASK_ULL(47, 32) | |
144 | #define CXLDEV_MBOX_BG_CMD_STATUS_OFFSET 0x18 | |
145 | #define CXLDEV_MBOX_PAYLOAD_OFFSET 0x20 | |
146 | ||
8ac75dd6 | 147 | /* |
301e68dd KC |
148 | * Using struct_group() allows for per register-block-type helper routines, |
149 | * without requiring block-type agnostic code to include the prefix. | |
8ac75dd6 DW |
150 | */ |
151 | struct cxl_regs { | |
301e68dd KC |
152 | /* |
153 | * Common set of CXL Component register block base pointers | |
154 | * @hdm_decoder: CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure | |
155 | */ | |
156 | struct_group_tagged(cxl_component_regs, component, | |
157 | void __iomem *hdm_decoder; | |
158 | ); | |
159 | /* | |
160 | * Common set of CXL Device register block base pointers | |
161 | * @status: CXL 2.0 8.2.8.3 Device Status Registers | |
162 | * @mbox: CXL 2.0 8.2.8.4 Mailbox Registers | |
163 | * @memdev: CXL 2.0 8.2.8.5 Memory Device Registers | |
164 | */ | |
165 | struct_group_tagged(cxl_device_regs, device_regs, | |
166 | void __iomem *status, *mbox, *memdev; | |
167 | ); | |
8ac75dd6 DW |
168 | }; |
169 | ||
30af9729 IW |
170 | struct cxl_reg_map { |
171 | bool valid; | |
172 | unsigned long offset; | |
173 | unsigned long size; | |
174 | }; | |
175 | ||
08422378 BW |
176 | struct cxl_component_reg_map { |
177 | struct cxl_reg_map hdm_decoder; | |
178 | }; | |
179 | ||
30af9729 IW |
180 | struct cxl_device_reg_map { |
181 | struct cxl_reg_map status; | |
182 | struct cxl_reg_map mbox; | |
183 | struct cxl_reg_map memdev; | |
184 | }; | |
185 | ||
a261e9a1 DW |
186 | /** |
187 | * struct cxl_register_map - DVSEC harvested register block mapping parameters | |
188 | * @base: virtual base of the register-block-BAR + @block_offset | |
189 | * @block_offset: offset to start of register block in @barno | |
190 | * @reg_type: see enum cxl_regloc_type | |
191 | * @barno: PCI BAR number containing the register block | |
192 | * @component_map: cxl_reg_map for component registers | |
193 | * @device_map: cxl_reg_maps for device registers | |
194 | */ | |
30af9729 | 195 | struct cxl_register_map { |
a261e9a1 | 196 | void __iomem *base; |
30af9729 IW |
197 | u64 block_offset; |
198 | u8 reg_type; | |
199 | u8 barno; | |
200 | union { | |
08422378 | 201 | struct cxl_component_reg_map component_map; |
30af9729 IW |
202 | struct cxl_device_reg_map device_map; |
203 | }; | |
204 | }; | |
205 | ||
08422378 BW |
206 | void cxl_probe_component_regs(struct device *dev, void __iomem *base, |
207 | struct cxl_component_reg_map *map); | |
30af9729 IW |
208 | void cxl_probe_device_regs(struct device *dev, void __iomem *base, |
209 | struct cxl_device_reg_map *map); | |
08422378 BW |
210 | int cxl_map_component_regs(struct pci_dev *pdev, |
211 | struct cxl_component_regs *regs, | |
212 | struct cxl_register_map *map); | |
30af9729 IW |
213 | int cxl_map_device_regs(struct pci_dev *pdev, |
214 | struct cxl_device_regs *regs, | |
215 | struct cxl_register_map *map); | |
399d34eb | 216 | |
303ebc1b BW |
217 | enum cxl_regloc_type; |
218 | int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type, | |
219 | struct cxl_register_map *map); | |
54cdbf84 BW |
220 | void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr, |
221 | resource_size_t length); | |
303ebc1b | 222 | |
4812be97 | 223 | #define CXL_RESOURCE_NONE ((resource_size_t) -1) |
7d4b5ca2 | 224 | #define CXL_TARGET_STRLEN 20 |
4812be97 | 225 | |
40ba17af DW |
226 | /* |
227 | * cxl_decoder flags that define the type of memory / devices this | |
228 | * decoder supports as well as configuration lock status See "CXL 2.0 | |
229 | * 8.2.5.12.7 CXL HDM Decoder 0 Control Register" for details. | |
230 | */ | |
231 | #define CXL_DECODER_F_RAM BIT(0) | |
232 | #define CXL_DECODER_F_PMEM BIT(1) | |
233 | #define CXL_DECODER_F_TYPE2 BIT(2) | |
234 | #define CXL_DECODER_F_TYPE3 BIT(3) | |
235 | #define CXL_DECODER_F_LOCK BIT(4) | |
d17d0540 DW |
236 | #define CXL_DECODER_F_ENABLE BIT(5) |
237 | #define CXL_DECODER_F_MASK GENMASK(5, 0) | |
40ba17af DW |
238 | |
239 | enum cxl_decoder_type { | |
240 | CXL_DECODER_ACCELERATOR = 2, | |
241 | CXL_DECODER_EXPANDER = 3, | |
242 | }; | |
243 | ||
a5c25802 DW |
244 | /* |
245 | * Current specification goes up to 8, double that seems a reasonable | |
246 | * software max for the foreseeable future | |
247 | */ | |
248 | #define CXL_DECODER_MAX_INTERLEAVE 16 | |
249 | ||
40ba17af | 250 | /** |
e636479e | 251 | * struct cxl_decoder - Common CXL HDM Decoder Attributes |
40ba17af DW |
252 | * @dev: this decoder's device |
253 | * @id: kernel device name id | |
e8b7ea58 | 254 | * @hpa_range: Host physical address range mapped by this decoder |
40ba17af DW |
255 | * @interleave_ways: number of cxl_dports in this decode |
256 | * @interleave_granularity: data stride per dport | |
257 | * @target_type: accelerator vs expander (type2 vs type3) selector | |
b9686e8c | 258 | * @region: currently assigned region for this decoder |
40ba17af | 259 | * @flags: memory type capabilities and locking |
40ba17af DW |
260 | */ |
261 | struct cxl_decoder { | |
262 | struct device dev; | |
263 | int id; | |
e50fe01e | 264 | struct range hpa_range; |
40ba17af DW |
265 | int interleave_ways; |
266 | int interleave_granularity; | |
267 | enum cxl_decoder_type target_type; | |
b9686e8c | 268 | struct cxl_region *region; |
40ba17af | 269 | unsigned long flags; |
e636479e DW |
270 | }; |
271 | ||
b9686e8c DW |
272 | /* |
273 | * CXL_DECODER_DEAD prevents endpoints from being reattached to regions | |
274 | * while cxld_unregister() is running | |
275 | */ | |
2c866903 DW |
276 | enum cxl_decoder_mode { |
277 | CXL_DECODER_NONE, | |
278 | CXL_DECODER_RAM, | |
279 | CXL_DECODER_PMEM, | |
280 | CXL_DECODER_MIXED, | |
b9686e8c | 281 | CXL_DECODER_DEAD, |
2c866903 DW |
282 | }; |
283 | ||
3bf65915 DW |
284 | /** |
285 | * struct cxl_endpoint_decoder - Endpoint / SPA to DPA decoder | |
286 | * @cxld: base cxl_decoder_object | |
287 | * @dpa_res: actively claimed DPA span of this decoder | |
288 | * @skip: offset into @dpa_res where @cxld.hpa_range maps | |
2c866903 | 289 | * @mode: which memory type / access-mode-partition this decoder targets |
b9686e8c | 290 | * @pos: interleave position in @cxld.region |
3bf65915 DW |
291 | */ |
292 | struct cxl_endpoint_decoder { | |
293 | struct cxl_decoder cxld; | |
294 | struct resource *dpa_res; | |
295 | resource_size_t skip; | |
2c866903 | 296 | enum cxl_decoder_mode mode; |
b9686e8c | 297 | int pos; |
3bf65915 DW |
298 | }; |
299 | ||
e636479e DW |
300 | /** |
301 | * struct cxl_switch_decoder - Switch specific CXL HDM Decoder | |
302 | * @cxld: base cxl_decoder object | |
303 | * @target_lock: coordinate coherent reads of the target list | |
304 | * @nr_targets: number of elements in @target | |
305 | * @target: active ordered target list in current decoder configuration | |
306 | * | |
307 | * The 'switch' decoder type represents the decoder instances of cxl_port's that | |
308 | * route from the root of a CXL memory decode topology to the endpoints. They | |
309 | * come in two flavors, root-level decoders, statically defined by platform | |
310 | * firmware, and mid-level decoders, where interleave-granularity, | |
311 | * interleave-width, and the target list are mutable. | |
312 | */ | |
313 | struct cxl_switch_decoder { | |
314 | struct cxl_decoder cxld; | |
86c8ea0f | 315 | seqlock_t target_lock; |
be185c29 | 316 | int nr_targets; |
40ba17af DW |
317 | struct cxl_dport *target[]; |
318 | }; | |
319 | ||
8fdcb170 | 320 | |
0f157c7f DW |
321 | /** |
322 | * struct cxl_root_decoder - Static platform CXL address decoder | |
323 | * @res: host / parent resource for region allocations | |
779dd20c | 324 | * @region_id: region id for next region provisioning event |
0f157c7f DW |
325 | * @cxlsd: base cxl switch decoder |
326 | */ | |
327 | struct cxl_root_decoder { | |
328 | struct resource *res; | |
779dd20c | 329 | atomic_t region_id; |
0f157c7f DW |
330 | struct cxl_switch_decoder cxlsd; |
331 | }; | |
332 | ||
dd5ba0eb BW |
333 | /* |
334 | * enum cxl_config_state - State machine for region configuration | |
335 | * @CXL_CONFIG_IDLE: Any sysfs attribute can be written freely | |
80d10a6c BW |
336 | * @CXL_CONFIG_INTERLEAVE_ACTIVE: region size has been set, no more |
337 | * changes to interleave_ways or interleave_granularity | |
dd5ba0eb BW |
338 | * @CXL_CONFIG_ACTIVE: All targets have been added the region is now |
339 | * active | |
340 | */ | |
341 | enum cxl_config_state { | |
342 | CXL_CONFIG_IDLE, | |
80d10a6c | 343 | CXL_CONFIG_INTERLEAVE_ACTIVE, |
dd5ba0eb BW |
344 | CXL_CONFIG_ACTIVE, |
345 | }; | |
346 | ||
347 | /** | |
348 | * struct cxl_region_params - region settings | |
349 | * @state: allow the driver to lockdown further parameter changes | |
350 | * @uuid: unique id for persistent regions | |
80d10a6c BW |
351 | * @interleave_ways: number of endpoints in the region |
352 | * @interleave_granularity: capacity each endpoint contributes to a stripe | |
23a22cd1 | 353 | * @res: allocated iomem capacity for this region |
dd5ba0eb BW |
354 | * |
355 | * State transitions are protected by the cxl_region_rwsem | |
356 | */ | |
357 | struct cxl_region_params { | |
358 | enum cxl_config_state state; | |
359 | uuid_t uuid; | |
80d10a6c BW |
360 | int interleave_ways; |
361 | int interleave_granularity; | |
23a22cd1 | 362 | struct resource *res; |
b9686e8c DW |
363 | struct cxl_endpoint_decoder *targets[CXL_DECODER_MAX_INTERLEAVE]; |
364 | int nr_targets; | |
dd5ba0eb BW |
365 | }; |
366 | ||
779dd20c BW |
367 | /** |
368 | * struct cxl_region - CXL region | |
369 | * @dev: This region's device | |
370 | * @id: This region's id. Id is globally unique across all regions | |
371 | * @mode: Endpoint decoder allocation / access mode | |
372 | * @type: Endpoint decoder target type | |
dd5ba0eb | 373 | * @params: active + config params for the region |
779dd20c BW |
374 | */ |
375 | struct cxl_region { | |
376 | struct device dev; | |
377 | int id; | |
378 | enum cxl_decoder_mode mode; | |
379 | enum cxl_decoder_type type; | |
dd5ba0eb | 380 | struct cxl_region_params params; |
779dd20c BW |
381 | }; |
382 | ||
53989fad DW |
383 | /** |
384 | * enum cxl_nvdimm_brige_state - state machine for managing bus rescans | |
385 | * @CXL_NVB_NEW: Set at bridge create and after cxl_pmem_wq is destroyed | |
386 | * @CXL_NVB_DEAD: Set at brige unregistration to preclude async probing | |
387 | * @CXL_NVB_ONLINE: Target state after successful ->probe() | |
388 | * @CXL_NVB_OFFLINE: Target state after ->remove() or failed ->probe() | |
389 | */ | |
8fdcb170 DW |
390 | enum cxl_nvdimm_brige_state { |
391 | CXL_NVB_NEW, | |
392 | CXL_NVB_DEAD, | |
393 | CXL_NVB_ONLINE, | |
394 | CXL_NVB_OFFLINE, | |
395 | }; | |
396 | ||
397 | struct cxl_nvdimm_bridge { | |
2e52b625 | 398 | int id; |
8fdcb170 DW |
399 | struct device dev; |
400 | struct cxl_port *port; | |
401 | struct nvdimm_bus *nvdimm_bus; | |
402 | struct nvdimm_bus_descriptor nd_desc; | |
403 | struct work_struct state_work; | |
404 | enum cxl_nvdimm_brige_state state; | |
405 | }; | |
406 | ||
21083f51 DW |
407 | struct cxl_nvdimm { |
408 | struct device dev; | |
409 | struct cxl_memdev *cxlmd; | |
21083f51 DW |
410 | }; |
411 | ||
4812be97 DW |
412 | /** |
413 | * struct cxl_port - logical collection of upstream port devices and | |
414 | * downstream port devices to construct a CXL memory | |
415 | * decode hierarchy. | |
416 | * @dev: this port's device | |
417 | * @uport: PCI or platform device implementing the upstream port capability | |
ee800010 | 418 | * @host_bridge: Shortcut to the platform attach point for this port |
4812be97 | 419 | * @id: id for port device-name |
7d4b5ca2 | 420 | * @dports: cxl_dport instances referenced by decoders |
2703c16c | 421 | * @endpoints: cxl_ep instances, endpoints that are a descendant of this port |
1b58b4ca | 422 | * @parent_dport: dport that points to this port in the parent |
40ba17af | 423 | * @decoder_ida: allocator for decoder ids |
0c33b393 | 424 | * @hdm_end: track last allocated HDM decoder instance for allocation ordering |
4812be97 | 425 | * @component_reg_phys: component register capability base address (optional) |
2703c16c | 426 | * @dead: last ep has been removed, force port re-creation |
53fa1bff | 427 | * @depth: How deep this port is relative to the root. depth 0 is the root. |
c9700604 IW |
428 | * @cdat: Cached CDAT data |
429 | * @cdat_available: Should a CDAT attribute be available in sysfs | |
4812be97 DW |
430 | */ |
431 | struct cxl_port { | |
432 | struct device dev; | |
433 | struct device *uport; | |
ee800010 | 434 | struct device *host_bridge; |
4812be97 | 435 | int id; |
39178585 | 436 | struct xarray dports; |
256d0e9e | 437 | struct xarray endpoints; |
1b58b4ca | 438 | struct cxl_dport *parent_dport; |
40ba17af | 439 | struct ida decoder_ida; |
0c33b393 | 440 | int hdm_end; |
4812be97 | 441 | resource_size_t component_reg_phys; |
2703c16c | 442 | bool dead; |
53fa1bff | 443 | unsigned int depth; |
c9700604 IW |
444 | struct cxl_cdat { |
445 | void *table; | |
446 | size_t length; | |
447 | } cdat; | |
448 | bool cdat_available; | |
4812be97 DW |
449 | }; |
450 | ||
39178585 DW |
451 | static inline struct cxl_dport * |
452 | cxl_find_dport_by_dev(struct cxl_port *port, const struct device *dport_dev) | |
453 | { | |
454 | return xa_load(&port->dports, (unsigned long)dport_dev); | |
455 | } | |
456 | ||
7d4b5ca2 DW |
457 | /** |
458 | * struct cxl_dport - CXL downstream port | |
459 | * @dport: PCI bridge or firmware device representing the downstream link | |
460 | * @port_id: unique hardware identifier for dport in decoder target list | |
461 | * @component_reg_phys: downstream port component registers | |
462 | * @port: reference to cxl_port that contains this downstream port | |
7d4b5ca2 DW |
463 | */ |
464 | struct cxl_dport { | |
465 | struct device *dport; | |
466 | int port_id; | |
467 | resource_size_t component_reg_phys; | |
468 | struct cxl_port *port; | |
7d4b5ca2 DW |
469 | }; |
470 | ||
2703c16c DW |
471 | /** |
472 | * struct cxl_ep - track an endpoint's interest in a port | |
473 | * @ep: device that hosts a generic CXL endpoint (expander or accelerator) | |
de516b40 | 474 | * @dport: which dport routes to this endpoint on @port |
7f8faf96 DW |
475 | * @next: cxl switch port across the link attached to @dport NULL if |
476 | * attached to an endpoint | |
2703c16c DW |
477 | */ |
478 | struct cxl_ep { | |
479 | struct device *ep; | |
de516b40 | 480 | struct cxl_dport *dport; |
7f8faf96 | 481 | struct cxl_port *next; |
2703c16c DW |
482 | }; |
483 | ||
d54c1bbe BW |
484 | /* |
485 | * The platform firmware device hosting the root is also the top of the | |
486 | * CXL port topology. All other CXL ports have another CXL port as their | |
487 | * parent and their ->uport / host device is out-of-line of the port | |
488 | * ancestry. | |
489 | */ | |
490 | static inline bool is_cxl_root(struct cxl_port *port) | |
491 | { | |
492 | return port->uport == port->dev.parent; | |
493 | } | |
494 | ||
3c5b9039 | 495 | bool is_cxl_port(struct device *dev); |
4812be97 | 496 | struct cxl_port *to_cxl_port(struct device *dev); |
98d2d3a2 | 497 | struct pci_bus; |
5ff7316f DW |
498 | int devm_cxl_register_pci_bus(struct device *host, struct device *uport, |
499 | struct pci_bus *bus); | |
500 | struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port); | |
4812be97 DW |
501 | struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport, |
502 | resource_size_t component_reg_phys, | |
1b58b4ca | 503 | struct cxl_dport *parent_dport); |
7f8faf96 DW |
504 | int devm_cxl_add_endpoint(struct cxl_memdev *cxlmd, |
505 | struct cxl_dport *parent_dport); | |
a46cfc0f | 506 | struct cxl_port *find_cxl_root(struct device *dev); |
2703c16c | 507 | int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd); |
8dd2bc0f | 508 | int cxl_bus_rescan(void); |
1b58b4ca DW |
509 | struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd, |
510 | struct cxl_dport **dport); | |
8dd2bc0f | 511 | bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd); |
2703c16c | 512 | |
664bf115 | 513 | struct cxl_dport *devm_cxl_add_dport(struct cxl_port *port, |
98d2d3a2 DW |
514 | struct device *dport, int port_id, |
515 | resource_size_t component_reg_phys); | |
2703c16c | 516 | |
40ba17af | 517 | struct cxl_decoder *to_cxl_decoder(struct device *dev); |
0f157c7f | 518 | struct cxl_root_decoder *to_cxl_root_decoder(struct device *dev); |
3bf65915 | 519 | struct cxl_endpoint_decoder *to_cxl_endpoint_decoder(struct device *dev); |
8fdcb170 | 520 | bool is_root_decoder(struct device *dev); |
8ae3cebc | 521 | bool is_endpoint_decoder(struct device *dev); |
0f157c7f DW |
522 | struct cxl_root_decoder *cxl_root_decoder_alloc(struct cxl_port *port, |
523 | unsigned int nr_targets); | |
e636479e DW |
524 | struct cxl_switch_decoder *cxl_switch_decoder_alloc(struct cxl_port *port, |
525 | unsigned int nr_targets); | |
48667f67 | 526 | int cxl_decoder_add(struct cxl_decoder *cxld, int *target_map); |
3bf65915 | 527 | struct cxl_endpoint_decoder *cxl_endpoint_decoder_alloc(struct cxl_port *port); |
d17d0540 | 528 | int cxl_decoder_add_locked(struct cxl_decoder *cxld, int *target_map); |
48667f67 | 529 | int cxl_decoder_autoremove(struct device *host, struct cxl_decoder *cxld); |
8dd2bc0f BW |
530 | int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint); |
531 | ||
d17d0540 | 532 | struct cxl_hdm; |
664bf115 DW |
533 | struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port); |
534 | int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm); | |
535 | int devm_cxl_add_passthrough_decoder(struct cxl_port *port); | |
40ba17af | 536 | |
779dd20c BW |
537 | bool is_cxl_region(struct device *dev); |
538 | ||
b39cb105 | 539 | extern struct bus_type cxl_bus_type; |
6af7139c DW |
540 | |
541 | struct cxl_driver { | |
542 | const char *name; | |
543 | int (*probe)(struct device *dev); | |
544 | void (*remove)(struct device *dev); | |
545 | struct device_driver drv; | |
546 | int id; | |
547 | }; | |
548 | ||
549 | static inline struct cxl_driver *to_cxl_drv(struct device_driver *drv) | |
550 | { | |
551 | return container_of(drv, struct cxl_driver, drv); | |
552 | } | |
553 | ||
554 | int __cxl_driver_register(struct cxl_driver *cxl_drv, struct module *owner, | |
555 | const char *modname); | |
556 | #define cxl_driver_register(x) __cxl_driver_register(x, THIS_MODULE, KBUILD_MODNAME) | |
557 | void cxl_driver_unregister(struct cxl_driver *cxl_drv); | |
558 | ||
c57cae78 BW |
559 | #define module_cxl_driver(__cxl_driver) \ |
560 | module_driver(__cxl_driver, cxl_driver_register, cxl_driver_unregister) | |
561 | ||
21083f51 DW |
562 | #define CXL_DEVICE_NVDIMM_BRIDGE 1 |
563 | #define CXL_DEVICE_NVDIMM 2 | |
54cdbf84 BW |
564 | #define CXL_DEVICE_PORT 3 |
565 | #define CXL_DEVICE_ROOT 4 | |
8dd2bc0f | 566 | #define CXL_DEVICE_MEMORY_EXPANDER 5 |
8fdcb170 | 567 | |
6af7139c DW |
568 | #define MODULE_ALIAS_CXL(type) MODULE_ALIAS("cxl:t" __stringify(type) "*") |
569 | #define CXL_MODALIAS_FMT "cxl:t%d" | |
570 | ||
8fdcb170 DW |
571 | struct cxl_nvdimm_bridge *to_cxl_nvdimm_bridge(struct device *dev); |
572 | struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host, | |
573 | struct cxl_port *port); | |
21083f51 DW |
574 | struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev); |
575 | bool is_cxl_nvdimm(struct device *dev); | |
53989fad | 576 | bool is_cxl_nvdimm_bridge(struct device *dev); |
21083f51 | 577 | int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd); |
7d3eb23c | 578 | struct cxl_nvdimm_bridge *cxl_find_nvdimm_bridge(struct cxl_nvdimm *cxl_nvd); |
67dcdd4d DW |
579 | |
580 | /* | |
581 | * Unit test builds overrides this to __weak, find the 'strong' version | |
582 | * of these symbols in tools/testing/cxl/. | |
583 | */ | |
584 | #ifndef __mock | |
585 | #define __mock static | |
586 | #endif | |
3c5b9039 | 587 | |
8adaf747 | 588 | #endif /* __CXL_H__ */ |