2013-11-13 13:38:27 +04:00
/*
* SCLP early driver
*
* Copyright IBM Corp . 2013
*/
# define KMSG_COMPONENT "sclp_early"
# define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
2015-06-25 10:32:22 +03:00
# include <linux/errno.h>
2013-11-13 13:38:27 +04:00
# include <asm/ctl_reg.h>
2013-11-13 13:38:27 +04:00
# include <asm/sclp.h>
# include <asm/ipl.h>
# include "sclp_sdias.h"
# include "sclp.h"
2013-11-13 13:38:27 +04:00
# define SCLP_CMDW_READ_SCP_INFO 0x00020001
# define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
struct read_info_sccb {
struct sccb_header header ; /* 0-7 */
u16 rnmax ; /* 8-9 */
u8 rnsize ; /* 10 */
2015-01-14 19:52:10 +03:00
u8 _pad_11 [ 16 - 11 ] ; /* 11-15 */
2014-03-10 17:50:16 +04:00
u16 ncpurl ; /* 16-17 */
2013-12-30 15:54:14 +04:00
u16 cpuoff ; /* 18-19 */
2015-01-14 19:52:10 +03:00
u8 _pad_20 [ 24 - 20 ] ; /* 20-23 */
2013-11-13 13:38:27 +04:00
u8 loadparm [ 8 ] ; /* 24-31 */
2015-01-14 19:52:10 +03:00
u8 _pad_32 [ 42 - 32 ] ; /* 32-41 */
u8 fac42 ; /* 42 */
u8 fac43 ; /* 43 */
u8 _pad_44 [ 48 - 44 ] ; /* 44-47 */
2013-11-13 13:38:27 +04:00
u64 facilities ; /* 48-55 */
2015-01-14 19:52:10 +03:00
u8 _pad_56 [ 66 - 56 ] ; /* 56-65 */
u8 fac66 ; /* 66 */
u8 _pad_67 [ 76 - 67 ] ; /* 67-83 */
2014-03-15 21:16:26 +04:00
u32 ibc ; /* 76-79 */
2015-01-14 19:52:10 +03:00
u8 _pad80 [ 84 - 80 ] ; /* 80-83 */
2013-11-13 13:38:27 +04:00
u8 fac84 ; /* 84 */
u8 fac85 ; /* 85 */
2015-01-14 19:52:10 +03:00
u8 _pad_86 [ 91 - 86 ] ; /* 86-90 */
2016-07-26 17:53:09 +03:00
u8 fac91 ; /* 91 */
2017-02-23 21:39:17 +03:00
u8 _pad_92 [ 98 - 92 ] ; /* 92-97 */
u8 fac98 ; /* 98 */
2014-12-01 19:24:42 +03:00
u8 hamaxpow ; /* 99 */
2013-11-13 13:38:27 +04:00
u32 rnsize2 ; /* 100-103 */
u64 rnmax2 ; /* 104-111 */
2014-10-09 18:04:48 +04:00
u8 _pad_112 [ 116 - 112 ] ; /* 112-115 */
u8 fac116 ; /* 116 */
2015-11-24 15:02:25 +03:00
u8 fac117 ; /* 117 */
u8 _pad_118 ; /* 118 */
2014-10-09 18:04:48 +04:00
u8 fac119 ; /* 119 */
2014-03-10 17:50:16 +04:00
u16 hcpua ; /* 120-121 */
2016-04-01 15:36:51 +03:00
u8 _pad_122 [ 124 - 122 ] ; /* 122-123 */
u32 hmfai ; /* 124-127 */
u8 _pad_128 [ 4096 - 128 ] ; /* 128-4095 */
2013-11-13 13:38:27 +04:00
} __packed __aligned ( PAGE_SIZE ) ;
2013-12-05 21:46:51 +04:00
static struct sclp_ipl_info sclp_ipl_info ;
2013-11-13 13:38:27 +04:00
2015-05-06 14:18:59 +03:00
struct sclp_info sclp ;
EXPORT_SYMBOL ( sclp ) ;
2013-11-13 13:38:27 +04:00
2017-01-24 17:58:52 +03:00
static int __init sclp_early_read_info ( struct read_info_sccb * sccb )
2013-11-13 13:38:27 +04:00
{
2017-02-02 14:33:03 +03:00
int i ;
2013-11-13 13:38:27 +04:00
sclp_cmdw_t commands [ ] = { SCLP_CMDW_READ_SCP_INFO_FORCED ,
SCLP_CMDW_READ_SCP_INFO } ;
for ( i = 0 ; i < ARRAY_SIZE ( commands ) ; i + + ) {
2017-02-02 14:33:03 +03:00
memset ( sccb , 0 , sizeof ( * sccb ) ) ;
sccb - > header . length = sizeof ( * sccb ) ;
sccb - > header . function_code = 0x80 ;
sccb - > header . control_mask [ 2 ] = 0x80 ;
if ( sclp_early_cmd ( commands [ i ] , sccb ) )
2013-11-13 13:38:27 +04:00
break ;
2013-12-05 21:46:51 +04:00
if ( sccb - > header . response_code = = 0x10 )
return 0 ;
2013-11-13 13:38:27 +04:00
if ( sccb - > header . response_code ! = 0x1f0 )
break ;
}
2013-12-05 21:46:51 +04:00
return - EIO ;
2013-11-13 13:38:27 +04:00
}
2017-01-24 17:58:52 +03:00
static void __init sclp_early_facilities_detect ( struct read_info_sccb * sccb )
2013-11-13 13:38:27 +04:00
{
2015-06-18 15:23:00 +03:00
struct sclp_core_entry * cpue ;
2013-12-30 15:54:14 +04:00
u16 boot_cpu_address , cpu ;
2017-01-24 17:58:52 +03:00
if ( sclp_early_read_info ( sccb ) )
2013-11-13 13:38:27 +04:00
return ;
2015-05-06 10:17:51 +03:00
sclp . facilities = sccb - > facilities ;
2015-05-06 14:18:59 +03:00
sclp . has_sprp = ! ! ( sccb - > fac84 & 0x02 ) ;
2015-06-18 15:23:00 +03:00
sclp . has_core_type = ! ! ( sccb - > fac84 & 0x01 ) ;
2015-11-24 14:53:46 +03:00
sclp . has_gsls = ! ! ( sccb - > fac85 & 0x80 ) ;
2015-11-24 14:49:43 +03:00
sclp . has_64bscao = ! ! ( sccb - > fac116 & 0x80 ) ;
2015-11-24 14:55:35 +03:00
sclp . has_cmma = ! ! ( sccb - > fac116 & 0x40 ) ;
2014-10-09 18:04:48 +04:00
sclp . has_esca = ! ! ( sccb - > fac116 & 0x08 ) ;
2015-11-24 15:02:25 +03:00
sclp . has_pfmfi = ! ! ( sccb - > fac117 & 0x40 ) ;
2015-11-24 15:02:52 +03:00
sclp . has_ibs = ! ! ( sccb - > fac117 & 0x20 ) ;
2014-10-09 18:04:48 +04:00
sclp . has_hvs = ! ! ( sccb - > fac119 & 0x80 ) ;
2017-02-23 21:39:17 +03:00
sclp . has_kss = ! ! ( sccb - > fac98 & 0x01 ) ;
2013-11-13 13:38:27 +04:00
if ( sccb - > fac85 & 0x02 )
S390_lowcore . machine_flags | = MACHINE_FLAG_ESOP ;
2016-07-26 17:53:09 +03:00
if ( sccb - > fac91 & 0x40 )
S390_lowcore . machine_flags | = MACHINE_FLAG_TLB_GUEST ;
2015-05-06 14:18:59 +03:00
sclp . rnmax = sccb - > rnmax ? sccb - > rnmax : sccb - > rnmax2 ;
sclp . rzm = sccb - > rnsize ? sccb - > rnsize : sccb - > rnsize2 ;
sclp . rzm < < = 20 ;
sclp . ibc = sccb - > ibc ;
2013-12-05 21:46:51 +04:00
2014-12-01 19:24:42 +03:00
if ( sccb - > hamaxpow & & sccb - > hamaxpow < 64 )
sclp . hamax = ( 1UL < < sccb - > hamaxpow ) - 1 ;
else
sclp . hamax = U64_MAX ;
2014-03-10 17:50:16 +04:00
if ( ! sccb - > hcpua ) {
if ( MACHINE_IS_VM )
2015-06-18 15:23:00 +03:00
sclp . max_cores = 64 ;
2014-03-10 17:50:16 +04:00
else
2015-06-18 15:23:00 +03:00
sclp . max_cores = sccb - > ncpurl ;
2014-03-10 17:50:16 +04:00
} else {
2015-06-18 15:23:00 +03:00
sclp . max_cores = sccb - > hcpua + 1 ;
2014-03-10 17:50:16 +04:00
}
2013-12-30 15:54:14 +04:00
boot_cpu_address = stap ( ) ;
cpue = ( void * ) sccb + sccb - > cpuoff ;
for ( cpu = 0 ; cpu < sccb - > ncpurl ; cpue + + , cpu + + ) {
2015-01-14 19:52:10 +03:00
if ( boot_cpu_address ! = cpue - > core_id )
2013-12-30 15:54:14 +04:00
continue ;
2015-05-06 14:18:59 +03:00
sclp . has_siif = cpue - > siif ;
sclp . has_sigpif = cpue - > sigpif ;
2015-02-24 17:51:55 +03:00
sclp . has_sief2 = cpue - > sief2 ;
2015-11-24 14:51:52 +03:00
sclp . has_gpere = cpue - > gpere ;
2015-11-24 14:59:03 +03:00
sclp . has_ib = cpue - > ib ;
2015-11-24 15:00:23 +03:00
sclp . has_cei = cpue - > cei ;
2015-11-24 14:56:43 +03:00
sclp . has_skey = cpue - > skey ;
2013-12-30 15:54:14 +04:00
break ;
}
2013-12-05 21:46:51 +04:00
/* Save IPL information */
sclp_ipl_info . is_valid = 1 ;
2016-07-26 17:53:09 +03:00
if ( sccb - > fac91 & 0x2 )
2013-12-05 21:46:51 +04:00
sclp_ipl_info . has_dump = 1 ;
memcpy ( & sclp_ipl_info . loadparm , & sccb - > loadparm , LOADPARM_LEN ) ;
2015-01-14 19:52:10 +03:00
2015-05-06 14:18:59 +03:00
sclp . mtid = ( sccb - > fac42 & 0x80 ) ? ( sccb - > fac42 & 31 ) : 0 ;
sclp . mtid_cp = ( sccb - > fac42 & 0x80 ) ? ( sccb - > fac43 & 31 ) : 0 ;
sclp . mtid_prev = ( sccb - > fac42 & 0x80 ) ? ( sccb - > fac66 & 31 ) : 0 ;
2016-04-01 15:36:51 +03:00
sclp . hmfai = sccb - > hmfai ;
2013-11-13 13:38:27 +04:00
}
/*
2017-01-24 17:58:52 +03:00
* This function will be called after sclp_early_facilities_detect ( ) , which gets
* called from early . c code . The sclp_early_facilities_detect ( ) function retrieves
2013-12-05 21:46:51 +04:00
* and saves the IPL information .
2013-11-13 13:38:27 +04:00
*/
2017-01-24 17:58:52 +03:00
void __init sclp_early_get_ipl_info ( struct sclp_ipl_info * info )
2013-11-13 13:38:27 +04:00
{
2013-12-05 21:46:51 +04:00
* info = sclp_ipl_info ;
2013-11-13 13:38:27 +04:00
}
2017-01-24 17:58:52 +03:00
static struct sclp_core_info sclp_early_core_info __initdata ;
static int sclp_early_core_info_valid __initdata ;
2013-11-13 13:38:27 +04:00
2017-01-24 17:58:52 +03:00
static void __init sclp_early_init_core_info ( struct read_cpu_info_sccb * sccb )
2016-12-03 11:48:01 +03:00
{
if ( ! SCLP_HAS_CPU_INFO )
return ;
memset ( sccb , 0 , sizeof ( * sccb ) ) ;
sccb - > header . length = sizeof ( * sccb ) ;
2017-02-02 14:33:03 +03:00
if ( sclp_early_cmd ( SCLP_CMDW_READ_CPU_INFO , sccb ) )
2016-12-03 11:48:01 +03:00
return ;
if ( sccb - > header . response_code ! = 0x0010 )
return ;
2017-01-24 17:58:52 +03:00
sclp_fill_core_info ( & sclp_early_core_info , sccb ) ;
sclp_early_core_info_valid = 1 ;
2016-12-03 11:48:01 +03:00
}
2017-01-24 17:58:52 +03:00
int __init sclp_early_get_core_info ( struct sclp_core_info * info )
2016-12-03 11:48:01 +03:00
{
2017-01-24 17:58:52 +03:00
if ( ! sclp_early_core_info_valid )
2016-12-03 11:48:01 +03:00
return - EIO ;
2017-01-24 17:58:52 +03:00
* info = sclp_early_core_info ;
2016-12-03 11:48:01 +03:00
return 0 ;
}
2017-01-24 17:58:52 +03:00
static long __init sclp_early_hsa_size_init ( struct sdias_sccb * sccb )
2013-11-13 13:38:27 +04:00
{
2017-01-24 17:58:52 +03:00
memset ( sccb , 0 , sizeof ( * sccb ) ) ;
sccb - > hdr . length = sizeof ( * sccb ) ;
sccb - > evbuf . hdr . length = sizeof ( struct sdias_evbuf ) ;
sccb - > evbuf . hdr . type = EVTYP_SDIAS ;
sccb - > evbuf . event_qual = SDIAS_EQ_SIZE ;
sccb - > evbuf . data_id = SDIAS_DI_FCP_DUMP ;
sccb - > evbuf . event_id = 4712 ;
sccb - > evbuf . dbs = 1 ;
if ( sclp_early_cmd ( SCLP_CMDW_WRITE_EVENT_DATA , sccb ) )
2013-11-13 13:38:27 +04:00
return - EIO ;
2017-02-02 14:33:03 +03:00
if ( sccb - > hdr . response_code ! = 0x20 )
return - EIO ;
2014-02-24 17:30:00 +04:00
if ( sccb - > evbuf . blk_cnt = = 0 )
return 0 ;
return ( sccb - > evbuf . blk_cnt - 1 ) * PAGE_SIZE ;
2013-11-13 13:38:27 +04:00
}
2017-01-24 17:58:52 +03:00
static long __init sclp_early_hsa_copy_wait ( struct sdias_sccb * sccb )
2013-11-13 13:38:27 +04:00
{
memset ( sccb , 0 , PAGE_SIZE ) ;
2017-01-24 17:58:52 +03:00
sccb - > hdr . length = PAGE_SIZE ;
if ( sclp_early_cmd ( SCLP_CMDW_READ_EVENT_DATA , sccb ) )
2013-11-13 13:38:27 +04:00
return - EIO ;
2017-02-02 14:33:03 +03:00
if ( ( sccb - > hdr . response_code ! = 0x20 ) & & ( sccb - > hdr . response_code ! = 0x220 ) )
return - EIO ;
2017-01-24 17:58:52 +03:00
if ( sccb - > evbuf . blk_cnt = = 0 )
2014-02-24 17:30:00 +04:00
return 0 ;
2017-01-24 17:58:52 +03:00
return ( sccb - > evbuf . blk_cnt - 1 ) * PAGE_SIZE ;
2013-11-13 13:38:27 +04:00
}
2017-01-24 17:58:52 +03:00
static void __init sclp_early_hsa_size_detect ( void * sccb )
2013-11-13 13:38:27 +04:00
{
2017-01-24 17:58:52 +03:00
unsigned long flags ;
long size = - EIO ;
2013-11-13 13:38:27 +04:00
2017-01-24 17:58:52 +03:00
raw_local_irq_save ( flags ) ;
if ( sclp_early_set_event_mask ( sccb , EVTYP_SDIAS_MASK , EVTYP_SDIAS_MASK ) )
2013-11-13 13:38:27 +04:00
goto out ;
2017-01-24 17:58:52 +03:00
size = sclp_early_hsa_size_init ( sccb ) ;
/* First check for synchronous response (LPAR) */
if ( size )
goto out_mask ;
if ( ! ( S390_lowcore . ext_params & 1 ) )
sclp_early_wait_irq ( ) ;
size = sclp_early_hsa_copy_wait ( sccb ) ;
out_mask :
sclp_early_set_event_mask ( sccb , 0 , 0 ) ;
2013-11-13 13:38:27 +04:00
out :
2017-01-24 17:58:52 +03:00
raw_local_irq_restore ( flags ) ;
if ( size > 0 )
sclp . hsa_size = size ;
2013-12-05 22:28:39 +04:00
}
2017-01-24 17:58:52 +03:00
static void __init sclp_early_console_detect ( struct init_sccb * sccb )
2013-12-05 22:28:39 +04:00
{
if ( sccb - > header . response_code ! = 0x20 )
return ;
if ( sccb - > sclp_send_mask & EVTYP_VT220MSG_MASK )
2015-05-06 14:18:59 +03:00
sclp . has_vt220 = 1 ;
2013-12-05 22:28:39 +04:00
2017-01-24 17:58:52 +03:00
if ( sclp_early_con_check_linemode ( sccb ) )
2015-05-06 14:18:59 +03:00
sclp . has_linemode = 1 ;
2013-12-05 22:28:39 +04:00
}
2013-11-13 13:38:27 +04:00
void __init sclp_early_detect ( void )
{
2017-01-24 17:58:52 +03:00
void * sccb = & sclp_early_sccb ;
2013-12-05 22:13:36 +04:00
2017-01-24 17:58:52 +03:00
sclp_early_facilities_detect ( sccb ) ;
sclp_early_init_core_info ( sccb ) ;
sclp_early_hsa_size_detect ( sccb ) ;
2013-12-05 22:28:39 +04:00
2017-01-24 17:58:52 +03:00
/*
* Turn off SCLP event notifications . Also save remote masks in the
2013-12-05 22:28:39 +04:00
* sccb . These are sufficient to detect sclp console capabilities .
*/
2017-01-24 17:58:52 +03:00
sclp_early_set_event_mask ( sccb , 0 , 0 ) ;
sclp_early_console_detect ( sccb ) ;
2013-11-13 13:38:27 +04:00
}