@@ -2723,6 +2723,97 @@ struct cxl_region *cxl_dpa_to_region(const struct cxl_memdev *cxlmd, u64 dpa)
27232723 return ctx .cxlr ;
27242724}
27252725
2726+ static bool cxl_is_hpa_in_range (u64 hpa , struct cxl_region * cxlr , int pos )
2727+ {
2728+ struct cxl_region_params * p = & cxlr -> params ;
2729+ int gran = p -> interleave_granularity ;
2730+ int ways = p -> interleave_ways ;
2731+ u64 offset ;
2732+
2733+ /* Is the hpa within this region at all */
2734+ if (hpa < p -> res -> start || hpa > p -> res -> end ) {
2735+ dev_dbg (& cxlr -> dev ,
2736+ "Addr trans fail: hpa 0x%llx not in region\n" , hpa );
2737+ return false;
2738+ }
2739+
2740+ /* Is the hpa in an expected chunk for its pos(-ition) */
2741+ offset = hpa - p -> res -> start ;
2742+ offset = do_div (offset , gran * ways );
2743+ if ((offset >= pos * gran ) && (offset < (pos + 1 ) * gran ))
2744+ return true;
2745+
2746+ dev_dbg (& cxlr -> dev ,
2747+ "Addr trans fail: hpa 0x%llx not in expected chunk\n" , hpa );
2748+
2749+ return false;
2750+ }
2751+
2752+ static u64 cxl_dpa_to_hpa (u64 dpa , struct cxl_region * cxlr ,
2753+ struct cxl_endpoint_decoder * cxled )
2754+ {
2755+ u64 dpa_offset , hpa_offset , bits_upper , mask_upper , hpa ;
2756+ struct cxl_region_params * p = & cxlr -> params ;
2757+ int pos = cxled -> pos ;
2758+ u16 eig = 0 ;
2759+ u8 eiw = 0 ;
2760+
2761+ ways_to_eiw (p -> interleave_ways , & eiw );
2762+ granularity_to_eig (p -> interleave_granularity , & eig );
2763+
2764+ /*
2765+ * The device position in the region interleave set was removed
2766+ * from the offset at HPA->DPA translation. To reconstruct the
2767+ * HPA, place the 'pos' in the offset.
2768+ *
2769+ * The placement of 'pos' in the HPA is determined by interleave
2770+ * ways and granularity and is defined in the CXL Spec 3.0 Section
2771+ * 8.2.4.19.13 Implementation Note: Device Decode Logic
2772+ */
2773+
2774+ /* Remove the dpa base */
2775+ dpa_offset = dpa - cxl_dpa_resource_start (cxled );
2776+
2777+ mask_upper = GENMASK_ULL (51 , eig + 8 );
2778+
2779+ if (eiw < 8 ) {
2780+ hpa_offset = (dpa_offset & mask_upper ) << eiw ;
2781+ hpa_offset |= pos << (eig + 8 );
2782+ } else {
2783+ bits_upper = (dpa_offset & mask_upper ) >> (eig + 8 );
2784+ bits_upper = bits_upper * 3 ;
2785+ hpa_offset = ((bits_upper << (eiw - 8 )) + pos ) << (eig + 8 );
2786+ }
2787+
2788+ /* The lower bits remain unchanged */
2789+ hpa_offset |= dpa_offset & GENMASK_ULL (eig + 7 , 0 );
2790+
2791+ /* Apply the hpa_offset to the region base address */
2792+ hpa = hpa_offset + p -> res -> start ;
2793+
2794+ if (!cxl_is_hpa_in_range (hpa , cxlr , cxled -> pos ))
2795+ return ULLONG_MAX ;
2796+
2797+ return hpa ;
2798+ }
2799+
2800+ u64 cxl_trace_hpa (struct cxl_region * cxlr , const struct cxl_memdev * cxlmd ,
2801+ u64 dpa )
2802+ {
2803+ struct cxl_region_params * p = & cxlr -> params ;
2804+ struct cxl_endpoint_decoder * cxled = NULL ;
2805+
2806+ for (int i = 0 ; i < p -> nr_targets ; i ++ ) {
2807+ cxled = p -> targets [i ];
2808+ if (cxlmd == cxled_to_memdev (cxled ))
2809+ break ;
2810+ }
2811+ if (!cxled || cxlmd != cxled_to_memdev (cxled ))
2812+ return ULLONG_MAX ;
2813+
2814+ return cxl_dpa_to_hpa (dpa , cxlr , cxled );
2815+ }
2816+
27262817static struct lock_class_key cxl_pmem_region_key ;
27272818
27282819static struct cxl_pmem_region * cxl_pmem_region_alloc (struct cxl_region * cxlr )
0 commit comments