88#include <linux/pci.h>
99#include "cxl.h"
1010
11- static struct acpi_table_header * acpi_cedt ;
12-
1311/* Encode defined in CXL 2.0 8.2.5.12.7 HDM Decoder Control Register */
1412#define CFMWS_INTERLEAVE_WAYS (x ) (1 << (x)->interleave_ways)
1513#define CFMWS_INTERLEAVE_GRANULARITY (x ) ((x)->granularity + 8)
@@ -74,134 +72,63 @@ static int cxl_acpi_cfmws_verify(struct device *dev,
7472 return 0 ;
7573}
7674
77- static void cxl_add_cfmws_decoders (struct device * dev ,
78- struct cxl_port * root_port )
75+ struct cxl_cfmws_context {
76+ struct device * dev ;
77+ struct cxl_port * root_port ;
78+ };
79+
80+ static int cxl_parse_cfmws (union acpi_subtable_headers * header , void * arg ,
81+ const unsigned long end )
7982{
8083 int target_map [CXL_DECODER_MAX_INTERLEAVE ];
84+ struct cxl_cfmws_context * ctx = arg ;
85+ struct cxl_port * root_port = ctx -> root_port ;
86+ struct device * dev = ctx -> dev ;
8187 struct acpi_cedt_cfmws * cfmws ;
8288 struct cxl_decoder * cxld ;
83- acpi_size len , cur = 0 ;
84- void * cedt_subtable ;
85- int rc ;
86-
87- len = acpi_cedt -> length - sizeof (* acpi_cedt );
88- cedt_subtable = acpi_cedt + 1 ;
89-
90- while (cur < len ) {
91- struct acpi_cedt_header * c = cedt_subtable + cur ;
92- int i ;
93-
94- if (c -> type != ACPI_CEDT_TYPE_CFMWS ) {
95- cur += c -> length ;
96- continue ;
97- }
89+ int rc , i ;
9890
99- cfmws = cedt_subtable + cur ;
91+ cfmws = ( struct acpi_cedt_cfmws * ) header ;
10092
101- if (cfmws -> header .length < sizeof (* cfmws )) {
102- dev_warn_once (dev ,
103- "CFMWS entry skipped:invalid length:%u\n" ,
104- cfmws -> header .length );
105- cur += c -> length ;
106- continue ;
107- }
108-
109- rc = cxl_acpi_cfmws_verify (dev , cfmws );
110- if (rc ) {
111- dev_err (dev , "CFMWS range %#llx-%#llx not registered\n" ,
112- cfmws -> base_hpa , cfmws -> base_hpa +
113- cfmws -> window_size - 1 );
114- cur += c -> length ;
115- continue ;
116- }
117-
118- for (i = 0 ; i < CFMWS_INTERLEAVE_WAYS (cfmws ); i ++ )
119- target_map [i ] = cfmws -> interleave_targets [i ];
120-
121- cxld = cxl_decoder_alloc (root_port ,
122- CFMWS_INTERLEAVE_WAYS (cfmws ));
123- if (IS_ERR (cxld ))
124- goto next ;
125-
126- cxld -> flags = cfmws_to_decoder_flags (cfmws -> restrictions );
127- cxld -> target_type = CXL_DECODER_EXPANDER ;
128- cxld -> range = (struct range ) {
129- .start = cfmws -> base_hpa ,
130- .end = cfmws -> base_hpa + cfmws -> window_size - 1 ,
131- };
132- cxld -> interleave_ways = CFMWS_INTERLEAVE_WAYS (cfmws );
133- cxld -> interleave_granularity =
134- CFMWS_INTERLEAVE_GRANULARITY (cfmws );
135-
136- rc = cxl_decoder_add (cxld , target_map );
137- if (rc )
138- put_device (& cxld -> dev );
139- else
140- rc = cxl_decoder_autoremove (dev , cxld );
141- if (rc ) {
142- dev_err (dev , "Failed to add decoder for %#llx-%#llx\n" ,
143- cfmws -> base_hpa , cfmws -> base_hpa +
144- cfmws -> window_size - 1 );
145- goto next ;
146- }
147- dev_dbg (dev , "add: %s range %#llx-%#llx\n" ,
148- dev_name (& cxld -> dev ), cfmws -> base_hpa ,
93+ rc = cxl_acpi_cfmws_verify (dev , cfmws );
94+ if (rc ) {
95+ dev_err (dev , "CFMWS range %#llx-%#llx not registered\n" ,
96+ cfmws -> base_hpa ,
14997 cfmws -> base_hpa + cfmws -> window_size - 1 );
150- next :
151- cur += c -> length ;
98+ return 0 ;
15299 }
153- }
154-
155- static struct acpi_cedt_chbs * cxl_acpi_match_chbs (struct device * dev , u32 uid )
156- {
157- struct acpi_cedt_chbs * chbs , * chbs_match = NULL ;
158- acpi_size len , cur = 0 ;
159- void * cedt_subtable ;
160100
161- len = acpi_cedt -> length - sizeof ( * acpi_cedt );
162- cedt_subtable = acpi_cedt + 1 ;
101+ for ( i = 0 ; i < CFMWS_INTERLEAVE_WAYS ( cfmws ); i ++ )
102+ target_map [ i ] = cfmws -> interleave_targets [ i ] ;
163103
164- while (cur < len ) {
165- struct acpi_cedt_header * c = cedt_subtable + cur ;
166-
167- if (c -> type != ACPI_CEDT_TYPE_CHBS ) {
168- cur += c -> length ;
169- continue ;
170- }
171-
172- chbs = cedt_subtable + cur ;
173-
174- if (chbs -> header .length < sizeof (* chbs )) {
175- dev_warn_once (dev ,
176- "CHBS entry skipped: invalid length:%u\n" ,
177- chbs -> header .length );
178- cur += c -> length ;
179- continue ;
180- }
181-
182- if (chbs -> uid != uid ) {
183- cur += c -> length ;
184- continue ;
185- }
104+ cxld = cxl_decoder_alloc (root_port , CFMWS_INTERLEAVE_WAYS (cfmws ));
105+ if (IS_ERR (cxld ))
106+ return 0 ;
186107
187- if (chbs_match ) {
188- dev_warn_once (dev ,
189- "CHBS entry skipped: duplicate UID:%u\n" ,
190- uid );
191- cur += c -> length ;
192- continue ;
193- }
108+ cxld -> flags = cfmws_to_decoder_flags (cfmws -> restrictions );
109+ cxld -> target_type = CXL_DECODER_EXPANDER ;
110+ cxld -> range = (struct range ){
111+ .start = cfmws -> base_hpa ,
112+ .end = cfmws -> base_hpa + cfmws -> window_size - 1 ,
113+ };
114+ cxld -> interleave_ways = CFMWS_INTERLEAVE_WAYS (cfmws );
115+ cxld -> interleave_granularity = CFMWS_INTERLEAVE_GRANULARITY (cfmws );
194116
195- chbs_match = chbs ;
196- cur += c -> length ;
117+ rc = cxl_decoder_add (cxld , target_map );
118+ if (rc )
119+ put_device (& cxld -> dev );
120+ else
121+ rc = cxl_decoder_autoremove (dev , cxld );
122+ if (rc ) {
123+ dev_err (dev , "Failed to add decoder for %#llx-%#llx\n" ,
124+ cfmws -> base_hpa ,
125+ cfmws -> base_hpa + cfmws -> window_size - 1 );
126+ return 0 ;
197127 }
128+ dev_dbg (dev , "add: %s range %#llx-%#llx\n" , dev_name (& cxld -> dev ),
129+ cfmws -> base_hpa , cfmws -> base_hpa + cfmws -> window_size - 1 );
198130
199- return chbs_match ? chbs_match : ERR_PTR (- ENODEV );
200- }
201-
202- static resource_size_t get_chbcr (struct acpi_cedt_chbs * chbs )
203- {
204- return IS_ERR (chbs ) ? CXL_RESOURCE_NONE : chbs -> base ;
131+ return 0 ;
205132}
206133
207134__mock int match_add_root_ports (struct pci_dev * pdev , void * data )
@@ -355,12 +282,35 @@ static int add_host_bridge_uport(struct device *match, void *arg)
355282 return rc ;
356283}
357284
285+ struct cxl_chbs_context {
286+ unsigned long long uid ;
287+ resource_size_t chbcr ;
288+ };
289+
290+ static int cxl_get_chbcr (union acpi_subtable_headers * header , void * arg ,
291+ const unsigned long end )
292+ {
293+ struct cxl_chbs_context * ctx = arg ;
294+ struct acpi_cedt_chbs * chbs ;
295+
296+ if (ctx -> chbcr )
297+ return 0 ;
298+
299+ chbs = (struct acpi_cedt_chbs * ) header ;
300+
301+ if (ctx -> uid != chbs -> uid )
302+ return 0 ;
303+ ctx -> chbcr = chbs -> base ;
304+
305+ return 0 ;
306+ }
307+
358308static int add_host_bridge_dport (struct device * match , void * arg )
359309{
360310 int rc ;
361311 acpi_status status ;
362312 unsigned long long uid ;
363- struct acpi_cedt_chbs * chbs ;
313+ struct cxl_chbs_context ctx ;
364314 struct cxl_port * root_port = arg ;
365315 struct device * host = root_port -> dev .parent ;
366316 struct acpi_device * bridge = to_cxl_host_bridge (host , match );
@@ -376,14 +326,18 @@ static int add_host_bridge_dport(struct device *match, void *arg)
376326 return - ENODEV ;
377327 }
378328
379- chbs = cxl_acpi_match_chbs (host , uid );
380- if (IS_ERR (chbs )) {
329+ ctx = (struct cxl_chbs_context ) {
330+ .uid = uid ,
331+ };
332+ acpi_table_parse_cedt (ACPI_CEDT_TYPE_CHBS , cxl_get_chbcr , & ctx );
333+
334+ if (ctx .chbcr == 0 ) {
381335 dev_warn (host , "No CHBS found for Host Bridge: %s\n" ,
382336 dev_name (match ));
383337 return 0 ;
384338 }
385339
386- rc = cxl_add_dport (root_port , match , uid , get_chbcr ( chbs ) );
340+ rc = cxl_add_dport (root_port , match , uid , ctx . chbcr );
387341 if (rc ) {
388342 dev_err (host , "failed to add downstream port: %s\n" ,
389343 dev_name (match ));
@@ -417,65 +371,50 @@ static int add_root_nvdimm_bridge(struct device *match, void *data)
417371 return 1 ;
418372}
419373
420- static u32 cedt_instance (struct platform_device * pdev )
421- {
422- const bool * native_acpi0017 = acpi_device_get_match_data (& pdev -> dev );
423-
424- if (native_acpi0017 && * native_acpi0017 )
425- return 0 ;
426-
427- /* for cxl_test request a non-canonical instance */
428- return U32_MAX ;
429- }
430-
431374static int cxl_acpi_probe (struct platform_device * pdev )
432375{
433376 int rc ;
434- acpi_status status ;
435377 struct cxl_port * root_port ;
436378 struct device * host = & pdev -> dev ;
437379 struct acpi_device * adev = ACPI_COMPANION (host );
380+ struct cxl_cfmws_context ctx ;
438381
439382 root_port = devm_cxl_add_port (host , host , CXL_RESOURCE_NONE , NULL );
440383 if (IS_ERR (root_port ))
441384 return PTR_ERR (root_port );
442385 dev_dbg (host , "add: %s\n" , dev_name (& root_port -> dev ));
443386
444- status = acpi_get_table (ACPI_SIG_CEDT , cedt_instance (pdev ), & acpi_cedt );
445- if (ACPI_FAILURE (status ))
446- return - ENXIO ;
447-
448387 rc = bus_for_each_dev (adev -> dev .bus , NULL , root_port ,
449388 add_host_bridge_dport );
450- if (rc )
451- goto out ;
389+ if (rc < 0 )
390+ return rc ;
452391
453- cxl_add_cfmws_decoders (host , root_port );
392+ ctx = (struct cxl_cfmws_context ) {
393+ .dev = host ,
394+ .root_port = root_port ,
395+ };
396+ acpi_table_parse_cedt (ACPI_CEDT_TYPE_CFMWS , cxl_parse_cfmws , & ctx );
454397
455398 /*
456399 * Root level scanned with host-bridge as dports, now scan host-bridges
457400 * for their role as CXL uports to their CXL-capable PCIe Root Ports.
458401 */
459402 rc = bus_for_each_dev (adev -> dev .bus , NULL , root_port ,
460403 add_host_bridge_uport );
461- if (rc )
462- goto out ;
404+ if (rc < 0 )
405+ return rc ;
463406
464407 if (IS_ENABLED (CONFIG_CXL_PMEM ))
465408 rc = device_for_each_child (& root_port -> dev , root_port ,
466409 add_root_nvdimm_bridge );
467-
468- out :
469- acpi_put_table (acpi_cedt );
470410 if (rc < 0 )
471411 return rc ;
412+
472413 return 0 ;
473414}
474415
475- static bool native_acpi0017 = true;
476-
477416static const struct acpi_device_id cxl_acpi_ids [] = {
478- { "ACPI0017" , ( unsigned long ) & native_acpi0017 },
417+ { "ACPI0017" },
479418 { },
480419};
481420MODULE_DEVICE_TABLE (acpi , cxl_acpi_ids );
@@ -491,3 +430,4 @@ static struct platform_driver cxl_acpi_driver = {
491430module_platform_driver (cxl_acpi_driver );
492431MODULE_LICENSE ("GPL v2" );
493432MODULE_IMPORT_NS (CXL );
433+ MODULE_IMPORT_NS (ACPI );
0 commit comments