Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright(c) 2021 Intel Corporation. All rights reserved.
3
4#include <linux/platform_device.h>
5#include <linux/genalloc.h>
6#include <linux/module.h>
7#include <linux/mutex.h>
8#include <linux/acpi.h>
9#include <linux/pci.h>
10#include <linux/mm.h>
11#include <cxlmem.h>
12#include "mock.h"
13
14static int interleave_arithmetic;
15
16#define NR_CXL_HOST_BRIDGES 2
17#define NR_CXL_SINGLE_HOST 1
18#define NR_CXL_RCH 1
19#define NR_CXL_ROOT_PORTS 2
20#define NR_CXL_SWITCH_PORTS 2
21#define NR_CXL_PORT_DECODERS 8
22#define NR_BRIDGES (NR_CXL_HOST_BRIDGES + NR_CXL_SINGLE_HOST + NR_CXL_RCH)
23
24static struct platform_device *cxl_acpi;
25static struct platform_device *cxl_host_bridge[NR_CXL_HOST_BRIDGES];
26#define NR_MULTI_ROOT (NR_CXL_HOST_BRIDGES * NR_CXL_ROOT_PORTS)
27static struct platform_device *cxl_root_port[NR_MULTI_ROOT];
28static struct platform_device *cxl_switch_uport[NR_MULTI_ROOT];
29#define NR_MEM_MULTI \
30 (NR_CXL_HOST_BRIDGES * NR_CXL_ROOT_PORTS * NR_CXL_SWITCH_PORTS)
31static struct platform_device *cxl_switch_dport[NR_MEM_MULTI];
32
33static struct platform_device *cxl_hb_single[NR_CXL_SINGLE_HOST];
34static struct platform_device *cxl_root_single[NR_CXL_SINGLE_HOST];
35static struct platform_device *cxl_swu_single[NR_CXL_SINGLE_HOST];
36#define NR_MEM_SINGLE (NR_CXL_SINGLE_HOST * NR_CXL_SWITCH_PORTS)
37static struct platform_device *cxl_swd_single[NR_MEM_SINGLE];
38
39struct platform_device *cxl_mem[NR_MEM_MULTI];
40struct platform_device *cxl_mem_single[NR_MEM_SINGLE];
41
42static struct platform_device *cxl_rch[NR_CXL_RCH];
43static struct platform_device *cxl_rcd[NR_CXL_RCH];
44
45static inline bool is_multi_bridge(struct device *dev)
46{
47 int i;
48
49 for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++)
50 if (&cxl_host_bridge[i]->dev == dev)
51 return true;
52 return false;
53}
54
55static inline bool is_single_bridge(struct device *dev)
56{
57 int i;
58
59 for (i = 0; i < ARRAY_SIZE(cxl_hb_single); i++)
60 if (&cxl_hb_single[i]->dev == dev)
61 return true;
62 return false;
63}
64
65static struct acpi_device acpi0017_mock;
66static struct acpi_device host_bridge[NR_BRIDGES] = {
67 [0] = {
68 .handle = &host_bridge[0],
69 },
70 [1] = {
71 .handle = &host_bridge[1],
72 },
73 [2] = {
74 .handle = &host_bridge[2],
75 },
76 [3] = {
77 .handle = &host_bridge[3],
78 },
79};
80
81static bool is_mock_dev(struct device *dev)
82{
83 int i;
84
85 for (i = 0; i < ARRAY_SIZE(cxl_mem); i++)
86 if (dev == &cxl_mem[i]->dev)
87 return true;
88 for (i = 0; i < ARRAY_SIZE(cxl_mem_single); i++)
89 if (dev == &cxl_mem_single[i]->dev)
90 return true;
91 for (i = 0; i < ARRAY_SIZE(cxl_rcd); i++)
92 if (dev == &cxl_rcd[i]->dev)
93 return true;
94 if (dev == &cxl_acpi->dev)
95 return true;
96 return false;
97}
98
99static bool is_mock_adev(struct acpi_device *adev)
100{
101 int i;
102
103 if (adev == &acpi0017_mock)
104 return true;
105
106 for (i = 0; i < ARRAY_SIZE(host_bridge); i++)
107 if (adev == &host_bridge[i])
108 return true;
109
110 return false;
111}
112
113static struct {
114 struct acpi_table_cedt cedt;
115 struct acpi_cedt_chbs chbs[NR_BRIDGES];
116 struct {
117 struct acpi_cedt_cfmws cfmws;
118 u32 target[1];
119 } cfmws0;
120 struct {
121 struct acpi_cedt_cfmws cfmws;
122 u32 target[2];
123 } cfmws1;
124 struct {
125 struct acpi_cedt_cfmws cfmws;
126 u32 target[1];
127 } cfmws2;
128 struct {
129 struct acpi_cedt_cfmws cfmws;
130 u32 target[2];
131 } cfmws3;
132 struct {
133 struct acpi_cedt_cfmws cfmws;
134 u32 target[1];
135 } cfmws4;
136 struct {
137 struct acpi_cedt_cfmws cfmws;
138 u32 target[1];
139 } cfmws5;
140 struct {
141 struct acpi_cedt_cfmws cfmws;
142 u32 target[1];
143 } cfmws6;
144 struct {
145 struct acpi_cedt_cfmws cfmws;
146 u32 target[2];
147 } cfmws7;
148 struct {
149 struct acpi_cedt_cfmws cfmws;
150 u32 target[4];
151 } cfmws8;
152 struct {
153 struct acpi_cedt_cxims cxims;
154 u64 xormap_list[2];
155 } cxims0;
156} __packed mock_cedt = {
157 .cedt = {
158 .header = {
159 .signature = "CEDT",
160 .length = sizeof(mock_cedt),
161 .revision = 1,
162 },
163 },
164 .chbs[0] = {
165 .header = {
166 .type = ACPI_CEDT_TYPE_CHBS,
167 .length = sizeof(mock_cedt.chbs[0]),
168 },
169 .uid = 0,
170 .cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20,
171 },
172 .chbs[1] = {
173 .header = {
174 .type = ACPI_CEDT_TYPE_CHBS,
175 .length = sizeof(mock_cedt.chbs[0]),
176 },
177 .uid = 1,
178 .cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20,
179 },
180 .chbs[2] = {
181 .header = {
182 .type = ACPI_CEDT_TYPE_CHBS,
183 .length = sizeof(mock_cedt.chbs[0]),
184 },
185 .uid = 2,
186 .cxl_version = ACPI_CEDT_CHBS_VERSION_CXL20,
187 },
188 .chbs[3] = {
189 .header = {
190 .type = ACPI_CEDT_TYPE_CHBS,
191 .length = sizeof(mock_cedt.chbs[0]),
192 },
193 .uid = 3,
194 .cxl_version = ACPI_CEDT_CHBS_VERSION_CXL11,
195 },
196 .cfmws0 = {
197 .cfmws = {
198 .header = {
199 .type = ACPI_CEDT_TYPE_CFMWS,
200 .length = sizeof(mock_cedt.cfmws0),
201 },
202 .interleave_ways = 0,
203 .granularity = 4,
204 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
205 ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
206 .qtg_id = 0,
207 .window_size = SZ_256M * 4UL,
208 },
209 .target = { 0 },
210 },
211 .cfmws1 = {
212 .cfmws = {
213 .header = {
214 .type = ACPI_CEDT_TYPE_CFMWS,
215 .length = sizeof(mock_cedt.cfmws1),
216 },
217 .interleave_ways = 1,
218 .granularity = 4,
219 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
220 ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
221 .qtg_id = 1,
222 .window_size = SZ_256M * 8UL,
223 },
224 .target = { 0, 1, },
225 },
226 .cfmws2 = {
227 .cfmws = {
228 .header = {
229 .type = ACPI_CEDT_TYPE_CFMWS,
230 .length = sizeof(mock_cedt.cfmws2),
231 },
232 .interleave_ways = 0,
233 .granularity = 4,
234 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
235 ACPI_CEDT_CFMWS_RESTRICT_PMEM,
236 .qtg_id = 2,
237 .window_size = SZ_256M * 4UL,
238 },
239 .target = { 0 },
240 },
241 .cfmws3 = {
242 .cfmws = {
243 .header = {
244 .type = ACPI_CEDT_TYPE_CFMWS,
245 .length = sizeof(mock_cedt.cfmws3),
246 },
247 .interleave_ways = 1,
248 .granularity = 4,
249 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
250 ACPI_CEDT_CFMWS_RESTRICT_PMEM,
251 .qtg_id = 3,
252 .window_size = SZ_256M * 8UL,
253 },
254 .target = { 0, 1, },
255 },
256 .cfmws4 = {
257 .cfmws = {
258 .header = {
259 .type = ACPI_CEDT_TYPE_CFMWS,
260 .length = sizeof(mock_cedt.cfmws4),
261 },
262 .interleave_ways = 0,
263 .granularity = 4,
264 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
265 ACPI_CEDT_CFMWS_RESTRICT_PMEM,
266 .qtg_id = 4,
267 .window_size = SZ_256M * 4UL,
268 },
269 .target = { 2 },
270 },
271 .cfmws5 = {
272 .cfmws = {
273 .header = {
274 .type = ACPI_CEDT_TYPE_CFMWS,
275 .length = sizeof(mock_cedt.cfmws5),
276 },
277 .interleave_ways = 0,
278 .granularity = 4,
279 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
280 ACPI_CEDT_CFMWS_RESTRICT_VOLATILE,
281 .qtg_id = 5,
282 .window_size = SZ_256M,
283 },
284 .target = { 3 },
285 },
286 /* .cfmws6,7,8 use ACPI_CEDT_CFMWS_ARITHMETIC_XOR */
287 .cfmws6 = {
288 .cfmws = {
289 .header = {
290 .type = ACPI_CEDT_TYPE_CFMWS,
291 .length = sizeof(mock_cedt.cfmws6),
292 },
293 .interleave_arithmetic = ACPI_CEDT_CFMWS_ARITHMETIC_XOR,
294 .interleave_ways = 0,
295 .granularity = 4,
296 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
297 ACPI_CEDT_CFMWS_RESTRICT_PMEM,
298 .qtg_id = 0,
299 .window_size = SZ_256M * 8UL,
300 },
301 .target = { 0, },
302 },
303 .cfmws7 = {
304 .cfmws = {
305 .header = {
306 .type = ACPI_CEDT_TYPE_CFMWS,
307 .length = sizeof(mock_cedt.cfmws7),
308 },
309 .interleave_arithmetic = ACPI_CEDT_CFMWS_ARITHMETIC_XOR,
310 .interleave_ways = 1,
311 .granularity = 0,
312 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
313 ACPI_CEDT_CFMWS_RESTRICT_PMEM,
314 .qtg_id = 1,
315 .window_size = SZ_256M * 8UL,
316 },
317 .target = { 0, 1, },
318 },
319 .cfmws8 = {
320 .cfmws = {
321 .header = {
322 .type = ACPI_CEDT_TYPE_CFMWS,
323 .length = sizeof(mock_cedt.cfmws8),
324 },
325 .interleave_arithmetic = ACPI_CEDT_CFMWS_ARITHMETIC_XOR,
326 .interleave_ways = 2,
327 .granularity = 0,
328 .restrictions = ACPI_CEDT_CFMWS_RESTRICT_TYPE3 |
329 ACPI_CEDT_CFMWS_RESTRICT_PMEM,
330 .qtg_id = 0,
331 .window_size = SZ_256M * 16UL,
332 },
333 .target = { 0, 1, 0, 1, },
334 },
335 .cxims0 = {
336 .cxims = {
337 .header = {
338 .type = ACPI_CEDT_TYPE_CXIMS,
339 .length = sizeof(mock_cedt.cxims0),
340 },
341 .hbig = 0,
342 .nr_xormaps = 2,
343 },
344 .xormap_list = { 0x404100, 0x808200, },
345 },
346};
347
348struct acpi_cedt_cfmws *mock_cfmws[] = {
349 [0] = &mock_cedt.cfmws0.cfmws,
350 [1] = &mock_cedt.cfmws1.cfmws,
351 [2] = &mock_cedt.cfmws2.cfmws,
352 [3] = &mock_cedt.cfmws3.cfmws,
353 [4] = &mock_cedt.cfmws4.cfmws,
354 [5] = &mock_cedt.cfmws5.cfmws,
355 /* Modulo Math above, XOR Math below */
356 [6] = &mock_cedt.cfmws6.cfmws,
357 [7] = &mock_cedt.cfmws7.cfmws,
358 [8] = &mock_cedt.cfmws8.cfmws,
359};
360
361static int cfmws_start;
362static int cfmws_end;
363#define CFMWS_MOD_ARRAY_START 0
364#define CFMWS_MOD_ARRAY_END 5
365#define CFMWS_XOR_ARRAY_START 6
366#define CFMWS_XOR_ARRAY_END 8
367
368struct acpi_cedt_cxims *mock_cxims[1] = {
369 [0] = &mock_cedt.cxims0.cxims,
370};
371
372struct cxl_mock_res {
373 struct list_head list;
374 struct range range;
375};
376
377static LIST_HEAD(mock_res);
378static DEFINE_MUTEX(mock_res_lock);
379static struct gen_pool *cxl_mock_pool;
380
381static void depopulate_all_mock_resources(void)
382{
383 struct cxl_mock_res *res, *_res;
384
385 mutex_lock(&mock_res_lock);
386 list_for_each_entry_safe(res, _res, &mock_res, list) {
387 gen_pool_free(cxl_mock_pool, res->range.start,
388 range_len(&res->range));
389 list_del(&res->list);
390 kfree(res);
391 }
392 mutex_unlock(&mock_res_lock);
393}
394
395static struct cxl_mock_res *alloc_mock_res(resource_size_t size, int align)
396{
397 struct cxl_mock_res *res = kzalloc(sizeof(*res), GFP_KERNEL);
398 struct genpool_data_align data = {
399 .align = align,
400 };
401 unsigned long phys;
402
403 INIT_LIST_HEAD(&res->list);
404 phys = gen_pool_alloc_algo(cxl_mock_pool, size,
405 gen_pool_first_fit_align, &data);
406 if (!phys)
407 return NULL;
408
409 res->range = (struct range) {
410 .start = phys,
411 .end = phys + size - 1,
412 };
413 mutex_lock(&mock_res_lock);
414 list_add(&res->list, &mock_res);
415 mutex_unlock(&mock_res_lock);
416
417 return res;
418}
419
420static int populate_cedt(void)
421{
422 struct cxl_mock_res *res;
423 int i;
424
425 for (i = 0; i < ARRAY_SIZE(mock_cedt.chbs); i++) {
426 struct acpi_cedt_chbs *chbs = &mock_cedt.chbs[i];
427 resource_size_t size;
428
429 if (chbs->cxl_version == ACPI_CEDT_CHBS_VERSION_CXL20)
430 size = ACPI_CEDT_CHBS_LENGTH_CXL20;
431 else
432 size = ACPI_CEDT_CHBS_LENGTH_CXL11;
433
434 res = alloc_mock_res(size, size);
435 if (!res)
436 return -ENOMEM;
437 chbs->base = res->range.start;
438 chbs->length = size;
439 }
440
441 for (i = cfmws_start; i <= cfmws_end; i++) {
442 struct acpi_cedt_cfmws *window = mock_cfmws[i];
443
444 res = alloc_mock_res(window->window_size, SZ_256M);
445 if (!res)
446 return -ENOMEM;
447 window->base_hpa = res->range.start;
448 }
449
450 return 0;
451}
452
453static bool is_mock_port(struct device *dev);
454
455/*
456 * WARNING, this hack assumes the format of 'struct cxl_cfmws_context'
457 * and 'struct cxl_chbs_context' share the property that the first
458 * struct member is a cxl_test device being probed by the cxl_acpi
459 * driver.
460 */
461struct cxl_cedt_context {
462 struct device *dev;
463};
464
465static int mock_acpi_table_parse_cedt(enum acpi_cedt_type id,
466 acpi_tbl_entry_handler_arg handler_arg,
467 void *arg)
468{
469 struct cxl_cedt_context *ctx = arg;
470 struct device *dev = ctx->dev;
471 union acpi_subtable_headers *h;
472 unsigned long end;
473 int i;
474
475 if (!is_mock_port(dev) && !is_mock_dev(dev))
476 return acpi_table_parse_cedt(id, handler_arg, arg);
477
478 if (id == ACPI_CEDT_TYPE_CHBS)
479 for (i = 0; i < ARRAY_SIZE(mock_cedt.chbs); i++) {
480 h = (union acpi_subtable_headers *)&mock_cedt.chbs[i];
481 end = (unsigned long)&mock_cedt.chbs[i + 1];
482 handler_arg(h, arg, end);
483 }
484
485 if (id == ACPI_CEDT_TYPE_CFMWS)
486 for (i = cfmws_start; i <= cfmws_end; i++) {
487 h = (union acpi_subtable_headers *) mock_cfmws[i];
488 end = (unsigned long) h + mock_cfmws[i]->header.length;
489 handler_arg(h, arg, end);
490 }
491
492 if (id == ACPI_CEDT_TYPE_CXIMS)
493 for (i = 0; i < ARRAY_SIZE(mock_cxims); i++) {
494 h = (union acpi_subtable_headers *)mock_cxims[i];
495 end = (unsigned long)h + mock_cxims[i]->header.length;
496 handler_arg(h, arg, end);
497 }
498
499 return 0;
500}
501
502static bool is_mock_bridge(struct device *dev)
503{
504 int i;
505
506 for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++)
507 if (dev == &cxl_host_bridge[i]->dev)
508 return true;
509 for (i = 0; i < ARRAY_SIZE(cxl_hb_single); i++)
510 if (dev == &cxl_hb_single[i]->dev)
511 return true;
512 for (i = 0; i < ARRAY_SIZE(cxl_rch); i++)
513 if (dev == &cxl_rch[i]->dev)
514 return true;
515
516 return false;
517}
518
519static bool is_mock_port(struct device *dev)
520{
521 int i;
522
523 if (is_mock_bridge(dev))
524 return true;
525
526 for (i = 0; i < ARRAY_SIZE(cxl_root_port); i++)
527 if (dev == &cxl_root_port[i]->dev)
528 return true;
529
530 for (i = 0; i < ARRAY_SIZE(cxl_switch_uport); i++)
531 if (dev == &cxl_switch_uport[i]->dev)
532 return true;
533
534 for (i = 0; i < ARRAY_SIZE(cxl_switch_dport); i++)
535 if (dev == &cxl_switch_dport[i]->dev)
536 return true;
537
538 for (i = 0; i < ARRAY_SIZE(cxl_root_single); i++)
539 if (dev == &cxl_root_single[i]->dev)
540 return true;
541
542 for (i = 0; i < ARRAY_SIZE(cxl_swu_single); i++)
543 if (dev == &cxl_swu_single[i]->dev)
544 return true;
545
546 for (i = 0; i < ARRAY_SIZE(cxl_swd_single); i++)
547 if (dev == &cxl_swd_single[i]->dev)
548 return true;
549
550 if (is_cxl_memdev(dev))
551 return is_mock_dev(dev->parent);
552
553 return false;
554}
555
556static int host_bridge_index(struct acpi_device *adev)
557{
558 return adev - host_bridge;
559}
560
561static struct acpi_device *find_host_bridge(acpi_handle handle)
562{
563 int i;
564
565 for (i = 0; i < ARRAY_SIZE(host_bridge); i++)
566 if (handle == host_bridge[i].handle)
567 return &host_bridge[i];
568 return NULL;
569}
570
571static acpi_status
572mock_acpi_evaluate_integer(acpi_handle handle, acpi_string pathname,
573 struct acpi_object_list *arguments,
574 unsigned long long *data)
575{
576 struct acpi_device *adev = find_host_bridge(handle);
577
578 if (!adev || strcmp(pathname, METHOD_NAME__UID) != 0)
579 return acpi_evaluate_integer(handle, pathname, arguments, data);
580
581 *data = host_bridge_index(adev);
582 return AE_OK;
583}
584
585static struct pci_bus mock_pci_bus[NR_BRIDGES];
586static struct acpi_pci_root mock_pci_root[ARRAY_SIZE(mock_pci_bus)] = {
587 [0] = {
588 .bus = &mock_pci_bus[0],
589 },
590 [1] = {
591 .bus = &mock_pci_bus[1],
592 },
593 [2] = {
594 .bus = &mock_pci_bus[2],
595 },
596 [3] = {
597 .bus = &mock_pci_bus[3],
598 },
599
600};
601
602static bool is_mock_bus(struct pci_bus *bus)
603{
604 int i;
605
606 for (i = 0; i < ARRAY_SIZE(mock_pci_bus); i++)
607 if (bus == &mock_pci_bus[i])
608 return true;
609 return false;
610}
611
612static struct acpi_pci_root *mock_acpi_pci_find_root(acpi_handle handle)
613{
614 struct acpi_device *adev = find_host_bridge(handle);
615
616 if (!adev)
617 return acpi_pci_find_root(handle);
618 return &mock_pci_root[host_bridge_index(adev)];
619}
620
621static struct cxl_hdm *mock_cxl_setup_hdm(struct cxl_port *port)
622{
623 struct cxl_hdm *cxlhdm = devm_kzalloc(&port->dev, sizeof(*cxlhdm), GFP_KERNEL);
624
625 if (!cxlhdm)
626 return ERR_PTR(-ENOMEM);
627
628 cxlhdm->port = port;
629 return cxlhdm;
630}
631
632static int mock_cxl_add_passthrough_decoder(struct cxl_port *port)
633{
634 dev_err(&port->dev, "unexpected passthrough decoder for cxl_test\n");
635 return -EOPNOTSUPP;
636}
637
638
639struct target_map_ctx {
640 int *target_map;
641 int index;
642 int target_count;
643};
644
645static int map_targets(struct device *dev, void *data)
646{
647 struct platform_device *pdev = to_platform_device(dev);
648 struct target_map_ctx *ctx = data;
649
650 ctx->target_map[ctx->index++] = pdev->id;
651
652 if (ctx->index > ctx->target_count) {
653 dev_WARN_ONCE(dev, 1, "too many targets found?\n");
654 return -ENXIO;
655 }
656
657 return 0;
658}
659
660static int mock_decoder_commit(struct cxl_decoder *cxld)
661{
662 struct cxl_port *port = to_cxl_port(cxld->dev.parent);
663 int id = cxld->id;
664
665 if (cxld->flags & CXL_DECODER_F_ENABLE)
666 return 0;
667
668 dev_dbg(&port->dev, "%s commit\n", dev_name(&cxld->dev));
669 if (port->commit_end + 1 != id) {
670 dev_dbg(&port->dev,
671 "%s: out of order commit, expected decoder%d.%d\n",
672 dev_name(&cxld->dev), port->id, port->commit_end + 1);
673 return -EBUSY;
674 }
675
676 port->commit_end++;
677 cxld->flags |= CXL_DECODER_F_ENABLE;
678
679 return 0;
680}
681
682static int mock_decoder_reset(struct cxl_decoder *cxld)
683{
684 struct cxl_port *port = to_cxl_port(cxld->dev.parent);
685 int id = cxld->id;
686
687 if ((cxld->flags & CXL_DECODER_F_ENABLE) == 0)
688 return 0;
689
690 dev_dbg(&port->dev, "%s reset\n", dev_name(&cxld->dev));
691 if (port->commit_end != id) {
692 dev_dbg(&port->dev,
693 "%s: out of order reset, expected decoder%d.%d\n",
694 dev_name(&cxld->dev), port->id, port->commit_end);
695 return -EBUSY;
696 }
697
698 port->commit_end--;
699 cxld->flags &= ~CXL_DECODER_F_ENABLE;
700
701 return 0;
702}
703
704static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
705{
706 struct cxl_port *port = cxlhdm->port;
707 struct cxl_port *parent_port = to_cxl_port(port->dev.parent);
708 int target_count, i;
709
710 if (is_cxl_endpoint(port))
711 target_count = 0;
712 else if (is_cxl_root(parent_port))
713 target_count = NR_CXL_ROOT_PORTS;
714 else
715 target_count = NR_CXL_SWITCH_PORTS;
716
717 for (i = 0; i < NR_CXL_PORT_DECODERS; i++) {
718 int target_map[CXL_DECODER_MAX_INTERLEAVE] = { 0 };
719 struct target_map_ctx ctx = {
720 .target_map = target_map,
721 .target_count = target_count,
722 };
723 struct cxl_decoder *cxld;
724 int rc;
725
726 if (target_count) {
727 struct cxl_switch_decoder *cxlsd;
728
729 cxlsd = cxl_switch_decoder_alloc(port, target_count);
730 if (IS_ERR(cxlsd)) {
731 dev_warn(&port->dev,
732 "Failed to allocate the decoder\n");
733 return PTR_ERR(cxlsd);
734 }
735 cxld = &cxlsd->cxld;
736 } else {
737 struct cxl_endpoint_decoder *cxled;
738
739 cxled = cxl_endpoint_decoder_alloc(port);
740
741 if (IS_ERR(cxled)) {
742 dev_warn(&port->dev,
743 "Failed to allocate the decoder\n");
744 return PTR_ERR(cxled);
745 }
746 cxld = &cxled->cxld;
747 }
748
749 cxld->hpa_range = (struct range) {
750 .start = 0,
751 .end = -1,
752 };
753
754 cxld->interleave_ways = min_not_zero(target_count, 1);
755 cxld->interleave_granularity = SZ_4K;
756 cxld->target_type = CXL_DECODER_EXPANDER;
757 cxld->commit = mock_decoder_commit;
758 cxld->reset = mock_decoder_reset;
759
760 if (target_count) {
761 rc = device_for_each_child(port->uport, &ctx,
762 map_targets);
763 if (rc) {
764 put_device(&cxld->dev);
765 return rc;
766 }
767 }
768
769 rc = cxl_decoder_add_locked(cxld, target_map);
770 if (rc) {
771 put_device(&cxld->dev);
772 dev_err(&port->dev, "Failed to add decoder\n");
773 return rc;
774 }
775
776 rc = cxl_decoder_autoremove(&port->dev, cxld);
777 if (rc)
778 return rc;
779 dev_dbg(&cxld->dev, "Added to port %s\n", dev_name(&port->dev));
780 }
781
782 return 0;
783}
784
785static int mock_cxl_port_enumerate_dports(struct cxl_port *port)
786{
787 struct platform_device **array;
788 int i, array_size;
789
790 if (port->depth == 1) {
791 if (is_multi_bridge(port->uport)) {
792 array_size = ARRAY_SIZE(cxl_root_port);
793 array = cxl_root_port;
794 } else if (is_single_bridge(port->uport)) {
795 array_size = ARRAY_SIZE(cxl_root_single);
796 array = cxl_root_single;
797 } else {
798 dev_dbg(&port->dev, "%s: unknown bridge type\n",
799 dev_name(port->uport));
800 return -ENXIO;
801 }
802 } else if (port->depth == 2) {
803 struct cxl_port *parent = to_cxl_port(port->dev.parent);
804
805 if (is_multi_bridge(parent->uport)) {
806 array_size = ARRAY_SIZE(cxl_switch_dport);
807 array = cxl_switch_dport;
808 } else if (is_single_bridge(parent->uport)) {
809 array_size = ARRAY_SIZE(cxl_swd_single);
810 array = cxl_swd_single;
811 } else {
812 dev_dbg(&port->dev, "%s: unknown bridge type\n",
813 dev_name(port->uport));
814 return -ENXIO;
815 }
816 } else {
817 dev_WARN_ONCE(&port->dev, 1, "unexpected depth %d\n",
818 port->depth);
819 return -ENXIO;
820 }
821
822 for (i = 0; i < array_size; i++) {
823 struct platform_device *pdev = array[i];
824 struct cxl_dport *dport;
825
826 if (pdev->dev.parent != port->uport) {
827 dev_dbg(&port->dev, "%s: mismatch parent %s\n",
828 dev_name(port->uport),
829 dev_name(pdev->dev.parent));
830 continue;
831 }
832
833 dport = devm_cxl_add_dport(port, &pdev->dev, pdev->id,
834 CXL_RESOURCE_NONE);
835
836 if (IS_ERR(dport))
837 return PTR_ERR(dport);
838 }
839
840 return 0;
841}
842
843resource_size_t mock_cxl_rcrb_to_component(struct device *dev,
844 resource_size_t rcrb,
845 enum cxl_rcrb which)
846{
847 dev_dbg(dev, "rcrb: %pa which: %d\n", &rcrb, which);
848
849 return (resource_size_t) which + 1;
850}
851
852static struct cxl_mock_ops cxl_mock_ops = {
853 .is_mock_adev = is_mock_adev,
854 .is_mock_bridge = is_mock_bridge,
855 .is_mock_bus = is_mock_bus,
856 .is_mock_port = is_mock_port,
857 .is_mock_dev = is_mock_dev,
858 .acpi_table_parse_cedt = mock_acpi_table_parse_cedt,
859 .acpi_evaluate_integer = mock_acpi_evaluate_integer,
860 .cxl_rcrb_to_component = mock_cxl_rcrb_to_component,
861 .acpi_pci_find_root = mock_acpi_pci_find_root,
862 .devm_cxl_port_enumerate_dports = mock_cxl_port_enumerate_dports,
863 .devm_cxl_setup_hdm = mock_cxl_setup_hdm,
864 .devm_cxl_add_passthrough_decoder = mock_cxl_add_passthrough_decoder,
865 .devm_cxl_enumerate_decoders = mock_cxl_enumerate_decoders,
866 .list = LIST_HEAD_INIT(cxl_mock_ops.list),
867};
868
869static void mock_companion(struct acpi_device *adev, struct device *dev)
870{
871 device_initialize(&adev->dev);
872 fwnode_init(&adev->fwnode, NULL);
873 dev->fwnode = &adev->fwnode;
874 adev->fwnode.dev = dev;
875}
876
877#ifndef SZ_64G
878#define SZ_64G (SZ_32G * 2)
879#endif
880
881#ifndef SZ_512G
882#define SZ_512G (SZ_64G * 8)
883#endif
884
885static __init int cxl_rch_init(void)
886{
887 int rc, i;
888
889 for (i = 0; i < ARRAY_SIZE(cxl_rch); i++) {
890 int idx = NR_CXL_HOST_BRIDGES + NR_CXL_SINGLE_HOST + i;
891 struct acpi_device *adev = &host_bridge[idx];
892 struct platform_device *pdev;
893
894 pdev = platform_device_alloc("cxl_host_bridge", idx);
895 if (!pdev)
896 goto err_bridge;
897
898 mock_companion(adev, &pdev->dev);
899 rc = platform_device_add(pdev);
900 if (rc) {
901 platform_device_put(pdev);
902 goto err_bridge;
903 }
904
905 cxl_rch[i] = pdev;
906 mock_pci_bus[idx].bridge = &pdev->dev;
907 rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj,
908 "firmware_node");
909 if (rc)
910 goto err_bridge;
911 }
912
913 for (i = 0; i < ARRAY_SIZE(cxl_rcd); i++) {
914 int idx = NR_MEM_MULTI + NR_MEM_SINGLE + i;
915 struct platform_device *rch = cxl_rch[i];
916 struct platform_device *pdev;
917
918 pdev = platform_device_alloc("cxl_rcd", idx);
919 if (!pdev)
920 goto err_mem;
921 pdev->dev.parent = &rch->dev;
922 set_dev_node(&pdev->dev, i % 2);
923
924 rc = platform_device_add(pdev);
925 if (rc) {
926 platform_device_put(pdev);
927 goto err_mem;
928 }
929 cxl_rcd[i] = pdev;
930 }
931
932 return 0;
933
934err_mem:
935 for (i = ARRAY_SIZE(cxl_rcd) - 1; i >= 0; i--)
936 platform_device_unregister(cxl_rcd[i]);
937err_bridge:
938 for (i = ARRAY_SIZE(cxl_rch) - 1; i >= 0; i--) {
939 struct platform_device *pdev = cxl_rch[i];
940
941 if (!pdev)
942 continue;
943 sysfs_remove_link(&pdev->dev.kobj, "firmware_node");
944 platform_device_unregister(cxl_rch[i]);
945 }
946
947 return rc;
948}
949
950static void cxl_rch_exit(void)
951{
952 int i;
953
954 for (i = ARRAY_SIZE(cxl_rcd) - 1; i >= 0; i--)
955 platform_device_unregister(cxl_rcd[i]);
956 for (i = ARRAY_SIZE(cxl_rch) - 1; i >= 0; i--) {
957 struct platform_device *pdev = cxl_rch[i];
958
959 if (!pdev)
960 continue;
961 sysfs_remove_link(&pdev->dev.kobj, "firmware_node");
962 platform_device_unregister(cxl_rch[i]);
963 }
964}
965
966static __init int cxl_single_init(void)
967{
968 int i, rc;
969
970 for (i = 0; i < ARRAY_SIZE(cxl_hb_single); i++) {
971 struct acpi_device *adev =
972 &host_bridge[NR_CXL_HOST_BRIDGES + i];
973 struct platform_device *pdev;
974
975 pdev = platform_device_alloc("cxl_host_bridge",
976 NR_CXL_HOST_BRIDGES + i);
977 if (!pdev)
978 goto err_bridge;
979
980 mock_companion(adev, &pdev->dev);
981 rc = platform_device_add(pdev);
982 if (rc) {
983 platform_device_put(pdev);
984 goto err_bridge;
985 }
986
987 cxl_hb_single[i] = pdev;
988 mock_pci_bus[i + NR_CXL_HOST_BRIDGES].bridge = &pdev->dev;
989 rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj,
990 "physical_node");
991 if (rc)
992 goto err_bridge;
993 }
994
995 for (i = 0; i < ARRAY_SIZE(cxl_root_single); i++) {
996 struct platform_device *bridge =
997 cxl_hb_single[i % ARRAY_SIZE(cxl_hb_single)];
998 struct platform_device *pdev;
999
1000 pdev = platform_device_alloc("cxl_root_port",
1001 NR_MULTI_ROOT + i);
1002 if (!pdev)
1003 goto err_port;
1004 pdev->dev.parent = &bridge->dev;
1005
1006 rc = platform_device_add(pdev);
1007 if (rc) {
1008 platform_device_put(pdev);
1009 goto err_port;
1010 }
1011 cxl_root_single[i] = pdev;
1012 }
1013
1014 for (i = 0; i < ARRAY_SIZE(cxl_swu_single); i++) {
1015 struct platform_device *root_port = cxl_root_single[i];
1016 struct platform_device *pdev;
1017
1018 pdev = platform_device_alloc("cxl_switch_uport",
1019 NR_MULTI_ROOT + i);
1020 if (!pdev)
1021 goto err_uport;
1022 pdev->dev.parent = &root_port->dev;
1023
1024 rc = platform_device_add(pdev);
1025 if (rc) {
1026 platform_device_put(pdev);
1027 goto err_uport;
1028 }
1029 cxl_swu_single[i] = pdev;
1030 }
1031
1032 for (i = 0; i < ARRAY_SIZE(cxl_swd_single); i++) {
1033 struct platform_device *uport =
1034 cxl_swu_single[i % ARRAY_SIZE(cxl_swu_single)];
1035 struct platform_device *pdev;
1036
1037 pdev = platform_device_alloc("cxl_switch_dport",
1038 i + NR_MEM_MULTI);
1039 if (!pdev)
1040 goto err_dport;
1041 pdev->dev.parent = &uport->dev;
1042
1043 rc = platform_device_add(pdev);
1044 if (rc) {
1045 platform_device_put(pdev);
1046 goto err_dport;
1047 }
1048 cxl_swd_single[i] = pdev;
1049 }
1050
1051 for (i = 0; i < ARRAY_SIZE(cxl_mem_single); i++) {
1052 struct platform_device *dport = cxl_swd_single[i];
1053 struct platform_device *pdev;
1054
1055 pdev = platform_device_alloc("cxl_mem", NR_MEM_MULTI + i);
1056 if (!pdev)
1057 goto err_mem;
1058 pdev->dev.parent = &dport->dev;
1059 set_dev_node(&pdev->dev, i % 2);
1060
1061 rc = platform_device_add(pdev);
1062 if (rc) {
1063 platform_device_put(pdev);
1064 goto err_mem;
1065 }
1066 cxl_mem_single[i] = pdev;
1067 }
1068
1069 return 0;
1070
1071err_mem:
1072 for (i = ARRAY_SIZE(cxl_mem_single) - 1; i >= 0; i--)
1073 platform_device_unregister(cxl_mem_single[i]);
1074err_dport:
1075 for (i = ARRAY_SIZE(cxl_swd_single) - 1; i >= 0; i--)
1076 platform_device_unregister(cxl_swd_single[i]);
1077err_uport:
1078 for (i = ARRAY_SIZE(cxl_swu_single) - 1; i >= 0; i--)
1079 platform_device_unregister(cxl_swu_single[i]);
1080err_port:
1081 for (i = ARRAY_SIZE(cxl_root_single) - 1; i >= 0; i--)
1082 platform_device_unregister(cxl_root_single[i]);
1083err_bridge:
1084 for (i = ARRAY_SIZE(cxl_hb_single) - 1; i >= 0; i--) {
1085 struct platform_device *pdev = cxl_hb_single[i];
1086
1087 if (!pdev)
1088 continue;
1089 sysfs_remove_link(&pdev->dev.kobj, "physical_node");
1090 platform_device_unregister(cxl_hb_single[i]);
1091 }
1092
1093 return rc;
1094}
1095
1096static void cxl_single_exit(void)
1097{
1098 int i;
1099
1100 for (i = ARRAY_SIZE(cxl_mem_single) - 1; i >= 0; i--)
1101 platform_device_unregister(cxl_mem_single[i]);
1102 for (i = ARRAY_SIZE(cxl_swd_single) - 1; i >= 0; i--)
1103 platform_device_unregister(cxl_swd_single[i]);
1104 for (i = ARRAY_SIZE(cxl_swu_single) - 1; i >= 0; i--)
1105 platform_device_unregister(cxl_swu_single[i]);
1106 for (i = ARRAY_SIZE(cxl_root_single) - 1; i >= 0; i--)
1107 platform_device_unregister(cxl_root_single[i]);
1108 for (i = ARRAY_SIZE(cxl_hb_single) - 1; i >= 0; i--) {
1109 struct platform_device *pdev = cxl_hb_single[i];
1110
1111 if (!pdev)
1112 continue;
1113 sysfs_remove_link(&pdev->dev.kobj, "physical_node");
1114 platform_device_unregister(cxl_hb_single[i]);
1115 }
1116}
1117
1118static __init int cxl_test_init(void)
1119{
1120 int rc, i;
1121
1122 register_cxl_mock_ops(&cxl_mock_ops);
1123
1124 cxl_mock_pool = gen_pool_create(ilog2(SZ_2M), NUMA_NO_NODE);
1125 if (!cxl_mock_pool) {
1126 rc = -ENOMEM;
1127 goto err_gen_pool_create;
1128 }
1129
1130 rc = gen_pool_add(cxl_mock_pool, iomem_resource.end + 1 - SZ_64G,
1131 SZ_64G, NUMA_NO_NODE);
1132 if (rc)
1133 goto err_gen_pool_add;
1134
1135 if (interleave_arithmetic == 1) {
1136 cfmws_start = CFMWS_XOR_ARRAY_START;
1137 cfmws_end = CFMWS_XOR_ARRAY_END;
1138 dev_dbg(NULL, "cxl_test loading xor math option\n");
1139 } else {
1140 cfmws_start = CFMWS_MOD_ARRAY_START;
1141 cfmws_end = CFMWS_MOD_ARRAY_END;
1142 dev_dbg(NULL, "cxl_test loading modulo math option\n");
1143 }
1144
1145 rc = populate_cedt();
1146 if (rc)
1147 goto err_populate;
1148
1149 for (i = 0; i < ARRAY_SIZE(cxl_host_bridge); i++) {
1150 struct acpi_device *adev = &host_bridge[i];
1151 struct platform_device *pdev;
1152
1153 pdev = platform_device_alloc("cxl_host_bridge", i);
1154 if (!pdev)
1155 goto err_bridge;
1156
1157 mock_companion(adev, &pdev->dev);
1158 rc = platform_device_add(pdev);
1159 if (rc) {
1160 platform_device_put(pdev);
1161 goto err_bridge;
1162 }
1163
1164 cxl_host_bridge[i] = pdev;
1165 mock_pci_bus[i].bridge = &pdev->dev;
1166 rc = sysfs_create_link(&pdev->dev.kobj, &pdev->dev.kobj,
1167 "physical_node");
1168 if (rc)
1169 goto err_bridge;
1170 }
1171
1172 for (i = 0; i < ARRAY_SIZE(cxl_root_port); i++) {
1173 struct platform_device *bridge =
1174 cxl_host_bridge[i % ARRAY_SIZE(cxl_host_bridge)];
1175 struct platform_device *pdev;
1176
1177 pdev = platform_device_alloc("cxl_root_port", i);
1178 if (!pdev)
1179 goto err_port;
1180 pdev->dev.parent = &bridge->dev;
1181
1182 rc = platform_device_add(pdev);
1183 if (rc) {
1184 platform_device_put(pdev);
1185 goto err_port;
1186 }
1187 cxl_root_port[i] = pdev;
1188 }
1189
1190 BUILD_BUG_ON(ARRAY_SIZE(cxl_switch_uport) != ARRAY_SIZE(cxl_root_port));
1191 for (i = 0; i < ARRAY_SIZE(cxl_switch_uport); i++) {
1192 struct platform_device *root_port = cxl_root_port[i];
1193 struct platform_device *pdev;
1194
1195 pdev = platform_device_alloc("cxl_switch_uport", i);
1196 if (!pdev)
1197 goto err_uport;
1198 pdev->dev.parent = &root_port->dev;
1199
1200 rc = platform_device_add(pdev);
1201 if (rc) {
1202 platform_device_put(pdev);
1203 goto err_uport;
1204 }
1205 cxl_switch_uport[i] = pdev;
1206 }
1207
1208 for (i = 0; i < ARRAY_SIZE(cxl_switch_dport); i++) {
1209 struct platform_device *uport =
1210 cxl_switch_uport[i % ARRAY_SIZE(cxl_switch_uport)];
1211 struct platform_device *pdev;
1212
1213 pdev = platform_device_alloc("cxl_switch_dport", i);
1214 if (!pdev)
1215 goto err_dport;
1216 pdev->dev.parent = &uport->dev;
1217
1218 rc = platform_device_add(pdev);
1219 if (rc) {
1220 platform_device_put(pdev);
1221 goto err_dport;
1222 }
1223 cxl_switch_dport[i] = pdev;
1224 }
1225
1226 for (i = 0; i < ARRAY_SIZE(cxl_mem); i++) {
1227 struct platform_device *dport = cxl_switch_dport[i];
1228 struct platform_device *pdev;
1229
1230 pdev = platform_device_alloc("cxl_mem", i);
1231 if (!pdev)
1232 goto err_mem;
1233 pdev->dev.parent = &dport->dev;
1234 set_dev_node(&pdev->dev, i % 2);
1235
1236 rc = platform_device_add(pdev);
1237 if (rc) {
1238 platform_device_put(pdev);
1239 goto err_mem;
1240 }
1241 cxl_mem[i] = pdev;
1242 }
1243
1244 rc = cxl_single_init();
1245 if (rc)
1246 goto err_mem;
1247
1248 rc = cxl_rch_init();
1249 if (rc)
1250 goto err_single;
1251
1252 cxl_acpi = platform_device_alloc("cxl_acpi", 0);
1253 if (!cxl_acpi)
1254 goto err_rch;
1255
1256 mock_companion(&acpi0017_mock, &cxl_acpi->dev);
1257 acpi0017_mock.dev.bus = &platform_bus_type;
1258
1259 rc = platform_device_add(cxl_acpi);
1260 if (rc)
1261 goto err_add;
1262
1263 return 0;
1264
1265err_add:
1266 platform_device_put(cxl_acpi);
1267err_rch:
1268 cxl_rch_exit();
1269err_single:
1270 cxl_single_exit();
1271err_mem:
1272 for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--)
1273 platform_device_unregister(cxl_mem[i]);
1274err_dport:
1275 for (i = ARRAY_SIZE(cxl_switch_dport) - 1; i >= 0; i--)
1276 platform_device_unregister(cxl_switch_dport[i]);
1277err_uport:
1278 for (i = ARRAY_SIZE(cxl_switch_uport) - 1; i >= 0; i--)
1279 platform_device_unregister(cxl_switch_uport[i]);
1280err_port:
1281 for (i = ARRAY_SIZE(cxl_root_port) - 1; i >= 0; i--)
1282 platform_device_unregister(cxl_root_port[i]);
1283err_bridge:
1284 for (i = ARRAY_SIZE(cxl_host_bridge) - 1; i >= 0; i--) {
1285 struct platform_device *pdev = cxl_host_bridge[i];
1286
1287 if (!pdev)
1288 continue;
1289 sysfs_remove_link(&pdev->dev.kobj, "physical_node");
1290 platform_device_unregister(cxl_host_bridge[i]);
1291 }
1292err_populate:
1293 depopulate_all_mock_resources();
1294err_gen_pool_add:
1295 gen_pool_destroy(cxl_mock_pool);
1296err_gen_pool_create:
1297 unregister_cxl_mock_ops(&cxl_mock_ops);
1298 return rc;
1299}
1300
1301static __exit void cxl_test_exit(void)
1302{
1303 int i;
1304
1305 platform_device_unregister(cxl_acpi);
1306 cxl_rch_exit();
1307 cxl_single_exit();
1308 for (i = ARRAY_SIZE(cxl_mem) - 1; i >= 0; i--)
1309 platform_device_unregister(cxl_mem[i]);
1310 for (i = ARRAY_SIZE(cxl_switch_dport) - 1; i >= 0; i--)
1311 platform_device_unregister(cxl_switch_dport[i]);
1312 for (i = ARRAY_SIZE(cxl_switch_uport) - 1; i >= 0; i--)
1313 platform_device_unregister(cxl_switch_uport[i]);
1314 for (i = ARRAY_SIZE(cxl_root_port) - 1; i >= 0; i--)
1315 platform_device_unregister(cxl_root_port[i]);
1316 for (i = ARRAY_SIZE(cxl_host_bridge) - 1; i >= 0; i--) {
1317 struct platform_device *pdev = cxl_host_bridge[i];
1318
1319 if (!pdev)
1320 continue;
1321 sysfs_remove_link(&pdev->dev.kobj, "physical_node");
1322 platform_device_unregister(cxl_host_bridge[i]);
1323 }
1324 depopulate_all_mock_resources();
1325 gen_pool_destroy(cxl_mock_pool);
1326 unregister_cxl_mock_ops(&cxl_mock_ops);
1327}
1328
1329module_param(interleave_arithmetic, int, 0000);
1330MODULE_PARM_DESC(interleave_arithmetic, "Modulo:0, XOR:1");
1331module_init(cxl_test_init);
1332module_exit(cxl_test_exit);
1333MODULE_LICENSE("GPL v2");
1334MODULE_IMPORT_NS(ACPI);
1335MODULE_IMPORT_NS(CXL);