@@ -2679,6 +2679,141 @@ int cxl_get_poison_by_endpoint(struct cxl_port *port)
26792679 return rc ;
26802680}
26812681
2682+ struct cxl_dpa_to_region_context {
2683+ struct cxl_region * cxlr ;
2684+ u64 dpa ;
2685+ };
2686+
2687+ static int __cxl_dpa_to_region (struct device * dev , void * arg )
2688+ {
2689+ struct cxl_dpa_to_region_context * ctx = arg ;
2690+ struct cxl_endpoint_decoder * cxled ;
2691+ u64 dpa = ctx -> dpa ;
2692+
2693+ if (!is_endpoint_decoder (dev ))
2694+ return 0 ;
2695+
2696+ cxled = to_cxl_endpoint_decoder (dev );
2697+ if (!cxled -> dpa_res || !resource_size (cxled -> dpa_res ))
2698+ return 0 ;
2699+
2700+ if (dpa > cxled -> dpa_res -> end || dpa < cxled -> dpa_res -> start )
2701+ return 0 ;
2702+
2703+ dev_dbg (dev , "dpa:0x%llx mapped in region:%s\n" , dpa ,
2704+ dev_name (& cxled -> cxld .region -> dev ));
2705+
2706+ ctx -> cxlr = cxled -> cxld .region ;
2707+
2708+ return 1 ;
2709+ }
2710+
2711+ struct cxl_region * cxl_dpa_to_region (const struct cxl_memdev * cxlmd , u64 dpa )
2712+ {
2713+ struct cxl_dpa_to_region_context ctx ;
2714+ struct cxl_port * port ;
2715+
2716+ ctx = (struct cxl_dpa_to_region_context ) {
2717+ .dpa = dpa ,
2718+ };
2719+ port = cxlmd -> endpoint ;
2720+ if (port && is_cxl_endpoint (port ) && cxl_num_decoders_committed (port ))
2721+ device_for_each_child (& port -> dev , & ctx , __cxl_dpa_to_region );
2722+
2723+ return ctx .cxlr ;
2724+ }
2725+
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+
26822817static struct lock_class_key cxl_pmem_region_key ;
26832818
26842819static struct cxl_pmem_region * cxl_pmem_region_alloc (struct cxl_region * cxlr )
0 commit comments