@@ -1101,6 +1101,26 @@ static int cxl_port_attach_region(struct cxl_port *port,
11011101 }
11021102 cxld = cxl_rr -> decoder ;
11031103
1104+ /*
1105+ * the number of targets should not exceed the target_count
1106+ * of the decoder
1107+ */
1108+ if (is_switch_decoder (& cxld -> dev )) {
1109+ struct cxl_switch_decoder * cxlsd ;
1110+
1111+ cxlsd = to_cxl_switch_decoder (& cxld -> dev );
1112+ if (cxl_rr -> nr_targets > cxlsd -> nr_targets ) {
1113+ dev_dbg (& cxlr -> dev ,
1114+ "%s:%s %s add: %s:%s @ %d overflows targets: %d\n" ,
1115+ dev_name (port -> uport_dev ), dev_name (& port -> dev ),
1116+ dev_name (& cxld -> dev ), dev_name (& cxlmd -> dev ),
1117+ dev_name (& cxled -> cxld .dev ), pos ,
1118+ cxlsd -> nr_targets );
1119+ rc = - ENXIO ;
1120+ goto out_erase ;
1121+ }
1122+ }
1123+
11041124 rc = cxl_rr_ep_add (cxl_rr , cxled );
11051125 if (rc ) {
11061126 dev_dbg (& cxlr -> dev ,
@@ -1210,6 +1230,50 @@ static int check_last_peer(struct cxl_endpoint_decoder *cxled,
12101230 return 0 ;
12111231}
12121232
1233+ static int check_interleave_cap (struct cxl_decoder * cxld , int iw , int ig )
1234+ {
1235+ struct cxl_port * port = to_cxl_port (cxld -> dev .parent );
1236+ struct cxl_hdm * cxlhdm = dev_get_drvdata (& port -> dev );
1237+ unsigned int interleave_mask ;
1238+ u8 eiw ;
1239+ u16 eig ;
1240+ int high_pos , low_pos ;
1241+
1242+ if (!test_bit (iw , & cxlhdm -> iw_cap_mask ))
1243+ return - ENXIO ;
1244+ /*
1245+ * Per CXL specification r3.1(8.2.4.20.13 Decoder Protection),
1246+ * if eiw < 8:
1247+ * DPAOFFSET[51: eig + 8] = HPAOFFSET[51: eig + 8 + eiw]
1248+ * DPAOFFSET[eig + 7: 0] = HPAOFFSET[eig + 7: 0]
1249+ *
1250+ * when the eiw is 0, all the bits of HPAOFFSET[51: 0] are used, the
1251+ * interleave bits are none.
1252+ *
1253+ * if eiw >= 8:
1254+ * DPAOFFSET[51: eig + 8] = HPAOFFSET[51: eig + eiw] / 3
1255+ * DPAOFFSET[eig + 7: 0] = HPAOFFSET[eig + 7: 0]
1256+ *
1257+ * when the eiw is 8, all the bits of HPAOFFSET[51: 0] are used, the
1258+ * interleave bits are none.
1259+ */
1260+ ways_to_eiw (iw , & eiw );
1261+ if (eiw == 0 || eiw == 8 )
1262+ return 0 ;
1263+
1264+ granularity_to_eig (ig , & eig );
1265+ if (eiw > 8 )
1266+ high_pos = eiw + eig - 1 ;
1267+ else
1268+ high_pos = eiw + eig + 7 ;
1269+ low_pos = eig + 8 ;
1270+ interleave_mask = GENMASK (high_pos , low_pos );
1271+ if (interleave_mask & ~cxlhdm -> interleave_mask )
1272+ return - ENXIO ;
1273+
1274+ return 0 ;
1275+ }
1276+
12131277static int cxl_port_setup_targets (struct cxl_port * port ,
12141278 struct cxl_region * cxlr ,
12151279 struct cxl_endpoint_decoder * cxled )
@@ -1360,6 +1424,15 @@ static int cxl_port_setup_targets(struct cxl_port *port,
13601424 return - ENXIO ;
13611425 }
13621426 } else {
1427+ rc = check_interleave_cap (cxld , iw , ig );
1428+ if (rc ) {
1429+ dev_dbg (& cxlr -> dev ,
1430+ "%s:%s iw: %d ig: %d is not supported\n" ,
1431+ dev_name (port -> uport_dev ),
1432+ dev_name (& port -> dev ), iw , ig );
1433+ return rc ;
1434+ }
1435+
13631436 cxld -> interleave_ways = iw ;
13641437 cxld -> interleave_granularity = ig ;
13651438 cxld -> hpa_range = (struct range ) {
@@ -1796,6 +1869,15 @@ static int cxl_region_attach(struct cxl_region *cxlr,
17961869 struct cxl_dport * dport ;
17971870 int rc = - ENXIO ;
17981871
1872+ rc = check_interleave_cap (& cxled -> cxld , p -> interleave_ways ,
1873+ p -> interleave_granularity );
1874+ if (rc ) {
1875+ dev_dbg (& cxlr -> dev , "%s iw: %d ig: %d is not supported\n" ,
1876+ dev_name (& cxled -> cxld .dev ), p -> interleave_ways ,
1877+ p -> interleave_granularity );
1878+ return rc ;
1879+ }
1880+
17991881 if (cxled -> mode != cxlr -> mode ) {
18001882 dev_dbg (& cxlr -> dev , "%s region mode: %d mismatch: %d\n" ,
18011883 dev_name (& cxled -> cxld .dev ), cxlr -> mode , cxled -> mode );
@@ -2688,22 +2770,33 @@ static int __cxl_dpa_to_region(struct device *dev, void *arg)
26882770{
26892771 struct cxl_dpa_to_region_context * ctx = arg ;
26902772 struct cxl_endpoint_decoder * cxled ;
2773+ struct cxl_region * cxlr ;
26912774 u64 dpa = ctx -> dpa ;
26922775
26932776 if (!is_endpoint_decoder (dev ))
26942777 return 0 ;
26952778
26962779 cxled = to_cxl_endpoint_decoder (dev );
2697- if (!cxled -> dpa_res || !resource_size (cxled -> dpa_res ))
2780+ if (!cxled || ! cxled -> dpa_res || !resource_size (cxled -> dpa_res ))
26982781 return 0 ;
26992782
27002783 if (dpa > cxled -> dpa_res -> end || dpa < cxled -> dpa_res -> start )
27012784 return 0 ;
27022785
2703- dev_dbg (dev , "dpa:0x%llx mapped in region:%s\n" , dpa ,
2704- dev_name (& cxled -> cxld .region -> dev ));
2786+ /*
2787+ * Stop the region search (return 1) when an endpoint mapping is
2788+ * found. The region may not be fully constructed so offering
2789+ * the cxlr in the context structure is not guaranteed.
2790+ */
2791+ cxlr = cxled -> cxld .region ;
2792+ if (cxlr )
2793+ dev_dbg (dev , "dpa:0x%llx mapped in region:%s\n" , dpa ,
2794+ dev_name (& cxlr -> dev ));
2795+ else
2796+ dev_dbg (dev , "dpa:0x%llx mapped in endpoint:%s\n" , dpa ,
2797+ dev_name (dev ));
27052798
2706- ctx -> cxlr = cxled -> cxld . region ;
2799+ ctx -> cxlr = cxlr ;
27072800
27082801 return 1 ;
27092802}
@@ -2847,7 +2940,7 @@ static int cxl_pmem_region_alloc(struct cxl_region *cxlr)
28472940 * bridge for one device is the same for all.
28482941 */
28492942 if (i == 0 ) {
2850- cxl_nvb = cxl_find_nvdimm_bridge (cxlmd );
2943+ cxl_nvb = cxl_find_nvdimm_bridge (cxlmd -> endpoint );
28512944 if (!cxl_nvb )
28522945 return - ENODEV ;
28532946 cxlr -> cxl_nvb = cxl_nvb ;
0 commit comments