1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright(c) 2021 Intel Corporation. All rights reserved. */
3 #include <linux/platform_device.h>
4 #include <linux/module.h>
5 #include <linux/device.h>
6 #include <linux/kernel.h>
7 #include <linux/acpi.h>
8 #include <linux/pci.h>
9 #include <linux/node.h>
10 #include <asm/div64.h>
11 #include "cxlpci.h"
12 #include "cxl.h"
13
14 struct cxl_cxims_data {
15 int nr_maps;
16 u64 xormaps[] __counted_by(nr_maps);
17 };
18
19 static const guid_t acpi_cxl_qtg_id_guid =
20 GUID_INIT(0xF365F9A6, 0xA7DE, 0x4071,
21 0xA6, 0x6A, 0xB4, 0x0C, 0x0B, 0x4F, 0x8E, 0x52);
22
23
cxl_xor_hpa_to_spa(struct cxl_root_decoder * cxlrd,u64 hpa)24 static u64 cxl_xor_hpa_to_spa(struct cxl_root_decoder *cxlrd, u64 hpa)
25 {
26 struct cxl_cxims_data *cximsd = cxlrd->platform_data;
27 int hbiw = cxlrd->cxlsd.nr_targets;
28 u64 val;
29 int pos;
30
31 /* No xormaps for host bridge interleave ways of 1 or 3 */
32 if (hbiw == 1 || hbiw == 3)
33 return hpa;
34
35 /*
36 * For root decoders using xormaps (hbiw: 2,4,6,8,12,16) restore
37 * the position bit to its value before the xormap was applied at
38 * HPA->DPA translation.
39 *
40 * pos is the lowest set bit in an XORMAP
41 * val is the XORALLBITS(HPA & XORMAP)
42 *
43 * XORALLBITS: The CXL spec (3.1 Table 9-22) defines XORALLBITS
44 * as an operation that outputs a single bit by XORing all the
45 * bits in the input (hpa & xormap). Implement XORALLBITS using
46 * hweight64(). If the hamming weight is even the XOR of those
47 * bits results in val==0, if odd the XOR result is val==1.
48 */
49
50 for (int i = 0; i < cximsd->nr_maps; i++) {
51 if (!cximsd->xormaps[i])
52 continue;
53 pos = __ffs(cximsd->xormaps[i]);
54 val = (hweight64(hpa & cximsd->xormaps[i]) & 1);
55 hpa = (hpa & ~(1ULL << pos)) | (val << pos);
56 }
57
58 return hpa;
59 }
60
61 struct cxl_cxims_context {
62 struct device *dev;
63 struct cxl_root_decoder *cxlrd;
64 };
65
cxl_parse_cxims(union acpi_subtable_headers * header,void * arg,const unsigned long end)66 static int cxl_parse_cxims(union acpi_subtable_headers *header, void *arg,
67 const unsigned long end)
68 {
69 struct acpi_cedt_cxims *cxims = (struct acpi_cedt_cxims *)header;
70 struct cxl_cxims_context *ctx = arg;
71 struct cxl_root_decoder *cxlrd = ctx->cxlrd;
72 struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
73 struct device *dev = ctx->dev;
74 struct cxl_cxims_data *cximsd;
75 unsigned int hbig, nr_maps;
76 int rc;
77
78 rc = eig_to_granularity(cxims->hbig, &hbig);
79 if (rc)
80 return rc;
81
82 /* Does this CXIMS entry apply to the given CXL Window? */
83 if (hbig != cxld->interleave_granularity)
84 return 0;
85
86 /* IW 1,3 do not use xormaps and skip this parsing entirely */
87 if (is_power_of_2(cxld->interleave_ways))
88 /* 2, 4, 8, 16 way */
89 nr_maps = ilog2(cxld->interleave_ways);
90 else
91 /* 6, 12 way */
92 nr_maps = ilog2(cxld->interleave_ways / 3);
93
94 if (cxims->nr_xormaps < nr_maps) {
95 dev_dbg(dev, "CXIMS nr_xormaps[%d] expected[%d]\n",
96 cxims->nr_xormaps, nr_maps);
97 return -ENXIO;
98 }
99
100 cximsd = devm_kzalloc(dev, struct_size(cximsd, xormaps, nr_maps),
101 GFP_KERNEL);
102 if (!cximsd)
103 return -ENOMEM;
104 cximsd->nr_maps = nr_maps;
105 memcpy(cximsd->xormaps, cxims->xormap_list,
106 nr_maps * sizeof(*cximsd->xormaps));
107 cxlrd->platform_data = cximsd;
108
109 return 0;
110 }
111
cfmws_to_decoder_flags(int restrictions)112 static unsigned long cfmws_to_decoder_flags(int restrictions)
113 {
114 unsigned long flags = CXL_DECODER_F_ENABLE;
115
116 if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_TYPE2)
117 flags |= CXL_DECODER_F_TYPE2;
118 if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_TYPE3)
119 flags |= CXL_DECODER_F_TYPE3;
120 if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_VOLATILE)
121 flags |= CXL_DECODER_F_RAM;
122 if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_PMEM)
123 flags |= CXL_DECODER_F_PMEM;
124 if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_FIXED)
125 flags |= CXL_DECODER_F_LOCK;
126
127 return flags;
128 }
129
cxl_acpi_cfmws_verify(struct device * dev,struct acpi_cedt_cfmws * cfmws)130 static int cxl_acpi_cfmws_verify(struct device *dev,
131 struct acpi_cedt_cfmws *cfmws)
132 {
133 int rc, expected_len;
134 unsigned int ways;
135
136 if (cfmws->interleave_arithmetic != ACPI_CEDT_CFMWS_ARITHMETIC_MODULO &&
137 cfmws->interleave_arithmetic != ACPI_CEDT_CFMWS_ARITHMETIC_XOR) {
138 dev_err(dev, "CFMWS Unknown Interleave Arithmetic: %d\n",
139 cfmws->interleave_arithmetic);
140 return -EINVAL;
141 }
142
143 if (!IS_ALIGNED(cfmws->base_hpa, SZ_256M)) {
144 dev_err(dev, "CFMWS Base HPA not 256MB aligned\n");
145 return -EINVAL;
146 }
147
148 if (!IS_ALIGNED(cfmws->window_size, SZ_256M)) {
149 dev_err(dev, "CFMWS Window Size not 256MB aligned\n");
150 return -EINVAL;
151 }
152
153 rc = eiw_to_ways(cfmws->interleave_ways, &ways);
154 if (rc) {
155 dev_err(dev, "CFMWS Interleave Ways (%d) invalid\n",
156 cfmws->interleave_ways);
157 return -EINVAL;
158 }
159
160 expected_len = struct_size(cfmws, interleave_targets, ways);
161
162 if (cfmws->header.length < expected_len) {
163 dev_err(dev, "CFMWS length %d less than expected %d\n",
164 cfmws->header.length, expected_len);
165 return -EINVAL;
166 }
167
168 if (cfmws->header.length > expected_len)
169 dev_dbg(dev, "CFMWS length %d greater than expected %d\n",
170 cfmws->header.length, expected_len);
171
172 return 0;
173 }
174
175 /*
176 * Note, @dev must be the first member, see 'struct cxl_chbs_context'
177 * and mock_acpi_table_parse_cedt()
178 */
179 struct cxl_cfmws_context {
180 struct device *dev;
181 struct cxl_port *root_port;
182 struct resource *cxl_res;
183 int id;
184 };
185
186 /**
187 * cxl_acpi_evaluate_qtg_dsm - Retrieve QTG ids via ACPI _DSM
188 * @handle: ACPI handle
189 * @coord: performance access coordinates
190 * @entries: number of QTG IDs to return
191 * @qos_class: int array provided by caller to return QTG IDs
192 *
193 * Return: number of QTG IDs returned, or -errno for errors
194 *
195 * Issue QTG _DSM with accompanied bandwidth and latency data in order to get
196 * the QTG IDs that are suitable for the performance point in order of most
197 * suitable to least suitable. Write back array of QTG IDs and return the
198 * actual number of QTG IDs written back.
199 */
200 static int
cxl_acpi_evaluate_qtg_dsm(acpi_handle handle,struct access_coordinate * coord,int entries,int * qos_class)201 cxl_acpi_evaluate_qtg_dsm(acpi_handle handle, struct access_coordinate *coord,
202 int entries, int *qos_class)
203 {
204 union acpi_object *out_obj, *out_buf, *obj;
205 union acpi_object in_array[4] = {
206 [0].integer = { ACPI_TYPE_INTEGER, coord->read_latency },
207 [1].integer = { ACPI_TYPE_INTEGER, coord->write_latency },
208 [2].integer = { ACPI_TYPE_INTEGER, coord->read_bandwidth },
209 [3].integer = { ACPI_TYPE_INTEGER, coord->write_bandwidth },
210 };
211 union acpi_object in_obj = {
212 .package = {
213 .type = ACPI_TYPE_PACKAGE,
214 .count = 4,
215 .elements = in_array,
216 },
217 };
218 int count, pkg_entries, i;
219 u16 max_qtg;
220 int rc;
221
222 if (!entries)
223 return -EINVAL;
224
225 out_obj = acpi_evaluate_dsm(handle, &acpi_cxl_qtg_id_guid, 1, 1, &in_obj);
226 if (!out_obj)
227 return -ENXIO;
228
229 if (out_obj->type != ACPI_TYPE_PACKAGE) {
230 rc = -ENXIO;
231 goto out;
232 }
233
234 /* Check Max QTG ID */
235 obj = &out_obj->package.elements[0];
236 if (obj->type != ACPI_TYPE_INTEGER) {
237 rc = -ENXIO;
238 goto out;
239 }
240
241 max_qtg = obj->integer.value;
242
243 /* It's legal to have 0 QTG entries */
244 pkg_entries = out_obj->package.count;
245 if (pkg_entries <= 1) {
246 rc = 0;
247 goto out;
248 }
249
250 /* Retrieve QTG IDs package */
251 obj = &out_obj->package.elements[1];
252 if (obj->type != ACPI_TYPE_PACKAGE) {
253 rc = -ENXIO;
254 goto out;
255 }
256
257 pkg_entries = obj->package.count;
258 count = min(entries, pkg_entries);
259 for (i = 0; i < count; i++) {
260 u16 qtg_id;
261
262 out_buf = &obj->package.elements[i];
263 if (out_buf->type != ACPI_TYPE_INTEGER) {
264 rc = -ENXIO;
265 goto out;
266 }
267
268 qtg_id = out_buf->integer.value;
269 if (qtg_id > max_qtg)
270 pr_warn("QTG ID %u greater than MAX %u\n",
271 qtg_id, max_qtg);
272
273 qos_class[i] = qtg_id;
274 }
275 rc = count;
276
277 out:
278 ACPI_FREE(out_obj);
279 return rc;
280 }
281
cxl_acpi_qos_class(struct cxl_root * cxl_root,struct access_coordinate * coord,int entries,int * qos_class)282 static int cxl_acpi_qos_class(struct cxl_root *cxl_root,
283 struct access_coordinate *coord, int entries,
284 int *qos_class)
285 {
286 struct device *dev = cxl_root->port.uport_dev;
287 acpi_handle handle;
288
289 if (!dev_is_platform(dev))
290 return -ENODEV;
291
292 handle = ACPI_HANDLE(dev);
293 if (!handle)
294 return -ENODEV;
295
296 return cxl_acpi_evaluate_qtg_dsm(handle, coord, entries, qos_class);
297 }
298
299 static const struct cxl_root_ops acpi_root_ops = {
300 .qos_class = cxl_acpi_qos_class,
301 };
302
del_cxl_resource(struct resource * res)303 static void del_cxl_resource(struct resource *res)
304 {
305 if (!res)
306 return;
307 kfree(res->name);
308 kfree(res);
309 }
310
alloc_cxl_resource(resource_size_t base,resource_size_t n,int id)311 static struct resource *alloc_cxl_resource(resource_size_t base,
312 resource_size_t n, int id)
313 {
314 struct resource *res __free(kfree) = kzalloc(sizeof(*res), GFP_KERNEL);
315
316 if (!res)
317 return NULL;
318
319 res->start = base;
320 res->end = base + n - 1;
321 res->flags = IORESOURCE_MEM;
322 res->name = kasprintf(GFP_KERNEL, "CXL Window %d", id);
323 if (!res->name)
324 return NULL;
325
326 return no_free_ptr(res);
327 }
328
add_or_reset_cxl_resource(struct resource * parent,struct resource * res)329 static int add_or_reset_cxl_resource(struct resource *parent, struct resource *res)
330 {
331 int rc = insert_resource(parent, res);
332
333 if (rc)
334 del_cxl_resource(res);
335 return rc;
336 }
337
cxl_acpi_set_cache_size(struct cxl_root_decoder * cxlrd)338 static int cxl_acpi_set_cache_size(struct cxl_root_decoder *cxlrd)
339 {
340 struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
341 struct range *hpa = &cxld->hpa_range;
342 resource_size_t size = range_len(hpa);
343 resource_size_t start = hpa->start;
344 resource_size_t cache_size;
345 struct resource res;
346 int nid, rc;
347
348 res = DEFINE_RES(start, size, 0);
349 nid = phys_to_target_node(start);
350
351 rc = hmat_get_extended_linear_cache_size(&res, nid, &cache_size);
352 if (rc)
353 return rc;
354
355 /*
356 * The cache range is expected to be within the CFMWS.
357 * Currently there is only support cache_size == cxl_size. CXL
358 * size is then half of the total CFMWS window size.
359 */
360 size = size >> 1;
361 if (cache_size && size != cache_size) {
362 dev_warn(&cxld->dev,
363 "Extended Linear Cache size %pa != CXL size %pa. No Support!",
364 &cache_size, &size);
365 return -ENXIO;
366 }
367
368 cxlrd->cache_size = cache_size;
369
370 return 0;
371 }
372
cxl_setup_extended_linear_cache(struct cxl_root_decoder * cxlrd)373 static void cxl_setup_extended_linear_cache(struct cxl_root_decoder *cxlrd)
374 {
375 int rc;
376
377 rc = cxl_acpi_set_cache_size(cxlrd);
378 if (!rc)
379 return;
380
381 if (rc != -EOPNOTSUPP) {
382 /*
383 * Failing to support extended linear cache region resize does not
384 * prevent the region from functioning. Only causes cxl list showing
385 * incorrect region size.
386 */
387 dev_warn(cxlrd->cxlsd.cxld.dev.parent,
388 "Extended linear cache calculation failed rc:%d\n", rc);
389 }
390
391 /* Ignoring return code */
392 cxlrd->cache_size = 0;
393 }
394
395 DEFINE_FREE(put_cxlrd, struct cxl_root_decoder *,
396 if (!IS_ERR_OR_NULL(_T)) put_device(&_T->cxlsd.cxld.dev))
DEFINE_FREE(del_cxl_resource,struct resource *,if (_T)del_cxl_resource (_T))397 DEFINE_FREE(del_cxl_resource, struct resource *, if (_T) del_cxl_resource(_T))
398 static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws,
399 struct cxl_cfmws_context *ctx)
400 {
401 int target_map[CXL_DECODER_MAX_INTERLEAVE];
402 struct cxl_port *root_port = ctx->root_port;
403 struct cxl_cxims_context cxims_ctx;
404 struct device *dev = ctx->dev;
405 struct cxl_decoder *cxld;
406 unsigned int ways, i, ig;
407 int rc;
408
409 rc = cxl_acpi_cfmws_verify(dev, cfmws);
410 if (rc)
411 return rc;
412
413 rc = eiw_to_ways(cfmws->interleave_ways, &ways);
414 if (rc)
415 return rc;
416 rc = eig_to_granularity(cfmws->granularity, &ig);
417 if (rc)
418 return rc;
419 for (i = 0; i < ways; i++)
420 target_map[i] = cfmws->interleave_targets[i];
421
422 struct resource *res __free(del_cxl_resource) = alloc_cxl_resource(
423 cfmws->base_hpa, cfmws->window_size, ctx->id++);
424 if (!res)
425 return -ENOMEM;
426
427 /* add to the local resource tracking to establish a sort order */
428 rc = add_or_reset_cxl_resource(ctx->cxl_res, no_free_ptr(res));
429 if (rc)
430 return rc;
431
432 struct cxl_root_decoder *cxlrd __free(put_cxlrd) =
433 cxl_root_decoder_alloc(root_port, ways);
434
435 if (IS_ERR(cxlrd))
436 return PTR_ERR(cxlrd);
437
438 cxld = &cxlrd->cxlsd.cxld;
439 cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions);
440 cxld->target_type = CXL_DECODER_HOSTONLYMEM;
441 cxld->hpa_range = (struct range) {
442 .start = cfmws->base_hpa,
443 .end = cfmws->base_hpa + cfmws->window_size - 1,
444 };
445 cxld->interleave_ways = ways;
446 /*
447 * Minimize the x1 granularity to advertise support for any
448 * valid region granularity
449 */
450 if (ways == 1)
451 ig = CXL_DECODER_MIN_GRANULARITY;
452 cxld->interleave_granularity = ig;
453
454 cxl_setup_extended_linear_cache(cxlrd);
455
456 if (cfmws->interleave_arithmetic == ACPI_CEDT_CFMWS_ARITHMETIC_XOR) {
457 if (ways != 1 && ways != 3) {
458 cxims_ctx = (struct cxl_cxims_context) {
459 .dev = dev,
460 .cxlrd = cxlrd,
461 };
462 rc = acpi_table_parse_cedt(ACPI_CEDT_TYPE_CXIMS,
463 cxl_parse_cxims, &cxims_ctx);
464 if (rc < 0)
465 return rc;
466 if (!cxlrd->platform_data) {
467 dev_err(dev, "No CXIMS for HBIG %u\n", ig);
468 return -EINVAL;
469 }
470 }
471 }
472
473 cxlrd->qos_class = cfmws->qtg_id;
474
475 if (cfmws->interleave_arithmetic == ACPI_CEDT_CFMWS_ARITHMETIC_XOR)
476 cxlrd->hpa_to_spa = cxl_xor_hpa_to_spa;
477
478 rc = cxl_decoder_add(cxld, target_map);
479 if (rc)
480 return rc;
481
482 rc = cxl_root_decoder_autoremove(dev, no_free_ptr(cxlrd));
483 if (rc)
484 return rc;
485
486 dev_dbg(root_port->dev.parent, "%s added to %s\n",
487 dev_name(&cxld->dev), dev_name(&root_port->dev));
488
489 return 0;
490 }
491
cxl_parse_cfmws(union acpi_subtable_headers * header,void * arg,const unsigned long end)492 static int cxl_parse_cfmws(union acpi_subtable_headers *header, void *arg,
493 const unsigned long end)
494 {
495 struct acpi_cedt_cfmws *cfmws = (struct acpi_cedt_cfmws *)header;
496 struct cxl_cfmws_context *ctx = arg;
497 struct device *dev = ctx->dev;
498 int rc;
499
500 rc = __cxl_parse_cfmws(cfmws, ctx);
501 if (rc)
502 dev_err(dev,
503 "Failed to add decode range: [%#llx - %#llx] (%d)\n",
504 cfmws->base_hpa,
505 cfmws->base_hpa + cfmws->window_size - 1, rc);
506 else
507 dev_dbg(dev, "decode range: node: %d range [%#llx - %#llx]\n",
508 phys_to_target_node(cfmws->base_hpa), cfmws->base_hpa,
509 cfmws->base_hpa + cfmws->window_size - 1);
510
511 /* never fail cxl_acpi load for a single window failure */
512 return 0;
513 }
514
to_cxl_host_bridge(struct device * host,struct device * dev)515 __mock struct acpi_device *to_cxl_host_bridge(struct device *host,
516 struct device *dev)
517 {
518 struct acpi_device *adev = to_acpi_device(dev);
519
520 if (!acpi_pci_find_root(adev->handle))
521 return NULL;
522
523 if (strcmp(acpi_device_hid(adev), "ACPI0016") == 0)
524 return adev;
525 return NULL;
526 }
527
528 /* Note, @dev is used by mock_acpi_table_parse_cedt() */
529 struct cxl_chbs_context {
530 struct device *dev;
531 unsigned long long uid;
532 resource_size_t base;
533 u32 cxl_version;
534 int nr_versions;
535 u32 saved_version;
536 };
537
cxl_get_chbs_iter(union acpi_subtable_headers * header,void * arg,const unsigned long end)538 static int cxl_get_chbs_iter(union acpi_subtable_headers *header, void *arg,
539 const unsigned long end)
540 {
541 struct cxl_chbs_context *ctx = arg;
542 struct acpi_cedt_chbs *chbs;
543
544 chbs = (struct acpi_cedt_chbs *) header;
545
546 if (chbs->cxl_version == ACPI_CEDT_CHBS_VERSION_CXL11 &&
547 chbs->length != ACPI_CEDT_CHBS_LENGTH_CXL11)
548 return 0;
549
550 if (chbs->cxl_version == ACPI_CEDT_CHBS_VERSION_CXL20 &&
551 chbs->length != ACPI_CEDT_CHBS_LENGTH_CXL20)
552 return 0;
553
554 if (!chbs->base)
555 return 0;
556
557 if (ctx->saved_version != chbs->cxl_version) {
558 /*
559 * cxl_version cannot be overwritten before the next two
560 * checks, then use saved_version
561 */
562 ctx->saved_version = chbs->cxl_version;
563 ctx->nr_versions++;
564 }
565
566 if (ctx->base != CXL_RESOURCE_NONE)
567 return 0;
568
569 if (ctx->uid != chbs->uid)
570 return 0;
571
572 ctx->cxl_version = chbs->cxl_version;
573 ctx->base = chbs->base;
574
575 return 0;
576 }
577
cxl_get_chbs(struct device * dev,struct acpi_device * hb,struct cxl_chbs_context * ctx)578 static int cxl_get_chbs(struct device *dev, struct acpi_device *hb,
579 struct cxl_chbs_context *ctx)
580 {
581 unsigned long long uid;
582 int rc;
583
584 rc = acpi_evaluate_integer(hb->handle, METHOD_NAME__UID, NULL, &uid);
585 if (rc != AE_OK) {
586 dev_err(dev, "unable to retrieve _UID\n");
587 return -ENOENT;
588 }
589
590 dev_dbg(dev, "UID found: %lld\n", uid);
591 *ctx = (struct cxl_chbs_context) {
592 .dev = dev,
593 .uid = uid,
594 .base = CXL_RESOURCE_NONE,
595 .cxl_version = UINT_MAX,
596 .saved_version = UINT_MAX,
597 };
598
599 acpi_table_parse_cedt(ACPI_CEDT_TYPE_CHBS, cxl_get_chbs_iter, ctx);
600
601 if (ctx->nr_versions > 1) {
602 /*
603 * Disclaim eRCD support given some component register may
604 * only be found via CHBCR
605 */
606 dev_info(dev, "Unsupported platform config, mixed Virtual Host and Restricted CXL Host hierarchy.");
607 }
608
609 return 0;
610 }
611
get_genport_coordinates(struct device * dev,struct cxl_dport * dport)612 static int get_genport_coordinates(struct device *dev, struct cxl_dport *dport)
613 {
614 struct acpi_device *hb = to_cxl_host_bridge(NULL, dev);
615 u32 uid;
616
617 if (kstrtou32(acpi_device_uid(hb), 0, &uid))
618 return -EINVAL;
619
620 return acpi_get_genport_coordinates(uid, dport->coord);
621 }
622
add_host_bridge_dport(struct device * match,void * arg)623 static int add_host_bridge_dport(struct device *match, void *arg)
624 {
625 int ret;
626 acpi_status rc;
627 struct device *bridge;
628 struct cxl_dport *dport;
629 struct cxl_chbs_context ctx;
630 struct acpi_pci_root *pci_root;
631 struct cxl_port *root_port = arg;
632 struct device *host = root_port->dev.parent;
633 struct acpi_device *hb = to_cxl_host_bridge(host, match);
634
635 if (!hb)
636 return 0;
637
638 rc = cxl_get_chbs(match, hb, &ctx);
639 if (rc)
640 return rc;
641
642 if (ctx.cxl_version == UINT_MAX) {
643 dev_warn(match, "No CHBS found for Host Bridge (UID %lld)\n",
644 ctx.uid);
645 return 0;
646 }
647
648 if (ctx.base == CXL_RESOURCE_NONE) {
649 dev_warn(match, "CHBS invalid for Host Bridge (UID %lld)\n",
650 ctx.uid);
651 return 0;
652 }
653
654 pci_root = acpi_pci_find_root(hb->handle);
655 bridge = pci_root->bus->bridge;
656
657 /*
658 * In RCH mode, bind the component regs base to the dport. In
659 * VH mode it will be bound to the CXL host bridge's port
660 * object later in add_host_bridge_uport().
661 */
662 if (ctx.cxl_version == ACPI_CEDT_CHBS_VERSION_CXL11) {
663 dev_dbg(match, "RCRB found for UID %lld: %pa\n", ctx.uid,
664 &ctx.base);
665 dport = devm_cxl_add_rch_dport(root_port, bridge, ctx.uid,
666 ctx.base);
667 } else {
668 dport = devm_cxl_add_dport(root_port, bridge, ctx.uid,
669 CXL_RESOURCE_NONE);
670 }
671
672 if (IS_ERR(dport))
673 return PTR_ERR(dport);
674
675 ret = get_genport_coordinates(match, dport);
676 if (ret)
677 dev_dbg(match, "Failed to get generic port perf coordinates.\n");
678
679 return 0;
680 }
681
682 /*
683 * A host bridge is a dport to a CFMWS decode and it is a uport to the
684 * dport (PCIe Root Ports) in the host bridge.
685 */
add_host_bridge_uport(struct device * match,void * arg)686 static int add_host_bridge_uport(struct device *match, void *arg)
687 {
688 struct cxl_port *root_port = arg;
689 struct device *host = root_port->dev.parent;
690 struct acpi_device *hb = to_cxl_host_bridge(host, match);
691 struct acpi_pci_root *pci_root;
692 struct cxl_dport *dport;
693 struct cxl_port *port;
694 struct device *bridge;
695 struct cxl_chbs_context ctx;
696 resource_size_t component_reg_phys;
697 int rc;
698
699 if (!hb)
700 return 0;
701
702 pci_root = acpi_pci_find_root(hb->handle);
703 bridge = pci_root->bus->bridge;
704 dport = cxl_find_dport_by_dev(root_port, bridge);
705 if (!dport) {
706 dev_dbg(host, "host bridge expected and not found\n");
707 return 0;
708 }
709
710 if (dport->rch) {
711 dev_info(bridge, "host supports CXL (restricted)\n");
712 return 0;
713 }
714
715 rc = cxl_get_chbs(match, hb, &ctx);
716 if (rc)
717 return rc;
718
719 if (ctx.cxl_version == ACPI_CEDT_CHBS_VERSION_CXL11) {
720 dev_warn(bridge,
721 "CXL CHBS version mismatch, skip port registration\n");
722 return 0;
723 }
724
725 component_reg_phys = ctx.base;
726 if (component_reg_phys != CXL_RESOURCE_NONE)
727 dev_dbg(match, "CHBCR found for UID %lld: %pa\n",
728 ctx.uid, &component_reg_phys);
729
730 rc = devm_cxl_register_pci_bus(host, bridge, pci_root->bus);
731 if (rc)
732 return rc;
733
734 port = devm_cxl_add_port(host, bridge, component_reg_phys, dport);
735 if (IS_ERR(port))
736 return PTR_ERR(port);
737
738 dev_info(bridge, "host supports CXL\n");
739
740 return 0;
741 }
742
add_root_nvdimm_bridge(struct device * match,void * data)743 static int add_root_nvdimm_bridge(struct device *match, void *data)
744 {
745 struct cxl_decoder *cxld;
746 struct cxl_port *root_port = data;
747 struct cxl_nvdimm_bridge *cxl_nvb;
748 struct device *host = root_port->dev.parent;
749
750 if (!is_root_decoder(match))
751 return 0;
752
753 cxld = to_cxl_decoder(match);
754 if (!(cxld->flags & CXL_DECODER_F_PMEM))
755 return 0;
756
757 cxl_nvb = devm_cxl_add_nvdimm_bridge(host, root_port);
758 if (IS_ERR(cxl_nvb)) {
759 dev_dbg(host, "failed to register pmem\n");
760 return PTR_ERR(cxl_nvb);
761 }
762 dev_dbg(host, "%s: add: %s\n", dev_name(&root_port->dev),
763 dev_name(&cxl_nvb->dev));
764 return 1;
765 }
766
767 static struct lock_class_key cxl_root_key;
768
cxl_acpi_lock_reset_class(void * dev)769 static void cxl_acpi_lock_reset_class(void *dev)
770 {
771 device_lock_reset_class(dev);
772 }
773
cxl_set_public_resource(struct resource * priv,struct resource * pub)774 static void cxl_set_public_resource(struct resource *priv, struct resource *pub)
775 {
776 priv->desc = (unsigned long) pub;
777 }
778
cxl_get_public_resource(struct resource * priv)779 static struct resource *cxl_get_public_resource(struct resource *priv)
780 {
781 return (struct resource *) priv->desc;
782 }
783
remove_cxl_resources(void * data)784 static void remove_cxl_resources(void *data)
785 {
786 struct resource *res, *next, *cxl = data;
787
788 for (res = cxl->child; res; res = next) {
789 struct resource *victim = cxl_get_public_resource(res);
790
791 next = res->sibling;
792 remove_resource(res);
793
794 if (victim) {
795 remove_resource(victim);
796 kfree(victim);
797 }
798
799 del_cxl_resource(res);
800 }
801 }
802
803 /**
804 * add_cxl_resources() - reflect CXL fixed memory windows in iomem_resource
805 * @cxl_res: A standalone resource tree where each CXL window is a sibling
806 *
807 * Walk each CXL window in @cxl_res and add it to iomem_resource potentially
808 * expanding its boundaries to ensure that any conflicting resources become
809 * children. If a window is expanded it may then conflict with a another window
810 * entry and require the window to be truncated or trimmed. Consider this
811 * situation::
812 *
813 * |-- "CXL Window 0" --||----- "CXL Window 1" -----|
814 * |--------------- "System RAM" -------------|
815 *
816 * ...where platform firmware has established as System RAM resource across 2
817 * windows, but has left some portion of window 1 for dynamic CXL region
818 * provisioning. In this case "Window 0" will span the entirety of the "System
819 * RAM" span, and "CXL Window 1" is truncated to the remaining tail past the end
820 * of that "System RAM" resource.
821 */
add_cxl_resources(struct resource * cxl_res)822 static int add_cxl_resources(struct resource *cxl_res)
823 {
824 struct resource *res, *new, *next;
825
826 for (res = cxl_res->child; res; res = next) {
827 new = kzalloc(sizeof(*new), GFP_KERNEL);
828 if (!new)
829 return -ENOMEM;
830 new->name = res->name;
831 new->start = res->start;
832 new->end = res->end;
833 new->flags = IORESOURCE_MEM;
834 new->desc = IORES_DESC_CXL;
835
836 /*
837 * Record the public resource in the private cxl_res tree for
838 * later removal.
839 */
840 cxl_set_public_resource(res, new);
841
842 insert_resource_expand_to_fit(&iomem_resource, new);
843
844 next = res->sibling;
845 while (next && resource_overlaps(new, next)) {
846 if (resource_contains(new, next)) {
847 struct resource *_next = next->sibling;
848
849 remove_resource(next);
850 del_cxl_resource(next);
851 next = _next;
852 } else
853 next->start = new->end + 1;
854 }
855 }
856 return 0;
857 }
858
pair_cxl_resource(struct device * dev,void * data)859 static int pair_cxl_resource(struct device *dev, void *data)
860 {
861 struct resource *cxl_res = data;
862 struct resource *p;
863
864 if (!is_root_decoder(dev))
865 return 0;
866
867 for (p = cxl_res->child; p; p = p->sibling) {
868 struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
869 struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld;
870 struct resource res = {
871 .start = cxld->hpa_range.start,
872 .end = cxld->hpa_range.end,
873 .flags = IORESOURCE_MEM,
874 };
875
876 if (resource_contains(p, &res)) {
877 cxlrd->res = cxl_get_public_resource(p);
878 break;
879 }
880 }
881
882 return 0;
883 }
884
cxl_acpi_probe(struct platform_device * pdev)885 static int cxl_acpi_probe(struct platform_device *pdev)
886 {
887 int rc;
888 struct resource *cxl_res;
889 struct cxl_root *cxl_root;
890 struct cxl_port *root_port;
891 struct device *host = &pdev->dev;
892 struct acpi_device *adev = ACPI_COMPANION(host);
893 struct cxl_cfmws_context ctx;
894
895 device_lock_set_class(&pdev->dev, &cxl_root_key);
896 rc = devm_add_action_or_reset(&pdev->dev, cxl_acpi_lock_reset_class,
897 &pdev->dev);
898 if (rc)
899 return rc;
900
901 cxl_res = devm_kzalloc(host, sizeof(*cxl_res), GFP_KERNEL);
902 if (!cxl_res)
903 return -ENOMEM;
904 cxl_res->name = "CXL mem";
905 cxl_res->start = 0;
906 cxl_res->end = -1;
907 cxl_res->flags = IORESOURCE_MEM;
908
909 cxl_root = devm_cxl_add_root(host, &acpi_root_ops);
910 if (IS_ERR(cxl_root))
911 return PTR_ERR(cxl_root);
912 root_port = &cxl_root->port;
913
914 rc = bus_for_each_dev(adev->dev.bus, NULL, root_port,
915 add_host_bridge_dport);
916 if (rc < 0)
917 return rc;
918
919 rc = devm_add_action_or_reset(host, remove_cxl_resources, cxl_res);
920 if (rc)
921 return rc;
922
923 ctx = (struct cxl_cfmws_context) {
924 .dev = host,
925 .root_port = root_port,
926 .cxl_res = cxl_res,
927 };
928 rc = acpi_table_parse_cedt(ACPI_CEDT_TYPE_CFMWS, cxl_parse_cfmws, &ctx);
929 if (rc < 0)
930 return -ENXIO;
931
932 rc = add_cxl_resources(cxl_res);
933 if (rc)
934 return rc;
935
936 /*
937 * Populate the root decoders with their related iomem resource,
938 * if present
939 */
940 device_for_each_child(&root_port->dev, cxl_res, pair_cxl_resource);
941
942 /*
943 * Root level scanned with host-bridge as dports, now scan host-bridges
944 * for their role as CXL uports to their CXL-capable PCIe Root Ports.
945 */
946 rc = bus_for_each_dev(adev->dev.bus, NULL, root_port,
947 add_host_bridge_uport);
948 if (rc < 0)
949 return rc;
950
951 if (IS_ENABLED(CONFIG_CXL_PMEM))
952 rc = device_for_each_child(&root_port->dev, root_port,
953 add_root_nvdimm_bridge);
954 if (rc < 0)
955 return rc;
956
957 /* In case PCI is scanned before ACPI re-trigger memdev attach */
958 cxl_bus_rescan();
959 return 0;
960 }
961
962 static const struct acpi_device_id cxl_acpi_ids[] = {
963 { "ACPI0017" },
964 { },
965 };
966 MODULE_DEVICE_TABLE(acpi, cxl_acpi_ids);
967
968 static const struct platform_device_id cxl_test_ids[] = {
969 { "cxl_acpi" },
970 { },
971 };
972 MODULE_DEVICE_TABLE(platform, cxl_test_ids);
973
974 static struct platform_driver cxl_acpi_driver = {
975 .probe = cxl_acpi_probe,
976 .driver = {
977 .name = KBUILD_MODNAME,
978 .acpi_match_table = cxl_acpi_ids,
979 },
980 .id_table = cxl_test_ids,
981 };
982
cxl_acpi_init(void)983 static int __init cxl_acpi_init(void)
984 {
985 return platform_driver_register(&cxl_acpi_driver);
986 }
987
cxl_acpi_exit(void)988 static void __exit cxl_acpi_exit(void)
989 {
990 platform_driver_unregister(&cxl_acpi_driver);
991 cxl_bus_drain();
992 }
993
994 /* load before dax_hmem sees 'Soft Reserved' CXL ranges */
995 subsys_initcall(cxl_acpi_init);
996
997 /*
998 * Arrange for host-bridge ports to be active synchronous with
999 * cxl_acpi_probe() exit.
1000 */
1001 MODULE_SOFTDEP("pre: cxl_port");
1002
1003 module_exit(cxl_acpi_exit);
1004 MODULE_DESCRIPTION("CXL ACPI: Platform Support");
1005 MODULE_LICENSE("GPL v2");
1006 MODULE_IMPORT_NS("CXL");
1007 MODULE_IMPORT_NS("ACPI");
1008