2019-06-03 07:44:50 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2017-07-10 18:07:09 -07:00
/*
* Copied from arch / arm64 / kernel / cpufeature . c
*
* Copyright ( C ) 2015 ARM Ltd .
* Copyright ( C ) 2017 SiFive
*/
2020-04-24 10:29:27 +05:30
# include <linux/bitmap.h>
2017-07-10 18:07:09 -07:00
# include <linux/of.h>
# include <asm/processor.h>
# include <asm/hwcap.h>
2019-02-22 11:41:40 -08:00
# include <asm/smp.h>
2019-10-17 15:21:28 -07:00
# include <asm/switch_to.h>
2017-07-10 18:07:09 -07:00
unsigned long elf_hwcap __read_mostly ;
2020-04-24 10:29:27 +05:30
/* Host ISA bitmap */
static DECLARE_BITMAP ( riscv_isa , RISCV_ISA_EXT_MAX ) __read_mostly ;
2018-10-09 10:18:34 +08:00
# ifdef CONFIG_FPU
2021-05-12 22:55:45 +08:00
__ro_after_init DEFINE_STATIC_KEY_FALSE ( cpu_hwcap_fpu ) ;
2018-10-09 10:18:34 +08:00
# endif
2017-07-10 18:07:09 -07:00
2020-04-24 10:29:27 +05:30
/**
* riscv_isa_extension_base ( ) - Get base extension word
*
* @ isa_bitmap : ISA bitmap to use
* Return : base extension word as unsigned long value
*
* NOTE : If isa_bitmap is NULL then Host ISA bitmap will be used .
*/
unsigned long riscv_isa_extension_base ( const unsigned long * isa_bitmap )
{
if ( ! isa_bitmap )
return riscv_isa [ 0 ] ;
return isa_bitmap [ 0 ] ;
}
EXPORT_SYMBOL_GPL ( riscv_isa_extension_base ) ;
/**
* __riscv_isa_extension_available ( ) - Check whether given extension
* is available or not
*
* @ isa_bitmap : ISA bitmap to use
* @ bit : bit position of the desired extension
* Return : true or false
*
* NOTE : If isa_bitmap is NULL then Host ISA bitmap will be used .
*/
bool __riscv_isa_extension_available ( const unsigned long * isa_bitmap , int bit )
{
const unsigned long * bmap = ( isa_bitmap ) ? isa_bitmap : riscv_isa ;
if ( bit > = RISCV_ISA_EXT_MAX )
return false ;
return test_bit ( bit , bmap ) ? true : false ;
}
EXPORT_SYMBOL_GPL ( __riscv_isa_extension_available ) ;
2017-07-10 18:07:09 -07:00
void riscv_fill_hwcap ( void )
{
2019-01-18 15:03:08 +01:00
struct device_node * node ;
2017-07-10 18:07:09 -07:00
const char * isa ;
2020-04-24 10:29:27 +05:30
char print_str [ BITS_PER_LONG + 1 ] ;
size_t i , j , isa_len ;
2017-07-10 18:07:09 -07:00
static unsigned long isa2hwcap [ 256 ] = { 0 } ;
isa2hwcap [ ' i ' ] = isa2hwcap [ ' I ' ] = COMPAT_HWCAP_ISA_I ;
isa2hwcap [ ' m ' ] = isa2hwcap [ ' M ' ] = COMPAT_HWCAP_ISA_M ;
isa2hwcap [ ' a ' ] = isa2hwcap [ ' A ' ] = COMPAT_HWCAP_ISA_A ;
isa2hwcap [ ' f ' ] = isa2hwcap [ ' F ' ] = COMPAT_HWCAP_ISA_F ;
isa2hwcap [ ' d ' ] = isa2hwcap [ ' D ' ] = COMPAT_HWCAP_ISA_D ;
isa2hwcap [ ' c ' ] = isa2hwcap [ ' C ' ] = COMPAT_HWCAP_ISA_C ;
elf_hwcap = 0 ;
2020-04-24 10:29:27 +05:30
bitmap_zero ( riscv_isa , RISCV_ISA_EXT_MAX ) ;
2019-01-18 15:03:08 +01:00
for_each_of_cpu_node ( node ) {
2019-02-22 11:41:40 -08:00
unsigned long this_hwcap = 0 ;
2020-04-24 10:29:27 +05:30
unsigned long this_isa = 0 ;
2017-07-10 18:07:09 -07:00
2019-02-22 11:41:40 -08:00
if ( riscv_of_processor_hartid ( node ) < 0 )
continue ;
2017-07-10 18:07:09 -07:00
2019-02-22 11:41:40 -08:00
if ( of_property_read_string ( node , " riscv,isa " , & isa ) ) {
pr_warn ( " Unable to find \" riscv,isa \" devicetree entry \n " ) ;
continue ;
}
2020-04-24 10:29:27 +05:30
i = 0 ;
isa_len = strlen ( isa ) ;
# if IS_ENABLED(CONFIG_32BIT)
if ( ! strncmp ( isa , " rv32 " , 4 ) )
i + = 4 ;
# elif IS_ENABLED(CONFIG_64BIT)
if ( ! strncmp ( isa , " rv64 " , 4 ) )
i + = 4 ;
# endif
for ( ; i < isa_len ; + + i ) {
2019-02-22 11:41:40 -08:00
this_hwcap | = isa2hwcap [ ( unsigned char ) ( isa [ i ] ) ] ;
2020-04-24 10:29:27 +05:30
/*
* TODO : X , Y and Z extension parsing for Host ISA
* bitmap will be added in - future .
*/
if ( ' a ' < = isa [ i ] & & isa [ i ] < ' x ' )
this_isa | = ( 1UL < < ( isa [ i ] - ' a ' ) ) ;
}
2019-02-22 11:41:40 -08:00
/*
* All " okay " hart should have same isa . Set HWCAP based on
* common capabilities of every " okay " hart , in case they don ' t
* have .
*/
if ( elf_hwcap )
elf_hwcap & = this_hwcap ;
else
elf_hwcap = this_hwcap ;
2020-04-24 10:29:27 +05:30
if ( riscv_isa [ 0 ] )
riscv_isa [ 0 ] & = this_isa ;
else
riscv_isa [ 0 ] = this_isa ;
2019-02-22 11:41:40 -08:00
}
2017-07-10 18:07:09 -07:00
2018-08-27 14:42:53 -07:00
/* We don't support systems with F but without D, so mask those out
* here . */
if ( ( elf_hwcap & COMPAT_HWCAP_ISA_F ) & & ! ( elf_hwcap & COMPAT_HWCAP_ISA_D ) ) {
2019-01-18 15:03:04 +01:00
pr_info ( " This kernel does not support systems with F but not D \n " ) ;
2018-08-27 14:42:53 -07:00
elf_hwcap & = ~ COMPAT_HWCAP_ISA_F ;
}
2020-04-24 10:29:27 +05:30
memset ( print_str , 0 , sizeof ( print_str ) ) ;
for ( i = 0 , j = 0 ; i < BITS_PER_LONG ; i + + )
if ( riscv_isa [ 0 ] & BIT_MASK ( i ) )
print_str [ j + + ] = ( char ) ( ' a ' + i ) ;
pr_info ( " riscv: ISA extensions %s \n " , print_str ) ;
memset ( print_str , 0 , sizeof ( print_str ) ) ;
for ( i = 0 , j = 0 ; i < BITS_PER_LONG ; i + + )
if ( elf_hwcap & BIT_MASK ( i ) )
print_str [ j + + ] = ( char ) ( ' a ' + i ) ;
pr_info ( " riscv: ELF capabilities %s \n " , print_str ) ;
2018-10-09 10:18:34 +08:00
# ifdef CONFIG_FPU
if ( elf_hwcap & ( COMPAT_HWCAP_ISA_F | COMPAT_HWCAP_ISA_D ) )
2021-05-12 22:55:45 +08:00
static_branch_enable ( & cpu_hwcap_fpu ) ;
2018-10-09 10:18:34 +08:00
# endif
2017-07-10 18:07:09 -07:00
}