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> | |
10 | #include <linux/io.h> | |
11 | ||
4812be97 DW |
12 | /** |
13 | * DOC: cxl objects | |
14 | * | |
15 | * The CXL core objects like ports, decoders, and regions are shared | |
16 | * between the subsystem drivers cxl_acpi, cxl_pci, and core drivers | |
17 | * (port-driver, region-driver, nvdimm object-drivers... etc). | |
18 | */ | |
19 | ||
08422378 BW |
20 | /* CXL 2.0 8.2.5 CXL.cache and CXL.mem Registers*/ |
21 | #define CXL_CM_OFFSET 0x1000 | |
22 | #define CXL_CM_CAP_HDR_OFFSET 0x0 | |
23 | #define CXL_CM_CAP_HDR_ID_MASK GENMASK(15, 0) | |
24 | #define CM_CAP_HDR_CAP_ID 1 | |
25 | #define CXL_CM_CAP_HDR_VERSION_MASK GENMASK(19, 16) | |
26 | #define CM_CAP_HDR_CAP_VERSION 1 | |
27 | #define CXL_CM_CAP_HDR_CACHE_MEM_VERSION_MASK GENMASK(23, 20) | |
28 | #define CM_CAP_HDR_CACHE_MEM_VERSION 1 | |
29 | #define CXL_CM_CAP_HDR_ARRAY_SIZE_MASK GENMASK(31, 24) | |
30 | #define CXL_CM_CAP_PTR_MASK GENMASK(31, 20) | |
31 | ||
32 | #define CXL_CM_CAP_CAP_ID_HDM 0x5 | |
33 | #define CXL_CM_CAP_CAP_HDM_VERSION 1 | |
34 | ||
35 | /* HDM decoders CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure */ | |
36 | #define CXL_HDM_DECODER_CAP_OFFSET 0x0 | |
37 | #define CXL_HDM_DECODER_COUNT_MASK GENMASK(3, 0) | |
38 | #define CXL_HDM_DECODER_TARGET_COUNT_MASK GENMASK(7, 4) | |
39 | #define CXL_HDM_DECODER0_BASE_LOW_OFFSET 0x10 | |
40 | #define CXL_HDM_DECODER0_BASE_HIGH_OFFSET 0x14 | |
41 | #define CXL_HDM_DECODER0_SIZE_LOW_OFFSET 0x18 | |
42 | #define CXL_HDM_DECODER0_SIZE_HIGH_OFFSET 0x1c | |
43 | #define CXL_HDM_DECODER0_CTRL_OFFSET 0x20 | |
44 | ||
6423035f BW |
45 | static inline int cxl_hdm_decoder_count(u32 cap_hdr) |
46 | { | |
47 | int val = FIELD_GET(CXL_HDM_DECODER_COUNT_MASK, cap_hdr); | |
48 | ||
49 | return val ? val * 2 : 1; | |
50 | } | |
51 | ||
8adaf747 BW |
52 | /* CXL 2.0 8.2.8.1 Device Capabilities Array Register */ |
53 | #define CXLDEV_CAP_ARRAY_OFFSET 0x0 | |
54 | #define CXLDEV_CAP_ARRAY_CAP_ID 0 | |
55 | #define CXLDEV_CAP_ARRAY_ID_MASK GENMASK_ULL(15, 0) | |
56 | #define CXLDEV_CAP_ARRAY_COUNT_MASK GENMASK_ULL(47, 32) | |
57 | /* CXL 2.0 8.2.8.2 CXL Device Capability Header Register */ | |
58 | #define CXLDEV_CAP_HDR_CAP_ID_MASK GENMASK(15, 0) | |
59 | /* CXL 2.0 8.2.8.2.1 CXL Device Capabilities */ | |
60 | #define CXLDEV_CAP_CAP_ID_DEVICE_STATUS 0x1 | |
61 | #define CXLDEV_CAP_CAP_ID_PRIMARY_MAILBOX 0x2 | |
62 | #define CXLDEV_CAP_CAP_ID_SECONDARY_MAILBOX 0x3 | |
63 | #define CXLDEV_CAP_CAP_ID_MEMDEV 0x4000 | |
64 | ||
65 | /* CXL 2.0 8.2.8.4 Mailbox Registers */ | |
66 | #define CXLDEV_MBOX_CAPS_OFFSET 0x00 | |
67 | #define CXLDEV_MBOX_CAP_PAYLOAD_SIZE_MASK GENMASK(4, 0) | |
68 | #define CXLDEV_MBOX_CTRL_OFFSET 0x04 | |
69 | #define CXLDEV_MBOX_CTRL_DOORBELL BIT(0) | |
70 | #define CXLDEV_MBOX_CMD_OFFSET 0x08 | |
71 | #define CXLDEV_MBOX_CMD_COMMAND_OPCODE_MASK GENMASK_ULL(15, 0) | |
72 | #define CXLDEV_MBOX_CMD_PAYLOAD_LENGTH_MASK GENMASK_ULL(36, 16) | |
73 | #define CXLDEV_MBOX_STATUS_OFFSET 0x10 | |
74 | #define CXLDEV_MBOX_STATUS_RET_CODE_MASK GENMASK_ULL(47, 32) | |
75 | #define CXLDEV_MBOX_BG_CMD_STATUS_OFFSET 0x18 | |
76 | #define CXLDEV_MBOX_PAYLOAD_OFFSET 0x20 | |
77 | ||
08422378 BW |
78 | #define CXL_COMPONENT_REGS() \ |
79 | void __iomem *hdm_decoder | |
80 | ||
8ac75dd6 DW |
81 | #define CXL_DEVICE_REGS() \ |
82 | void __iomem *status; \ | |
83 | void __iomem *mbox; \ | |
84 | void __iomem *memdev | |
85 | ||
86 | /* See note for 'struct cxl_regs' for the rationale of this organization */ | |
08422378 BW |
87 | /* |
88 | * CXL_COMPONENT_REGS - Common set of CXL Component register block base pointers | |
89 | * @hdm_decoder: CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure | |
90 | */ | |
91 | struct cxl_component_regs { | |
92 | CXL_COMPONENT_REGS(); | |
93 | }; | |
94 | ||
95 | /* See note for 'struct cxl_regs' for the rationale of this organization */ | |
96 | /* | |
97 | * CXL_DEVICE_REGS - Common set of CXL Device register block base pointers | |
98 | * @status: CXL 2.0 8.2.8.3 Device Status Registers | |
99 | * @mbox: CXL 2.0 8.2.8.4 Mailbox Registers | |
100 | * @memdev: CXL 2.0 8.2.8.5 Memory Device Registers | |
101 | */ | |
8ac75dd6 DW |
102 | struct cxl_device_regs { |
103 | CXL_DEVICE_REGS(); | |
104 | }; | |
105 | ||
106 | /* | |
107 | * Note, the anonymous union organization allows for per | |
108 | * register-block-type helper routines, without requiring block-type | |
30af9729 | 109 | * agnostic code to include the prefix. |
8ac75dd6 DW |
110 | */ |
111 | struct cxl_regs { | |
08422378 BW |
112 | union { |
113 | struct { | |
114 | CXL_COMPONENT_REGS(); | |
115 | }; | |
116 | struct cxl_component_regs component; | |
117 | }; | |
8ac75dd6 DW |
118 | union { |
119 | struct { | |
120 | CXL_DEVICE_REGS(); | |
121 | }; | |
122 | struct cxl_device_regs device_regs; | |
123 | }; | |
124 | }; | |
125 | ||
30af9729 IW |
126 | struct cxl_reg_map { |
127 | bool valid; | |
128 | unsigned long offset; | |
129 | unsigned long size; | |
130 | }; | |
131 | ||
08422378 BW |
132 | struct cxl_component_reg_map { |
133 | struct cxl_reg_map hdm_decoder; | |
134 | }; | |
135 | ||
30af9729 IW |
136 | struct cxl_device_reg_map { |
137 | struct cxl_reg_map status; | |
138 | struct cxl_reg_map mbox; | |
139 | struct cxl_reg_map memdev; | |
140 | }; | |
141 | ||
142 | struct cxl_register_map { | |
30af9729 IW |
143 | u64 block_offset; |
144 | u8 reg_type; | |
145 | u8 barno; | |
146 | union { | |
08422378 | 147 | struct cxl_component_reg_map component_map; |
30af9729 IW |
148 | struct cxl_device_reg_map device_map; |
149 | }; | |
150 | }; | |
151 | ||
08422378 BW |
152 | void cxl_probe_component_regs(struct device *dev, void __iomem *base, |
153 | struct cxl_component_reg_map *map); | |
30af9729 IW |
154 | void cxl_probe_device_regs(struct device *dev, void __iomem *base, |
155 | struct cxl_device_reg_map *map); | |
08422378 BW |
156 | int cxl_map_component_regs(struct pci_dev *pdev, |
157 | struct cxl_component_regs *regs, | |
158 | struct cxl_register_map *map); | |
30af9729 IW |
159 | int cxl_map_device_regs(struct pci_dev *pdev, |
160 | struct cxl_device_regs *regs, | |
161 | struct cxl_register_map *map); | |
399d34eb | 162 | |
4812be97 | 163 | #define CXL_RESOURCE_NONE ((resource_size_t) -1) |
7d4b5ca2 | 164 | #define CXL_TARGET_STRLEN 20 |
4812be97 | 165 | |
40ba17af DW |
166 | /* |
167 | * cxl_decoder flags that define the type of memory / devices this | |
168 | * decoder supports as well as configuration lock status See "CXL 2.0 | |
169 | * 8.2.5.12.7 CXL HDM Decoder 0 Control Register" for details. | |
170 | */ | |
171 | #define CXL_DECODER_F_RAM BIT(0) | |
172 | #define CXL_DECODER_F_PMEM BIT(1) | |
173 | #define CXL_DECODER_F_TYPE2 BIT(2) | |
174 | #define CXL_DECODER_F_TYPE3 BIT(3) | |
175 | #define CXL_DECODER_F_LOCK BIT(4) | |
176 | #define CXL_DECODER_F_MASK GENMASK(4, 0) | |
177 | ||
178 | enum cxl_decoder_type { | |
179 | CXL_DECODER_ACCELERATOR = 2, | |
180 | CXL_DECODER_EXPANDER = 3, | |
181 | }; | |
182 | ||
183 | /** | |
184 | * struct cxl_decoder - CXL address range decode configuration | |
185 | * @dev: this decoder's device | |
186 | * @id: kernel device name id | |
187 | * @range: address range considered by this decoder | |
188 | * @interleave_ways: number of cxl_dports in this decode | |
189 | * @interleave_granularity: data stride per dport | |
190 | * @target_type: accelerator vs expander (type2 vs type3) selector | |
191 | * @flags: memory type capabilities and locking | |
192 | * @target: active ordered target list in current decoder configuration | |
193 | */ | |
194 | struct cxl_decoder { | |
195 | struct device dev; | |
196 | int id; | |
197 | struct range range; | |
198 | int interleave_ways; | |
199 | int interleave_granularity; | |
200 | enum cxl_decoder_type target_type; | |
201 | unsigned long flags; | |
202 | struct cxl_dport *target[]; | |
203 | }; | |
204 | ||
8fdcb170 DW |
205 | |
206 | enum cxl_nvdimm_brige_state { | |
207 | CXL_NVB_NEW, | |
208 | CXL_NVB_DEAD, | |
209 | CXL_NVB_ONLINE, | |
210 | CXL_NVB_OFFLINE, | |
211 | }; | |
212 | ||
213 | struct cxl_nvdimm_bridge { | |
214 | struct device dev; | |
215 | struct cxl_port *port; | |
216 | struct nvdimm_bus *nvdimm_bus; | |
217 | struct nvdimm_bus_descriptor nd_desc; | |
218 | struct work_struct state_work; | |
219 | enum cxl_nvdimm_brige_state state; | |
220 | }; | |
221 | ||
21083f51 DW |
222 | struct cxl_nvdimm { |
223 | struct device dev; | |
224 | struct cxl_memdev *cxlmd; | |
225 | struct nvdimm *nvdimm; | |
226 | }; | |
227 | ||
4812be97 DW |
228 | /** |
229 | * struct cxl_port - logical collection of upstream port devices and | |
230 | * downstream port devices to construct a CXL memory | |
231 | * decode hierarchy. | |
232 | * @dev: this port's device | |
233 | * @uport: PCI or platform device implementing the upstream port capability | |
234 | * @id: id for port device-name | |
7d4b5ca2 | 235 | * @dports: cxl_dport instances referenced by decoders |
40ba17af | 236 | * @decoder_ida: allocator for decoder ids |
4812be97 DW |
237 | * @component_reg_phys: component register capability base address (optional) |
238 | */ | |
239 | struct cxl_port { | |
240 | struct device dev; | |
241 | struct device *uport; | |
242 | int id; | |
7d4b5ca2 | 243 | struct list_head dports; |
40ba17af | 244 | struct ida decoder_ida; |
4812be97 DW |
245 | resource_size_t component_reg_phys; |
246 | }; | |
247 | ||
7d4b5ca2 DW |
248 | /** |
249 | * struct cxl_dport - CXL downstream port | |
250 | * @dport: PCI bridge or firmware device representing the downstream link | |
251 | * @port_id: unique hardware identifier for dport in decoder target list | |
252 | * @component_reg_phys: downstream port component registers | |
253 | * @port: reference to cxl_port that contains this downstream port | |
254 | * @list: node for a cxl_port's list of cxl_dport instances | |
255 | */ | |
256 | struct cxl_dport { | |
257 | struct device *dport; | |
258 | int port_id; | |
259 | resource_size_t component_reg_phys; | |
260 | struct cxl_port *port; | |
261 | struct list_head list; | |
262 | }; | |
263 | ||
4812be97 DW |
264 | struct cxl_port *to_cxl_port(struct device *dev); |
265 | struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport, | |
266 | resource_size_t component_reg_phys, | |
267 | struct cxl_port *parent_port); | |
268 | ||
7d4b5ca2 DW |
269 | int cxl_add_dport(struct cxl_port *port, struct device *dport, int port_id, |
270 | resource_size_t component_reg_phys); | |
40ba17af DW |
271 | |
272 | struct cxl_decoder *to_cxl_decoder(struct device *dev); | |
8fdcb170 | 273 | bool is_root_decoder(struct device *dev); |
40ba17af DW |
274 | struct cxl_decoder * |
275 | devm_cxl_add_decoder(struct device *host, struct cxl_port *port, int nr_targets, | |
276 | resource_size_t base, resource_size_t len, | |
277 | int interleave_ways, int interleave_granularity, | |
278 | enum cxl_decoder_type type, unsigned long flags); | |
279 | ||
280 | /* | |
281 | * Per the CXL specification (8.2.5.12 CXL HDM Decoder Capability Structure) | |
282 | * single ported host-bridges need not publish a decoder capability when a | |
283 | * passthrough decode can be assumed, i.e. all transactions that the uport sees | |
284 | * are claimed and passed to the single dport. Default the range a 0-base | |
285 | * 0-length until the first CXL region is activated. | |
286 | */ | |
287 | static inline struct cxl_decoder * | |
288 | devm_cxl_add_passthrough_decoder(struct device *host, struct cxl_port *port) | |
289 | { | |
290 | return devm_cxl_add_decoder(host, port, 1, 0, 0, 1, PAGE_SIZE, | |
291 | CXL_DECODER_EXPANDER, 0); | |
292 | } | |
293 | ||
b39cb105 | 294 | extern struct bus_type cxl_bus_type; |
6af7139c DW |
295 | |
296 | struct cxl_driver { | |
297 | const char *name; | |
298 | int (*probe)(struct device *dev); | |
299 | void (*remove)(struct device *dev); | |
300 | struct device_driver drv; | |
301 | int id; | |
302 | }; | |
303 | ||
304 | static inline struct cxl_driver *to_cxl_drv(struct device_driver *drv) | |
305 | { | |
306 | return container_of(drv, struct cxl_driver, drv); | |
307 | } | |
308 | ||
309 | int __cxl_driver_register(struct cxl_driver *cxl_drv, struct module *owner, | |
310 | const char *modname); | |
311 | #define cxl_driver_register(x) __cxl_driver_register(x, THIS_MODULE, KBUILD_MODNAME) | |
312 | void cxl_driver_unregister(struct cxl_driver *cxl_drv); | |
313 | ||
21083f51 DW |
314 | #define CXL_DEVICE_NVDIMM_BRIDGE 1 |
315 | #define CXL_DEVICE_NVDIMM 2 | |
8fdcb170 | 316 | |
6af7139c DW |
317 | #define MODULE_ALIAS_CXL(type) MODULE_ALIAS("cxl:t" __stringify(type) "*") |
318 | #define CXL_MODALIAS_FMT "cxl:t%d" | |
319 | ||
8fdcb170 DW |
320 | struct cxl_nvdimm_bridge *to_cxl_nvdimm_bridge(struct device *dev); |
321 | struct cxl_nvdimm_bridge *devm_cxl_add_nvdimm_bridge(struct device *host, | |
322 | struct cxl_port *port); | |
21083f51 DW |
323 | struct cxl_nvdimm *to_cxl_nvdimm(struct device *dev); |
324 | bool is_cxl_nvdimm(struct device *dev); | |
325 | int devm_cxl_add_nvdimm(struct device *host, struct cxl_memdev *cxlmd); | |
8adaf747 | 326 | #endif /* __CXL_H__ */ |