@@ -259,80 +259,6 @@ static int devm_cxl_enable_hdm(struct device *host, struct cxl_hdm *cxlhdm)
259259 return devm_add_action_or_reset (host , disable_hdm , cxlhdm );
260260}
261261
262- static bool __cxl_hdm_decode_init (struct cxl_dev_state * cxlds ,
263- struct cxl_hdm * cxlhdm ,
264- struct cxl_endpoint_dvsec_info * info )
265- {
266- void __iomem * hdm = cxlhdm -> regs .hdm_decoder ;
267- struct cxl_port * port = cxlhdm -> port ;
268- struct device * dev = cxlds -> dev ;
269- struct cxl_port * root ;
270- int i , rc , allowed ;
271- u32 global_ctrl ;
272-
273- global_ctrl = readl (hdm + CXL_HDM_DECODER_CTRL_OFFSET );
274-
275- /*
276- * If the HDM Decoder Capability is already enabled then assume
277- * that some other agent like platform firmware set it up.
278- */
279- if (global_ctrl & CXL_HDM_DECODER_ENABLE ) {
280- rc = devm_cxl_enable_mem (& port -> dev , cxlds );
281- if (rc )
282- return false;
283- return true;
284- }
285-
286- root = to_cxl_port (port -> dev .parent );
287- while (!is_cxl_root (root ) && is_cxl_port (root -> dev .parent ))
288- root = to_cxl_port (root -> dev .parent );
289- if (!is_cxl_root (root )) {
290- dev_err (dev , "Failed to acquire root port for HDM enable\n" );
291- return false;
292- }
293-
294- for (i = 0 , allowed = 0 ; info -> mem_enabled && i < info -> ranges ; i ++ ) {
295- struct device * cxld_dev ;
296-
297- cxld_dev = device_find_child (& root -> dev , & info -> dvsec_range [i ],
298- dvsec_range_allowed );
299- if (!cxld_dev ) {
300- dev_dbg (dev , "DVSEC Range%d denied by platform\n" , i );
301- continue ;
302- }
303- dev_dbg (dev , "DVSEC Range%d allowed by platform\n" , i );
304- put_device (cxld_dev );
305- allowed ++ ;
306- }
307-
308- if (!allowed ) {
309- cxl_set_mem_enable (cxlds , 0 );
310- info -> mem_enabled = 0 ;
311- }
312-
313- /*
314- * Per CXL 2.0 Section 8.1.3.8.3 and 8.1.3.8.4 DVSEC CXL Range 1 Base
315- * [High,Low] when HDM operation is enabled the range register values
316- * are ignored by the device, but the spec also recommends matching the
317- * DVSEC Range 1,2 to HDM Decoder Range 0,1. So, non-zero info->ranges
318- * are expected even though Linux does not require or maintain that
319- * match. If at least one DVSEC range is enabled and allowed, skip HDM
320- * Decoder Capability Enable.
321- */
322- if (info -> mem_enabled )
323- return false;
324-
325- rc = devm_cxl_enable_hdm (& port -> dev , cxlhdm );
326- if (rc )
327- return false;
328-
329- rc = devm_cxl_enable_mem (& port -> dev , cxlds );
330- if (rc )
331- return false;
332-
333- return true;
334- }
335-
336262int cxl_dvsec_rr_decode (struct device * dev , int d ,
337263 struct cxl_endpoint_dvsec_info * info )
338264{
@@ -447,19 +373,66 @@ EXPORT_SYMBOL_NS_GPL(cxl_dvsec_rr_decode, CXL);
447373int cxl_hdm_decode_init (struct cxl_dev_state * cxlds , struct cxl_hdm * cxlhdm ,
448374 struct cxl_endpoint_dvsec_info * info )
449375{
376+ void __iomem * hdm = cxlhdm -> regs .hdm_decoder ;
377+ struct cxl_port * port = cxlhdm -> port ;
450378 struct device * dev = cxlds -> dev ;
379+ struct cxl_port * root ;
380+ int i , rc , allowed ;
381+ u32 global_ctrl ;
382+
383+ global_ctrl = readl (hdm + CXL_HDM_DECODER_CTRL_OFFSET );
451384
452385 /*
453- * If DVSEC ranges are being used instead of HDM decoder registers there
454- * is no use in trying to manage those .
386+ * If the HDM Decoder Capability is already enabled then assume
387+ * that some other agent like platform firmware set it up .
455388 */
456- if (!__cxl_hdm_decode_init (cxlds , cxlhdm , info )) {
457- dev_err (dev ,
458- "Legacy range registers configuration prevents HDM operation.\n" );
459- return - EBUSY ;
389+ if (global_ctrl & CXL_HDM_DECODER_ENABLE )
390+ return devm_cxl_enable_mem (& port -> dev , cxlds );
391+
392+ root = to_cxl_port (port -> dev .parent );
393+ while (!is_cxl_root (root ) && is_cxl_port (root -> dev .parent ))
394+ root = to_cxl_port (root -> dev .parent );
395+ if (!is_cxl_root (root )) {
396+ dev_err (dev , "Failed to acquire root port for HDM enable\n" );
397+ return - ENODEV ;
460398 }
461399
462- return 0 ;
400+ for (i = 0 , allowed = 0 ; info -> mem_enabled && i < info -> ranges ; i ++ ) {
401+ struct device * cxld_dev ;
402+
403+ cxld_dev = device_find_child (& root -> dev , & info -> dvsec_range [i ],
404+ dvsec_range_allowed );
405+ if (!cxld_dev ) {
406+ dev_dbg (dev , "DVSEC Range%d denied by platform\n" , i );
407+ continue ;
408+ }
409+ dev_dbg (dev , "DVSEC Range%d allowed by platform\n" , i );
410+ put_device (cxld_dev );
411+ allowed ++ ;
412+ }
413+
414+ if (!allowed ) {
415+ cxl_set_mem_enable (cxlds , 0 );
416+ info -> mem_enabled = 0 ;
417+ }
418+
419+ /*
420+ * Per CXL 2.0 Section 8.1.3.8.3 and 8.1.3.8.4 DVSEC CXL Range 1 Base
421+ * [High,Low] when HDM operation is enabled the range register values
422+ * are ignored by the device, but the spec also recommends matching the
423+ * DVSEC Range 1,2 to HDM Decoder Range 0,1. So, non-zero info->ranges
424+ * are expected even though Linux does not require or maintain that
425+ * match. If at least one DVSEC range is enabled and allowed, skip HDM
426+ * Decoder Capability Enable.
427+ */
428+ if (info -> mem_enabled )
429+ return - EBUSY ;
430+
431+ rc = devm_cxl_enable_hdm (& port -> dev , cxlhdm );
432+ if (rc )
433+ return rc ;
434+
435+ return devm_cxl_enable_mem (& port -> dev , cxlds );
463436}
464437EXPORT_SYMBOL_NS_GPL (cxl_hdm_decode_init , CXL );
465438
0 commit comments