Skip to content

Commit 4603745

Browse files
committed
Merge branch 'for-6.18/cxl-delay-dport' into cxl-for-next
Add changes to delay the allocation and setup of dports until when the endpoint device is being probed. At this point, the CXL link is established from endpoint to host bridge. Addresses issues seen on some platforms when dports are probed earlier. Link: https://lore.kernel.org/linux-cxl/20250829180928.842707-1-dave.jiang@intel.com/
2 parents c5dca38 + f6ee249 commit 4603745

16 files changed

Lines changed: 642 additions & 265 deletions

File tree

drivers/cxl/acpi.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,6 @@ DEFINE_FREE(del_cxl_resource, struct resource *, if (_T) del_cxl_resource(_T))
401401
static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws,
402402
struct cxl_cfmws_context *ctx)
403403
{
404-
int target_map[CXL_DECODER_MAX_INTERLEAVE];
405404
struct cxl_port *root_port = ctx->root_port;
406405
struct cxl_cxims_context cxims_ctx;
407406
struct device *dev = ctx->dev;
@@ -419,8 +418,6 @@ static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws,
419418
rc = eig_to_granularity(cfmws->granularity, &ig);
420419
if (rc)
421420
return rc;
422-
for (i = 0; i < ways; i++)
423-
target_map[i] = cfmws->interleave_targets[i];
424421

425422
struct resource *res __free(del_cxl_resource) = alloc_cxl_resource(
426423
cfmws->base_hpa, cfmws->window_size, ctx->id++);
@@ -446,6 +443,8 @@ static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws,
446443
.end = cfmws->base_hpa + cfmws->window_size - 1,
447444
};
448445
cxld->interleave_ways = ways;
446+
for (i = 0; i < ways; i++)
447+
cxld->target_map[i] = cfmws->interleave_targets[i];
449448
/*
450449
* Minimize the x1 granularity to advertise support for any
451450
* valid region granularity
@@ -484,7 +483,7 @@ static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws,
484483
cxlrd->ops->spa_to_hpa = cxl_apply_xor_maps;
485484
}
486485

487-
rc = cxl_decoder_add(cxld, target_map);
486+
rc = cxl_decoder_add(cxld);
488487
if (rc)
489488
return rc;
490489

drivers/cxl/core/cdat.c

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ static int match_cxlrd_hb(struct device *dev, void *data)
338338

339339
guard(rwsem_read)(&cxl_rwsem.region);
340340
for (int i = 0; i < cxlsd->nr_targets; i++) {
341-
if (host_bridge == cxlsd->target[i]->dport_dev)
341+
if (cxlsd->target[i] && host_bridge == cxlsd->target[i]->dport_dev)
342342
return 1;
343343
}
344344

@@ -440,8 +440,8 @@ static int cdat_sslbis_handler(union acpi_subtable_headers *header, void *arg,
440440
} *tbl = (struct acpi_cdat_sslbis_table *)header;
441441
int size = sizeof(header->cdat) + sizeof(tbl->sslbis_header);
442442
struct acpi_cdat_sslbis *sslbis;
443-
struct cxl_port *port = arg;
444-
struct device *dev = &port->dev;
443+
struct cxl_dport *dport = arg;
444+
struct device *dev = &dport->port->dev;
445445
int remain, entries, i;
446446
u16 len;
447447

@@ -467,8 +467,6 @@ static int cdat_sslbis_handler(union acpi_subtable_headers *header, void *arg,
467467
u16 y = le16_to_cpu((__force __le16)tbl->entries[i].porty_id);
468468
__le64 le_base;
469469
__le16 le_val;
470-
struct cxl_dport *dport;
471-
unsigned long index;
472470
u16 dsp_id;
473471
u64 val;
474472

@@ -499,28 +497,27 @@ static int cdat_sslbis_handler(union acpi_subtable_headers *header, void *arg,
499497
val = cdat_normalize(le16_to_cpu(le_val), le64_to_cpu(le_base),
500498
sslbis->data_type);
501499

502-
xa_for_each(&port->dports, index, dport) {
503-
if (dsp_id == ACPI_CDAT_SSLBIS_ANY_PORT ||
504-
dsp_id == dport->port_id) {
505-
cxl_access_coordinate_set(dport->coord,
506-
sslbis->data_type,
507-
val);
508-
}
500+
if (dsp_id == ACPI_CDAT_SSLBIS_ANY_PORT ||
501+
dsp_id == dport->port_id) {
502+
cxl_access_coordinate_set(dport->coord,
503+
sslbis->data_type, val);
504+
return 0;
509505
}
510506
}
511507

512508
return 0;
513509
}
514510

515-
void cxl_switch_parse_cdat(struct cxl_port *port)
511+
void cxl_switch_parse_cdat(struct cxl_dport *dport)
516512
{
513+
struct cxl_port *port = dport->port;
517514
int rc;
518515

519516
if (!port->cdat.table)
520517
return;
521518

522519
rc = cdat_table_parse(ACPI_CDAT_TYPE_SSLBIS, cdat_sslbis_handler,
523-
port, port->cdat.table, port->cdat.length);
520+
dport, port->cdat.table, port->cdat.length);
524521
rc = cdat_table_parse_output(rc);
525522
if (rc)
526523
dev_dbg(&port->dev, "Failed to parse SSLBIS: %d\n", rc);

drivers/cxl/core/core.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,11 @@ int cxl_ras_init(void);
148148
void cxl_ras_exit(void);
149149
int cxl_gpf_port_setup(struct cxl_dport *dport);
150150

151+
struct cxl_hdm;
152+
int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
153+
struct cxl_endpoint_dvsec_info *info);
154+
int cxl_port_get_possible_dports(struct cxl_port *port);
155+
151156
#ifdef CONFIG_CXL_FEATURES
152157
struct cxl_feat_entry *
153158
cxl_feature_info(struct cxl_features_state *cxlfs, const uuid_t *uuid);

drivers/cxl/core/hdm.c

Lines changed: 80 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,11 @@ struct cxl_rwsem cxl_rwsem = {
2121
.dpa = __RWSEM_INITIALIZER(cxl_rwsem.dpa),
2222
};
2323

24-
static int add_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
25-
int *target_map)
24+
static int add_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld)
2625
{
2726
int rc;
2827

29-
rc = cxl_decoder_add_locked(cxld, target_map);
28+
rc = cxl_decoder_add_locked(cxld);
3029
if (rc) {
3130
put_device(&cxld->dev);
3231
dev_err(&port->dev, "Failed to add decoder\n");
@@ -50,12 +49,9 @@ static int add_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
5049
* are claimed and passed to the single dport. Disable the range until the first
5150
* CXL region is enumerated / activated.
5251
*/
53-
int devm_cxl_add_passthrough_decoder(struct cxl_port *port)
52+
static int devm_cxl_add_passthrough_decoder(struct cxl_port *port)
5453
{
5554
struct cxl_switch_decoder *cxlsd;
56-
struct cxl_dport *dport = NULL;
57-
int single_port_map[1];
58-
unsigned long index;
5955
struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev);
6056

