@@ -1295,6 +1295,7 @@ static int cxl_port_setup_targets(struct cxl_port *port,
1295
1295
struct cxl_region_params * p = & cxlr -> params ;
1296
1296
struct cxl_decoder * cxld = cxl_rr -> decoder ;
1297
1297
struct cxl_switch_decoder * cxlsd ;
1298
+ struct cxl_port * iter = port ;
1298
1299
u16 eig , peig ;
1299
1300
u8 eiw , peiw ;
1300
1301
@@ -1311,16 +1312,26 @@ static int cxl_port_setup_targets(struct cxl_port *port,
1311
1312
1312
1313
cxlsd = to_cxl_switch_decoder (& cxld -> dev );
1313
1314
if (cxl_rr -> nr_targets_set ) {
1314
- int i , distance ;
1315
+ int i , distance = 1 ;
1316
+ struct cxl_region_ref * cxl_rr_iter ;
1315
1317
1316
1318
/*
1317
- * Passthrough decoders impose no distance requirements between
1318
- * peers
1319
+ * The "distance" between peer downstream ports represents which
1320
+ * endpoint positions in the region interleave a given port can
1321
+ * host.
1322
+ *
1323
+ * For example, at the root of a hierarchy the distance is
1324
+ * always 1 as every index targets a different host-bridge. At
1325
+ * each subsequent switch level those ports map every Nth region
1326
+ * position where N is the width of the switch == distance.
1319
1327
*/
1320
- if (cxl_rr -> nr_targets == 1 )
1321
- distance = 0 ;
1322
- else
1323
- distance = p -> nr_targets / cxl_rr -> nr_targets ;
1328
+ do {
1329
+ cxl_rr_iter = cxl_rr_load (iter , cxlr );
1330
+ distance *= cxl_rr_iter -> nr_targets ;
1331
+ iter = to_cxl_port (iter -> dev .parent );
1332
+ } while (!is_cxl_root (iter ));
1333
+ distance *= cxlrd -> cxlsd .cxld .interleave_ways ;
1334
+
1324
1335
for (i = 0 ; i < cxl_rr -> nr_targets_set ; i ++ )
1325
1336
if (ep -> dport == cxlsd -> target [i ]) {
1326
1337
rc = check_last_peer (cxled , ep , cxl_rr ,
0 commit comments