@@ -72,51 +72,55 @@ bool __riscv_isa_extension_available(const unsigned long *isa_bitmap, unsigned i
7272}
7373EXPORT_SYMBOL_GPL (__riscv_isa_extension_available );
7474
75- static bool riscv_isa_extension_check (int id )
75+ static int riscv_ext_zicbom_validate (const struct riscv_isa_ext_data * data ,
76+ const unsigned long * isa_bitmap )
7677{
77- switch (id ) {
78- case RISCV_ISA_EXT_ZICBOM :
79- if (!riscv_cbom_block_size ) {
80- pr_err ("Zicbom detected in ISA string, disabling as no cbom-block-size found\n" );
81- return false;
82- } else if (!is_power_of_2 (riscv_cbom_block_size )) {
83- pr_err ("Zicbom disabled as cbom-block-size present, but is not a power-of-2\n" );
84- return false;
85- }
86- return true;
87- case RISCV_ISA_EXT_ZICBOZ :
88- if (!riscv_cboz_block_size ) {
89- pr_err ("Zicboz detected in ISA string, disabling as no cboz-block-size found\n" );
90- return false;
91- } else if (!is_power_of_2 (riscv_cboz_block_size )) {
92- pr_err ("Zicboz disabled as cboz-block-size present, but is not a power-of-2\n" );
93- return false;
94- }
95- return true;
96- case RISCV_ISA_EXT_INVALID :
97- return false;
78+ if (!riscv_cbom_block_size ) {
79+ pr_err ("Zicbom detected in ISA string, disabling as no cbom-block-size found\n" );
80+ return - EINVAL ;
9881 }
82+ if (!is_power_of_2 (riscv_cbom_block_size )) {
83+ pr_err ("Zicbom disabled as cbom-block-size present, but is not a power-of-2\n" );
84+ return - EINVAL ;
85+ }
86+ return 0 ;
87+ }
9988
100- return true;
89+ static int riscv_ext_zicboz_validate (const struct riscv_isa_ext_data * data ,
90+ const unsigned long * isa_bitmap )
91+ {
92+ if (!riscv_cboz_block_size ) {
93+ pr_err ("Zicboz detected in ISA string, disabling as no cboz-block-size found\n" );
94+ return - EINVAL ;
95+ }
96+ if (!is_power_of_2 (riscv_cboz_block_size )) {
97+ pr_err ("Zicboz disabled as cboz-block-size present, but is not a power-of-2\n" );
98+ return - EINVAL ;
99+ }
100+ return 0 ;
101101}
102102
103- #define _RISCV_ISA_EXT_DATA (_name , _id , _subset_exts , _subset_exts_size ) { \
104- .name = #_name, \
105- .property = #_name, \
106- .id = _id, \
107- .subset_ext_ids = _subset_exts, \
108- .subset_ext_size = _subset_exts_size \
103+ #define _RISCV_ISA_EXT_DATA (_name , _id , _subset_exts , _subset_exts_size , _validate ) { \
104+ .name = #_name, \
105+ .property = #_name, \
106+ .id = _id, \
107+ .subset_ext_ids = _subset_exts, \
108+ .subset_ext_size = _subset_exts_size, \
109+ .validate = _validate \
109110}
110111
111- #define __RISCV_ISA_EXT_DATA (_name , _id ) _RISCV_ISA_EXT_DATA(_name, _id, NULL, 0)
112+ #define __RISCV_ISA_EXT_DATA (_name , _id ) _RISCV_ISA_EXT_DATA(_name, _id, NULL, 0, NULL )
112113
113114/* Used to declare pure "lasso" extension (Zk for instance) */
114115#define __RISCV_ISA_EXT_BUNDLE (_name , _bundled_exts ) \
115- _RISCV_ISA_EXT_DATA(_name, RISCV_ISA_EXT_INVALID, _bundled_exts, ARRAY_SIZE(_bundled_exts))
116+ _RISCV_ISA_EXT_DATA(_name, RISCV_ISA_EXT_INVALID, _bundled_exts, \
117+ ARRAY_SIZE(_bundled_exts), NULL)
116118
117119/* Used to declare extensions that are a superset of other extensions (Zvbb for instance) */
118120#define __RISCV_ISA_EXT_SUPERSET (_name , _id , _sub_exts ) \
119- _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts))
121+ _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), NULL)
122+ #define __RISCV_ISA_EXT_SUPERSET_VALIDATE (_name , _id , _sub_exts , _validate ) \
123+ _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), _validate)
120124
121125static const unsigned int riscv_zk_bundled_exts [] = {
122126 RISCV_ISA_EXT_ZBKB ,
@@ -281,8 +285,10 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
281285 __RISCV_ISA_EXT_DATA (c , RISCV_ISA_EXT_c ),
282286 __RISCV_ISA_EXT_SUPERSET (v , RISCV_ISA_EXT_v , riscv_v_exts ),
283287 __RISCV_ISA_EXT_DATA (h , RISCV_ISA_EXT_h ),
284- __RISCV_ISA_EXT_SUPERSET (zicbom , RISCV_ISA_EXT_ZICBOM , riscv_xlinuxenvcfg_exts ),
285- __RISCV_ISA_EXT_SUPERSET (zicboz , RISCV_ISA_EXT_ZICBOZ , riscv_xlinuxenvcfg_exts ),
288+ __RISCV_ISA_EXT_SUPERSET_VALIDATE (zicbom , RISCV_ISA_EXT_ZICBOM , riscv_xlinuxenvcfg_exts ,
289+ riscv_ext_zicbom_validate ),
290+ __RISCV_ISA_EXT_SUPERSET_VALIDATE (zicboz , RISCV_ISA_EXT_ZICBOZ , riscv_xlinuxenvcfg_exts ,
291+ riscv_ext_zicboz_validate ),
286292 __RISCV_ISA_EXT_DATA (zicntr , RISCV_ISA_EXT_ZICNTR ),
287293 __RISCV_ISA_EXT_DATA (zicond , RISCV_ISA_EXT_ZICOND ),
288294 __RISCV_ISA_EXT_DATA (zicsr , RISCV_ISA_EXT_ZICSR ),
@@ -349,33 +355,93 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
349355
350356const size_t riscv_isa_ext_count = ARRAY_SIZE (riscv_isa_ext );
351357
352- static void __init match_isa_ext (const struct riscv_isa_ext_data * ext , const char * name ,
353- const char * name_end , struct riscv_isainfo * isainfo )
358+ static void riscv_isa_set_ext (const struct riscv_isa_ext_data * ext , unsigned long * bitmap )
354359{
355- if ((name_end - name == strlen (ext -> name )) &&
356- !strncasecmp (name , ext -> name , name_end - name )) {
357- /*
358- * If this is a bundle, enable all the ISA extensions that
359- * comprise the bundle.
360- */
361- if (ext -> subset_ext_size ) {
362- for (int i = 0 ; i < ext -> subset_ext_size ; i ++ ) {
363- if (riscv_isa_extension_check (ext -> subset_ext_ids [i ]))
364- set_bit (ext -> subset_ext_ids [i ], isainfo -> isa );
360+ if (ext -> id != RISCV_ISA_EXT_INVALID )
361+ set_bit (ext -> id , bitmap );
362+
363+ for (int i = 0 ; i < ext -> subset_ext_size ; i ++ ) {
364+ if (ext -> subset_ext_ids [i ] != RISCV_ISA_EXT_INVALID )
365+ set_bit (ext -> subset_ext_ids [i ], bitmap );
366+ }
367+ }
368+
369+ static const struct riscv_isa_ext_data * riscv_get_isa_ext_data (unsigned int ext_id )
370+ {
371+ for (int i = 0 ; i < riscv_isa_ext_count ; i ++ ) {
372+ if (riscv_isa_ext [i ].id == ext_id )
373+ return & riscv_isa_ext [i ];
374+ }
375+
376+ return NULL ;
377+ }
378+
379+ /*
380+ * "Resolve" a source ISA bitmap into one that matches kernel configuration as
381+ * well as correct extension dependencies. Some extensions depends on specific
382+ * kernel configuration to be usable (V needs CONFIG_RISCV_ISA_V for instance)
383+ * and this function will actually validate all the extensions provided in
384+ * source_isa into the resolved_isa based on extensions validate() callbacks.
385+ */
386+ static void __init riscv_resolve_isa (unsigned long * source_isa ,
387+ unsigned long * resolved_isa , unsigned long * this_hwcap ,
388+ unsigned long * isa2hwcap )
389+ {
390+ bool loop ;
391+ const struct riscv_isa_ext_data * ext ;
392+ DECLARE_BITMAP (prev_resolved_isa , RISCV_ISA_EXT_MAX );
393+ int max_loop_count = riscv_isa_ext_count , ret ;
394+ unsigned int bit ;
395+
396+ do {
397+ loop = false;
398+ if (max_loop_count -- < 0 ) {
399+ pr_err ("Failed to reach a stable ISA state\n" );
400+ return ;
401+ }
402+ bitmap_copy (prev_resolved_isa , resolved_isa , RISCV_ISA_EXT_MAX );
403+ for_each_set_bit (bit , source_isa , RISCV_ISA_EXT_MAX ) {
404+ ext = riscv_get_isa_ext_data (bit );
405+ if (!ext )
406+ continue ;
407+
408+ if (ext -> validate ) {
409+ ret = ext -> validate (ext , resolved_isa );
410+ if (ret == - EPROBE_DEFER ) {
411+ loop = true;
412+ continue ;
413+ } else if (ret ) {
414+ /* Disable the extension entirely */
415+ clear_bit (ext -> id , source_isa );
416+ continue ;
417+ }
365418 }
419+
420+ set_bit (ext -> id , resolved_isa );
421+ /* No need to keep it in source isa now that it is enabled */
422+ clear_bit (ext -> id , source_isa );
423+
424+ /* Single letter extensions get set in hwcap */
425+ if (ext -> id < RISCV_ISA_EXT_BASE )
426+ * this_hwcap |= isa2hwcap [ext -> id ];
366427 }
428+ } while (loop && memcmp (prev_resolved_isa , resolved_isa , sizeof (prev_resolved_isa )));
429+ }
367430
368- /*
369- * This is valid even for bundle extensions which uses the RISCV_ISA_EXT_INVALID id
370- * (rejected by riscv_isa_extension_check()).
371- */
372- if (riscv_isa_extension_check (ext -> id ))
373- set_bit (ext -> id , isainfo -> isa );
431+ static void __init match_isa_ext (const char * name , const char * name_end , unsigned long * bitmap )
432+ {
433+ for (int i = 0 ; i < riscv_isa_ext_count ; i ++ ) {
434+ const struct riscv_isa_ext_data * ext = & riscv_isa_ext [i ];
435+
436+ if ((name_end - name == strlen (ext -> name )) &&
437+ !strncasecmp (name , ext -> name , name_end - name )) {
438+ riscv_isa_set_ext (ext , bitmap );
439+ break ;
440+ }
374441 }
375442}
376443
377- static void __init riscv_parse_isa_string (unsigned long * this_hwcap , struct riscv_isainfo * isainfo ,
378- unsigned long * isa2hwcap , const char * isa )
444+ static void __init riscv_parse_isa_string (const char * isa , unsigned long * bitmap )
379445{
380446 /*
381447 * For all possible cpus, we have already validated in
@@ -388,7 +454,7 @@ static void __init riscv_parse_isa_string(unsigned long *this_hwcap, struct risc
388454 while (* isa ) {
389455 const char * ext = isa ++ ;
390456 const char * ext_end = isa ;
391- bool ext_long = false, ext_err = false;
457+ bool ext_err = false;
392458
393459 switch (* ext ) {
394460 case 's' :
@@ -428,7 +494,6 @@ static void __init riscv_parse_isa_string(unsigned long *this_hwcap, struct risc
428494 * character itself while eliminating the extensions version number.
429495 * A simple re-increment solves this problem.
430496 */
431- ext_long = true;
432497 for (; * isa && * isa != '_' ; ++ isa )
433498 if (unlikely (!isalnum (* isa )))
434499 ext_err = true;
@@ -509,15 +574,7 @@ static void __init riscv_parse_isa_string(unsigned long *this_hwcap, struct risc
509574 if (unlikely (ext_err ))
510575 continue ;
511576
512- for (int i = 0 ; i < riscv_isa_ext_count ; i ++ )
513- match_isa_ext (& riscv_isa_ext [i ], ext , ext_end , isainfo );
514-
515- if (!ext_long ) {
516- int nr = tolower (* ext ) - 'a' ;
517-
518- if (riscv_isa_extension_check (nr ))
519- * this_hwcap |= isa2hwcap [nr ];
520- }
577+ match_isa_ext (ext , ext_end , bitmap );
521578 }
522579}
523580
@@ -544,6 +601,7 @@ static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap)
544601 for_each_possible_cpu (cpu ) {
545602 struct riscv_isainfo * isainfo = & hart_isa [cpu ];
546603 unsigned long this_hwcap = 0 ;
604+ DECLARE_BITMAP (source_isa , RISCV_ISA_EXT_MAX ) = { 0 };
547605
548606 if (acpi_disabled ) {
549607 node = of_cpu_device_node_get (cpu );
@@ -566,18 +624,18 @@ static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap)
566624 }
567625 }
568626
569- riscv_parse_isa_string (& this_hwcap , isainfo , isa2hwcap , isa );
627+ riscv_parse_isa_string (isa , source_isa );
570628
571629 /*
572630 * These ones were as they were part of the base ISA when the
573631 * port & dt-bindings were upstreamed, and so can be set
574632 * unconditionally where `i` is in riscv,isa on DT systems.
575633 */
576634 if (acpi_disabled ) {
577- set_bit (RISCV_ISA_EXT_ZICSR , isainfo -> isa );
578- set_bit (RISCV_ISA_EXT_ZIFENCEI , isainfo -> isa );
579- set_bit (RISCV_ISA_EXT_ZICNTR , isainfo -> isa );
580- set_bit (RISCV_ISA_EXT_ZIHPM , isainfo -> isa );
635+ set_bit (RISCV_ISA_EXT_ZICSR , source_isa );
636+ set_bit (RISCV_ISA_EXT_ZIFENCEI , source_isa );
637+ set_bit (RISCV_ISA_EXT_ZICNTR , source_isa );
638+ set_bit (RISCV_ISA_EXT_ZIHPM , source_isa );
581639 }
582640
583641 /*
@@ -590,9 +648,11 @@ static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap)
590648 */
591649 if (acpi_disabled && boot_vendorid == THEAD_VENDOR_ID && boot_archid == 0x0 ) {
592650 this_hwcap &= ~isa2hwcap [RISCV_ISA_EXT_v ];
593- clear_bit (RISCV_ISA_EXT_v , isainfo -> isa );
651+ clear_bit (RISCV_ISA_EXT_v , source_isa );
594652 }
595653
654+ riscv_resolve_isa (source_isa , isainfo -> isa , & this_hwcap , isa2hwcap );
655+
596656 /*
597657 * All "okay" hart should have same isa. Set HWCAP based on
598658 * common capabilities of every "okay" hart, in case they don't
@@ -621,6 +681,7 @@ static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap)
621681 unsigned long this_hwcap = 0 ;
622682 struct device_node * cpu_node ;
623683 struct riscv_isainfo * isainfo = & hart_isa [cpu ];
684+ DECLARE_BITMAP (source_isa , RISCV_ISA_EXT_MAX ) = { 0 };
624685
625686 cpu_node = of_cpu_device_node_get (cpu );
626687 if (!cpu_node ) {
@@ -640,22 +701,11 @@ static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap)
640701 ext -> property ) < 0 )
641702 continue ;
642703
643- if (ext -> subset_ext_size ) {
644- for (int j = 0 ; j < ext -> subset_ext_size ; j ++ ) {
645- if (riscv_isa_extension_check (ext -> subset_ext_ids [j ]))
646- set_bit (ext -> subset_ext_ids [j ], isainfo -> isa );
647- }
648- }
649-
650- if (riscv_isa_extension_check (ext -> id )) {
651- set_bit (ext -> id , isainfo -> isa );
652-
653- /* Only single letter extensions get set in hwcap */
654- if (strnlen (riscv_isa_ext [i ].name , 2 ) == 1 )
655- this_hwcap |= isa2hwcap [riscv_isa_ext [i ].id ];
656- }
704+ riscv_isa_set_ext (ext , source_isa );
657705 }
658706
707+ riscv_resolve_isa (source_isa , isainfo -> isa , & this_hwcap , isa2hwcap );
708+
659709 of_node_put (cpu_node );
660710
661711 /*
0 commit comments