6157
/*
@@ -71,13 +67,8 @@ int devm_cxl_add_passthrough_decoder(struct cxl_port *port)
7167

7268
device_lock_assert(&port->dev);
7369

74-
xa_for_each(&port->dports, index, dport)
75-
break;
76-
single_port_map[0] = dport->port_id;
77-
78-
return add_hdm_decoder(port, &cxlsd->cxld, single_port_map);
70+
return add_hdm_decoder(port, &cxlsd->cxld);
7971
}
80-
EXPORT_SYMBOL_NS_GPL(devm_cxl_add_passthrough_decoder, "CXL");
8172

8273
static void parse_hdm_decoder_caps(struct cxl_hdm *cxlhdm)
8374
{
@@ -147,8 +138,8 @@ static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info)
147138
* @port: cxl_port to map
148139
* @info: cached DVSEC range register info
149140
*/
150-
struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,
151-
struct cxl_endpoint_dvsec_info *info)
141+
static struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,
142+
struct cxl_endpoint_dvsec_info *info)
152143
{
153144
struct cxl_register_map *reg_map = &port->reg_map;
154145
struct device *dev = &port->dev;
@@ -203,7 +194,6 @@ struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,
203194

204195
return cxlhdm;
205196
}
206-
EXPORT_SYMBOL_NS_GPL(devm_cxl_setup_hdm, "CXL");
207197

