2005-04-17 02:20:36 +04:00
/*
* PowerPC64 LPAR Configuration Information Driver
*
* Dave Engebretsen engebret @ us . ibm . com
* Copyright ( c ) 2003 Dave Engebretsen
* Will Schmidt willschm @ us . ibm . com
* SPLPAR updates , Copyright ( c ) 2003 Will Schmidt IBM Corporation .
* seq_file updates , Copyright ( c ) 2004 Will Schmidt IBM Corporation .
* Nathan Lynch nathanl @ austin . ibm . com
* Added lparcfg_write , Copyright ( C ) 2004 Nathan Lynch IBM Corporation .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*
* This driver creates a proc file at / proc / ppc64 / lparcfg which contains
* keyword - value pairs that specify the configuration of the partition .
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/errno.h>
# include <linux/proc_fs.h>
# include <linux/init.h>
# include <linux/seq_file.h>
# include <asm/uaccess.h>
2005-11-02 03:55:28 +03:00
# include <asm/iseries/hv_lp_config.h>
2005-04-17 02:20:36 +04:00
# include <asm/lppaca.h>
# include <asm/hvcall.h>
2005-08-03 08:35:25 +04:00
# include <asm/firmware.h>
2005-04-17 02:20:36 +04:00
# include <asm/rtas.h>
# include <asm/system.h>
# include <asm/time.h>
2005-06-26 01:54:42 +04:00
# include <asm/prom.h>
2005-11-11 15:04:40 +03:00
# include <asm/vdso_datapage.h>
2008-07-23 22:31:52 +04:00
# include <asm/vio.h>
2005-04-17 02:20:36 +04:00
2008-07-23 22:27:30 +04:00
# define MODULE_VERS "1.8"
2005-04-17 02:20:36 +04:00
# define MODULE_NAME "lparcfg"
/* #define LPARCFG_DEBUG */
static struct proc_dir_entry * proc_ppc64_lparcfg ;
/*
2006-06-29 09:07:42 +04:00
* Track sum of all purrs across all processors . This is used to further
* calculate usage values by different applications
2005-04-17 02:20:36 +04:00
*/
static unsigned long get_purr ( void )
{
unsigned long sum_purr = 0 ;
int cpu ;
2006-03-29 02:50:51 +04:00
for_each_possible_cpu ( cpu ) {
2006-06-29 09:07:42 +04:00
if ( firmware_has_feature ( FW_FEATURE_ISERIES ) )
sum_purr + = lppaca [ cpu ] . emulated_time_base ;
else {
struct cpu_usage * cu ;
2005-04-17 02:20:36 +04:00
2006-06-29 09:07:42 +04:00
cu = & per_cpu ( cpu_usage_array , cpu ) ;
sum_purr + = cu - > current_tb ;
}
2005-04-17 02:20:36 +04:00
}
return sum_purr ;
}
2006-06-29 09:07:42 +04:00
# ifdef CONFIG_PPC_ISERIES
2005-04-17 02:20:36 +04:00
2005-11-10 07:26:20 +03:00
/*
2005-04-17 02:20:36 +04:00
* Methods used to fetch LPAR data when running on an iSeries platform .
*/
2006-06-29 09:07:42 +04:00
static int iseries_lparcfg_data ( struct seq_file * m , void * v )
2005-04-17 02:20:36 +04:00
{
2006-06-29 09:07:42 +04:00
unsigned long pool_id ;
2005-04-17 02:20:36 +04:00
int shared , entitled_capacity , max_entitled_capacity ;
int processors , max_processors ;
unsigned long purr = get_purr ( ) ;
2006-10-31 21:44:54 +03:00
shared = ( int ) ( local_paca - > lppaca_ptr - > shared_proc ) ;
2005-04-17 02:20:36 +04:00
seq_printf ( m , " system_active_processors=%d \n " ,
( int ) HvLpConfig_getSystemPhysicalProcessors ( ) ) ;
seq_printf ( m , " system_potential_processors=%d \n " ,
( int ) HvLpConfig_getSystemPhysicalProcessors ( ) ) ;
processors = ( int ) HvLpConfig_getPhysicalProcessors ( ) ;
seq_printf ( m , " partition_active_processors=%d \n " , processors ) ;
max_processors = ( int ) HvLpConfig_getMaxPhysicalProcessors ( ) ;
seq_printf ( m , " partition_potential_processors=%d \n " , max_processors ) ;
if ( shared ) {
entitled_capacity = HvLpConfig_getSharedProcUnits ( ) ;
max_entitled_capacity = HvLpConfig_getMaxSharedProcUnits ( ) ;
} else {
entitled_capacity = processors * 100 ;
max_entitled_capacity = max_processors * 100 ;
}
seq_printf ( m , " partition_entitled_capacity=%d \n " , entitled_capacity ) ;
seq_printf ( m , " partition_max_entitled_capacity=%d \n " ,
max_entitled_capacity ) ;
if ( shared ) {
pool_id = HvLpConfig_getSharedPoolIndex ( ) ;
seq_printf ( m , " pool=%d \n " , ( int ) pool_id ) ;
seq_printf ( m , " pool_capacity=%d \n " ,
( int ) ( HvLpConfig_getNumProcsInSharedPool ( pool_id ) *
100 ) ) ;
seq_printf ( m , " purr=%ld \n " , purr ) ;
}
seq_printf ( m , " shared_processor_mode=%d \n " , shared ) ;
return 0 ;
}
2006-06-29 09:07:42 +04:00
# else /* CONFIG_PPC_ISERIES */
static int iseries_lparcfg_data ( struct seq_file * m , void * v )
{
return 0 ;
}
2005-04-17 02:20:36 +04:00
# endif /* CONFIG_PPC_ISERIES */
# ifdef CONFIG_PPC_PSERIES
2005-11-10 07:26:20 +03:00
/*
2005-04-17 02:20:36 +04:00
* Methods used to fetch LPAR data when running on a pSeries platform .
*/
2008-07-23 22:27:30 +04:00
/**
* h_get_mpp
* H_GET_MPP hcall returns info in 7 parms
*/
int h_get_mpp ( struct hvcall_mpp_data * mpp_data )
{
int rc ;
unsigned long retbuf [ PLPAR_HCALL9_BUFSIZE ] ;
rc = plpar_hcall9 ( H_GET_MPP , retbuf ) ;
mpp_data - > entitled_mem = retbuf [ 0 ] ;
mpp_data - > mapped_mem = retbuf [ 1 ] ;
mpp_data - > group_num = ( retbuf [ 2 ] > > 2 * 8 ) & 0xffff ;
mpp_data - > pool_num = retbuf [ 2 ] & 0xffff ;
mpp_data - > mem_weight = ( retbuf [ 3 ] > > 7 * 8 ) & 0xff ;
mpp_data - > unallocated_mem_weight = ( retbuf [ 3 ] > > 6 * 8 ) & 0xff ;
mpp_data - > unallocated_entitlement = retbuf [ 3 ] & 0xffffffffffff ;
mpp_data - > pool_size = retbuf [ 4 ] ;
mpp_data - > loan_request = retbuf [ 5 ] ;
mpp_data - > backing_mem = retbuf [ 6 ] ;
return rc ;
}
EXPORT_SYMBOL ( h_get_mpp ) ;
2008-07-23 22:28:05 +04:00
struct hvcall_ppp_data {
u64 entitlement ;
u64 unallocated_entitlement ;
u16 group_num ;
u16 pool_num ;
u8 capped ;
u8 weight ;
u8 unallocated_weight ;
u16 active_procs_in_pool ;
u16 active_system_procs ;
} ;
2005-04-17 02:20:36 +04:00
/*
* H_GET_PPP hcall returns info in 4 parms .
* entitled_capacity , unallocated_capacity ,
* aggregation , resource_capability ) .
*
2005-11-10 07:26:20 +03:00
* R4 = Entitled Processor Capacity Percentage .
2005-04-17 02:20:36 +04:00
* R5 = Unallocated Processor Capacity Percentage .
* R6 ( AABBCCDDEEFFGGHH ) .
* XXXX - reserved ( 0 )
* XXXX - reserved ( 0 )
* XXXX - Group Number
* XXXX - Pool Number .
* R7 ( IIJJKKLLMMNNOOPP ) .
* XX - reserved . ( 0 )
* XX - bit 0 - 6 reserved ( 0 ) . bit 7 is Capped indicator .
* XX - variable processor Capacity Weight
* XX - Unallocated Variable Processor Capacity Weight .
* XXXX - Active processors in Physical Processor Pool .
2005-11-10 07:26:20 +03:00
* XXXX - Processors active on platform .
2005-04-17 02:20:36 +04:00
*/
2008-07-23 22:28:05 +04:00
static unsigned int h_get_ppp ( struct hvcall_ppp_data * ppp_data )
2005-04-17 02:20:36 +04:00
{
unsigned long rc ;
2006-07-19 02:01:28 +04:00
unsigned long retbuf [ PLPAR_HCALL_BUFSIZE ] ;
rc = plpar_hcall ( H_GET_PPP , retbuf ) ;
2008-07-23 22:28:05 +04:00
ppp_data - > entitlement = retbuf [ 0 ] ;
ppp_data - > unallocated_entitlement = retbuf [ 1 ] ;
ppp_data - > group_num = ( retbuf [ 2 ] > > 2 * 8 ) & 0xffff ;
ppp_data - > pool_num = retbuf [ 2 ] & 0xffff ;
ppp_data - > capped = ( retbuf [ 3 ] > > 6 * 8 ) & 0x01 ;
ppp_data - > weight = ( retbuf [ 3 ] > > 5 * 8 ) & 0xff ;
ppp_data - > unallocated_weight = ( retbuf [ 3 ] > > 4 * 8 ) & 0xff ;
ppp_data - > active_procs_in_pool = ( retbuf [ 3 ] > > 2 * 8 ) & 0xffff ;
ppp_data - > active_system_procs = retbuf [ 3 ] & 0xffff ;
2005-04-17 02:20:36 +04:00
return rc ;
}
2008-07-23 22:25:16 +04:00
static unsigned h_pic ( unsigned long * pool_idle_time ,
unsigned long * num_procs )
2005-04-17 02:20:36 +04:00
{
unsigned long rc ;
2006-07-19 02:01:28 +04:00
unsigned long retbuf [ PLPAR_HCALL_BUFSIZE ] ;
rc = plpar_hcall ( H_PIC , retbuf ) ;
* pool_idle_time = retbuf [ 0 ] ;
* num_procs = retbuf [ 1 ] ;
2008-07-23 22:25:16 +04:00
return rc ;
}
/*
* parse_ppp_data
* Parse out the data returned from h_get_ppp and h_pic
*/
static void parse_ppp_data ( struct seq_file * m )
{
2008-07-23 22:28:05 +04:00
struct hvcall_ppp_data ppp_data ;
2008-07-23 22:25:16 +04:00
int rc ;
2008-07-23 22:28:05 +04:00
rc = h_get_ppp ( & ppp_data ) ;
2008-07-23 22:25:16 +04:00
if ( rc )
return ;
2009-01-06 17:26:03 +03:00
seq_printf ( m , " partition_entitled_capacity=%lld \n " ,
2008-07-23 22:28:05 +04:00
ppp_data . entitlement ) ;
seq_printf ( m , " group=%d \n " , ppp_data . group_num ) ;
seq_printf ( m , " system_active_processors=%d \n " ,
ppp_data . active_system_procs ) ;
2008-07-23 22:25:16 +04:00
/* pool related entries are apropriate for shared configs */
if ( lppaca [ 0 ] . shared_proc ) {
unsigned long pool_idle_time , pool_procs ;
2008-07-23 22:28:05 +04:00
seq_printf ( m , " pool=%d \n " , ppp_data . pool_num ) ;
2008-07-23 22:25:16 +04:00
/* report pool_capacity in percentage */
2008-07-23 22:28:05 +04:00
seq_printf ( m , " pool_capacity=%d \n " ,
ppp_data . active_procs_in_pool * 100 ) ;
2008-07-23 22:25:16 +04:00
h_pic ( & pool_idle_time , & pool_procs ) ;
seq_printf ( m , " pool_idle_time=%ld \n " , pool_idle_time ) ;
seq_printf ( m , " pool_num_procs=%ld \n " , pool_procs ) ;
}
2008-07-23 22:28:05 +04:00
seq_printf ( m , " unallocated_capacity_weight=%d \n " ,
ppp_data . unallocated_weight ) ;
seq_printf ( m , " capacity_weight=%d \n " , ppp_data . weight ) ;
seq_printf ( m , " capped=%d \n " , ppp_data . capped ) ;
2009-01-06 17:26:03 +03:00
seq_printf ( m , " unallocated_capacity=%lld \n " ,
2008-07-23 22:28:05 +04:00
ppp_data . unallocated_entitlement ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-23 22:27:30 +04:00
/**
* parse_mpp_data
* Parse out data returned from h_get_mpp
*/
static void parse_mpp_data ( struct seq_file * m )
{
struct hvcall_mpp_data mpp_data ;
int rc ;
rc = h_get_mpp ( & mpp_data ) ;
if ( rc )
return ;
seq_printf ( m , " entitled_memory=%ld \n " , mpp_data . entitled_mem ) ;
if ( mpp_data . mapped_mem ! = - 1 )
seq_printf ( m , " mapped_entitled_memory=%ld \n " ,
mpp_data . mapped_mem ) ;
seq_printf ( m , " entitled_memory_group_number=%d \n " , mpp_data . group_num ) ;
seq_printf ( m , " entitled_memory_pool_number=%d \n " , mpp_data . pool_num ) ;
seq_printf ( m , " entitled_memory_weight=%d \n " , mpp_data . mem_weight ) ;
seq_printf ( m , " unallocated_entitled_memory_weight=%d \n " ,
mpp_data . unallocated_mem_weight ) ;
seq_printf ( m , " unallocated_io_mapping_entitlement=%ld \n " ,
mpp_data . unallocated_entitlement ) ;
if ( mpp_data . pool_size ! = - 1 )
seq_printf ( m , " entitled_memory_pool_size=%ld bytes \n " ,
mpp_data . pool_size ) ;
seq_printf ( m , " entitled_memory_loan_request=%ld \n " ,
mpp_data . loan_request ) ;
seq_printf ( m , " backing_memory=%ld bytes \n " , mpp_data . backing_mem ) ;
}
2005-04-17 02:20:36 +04:00
# define SPLPAR_CHARACTERISTICS_TOKEN 20
# define SPLPAR_MAXLENGTH 1026*(sizeof(char))
/*
* parse_system_parameter_string ( )
* Retrieve the potential_processors , max_entitled_capacity and friends
* through the get - system - parameter rtas call . Replace keyword strings as
* necessary .
*/
static void parse_system_parameter_string ( struct seq_file * m )
{
int call_status ;
[PATCH] powerpc/pseries: misc lparcfg fixes
This fixes several problems with the lparcfg code. In case
someone gets a sense of deja-vu, part of this was submitted last Sep, I
thought the changes went in, but either got backed out, or just got
lost.
First, change the local_buffer declaration to be unsigned char *. We
had a bad-math problem in a 2.4 tree which was built with a
"-fsigned-char" parm. I dont believe we ever build with that parm
now-a-days, but to be safe, I'd prefer the declaration be explicit.
Second, fix a bad math calculation for splpar_strlen.
Third, on the rtas_call for get-system-parameter, pass in
RTAS_DATA_BUF_SIZE for the rtas_data_buf size, instead of letting random
data determine the size. Until recently, we've had a sufficiently
large 'random data' value get passed in, so the function just happens to
have worked OK. Now it's getting passed a '0', which causes the
rtas_call to return success, but no data shows up in the buffer.
(oops!). This was found by the LTC test org.
This is in a branch of code that only gets run on SPLPAR systems.
Tested on power5 Lpar.
Signed-off-by: Will Schmidt <willschm@us.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2006-03-31 19:07:48 +04:00
unsigned char * local_buffer = kmalloc ( SPLPAR_MAXLENGTH , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! local_buffer ) {
printk ( KERN_ERR " %s %s kmalloc failure at line %d \n " ,
2008-03-29 00:21:07 +03:00
__FILE__ , __func__ , __LINE__ ) ;
2005-04-17 02:20:36 +04:00
return ;
}
spin_lock ( & rtas_data_buf_lock ) ;
memset ( rtas_data_buf , 0 , SPLPAR_MAXLENGTH ) ;
call_status = rtas_call ( rtas_token ( " ibm,get-system-parameter " ) , 3 , 1 ,
NULL ,
SPLPAR_CHARACTERISTICS_TOKEN ,
[PATCH] powerpc/pseries: misc lparcfg fixes
This fixes several problems with the lparcfg code. In case
someone gets a sense of deja-vu, part of this was submitted last Sep, I
thought the changes went in, but either got backed out, or just got
lost.
First, change the local_buffer declaration to be unsigned char *. We
had a bad-math problem in a 2.4 tree which was built with a
"-fsigned-char" parm. I dont believe we ever build with that parm
now-a-days, but to be safe, I'd prefer the declaration be explicit.
Second, fix a bad math calculation for splpar_strlen.
Third, on the rtas_call for get-system-parameter, pass in
RTAS_DATA_BUF_SIZE for the rtas_data_buf size, instead of letting random
data determine the size. Until recently, we've had a sufficiently
large 'random data' value get passed in, so the function just happens to
have worked OK. Now it's getting passed a '0', which causes the
rtas_call to return success, but no data shows up in the buffer.
(oops!). This was found by the LTC test org.
This is in a branch of code that only gets run on SPLPAR systems.
Tested on power5 Lpar.
Signed-off-by: Will Schmidt <willschm@us.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2006-03-31 19:07:48 +04:00
__pa ( rtas_data_buf ) ,
RTAS_DATA_BUF_SIZE ) ;
2005-04-17 02:20:36 +04:00
memcpy ( local_buffer , rtas_data_buf , SPLPAR_MAXLENGTH ) ;
spin_unlock ( & rtas_data_buf_lock ) ;
if ( call_status ! = 0 ) {
printk ( KERN_INFO
" %s %s Error calling get-system-parameter (0x%x) \n " ,
2008-03-29 00:21:07 +03:00
__FILE__ , __func__ , call_status ) ;
2005-04-17 02:20:36 +04:00
} else {
int splpar_strlen ;
int idx , w_idx ;
some kmalloc/memset ->kzalloc (tree wide)
Transform some calls to kmalloc/memset to a single kzalloc (or kcalloc).
Here is a short excerpt of the semantic patch performing
this transformation:
@@
type T2;
expression x;
identifier f,fld;
expression E;
expression E1,E2;
expression e1,e2,e3,y;
statement S;
@@
x =
- kmalloc
+ kzalloc
(E1,E2)
... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\)
- memset((T2)x,0,E1);
@@
expression E1,E2,E3;
@@
- kzalloc(E1 * E2,E3)
+ kcalloc(E1,E2,E3)
[akpm@linux-foundation.org: get kcalloc args the right way around]
Signed-off-by: Yoann Padioleau <padator@wanadoo.fr>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Acked-by: Russell King <rmk@arm.linux.org.uk>
Cc: Bryan Wu <bryan.wu@analog.com>
Acked-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Dave Airlie <airlied@linux.ie>
Acked-by: Roland Dreier <rolandd@cisco.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Acked-by: Pierre Ossman <drzeus-list@drzeus.cx>
Cc: Jeff Garzik <jeff@garzik.org>
Cc: "David S. Miller" <davem@davemloft.net>
Acked-by: Greg KH <greg@kroah.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 12:49:03 +04:00
char * workbuffer = kzalloc ( SPLPAR_MAXLENGTH , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! workbuffer ) {
printk ( KERN_ERR " %s %s kmalloc failure at line %d \n " ,
2008-03-29 00:21:07 +03:00
__FILE__ , __func__ , __LINE__ ) ;
2005-11-10 07:26:20 +03:00
kfree ( local_buffer ) ;
2005-04-17 02:20:36 +04:00
return ;
}
# ifdef LPARCFG_DEBUG
printk ( KERN_INFO " success calling get-system-parameter \n " ) ;
# endif
[PATCH] powerpc/pseries: misc lparcfg fixes
This fixes several problems with the lparcfg code. In case
someone gets a sense of deja-vu, part of this was submitted last Sep, I
thought the changes went in, but either got backed out, or just got
lost.
First, change the local_buffer declaration to be unsigned char *. We
had a bad-math problem in a 2.4 tree which was built with a
"-fsigned-char" parm. I dont believe we ever build with that parm
now-a-days, but to be safe, I'd prefer the declaration be explicit.
Second, fix a bad math calculation for splpar_strlen.
Third, on the rtas_call for get-system-parameter, pass in
RTAS_DATA_BUF_SIZE for the rtas_data_buf size, instead of letting random
data determine the size. Until recently, we've had a sufficiently
large 'random data' value get passed in, so the function just happens to
have worked OK. Now it's getting passed a '0', which causes the
rtas_call to return success, but no data shows up in the buffer.
(oops!). This was found by the LTC test org.
This is in a branch of code that only gets run on SPLPAR systems.
Tested on power5 Lpar.
Signed-off-by: Will Schmidt <willschm@us.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2006-03-31 19:07:48 +04:00
splpar_strlen = local_buffer [ 0 ] * 256 + local_buffer [ 1 ] ;
2005-04-17 02:20:36 +04:00
local_buffer + = 2 ; /* step over strlen value */
w_idx = 0 ;
idx = 0 ;
while ( ( * local_buffer ) & & ( idx < splpar_strlen ) ) {
workbuffer [ w_idx + + ] = local_buffer [ idx + + ] ;
if ( ( local_buffer [ idx ] = = ' , ' )
| | ( local_buffer [ idx ] = = ' \0 ' ) ) {
workbuffer [ w_idx ] = ' \0 ' ;
if ( w_idx ) {
/* avoid the empty string */
seq_printf ( m , " %s \n " , workbuffer ) ;
}
memset ( workbuffer , 0 , SPLPAR_MAXLENGTH ) ;
idx + + ; /* skip the comma */
w_idx = 0 ;
} else if ( local_buffer [ idx ] = = ' = ' ) {
/* code here to replace workbuffer contents
with different keyword strings */
if ( 0 = = strcmp ( workbuffer , " MaxEntCap " ) ) {
strcpy ( workbuffer ,
" partition_max_entitled_capacity " ) ;
w_idx = strlen ( workbuffer ) ;
}
if ( 0 = = strcmp ( workbuffer , " MaxPlatProcs " ) ) {
strcpy ( workbuffer ,
" system_potential_processors " ) ;
w_idx = strlen ( workbuffer ) ;
}
}
}
kfree ( workbuffer ) ;
local_buffer - = 2 ; /* back up over strlen value */
}
kfree ( local_buffer ) ;
}
/* Return the number of processors in the system.
* This function reads through the device tree and counts
* the virtual processors , this does not include threads .
*/
static int lparcfg_count_active_processors ( void )
{
struct device_node * cpus_dn = NULL ;
int count = 0 ;
while ( ( cpus_dn = of_find_node_by_type ( cpus_dn , " cpu " ) ) ) {
# ifdef LPARCFG_DEBUG
printk ( KERN_ERR " cpus_dn %p \n " , cpus_dn ) ;
# endif
count + + ;
}
return count ;
}
2008-07-23 22:30:58 +04:00
static void pseries_cmo_data ( struct seq_file * m )
{
int cpu ;
unsigned long cmo_faults = 0 ;
unsigned long cmo_fault_time = 0 ;
2008-08-15 23:10:18 +04:00
seq_printf ( m , " cmo_enabled=%d \n " , firmware_has_feature ( FW_FEATURE_CMO ) ) ;
2008-07-23 22:30:58 +04:00
if ( ! firmware_has_feature ( FW_FEATURE_CMO ) )
return ;
for_each_possible_cpu ( cpu ) {
cmo_faults + = lppaca [ cpu ] . cmo_faults ;
cmo_fault_time + = lppaca [ cpu ] . cmo_fault_time ;
}
seq_printf ( m , " cmo_faults=%lu \n " , cmo_faults ) ;
seq_printf ( m , " cmo_fault_time_usec=%lu \n " ,
cmo_fault_time / tb_ticks_per_usec ) ;
2008-08-15 23:10:18 +04:00
seq_printf ( m , " cmo_primary_psp=%d \n " , cmo_get_primary_psp ( ) ) ;
seq_printf ( m , " cmo_secondary_psp=%d \n " , cmo_get_secondary_psp ( ) ) ;
seq_printf ( m , " cmo_page_size=%lu \n " , cmo_get_page_size ( ) ) ;
2008-07-23 22:30:58 +04:00
}
2006-06-29 09:07:42 +04:00
static int pseries_lparcfg_data ( struct seq_file * m , void * v )
2005-04-17 02:20:36 +04:00
{
int partition_potential_processors ;
int partition_active_processors ;
struct device_node * rtas_node ;
2006-07-12 09:35:54 +04:00
const int * lrdrp = NULL ;
2005-04-17 02:20:36 +04:00
2007-04-24 07:50:55 +04:00
rtas_node = of_find_node_by_path ( " /rtas " ) ;
2006-02-16 06:40:44 +03:00
if ( rtas_node )
2007-04-03 16:26:41 +04:00
lrdrp = of_get_property ( rtas_node , " ibm,lrdr-capacity " , NULL ) ;
2005-04-17 02:20:36 +04:00
if ( lrdrp = = NULL ) {
2005-11-11 15:04:40 +03:00
partition_potential_processors = vdso_data - > processorCount ;
2005-04-17 02:20:36 +04:00
} else {
partition_potential_processors = * ( lrdrp + 4 ) ;
}
2007-04-24 07:50:55 +04:00
of_node_put ( rtas_node ) ;
2005-04-17 02:20:36 +04:00
partition_active_processors = lparcfg_count_active_processors ( ) ;
2005-08-03 08:35:25 +04:00
if ( firmware_has_feature ( FW_FEATURE_SPLPAR ) ) {
2005-04-17 02:20:36 +04:00
/* this call handles the ibm,get-system-parameter contents */
parse_system_parameter_string ( m ) ;
2008-07-23 22:25:16 +04:00
parse_ppp_data ( m ) ;
2008-07-23 22:27:30 +04:00
parse_mpp_data ( m ) ;
2008-07-23 22:30:58 +04:00
pseries_cmo_data ( m ) ;
2005-04-17 02:20:36 +04:00
2008-07-23 22:25:16 +04:00
seq_printf ( m , " purr=%ld \n " , get_purr ( ) ) ;
2005-04-17 02:20:36 +04:00
} else { /* non SPLPAR case */
seq_printf ( m , " system_active_processors=%d \n " ,
partition_potential_processors ) ;
seq_printf ( m , " system_potential_processors=%d \n " ,
partition_potential_processors ) ;
seq_printf ( m , " partition_max_entitled_capacity=%d \n " ,
partition_potential_processors * 100 ) ;
seq_printf ( m , " partition_entitled_capacity=%d \n " ,
partition_active_processors * 100 ) ;
}
seq_printf ( m , " partition_active_processors=%d \n " ,
partition_active_processors ) ;
seq_printf ( m , " partition_potential_processors=%d \n " ,
partition_potential_processors ) ;
2006-01-13 02:26:42 +03:00
seq_printf ( m , " shared_processor_mode=%d \n " , lppaca [ 0 ] . shared_proc ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-07-23 22:25:16 +04:00
static ssize_t update_ppp ( u64 * entitlement , u8 * weight )
{
2008-07-23 22:28:05 +04:00
struct hvcall_ppp_data ppp_data ;
u8 new_weight ;
2008-07-23 22:25:16 +04:00
u64 new_entitled ;
ssize_t retval ;
/* Get our current parameters */
2008-07-23 22:28:05 +04:00
retval = h_get_ppp ( & ppp_data ) ;
2008-07-23 22:25:16 +04:00
if ( retval )
return retval ;
if ( entitlement ) {
2008-07-23 22:28:05 +04:00
new_weight = ppp_data . weight ;
2008-07-23 22:25:16 +04:00
new_entitled = * entitlement ;
} else if ( weight ) {
new_weight = * weight ;
2008-07-23 22:28:05 +04:00
new_entitled = ppp_data . entitlement ;
2008-07-23 22:25:16 +04:00
} else
return - EINVAL ;
2009-01-06 17:26:03 +03:00
pr_debug ( " %s: current_entitled = %llu, current_weight = %u \n " ,
2008-07-30 23:29:03 +04:00
__func__ , ppp_data . entitlement , ppp_data . weight ) ;
2008-07-23 22:25:16 +04:00
2009-01-06 17:26:03 +03:00
pr_debug ( " %s: new_entitled = %llu, new_weight = %u \n " ,
2008-07-30 23:29:03 +04:00
__func__ , new_entitled , new_weight ) ;
2008-07-23 22:25:16 +04:00
retval = plpar_hcall_norets ( H_SET_PPP , new_entitled , new_weight ) ;
return retval ;
}
2008-07-23 22:27:30 +04:00
/**
* update_mpp
*
* Update the memory entitlement and weight for the partition . Caller must
* specify either a new entitlement or weight , not both , to be updated
* since the h_set_mpp call takes both entitlement and weight as parameters .
*/
static ssize_t update_mpp ( u64 * entitlement , u8 * weight )
{
struct hvcall_mpp_data mpp_data ;
u64 new_entitled ;
u8 new_weight ;
ssize_t rc ;
2008-07-23 22:31:52 +04:00
if ( entitlement ) {
/* Check with vio to ensure the new memory entitlement
* can be handled .
*/
rc = vio_cmo_entitlement_update ( * entitlement ) ;
if ( rc )
return rc ;
}
2008-07-23 22:27:30 +04:00
rc = h_get_mpp ( & mpp_data ) ;
if ( rc )
return rc ;
if ( entitlement ) {
new_weight = mpp_data . mem_weight ;
new_entitled = * entitlement ;
} else if ( weight ) {
new_weight = * weight ;
new_entitled = mpp_data . entitled_mem ;
} else
return - EINVAL ;
pr_debug ( " %s: current_entitled = %lu, current_weight = %u \n " ,
2008-07-30 23:29:03 +04:00
__func__ , mpp_data . entitled_mem , mpp_data . mem_weight ) ;
2008-07-23 22:27:30 +04:00
2009-01-06 17:26:03 +03:00
pr_debug ( " %s: new_entitled = %llu, new_weight = %u \n " ,
2008-07-30 23:29:03 +04:00
__func__ , new_entitled , new_weight ) ;
2008-07-23 22:27:30 +04:00
rc = plpar_hcall_norets ( H_SET_MPP , new_entitled , new_weight ) ;
return rc ;
}
2005-04-17 02:20:36 +04:00
/*
* Interface for changing system parameters ( variable capacity weight
* and entitled capacity ) . Format of input is " param_name=value " ;
* anything after value is ignored . Valid parameters at this time are
* " partition_entitled_capacity " and " capacity_weight " . We use
* H_SET_PPP to alter parameters .
*
* This function should be invoked only on systems with
* FW_FEATURE_SPLPAR .
*/
static ssize_t lparcfg_write ( struct file * file , const char __user * buf ,
size_t count , loff_t * off )
{
2008-07-23 23:10:46 +04:00
int kbuf_sz = 64 ;
char kbuf [ kbuf_sz ] ;
2005-04-17 02:20:36 +04:00
char * tmp ;
u64 new_entitled , * new_entitled_ptr = & new_entitled ;
u8 new_weight , * new_weight_ptr = & new_weight ;
2008-07-23 23:10:46 +04:00
ssize_t retval ;
2005-04-17 02:20:36 +04:00
2007-02-06 03:14:05 +03:00
if ( ! firmware_has_feature ( FW_FEATURE_SPLPAR ) | |
firmware_has_feature ( FW_FEATURE_ISERIES ) )
return - EINVAL ;
2008-07-23 23:10:46 +04:00
if ( count > kbuf_sz )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( copy_from_user ( kbuf , buf , count ) )
2008-07-23 23:10:46 +04:00
return - EFAULT ;
2005-04-17 02:20:36 +04:00
kbuf [ count - 1 ] = ' \0 ' ;
tmp = strchr ( kbuf , ' = ' ) ;
if ( ! tmp )
2008-07-23 23:10:46 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
* tmp + + = ' \0 ' ;
if ( ! strcmp ( kbuf , " partition_entitled_capacity " ) ) {
char * endp ;
* new_entitled_ptr = ( u64 ) simple_strtoul ( tmp , & endp , 10 ) ;
if ( endp = = tmp )
2008-07-23 23:10:46 +04:00
return - EINVAL ;
2008-07-23 22:25:16 +04:00
retval = update_ppp ( new_entitled_ptr , NULL ) ;
2005-04-17 02:20:36 +04:00
} else if ( ! strcmp ( kbuf , " capacity_weight " ) ) {
char * endp ;
* new_weight_ptr = ( u8 ) simple_strtoul ( tmp , & endp , 10 ) ;
if ( endp = = tmp )
2008-07-23 23:10:46 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2008-07-23 22:25:16 +04:00
retval = update_ppp ( NULL , new_weight_ptr ) ;
2008-07-23 22:27:30 +04:00
} else if ( ! strcmp ( kbuf , " entitled_memory " ) ) {
char * endp ;
* new_entitled_ptr = ( u64 ) simple_strtoul ( tmp , & endp , 10 ) ;
if ( endp = = tmp )
2008-07-23 23:10:46 +04:00
return - EINVAL ;
2008-07-23 22:27:30 +04:00
retval = update_mpp ( new_entitled_ptr , NULL ) ;
} else if ( ! strcmp ( kbuf , " entitled_memory_weight " ) ) {
char * endp ;
* new_weight_ptr = ( u8 ) simple_strtoul ( tmp , & endp , 10 ) ;
if ( endp = = tmp )
2008-07-23 23:10:46 +04:00
return - EINVAL ;
2008-07-23 22:27:30 +04:00
retval = update_mpp ( NULL , new_weight_ptr ) ;
2008-07-23 22:25:16 +04:00
} else
2008-07-23 23:10:46 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2006-03-30 16:49:40 +04:00
if ( retval = = H_SUCCESS | | retval = = H_CONSTRAINED ) {
2005-04-17 02:20:36 +04:00
retval = count ;
2006-03-30 16:49:40 +04:00
} else if ( retval = = H_BUSY ) {
2005-04-17 02:20:36 +04:00
retval = - EBUSY ;
2006-03-30 16:49:40 +04:00
} else if ( retval = = H_HARDWARE ) {
2005-04-17 02:20:36 +04:00
retval = - EIO ;
2006-03-30 16:49:40 +04:00
} else if ( retval = = H_PARAMETER ) {
2005-04-17 02:20:36 +04:00
retval = - EINVAL ;
}
return retval ;
}
2006-06-29 09:07:42 +04:00
# else /* CONFIG_PPC_PSERIES */
static int pseries_lparcfg_data ( struct seq_file * m , void * v )
{
return 0 ;
}
static ssize_t lparcfg_write ( struct file * file , const char __user * buf ,
size_t count , loff_t * off )
{
2007-02-06 03:14:05 +03:00
return - EINVAL ;
2006-06-29 09:07:42 +04:00
}
2005-04-17 02:20:36 +04:00
# endif /* CONFIG_PPC_PSERIES */
2006-06-29 09:07:42 +04:00
static int lparcfg_data ( struct seq_file * m , void * v )
{
struct device_node * rootdn ;
const char * model = " " ;
const char * system_id = " " ;
const char * tmp ;
2006-07-12 09:35:54 +04:00
const unsigned int * lp_index_ptr ;
unsigned int lp_index = 0 ;
2006-06-29 09:07:42 +04:00
seq_printf ( m , " %s %s \n " , MODULE_NAME , MODULE_VERS ) ;
2007-04-24 07:50:55 +04:00
rootdn = of_find_node_by_path ( " / " ) ;
2006-06-29 09:07:42 +04:00
if ( rootdn ) {
2007-04-03 16:26:41 +04:00
tmp = of_get_property ( rootdn , " model " , NULL ) ;
2006-06-29 09:07:42 +04:00
if ( tmp ) {
model = tmp ;
/* Skip "IBM," - see platforms/iseries/dt.c */
if ( firmware_has_feature ( FW_FEATURE_ISERIES ) )
model + = 4 ;
}
2007-04-03 16:26:41 +04:00
tmp = of_get_property ( rootdn , " system-id " , NULL ) ;
2006-06-29 09:07:42 +04:00
if ( tmp ) {
system_id = tmp ;
/* Skip "IBM," - see platforms/iseries/dt.c */
if ( firmware_has_feature ( FW_FEATURE_ISERIES ) )
system_id + = 4 ;
}
2007-04-03 16:26:41 +04:00
lp_index_ptr = of_get_property ( rootdn , " ibm,partition-no " ,
NULL ) ;
2006-06-29 09:07:42 +04:00
if ( lp_index_ptr )
lp_index = * lp_index_ptr ;
2007-04-24 07:50:55 +04:00
of_node_put ( rootdn ) ;
2006-06-29 09:07:42 +04:00
}
seq_printf ( m , " serial_number=%s \n " , system_id ) ;
seq_printf ( m , " system_type=%s \n " , model ) ;
seq_printf ( m , " partition_id=%d \n " , ( int ) lp_index ) ;
if ( firmware_has_feature ( FW_FEATURE_ISERIES ) )
return iseries_lparcfg_data ( m , v ) ;
return pseries_lparcfg_data ( m , v ) ;
}
2005-04-17 02:20:36 +04:00
static int lparcfg_open ( struct inode * inode , struct file * file )
{
return single_open ( file , lparcfg_data , NULL ) ;
}
2008-05-08 08:27:19 +04:00
static const struct file_operations lparcfg_fops = {
2005-11-11 05:53:11 +03:00
. owner = THIS_MODULE ,
. read = seq_read ,
2007-02-06 03:14:05 +03:00
. write = lparcfg_write ,
2005-11-11 05:53:11 +03:00
. open = lparcfg_open ,
. release = single_release ,
2005-04-17 02:20:36 +04:00
} ;
2008-05-08 08:27:19 +04:00
static int __init lparcfg_init ( void )
2005-04-17 02:20:36 +04:00
{
struct proc_dir_entry * ent ;
2005-09-06 07:22:47 +04:00
mode_t mode = S_IRUSR | S_IRGRP | S_IROTH ;
2005-04-17 02:20:36 +04:00
/* Allow writing if we have FW_FEATURE_SPLPAR */
2006-06-29 09:07:42 +04:00
if ( firmware_has_feature ( FW_FEATURE_SPLPAR ) & &
2007-02-06 03:14:05 +03:00
! firmware_has_feature ( FW_FEATURE_ISERIES ) )
2005-04-17 02:20:36 +04:00
mode | = S_IWUSR ;
2008-04-29 12:02:26 +04:00
ent = proc_create ( " ppc64/lparcfg " , mode , NULL , & lparcfg_fops ) ;
if ( ! ent ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " Failed to create ppc64/lparcfg \n " ) ;
return - EIO ;
}
proc_ppc64_lparcfg = ent ;
return 0 ;
}
2008-05-08 08:27:19 +04:00
static void __exit lparcfg_cleanup ( void )
2005-04-17 02:20:36 +04:00
{
2007-12-04 19:03:49 +03:00
if ( proc_ppc64_lparcfg )
2005-04-17 02:20:36 +04:00
remove_proc_entry ( " lparcfg " , proc_ppc64_lparcfg - > parent ) ;
}
module_init ( lparcfg_init ) ;
module_exit ( lparcfg_cleanup ) ;
MODULE_DESCRIPTION ( " Interface for LPAR configuration data " ) ;
MODULE_AUTHOR ( " Dave Engebretsen " ) ;
MODULE_LICENSE ( " GPL " ) ;