2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2006-02-10 07:47:36 +03:00
/*
* pSeries firmware setup code .
*
* Portions from arch / powerpc / platforms / pseries / setup . c :
* Copyright ( C ) 1995 Linus Torvalds
* Adapted from ' alpha ' version by Gary Thomas
* Modified by Cort Dougan ( cort @ cs . nmt . edu )
* Modified by PPC64 Team , IBM Corp
*
* Portions from arch / powerpc / kernel / firmware . c
* Copyright ( C ) 2001 Ben . Herrenschmidt ( benh @ kernel . crashing . org )
* Modifications for ppc64 :
* Copyright ( C ) 2003 Dave Engebretsen < engebret @ us . ibm . com >
* Copyright ( C ) 2005 Stephen Rothwell , IBM Corporation
*
* Copyright 2006 IBM Corporation .
*/
2016-07-05 08:03:48 +03:00
# include <linux/of_fdt.h>
2006-02-10 07:47:36 +03:00
# include <asm/firmware.h>
# include <asm/prom.h>
2007-10-29 22:24:19 +03:00
# include <asm/udbg.h>
2019-12-16 07:19:24 +03:00
# include <asm/svm.h>
2006-02-10 07:47:36 +03:00
2008-05-08 08:27:21 +04:00
# include "pseries.h"
2006-02-10 07:47:36 +03:00
2013-04-24 09:57:18 +04:00
struct hypertas_fw_feature {
2006-02-10 07:47:36 +03:00
unsigned long val ;
char * name ;
2013-04-24 09:57:18 +04:00
} ;
2006-02-10 07:47:36 +03:00
2012-11-06 18:49:15 +04:00
/*
* The names in this table match names in rtas / ibm , hypertas - functions . If the
* entry ends in a ' * ' , only upto the ' * ' is matched . Otherwise the entire
* string must match .
*/
2013-04-24 09:57:18 +04:00
static __initdata struct hypertas_fw_feature
hypertas_fw_features_table [ ] = {
2006-02-10 07:47:36 +03:00
{ FW_FEATURE_PFT , " hcall-pft " } ,
{ FW_FEATURE_TCE , " hcall-tce " } ,
{ FW_FEATURE_SPRG0 , " hcall-sprg0 " } ,
{ FW_FEATURE_DABR , " hcall-dabr " } ,
{ FW_FEATURE_COPY , " hcall-copy " } ,
{ FW_FEATURE_ASR , " hcall-asr " } ,
{ FW_FEATURE_DEBUG , " hcall-debug " } ,
{ FW_FEATURE_PERF , " hcall-perf " } ,
{ FW_FEATURE_DUMP , " hcall-dump " } ,
{ FW_FEATURE_INTERRUPT , " hcall-interrupt " } ,
{ FW_FEATURE_MIGRATE , " hcall-migrate " } ,
{ FW_FEATURE_PERFMON , " hcall-perfmon " } ,
{ FW_FEATURE_CRQ , " hcall-crq " } ,
{ FW_FEATURE_VIO , " hcall-vio " } ,
{ FW_FEATURE_RDMA , " hcall-rdma " } ,
{ FW_FEATURE_LLAN , " hcall-lLAN " } ,
2009-10-12 01:47:34 +04:00
{ FW_FEATURE_BULK_REMOVE , " hcall-bulk " } ,
2006-02-10 07:47:36 +03:00
{ FW_FEATURE_XDABR , " hcall-xdabr " } ,
2019-12-16 07:19:23 +03:00
{ FW_FEATURE_PUT_TCE_IND | FW_FEATURE_STUFF_TCE ,
" hcall-multi-tce " } ,
2006-02-10 07:47:36 +03:00
{ FW_FEATURE_SPLPAR , " hcall-splpar " } ,
2010-11-09 16:24:48 +03:00
{ FW_FEATURE_VPHN , " hcall-vphn " } ,
2012-11-06 09:15:17 +04:00
{ FW_FEATURE_SET_MODE , " hcall-set-mode " } ,
2012-11-06 18:49:16 +04:00
{ FW_FEATURE_BEST_ENERGY , " hcall-best-energy-1* " } ,
2016-12-09 03:07:35 +03:00
{ FW_FEATURE_HPT_RESIZE , " hcall-hpt-resize " } ,
2018-08-20 17:29:34 +03:00
{ FW_FEATURE_BLOCK_REMOVE , " hcall-block-remove " } ,
2018-10-15 02:18:27 +03:00
{ FW_FEATURE_PAPR_SCM , " hcall-scm " } ,
2020-07-27 11:59:08 +03:00
{ FW_FEATURE_RPT_INVALIDATE , " hcall-rpt-invalidate " } ,
powerpc/pseries: Interface to represent PAPR firmware attributes
Adds a syscall interface to represent the energy and frequency related
PAPR attributes on the system using the new H_CALL
"H_GET_ENERGY_SCALE_INFO".
H_GET_EM_PARMS H_CALL was previously responsible for exporting this
information in the lparcfg, however the H_GET_EM_PARMS H_CALL
will be deprecated P10 onwards.
The H_GET_ENERGY_SCALE_INFO H_CALL is of the following call format:
hcall(
uint64 H_GET_ENERGY_SCALE_INFO, // Get energy scale info
uint64 flags, // Per the flag request
uint64 firstAttributeId,// The attribute id
uint64 bufferAddress, // Guest physical address of the output buffer
uint64 bufferSize // The size in bytes of the output buffer
);
As specified in PAPR+ v2.11, section 14.14.3.
This H_CALL can query either all the attributes at once with
firstAttributeId = 0, flags = 0 as well as query only one attribute
at a time with firstAttributeId = id, flags = 1.
The output buffer consists of the following
1. number of attributes - 8 bytes
2. array offset to the data location - 8 bytes
3. version info - 1 byte
4. A data array of size num attributes, which contains the following:
a. attribute ID - 8 bytes
b. attribute value in number - 8 bytes
c. attribute name in string - 64 bytes
d. attribute value in string - 64 bytes
The new H_CALL exports information in direct string value format, hence
a new interface has been introduced in
/sys/firmware/papr/energy_scale_info to export this information to
userspace so that the firmware can add new values without the need for
the kernel to be changed.
The H_CALL returns the name, numeric value and string value (if exists)
The format of exposing the sysfs information is as follows:
/sys/firmware/papr/energy_scale_info/
|-- <id>/
|-- desc
|-- value
|-- value_desc (if exists)
|-- <id>/
|-- desc
|-- value
|-- value_desc (if exists)
...
The energy information that is exported is useful for userspace tools
such as powerpc-utils. Currently these tools infer the
"power_mode_data" value in the lparcfg, which in turn is obtained from
the to be deprecated H_GET_EM_PARMS H_CALL.
On future platforms, such userspace utilities will have to look at the
data returned from the new H_CALL being populated in this new sysfs
interface and report this information directly without the need of
interpretation.
Signed-off-by: Pratik R. Sampat <psampat@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20220217105321.52941-2-psampat@linux.ibm.com
2022-02-17 13:53:20 +03:00
{ FW_FEATURE_ENERGY_SCALE_INFO , " hcall-energy-scale-info " } ,
2022-07-13 23:23:33 +03:00
{ FW_FEATURE_WATCHDOG , " hcall-watchdog " } ,
2023-02-24 07:10:12 +03:00
{ FW_FEATURE_PLPKS , " hcall-pks " } ,
2006-02-10 07:47:36 +03:00
} ;
/* Build up the firmware features bitmask using the contents of
* device - tree / ibm , hypertas - functions . Ultimately this functionality may
* be moved into prom . c prom_init ( ) .
*/
2016-07-05 08:03:48 +03:00
static void __init fw_hypertas_feature_init ( const char * hypertas ,
unsigned long len )
2006-02-10 07:47:36 +03:00
{
2007-07-19 01:56:32 +04:00
const char * s ;
int i ;
2006-02-10 07:47:36 +03:00
2013-04-24 09:57:18 +04:00
pr_debug ( " -> fw_hypertas_feature_init() \n " ) ;
2006-02-10 07:47:36 +03:00
for ( s = hypertas ; s < hypertas + len ; s + = strlen ( s ) + 1 ) {
2013-04-24 09:57:18 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( hypertas_fw_features_table ) ; i + + ) {
const char * name = hypertas_fw_features_table [ i ] . name ;
2012-11-06 18:49:15 +04:00
size_t size ;
2013-04-24 09:55:08 +04:00
2012-11-06 18:49:15 +04:00
/*
* If there is a ' * ' at the end of name , only check
* upto there
*/
size = strlen ( name ) ;
if ( size & & name [ size - 1 ] = = ' * ' ) {
if ( strncmp ( name , s , size - 1 ) )
continue ;
} else if ( strcmp ( name , s ) )
2006-02-10 07:47:36 +03:00
continue ;
/* we have a match */
2006-03-27 07:26:25 +04:00
powerpc_firmware_features | =
2013-04-24 09:57:18 +04:00
hypertas_fw_features_table [ i ] . val ;
2006-02-10 07:47:36 +03:00
break ;
}
}
2019-12-16 07:19:24 +03:00
if ( is_secure_guest ( ) & &
( powerpc_firmware_features & FW_FEATURE_PUT_TCE_IND ) ) {
powerpc_firmware_features & = ~ FW_FEATURE_PUT_TCE_IND ;
pr_debug ( " SVM: disabling PUT_TCE_IND firmware feature \n " ) ;
}
2013-04-24 09:57:18 +04:00
pr_debug ( " <- fw_hypertas_feature_init() \n " ) ;
}
struct vec5_fw_feature {
unsigned long val ;
unsigned int feature ;
} ;
static __initdata struct vec5_fw_feature
vec5_fw_features_table [ ] = {
2021-08-12 16:22:20 +03:00
{ FW_FEATURE_FORM1_AFFINITY , OV5_FORM1_AFFINITY } ,
2013-04-24 10:00:35 +04:00
{ FW_FEATURE_PRRN , OV5_PRRN } ,
2017-12-01 19:48:03 +03:00
{ FW_FEATURE_DRMEM_V2 , OV5_DRMEM_V2 } ,
2017-12-02 02:19:40 +03:00
{ FW_FEATURE_DRC_INFO , OV5_DRC_INFO } ,
2021-08-12 16:22:23 +03:00
{ FW_FEATURE_FORM2_AFFINITY , OV5_FORM2_AFFINITY } ,
2013-04-24 09:57:18 +04:00
} ;
2016-07-05 08:03:48 +03:00
static void __init fw_vec5_feature_init ( const char * vec5 , unsigned long len )
2013-04-24 09:57:18 +04:00
{
unsigned int index , feat ;
int i ;
pr_debug ( " -> fw_vec5_feature_init() \n " ) ;
for ( i = 0 ; i < ARRAY_SIZE ( vec5_fw_features_table ) ; i + + ) {
index = OV5_INDX ( vec5_fw_features_table [ i ] . feature ) ;
feat = OV5_FEAT ( vec5_fw_features_table [ i ] . feature ) ;
2017-01-30 13:21:35 +03:00
if ( index < len & & ( vec5 [ index ] & feat ) )
2013-04-24 09:57:18 +04:00
powerpc_firmware_features | =
vec5_fw_features_table [ i ] . val ;
}
pr_debug ( " <- fw_vec5_feature_init() \n " ) ;
2006-02-10 07:47:36 +03:00
}
2016-07-05 08:03:48 +03:00
/*
* Called very early , MMU is off , device - tree isn ' t unflattened
*/
static int __init probe_fw_features ( unsigned long node , const char * uname , int
depth , void * data )
{
const char * prop ;
int len ;
static int hypertas_found ;
static int vec5_found ;
if ( depth ! = 1 )
return 0 ;
if ( ! strcmp ( uname , " rtas " ) | | ! strcmp ( uname , " rtas@0 " ) ) {
prop = of_get_flat_dt_prop ( node , " ibm,hypertas-functions " ,
& len ) ;
if ( prop ) {
powerpc_firmware_features | = FW_FEATURE_LPAR ;
fw_hypertas_feature_init ( prop , len ) ;
}
hypertas_found = 1 ;
}
if ( ! strcmp ( uname , " chosen " ) ) {
prop = of_get_flat_dt_prop ( node , " ibm,architecture-vec-5 " ,
& len ) ;
if ( prop )
fw_vec5_feature_init ( prop , len ) ;
vec5_found = 1 ;
}
return hypertas_found & & vec5_found ;
}
void __init pseries_probe_fw_features ( void )
{
of_scan_flat_dt ( probe_fw_features , NULL ) ;
}