208198
static void __cxl_dpa_debug(struct seq_file *file, struct resource *r, int depth)
209199
{
@@ -984,7 +974,7 @@ static int cxl_setup_hdm_decoder_from_dvsec(
984974
}
985975

986976
static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
987-
int *target_map, void __iomem *hdm, int which,
977+
void __iomem *hdm, int which,
988978
u64 *dpa_base, struct cxl_endpoint_dvsec_info *info)
989979
{
990980
struct cxl_endpoint_decoder *cxled = NULL;
@@ -1103,7 +1093,7 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
11031093
hi = readl(hdm + CXL_HDM_DECODER0_TL_HIGH(which));
11041094
target_list.value = (hi << 32) + lo;
11051095
for (i = 0; i < cxld->interleave_ways; i++)
1106-
target_map[i] = target_list.target_id[i];
1096+
cxld->target_map[i] = target_list.target_id[i];
11071097

11081098
return 0;
11091099
}
@@ -1168,8 +1158,8 @@ static void cxl_settle_decoders(struct cxl_hdm *cxlhdm)
11681158
* @cxlhdm: Structure to populate with HDM capabilities
11691159
* @info: cached DVSEC range register info
11701160
*/
1171-
int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
1172-
struct cxl_endpoint_dvsec_info *info)
1161+
static int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
1162+
struct cxl_endpoint_dvsec_info *info)
11731163
{
11741164
void __iomem *hdm = cxlhdm->regs.hdm_decoder;
11751165
struct cxl_port *port = cxlhdm->port;
@@ -1179,7 +1169,6 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
11791169
cxl_settle_decoders(cxlhdm);
11801170

11811171
for (i = 0; i < cxlhdm->decoder_count; i++) {
1182-
int target_map[CXL_DECODER_MAX_INTERLEAVE] = { 0 };
11831172
int rc, target_count = cxlhdm->target_count;
11841173
struct cxl_decoder *cxld;
11851174

@@ -1207,16 +1196,15 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
12071196
cxld = &cxlsd->cxld;
12081197
}
12091198

1210-
rc = init_hdm_decoder(port, cxld, target_map, hdm, i,
1211-
&dpa_base, info);
1199+
rc = init_hdm_decoder(port, cxld, hdm, i, &dpa_base, info);
12121200
if (rc) {
12131201
dev_warn(&port->dev,
12141202
"Failed to initialize decoder%d.%d\n",
12151203
port->id, i);
12161204
put_device(&cxld->dev);
12171205
return rc;
12181206
}
1219-
rc = add_hdm_decoder(port, cxld, target_map);
1207+
rc = add_hdm_decoder(port, cxld);
12201208
if (rc) {
12211209
dev_warn(&port->dev,
12221210
"Failed to add decoder%d.%d\n", port->id, i);
@@ -1226,4 +1214,71 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
12261214

12271215
return 0;
12281216
}
1229-
EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_decoders, "CXL");
1217+
1218+
/**
1219+
* __devm_cxl_switch_port_decoders_setup - allocate and setup switch decoders
1220+
* @port: CXL port context
1221+
*
1222+
* Return 0 or -errno on error
1223+
*/
1224+
int __devm_cxl_switch_port_decoders_setup(struct cxl_port *port)
1225+
{
1226+
struct cxl_hdm *cxlhdm;
1227+
1228+
if (is_cxl_root(port) || is_cxl_endpoint(port))
1229+
return -EOPNOTSUPP;
1230+
1231+
cxlhdm = devm_cxl_setup_hdm(port, NULL);
1232+
if (!IS_ERR(cxlhdm))
1233+
return devm_cxl_enumerate_decoders(cxlhdm, NULL);
1234+
1235+
if (PTR_ERR(cxlhdm) != -ENODEV) {
1236+
dev_err(&port->dev, "Failed to map HDM decoder capability\n");
1237+
return PTR_ERR(cxlhdm);
1238+
}
1239+
1240+
if (cxl_port_get_possible_dports(port) == 1) {
1241+
dev_dbg(&port->dev, "Fallback to passthrough decoder\n");
1242+
return devm_cxl_add_passthrough_decoder(port);
1243+
}
1244+
1245+
dev_err(&port->dev, "HDM decoder capability not found\n");
1246+
return -ENXIO;
1247+
}
1248+
EXPORT_SYMBOL_NS_GPL(__devm_cxl_switch_port_decoders_setup, "CXL");
1249+
1250+
/**
1251+
* devm_cxl_endpoint_decoders_setup - allocate and setup endpoint decoders
1252+
* @port: CXL port context
1253+
*
1254+
* Return 0 or -errno on error
1255+
*/
1256+
int devm_cxl_endpoint_decoders_setup(struct cxl_port *port)
1257+
{
1258+
struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
1259+
struct cxl_endpoint_dvsec_info info = { .port = port };
1260+
struct cxl_dev_state *cxlds = cxlmd->cxlds;
1261+
struct cxl_hdm *cxlhdm;
1262+
int rc;
1263+
1264+
if (!is_cxl_endpoint(port))
1265+
return -EOPNOTSUPP;
1266+
1267+
rc = cxl_dvsec_rr_decode(cxlds, &info);
1268+
if (rc < 0)
1269+
return rc;
1270+
1271+
cxlhdm = devm_cxl_setup_hdm(port, &info);
1272+
if (IS_ERR(cxlhdm)) {
1273+
if (PTR_ERR(cxlhdm) == -ENODEV)
1274+
dev_err(&port->dev, "HDM decoder registers not found\n");
1275+
return PTR_ERR(cxlhdm);
1276+
}
1277+
1278+
rc = cxl_hdm_decode_init(cxlds, cxlhdm, &info);
1279+
if (rc)
1280+
return rc;
1281+
1282+
return devm_cxl_enumerate_decoders(cxlhdm, &info);
1283+
}
1284+
EXPORT_SYMBOL_NS_GPL(devm_cxl_endpoint_decoders_setup, "CXL");

0 commit comments

Comments
 (0)