@@ -101,11 +101,34 @@ static int map_hdm_decoder_regs(struct cxl_port *port, void __iomem *crb,
101101 BIT (CXL_CM_CAP_CAP_ID_HDM ));
102102}
103103
104+ static struct cxl_hdm * devm_cxl_setup_emulated_hdm (struct cxl_port * port ,
105+ struct cxl_endpoint_dvsec_info * info )
106+ {
107+ struct device * dev = & port -> dev ;
108+ struct cxl_hdm * cxlhdm ;
109+
110+ if (!info -> mem_enabled )
111+ return ERR_PTR (- ENODEV );
112+
113+ cxlhdm = devm_kzalloc (dev , sizeof (* cxlhdm ), GFP_KERNEL );
114+ if (!cxlhdm )
115+ return ERR_PTR (- ENOMEM );
116+
117+ cxlhdm -> port = port ;
118+ cxlhdm -> decoder_count = info -> ranges ;
119+ cxlhdm -> target_count = info -> ranges ;
120+ dev_set_drvdata (& port -> dev , cxlhdm );
121+
122+ return cxlhdm ;
123+ }
124+
104125/**
105126 * devm_cxl_setup_hdm - map HDM decoder component registers
106127 * @port: cxl_port to map
128+ * @info: cached DVSEC range register info
107129 */
108- struct cxl_hdm * devm_cxl_setup_hdm (struct cxl_port * port )
130+ struct cxl_hdm * devm_cxl_setup_hdm (struct cxl_port * port ,
131+ struct cxl_endpoint_dvsec_info * info )
109132{
110133 struct device * dev = & port -> dev ;
111134 struct cxl_hdm * cxlhdm ;
@@ -119,6 +142,9 @@ struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port)
119142 cxlhdm -> port = port ;
120143 crb = ioremap (port -> component_reg_phys , CXL_COMPONENT_REG_BLOCK_SIZE );
121144 if (!crb ) {
145+ if (info && info -> mem_enabled )
146+ return devm_cxl_setup_emulated_hdm (port , info );
147+
122148 dev_err (dev , "No component registers mapped\n" );
123149 return ERR_PTR (- ENXIO );
124150 }
@@ -688,9 +714,60 @@ static int cxl_decoder_reset(struct cxl_decoder *cxld)
688714 return 0 ;
689715}
690716
717+ static int cxl_setup_hdm_decoder_from_dvsec (struct cxl_port * port ,
718+ struct cxl_decoder * cxld , int which ,
719+ struct cxl_endpoint_dvsec_info * info )
720+ {
721+ if (!is_cxl_endpoint (port ))
722+ return - EOPNOTSUPP ;
723+
724+ if (!range_len (& info -> dvsec_range [which ]))
725+ return - ENOENT ;
726+
727+ cxld -> target_type = CXL_DECODER_EXPANDER ;
728+ cxld -> commit = NULL ;
729+ cxld -> reset = NULL ;
730+ cxld -> hpa_range = info -> dvsec_range [which ];
731+
732+ /*
733+ * Set the emulated decoder as locked pending additional support to
734+ * change the range registers at run time.
735+ */
736+ cxld -> flags |= CXL_DECODER_F_ENABLE | CXL_DECODER_F_LOCK ;
737+ port -> commit_end = cxld -> id ;
738+
739+ return 0 ;
740+ }
741+
742+ static bool should_emulate_decoders (struct cxl_port * port )
743+ {
744+ struct cxl_hdm * cxlhdm = dev_get_drvdata (& port -> dev );
745+ void __iomem * hdm = cxlhdm -> regs .hdm_decoder ;
746+ u32 ctrl ;
747+ int i ;
748+
749+ if (!is_cxl_endpoint (cxlhdm -> port ))
750+ return false;
751+
752+ if (!hdm )
753+ return true;
754+
755+ /*
756+ * If any decoders are committed already, there should not be any
757+ * emulated DVSEC decoders.
758+ */
759+ for (i = 0 ; i < cxlhdm -> decoder_count ; i ++ ) {
760+ ctrl = readl (hdm + CXL_HDM_DECODER0_CTRL_OFFSET (i ));
761+ if (FIELD_GET (CXL_HDM_DECODER0_CTRL_COMMITTED , ctrl ))
762+ return false;
763+ }
764+
765+ return true;
766+ }
767+
691768static int init_hdm_decoder (struct cxl_port * port , struct cxl_decoder * cxld ,
692769 int * target_map , void __iomem * hdm , int which ,
693- u64 * dpa_base )
770+ u64 * dpa_base , struct cxl_endpoint_dvsec_info * info )
694771{
695772 struct cxl_endpoint_decoder * cxled = NULL ;
696773 u64 size , base , skip , dpa_size ;
@@ -703,6 +780,9 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
703780 unsigned char target_id [8 ];
704781 } target_list ;
705782
783+ if (should_emulate_decoders (port ))
784+ return cxl_setup_hdm_decoder_from_dvsec (port , cxld , which , info );
785+
706786 if (is_endpoint_decoder (& cxld -> dev ))
707787 cxled = to_cxl_endpoint_decoder (& cxld -> dev );
708788
@@ -726,6 +806,9 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
726806 .end = base + size - 1 ,
727807 };
728808
809+ if (cxled && !committed && range_len (& info -> dvsec_range [which ]))
810+ return cxl_setup_hdm_decoder_from_dvsec (port , cxld , which , info );
811+
729812 /* decoders are enabled if committed */
730813 if (committed ) {
731814 cxld -> flags |= CXL_DECODER_F_ENABLE ;
@@ -798,18 +881,15 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
798881 return 0 ;
799882}
800883
801- /**
802- * devm_cxl_enumerate_decoders - add decoder objects per HDM register set
803- * @cxlhdm: Structure to populate with HDM capabilities
804- */
805- int devm_cxl_enumerate_decoders (struct cxl_hdm * cxlhdm )
884+ static void cxl_settle_decoders (struct cxl_hdm * cxlhdm )
806885{
807886 void __iomem * hdm = cxlhdm -> regs .hdm_decoder ;
808- struct cxl_port * port = cxlhdm -> port ;
809- int i , committed ;
810- u64 dpa_base = 0 ;
887+ int committed , i ;
811888 u32 ctrl ;
812889
890+ if (!hdm )
891+ return ;
892+
813893 /*
814894 * Since the register resource was recently claimed via request_region()
815895 * be careful about trusting the "not-committed" status until the commit
@@ -826,6 +906,22 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
826906 /* ensure that future checks of committed can be trusted */
827907 if (committed != cxlhdm -> decoder_count )
828908 msleep (20 );
909+ }
910+
911+ /**
912+ * devm_cxl_enumerate_decoders - add decoder objects per HDM register set
913+ * @cxlhdm: Structure to populate with HDM capabilities
914+ * @info: cached DVSEC range register info
915+ */
916+ int devm_cxl_enumerate_decoders (struct cxl_hdm * cxlhdm ,
917+ struct cxl_endpoint_dvsec_info * info )
918+ {
919+ void __iomem * hdm = cxlhdm -> regs .hdm_decoder ;
920+ struct cxl_port * port = cxlhdm -> port ;
921+ int i ;
922+ u64 dpa_base = 0 ;
923+
924+ cxl_settle_decoders (cxlhdm );
829925
830926 for (i = 0 ; i < cxlhdm -> decoder_count ; i ++ ) {
831927 int target_map [CXL_DECODER_MAX_INTERLEAVE ] = { 0 };
@@ -856,7 +952,8 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm)
856952 cxld = & cxlsd -> cxld ;
857953 }
858954
859- rc = init_hdm_decoder (port , cxld , target_map , hdm , i , & dpa_base );
955+ rc = init_hdm_decoder (port , cxld , target_map , hdm , i ,
956+ & dpa_base , info );
860957 if (rc ) {
861958 dev_warn (& port -> dev ,
862959 "Failed to initialize decoder%d.%d\n" ,
0 commit comments