diff options
| -rw-r--r-- | arch/s390/kernel/early.c | 44 | ||||
| -rw-r--r-- | arch/s390/kernel/ipl.c | 17 | ||||
| -rw-r--r-- | drivers/s390/char/sclp.h | 7 | ||||
| -rw-r--r-- | drivers/s390/char/sclp_info.c | 108 | ||||
| -rw-r--r-- | include/asm-s390/sclp.h | 46 |
5 files changed, 121 insertions, 101 deletions
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 50538e545618..9fcf3f1f47b6 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c | |||
| @@ -171,37 +171,6 @@ static inline int memory_fast_detect(void) | |||
| 171 | } | 171 | } |
| 172 | #endif | 172 | #endif |
| 173 | 173 | ||
| 174 | #define ADDR2G (1UL << 31) | ||
| 175 | |||
| 176 | static noinline __init unsigned long sclp_memory_detect(void) | ||
| 177 | { | ||
| 178 | struct sclp_readinfo_sccb *sccb; | ||
| 179 | unsigned long long memsize; | ||
| 180 | |||
| 181 | sccb = &s390_readinfo_sccb; | ||
| 182 | |||
| 183 | if (sccb->header.response_code != 0x10) | ||
| 184 | return 0; | ||
| 185 | |||
| 186 | if (sccb->rnsize) | ||
| 187 | memsize = sccb->rnsize << 20; | ||
| 188 | else | ||
| 189 | memsize = sccb->rnsize2 << 20; | ||
| 190 | if (sccb->rnmax) | ||
| 191 | memsize *= sccb->rnmax; | ||
| 192 | else | ||
| 193 | memsize *= sccb->rnmax2; | ||
| 194 | #ifndef CONFIG_64BIT | ||
| 195 | /* | ||
| 196 | * Can't deal with more than 2G in 31 bit addressing mode, so | ||
| 197 | * limit the value in order to avoid strange side effects. | ||
| 198 | */ | ||
| 199 | if (memsize > ADDR2G) | ||
| 200 | memsize = ADDR2G; | ||
| 201 | #endif | ||
| 202 | return (unsigned long) memsize; | ||
| 203 | } | ||
| 204 | |||
| 205 | static inline __init unsigned long __tprot(unsigned long addr) | 174 | static inline __init unsigned long __tprot(unsigned long addr) |
| 206 | { | 175 | { |
| 207 | int cc = -1; | 176 | int cc = -1; |
| @@ -218,6 +187,7 @@ static inline __init unsigned long __tprot(unsigned long addr) | |||
| 218 | 187 | ||
| 219 | /* Checking memory in 128KB increments. */ | 188 | /* Checking memory in 128KB increments. */ |
| 220 | #define CHUNK_INCR (1UL << 17) | 189 | #define CHUNK_INCR (1UL << 17) |
| 190 | #define ADDR2G (1UL << 31) | ||
| 221 | 191 | ||
| 222 | static noinline __init void find_memory_chunks(unsigned long memsize) | 192 | static noinline __init void find_memory_chunks(unsigned long memsize) |
| 223 | { | 193 | { |
| @@ -293,7 +263,7 @@ static noinline __init void setup_lowcore_early(void) | |||
| 293 | */ | 263 | */ |
| 294 | void __init startup_init(void) | 264 | void __init startup_init(void) |
| 295 | { | 265 | { |
| 296 | unsigned long memsize; | 266 | unsigned long long memsize; |
| 297 | 267 | ||
| 298 | ipl_save_parameters(); | 268 | ipl_save_parameters(); |
| 299 | clear_bss_section(); | 269 | clear_bss_section(); |
| @@ -306,7 +276,15 @@ void __init startup_init(void) | |||
| 306 | setup_lowcore_early(); | 276 | setup_lowcore_early(); |
| 307 | sclp_readinfo_early(); | 277 | sclp_readinfo_early(); |
| 308 | memsize = sclp_memory_detect(); | 278 | memsize = sclp_memory_detect(); |
| 279 | #ifndef CONFIG_64BIT | ||
| 280 | /* | ||
| 281 | * Can't deal with more than 2G in 31 bit addressing mode, so | ||
| 282 | * limit the value in order to avoid strange side effects. | ||
| 283 | */ | ||
| 284 | if (memsize > ADDR2G) | ||
| 285 | memsize = ADDR2G; | ||
| 286 | #endif | ||
| 309 | if (memory_fast_detect() < 0) | 287 | if (memory_fast_detect() < 0) |
| 310 | find_memory_chunks(memsize); | 288 | find_memory_chunks((unsigned long) memsize); |
| 311 | lockdep_on(); | 289 | lockdep_on(); |
| 312 | } | 290 | } |
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 367caf92ea78..82b131ddd7ff 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c | |||
| @@ -25,10 +25,6 @@ | |||
| 25 | 25 | ||
| 26 | #define IPL_PARM_BLOCK_VERSION 0 | 26 | #define IPL_PARM_BLOCK_VERSION 0 |
| 27 | 27 | ||
| 28 | #define SCCB_VALID (s390_readinfo_sccb.header.response_code == 0x10) | ||
| 29 | #define SCCB_LOADPARM (&s390_readinfo_sccb.loadparm) | ||
| 30 | #define SCCB_FLAG (s390_readinfo_sccb.flags) | ||
| 31 | |||
| 32 | #define IPL_UNKNOWN_STR "unknown" | 28 | #define IPL_UNKNOWN_STR "unknown" |
| 33 | #define IPL_CCW_STR "ccw" | 29 | #define IPL_CCW_STR "ccw" |
| 34 | #define IPL_FCP_STR "fcp" | 30 | #define IPL_FCP_STR "fcp" |
| @@ -146,6 +142,8 @@ static struct ipl_parameter_block *dump_block_ccw; | |||
| 146 | 142 | ||
| 147 | static enum shutdown_action on_panic_action = SHUTDOWN_STOP; | 143 | static enum shutdown_action on_panic_action = SHUTDOWN_STOP; |
| 148 | 144 | ||
| 145 | static struct sclp_ipl_info sclp_ipl_info; | ||
| 146 | |||
| 149 | int diag308(unsigned long subcode, void *addr) | 147 | int diag308(unsigned long subcode, void *addr) |
| 150 | { | 148 | { |
| 151 | register unsigned long _addr asm("0") = (unsigned long) addr; | 149 | register unsigned long _addr asm("0") = (unsigned long) addr; |
| @@ -375,9 +373,9 @@ static ssize_t ipl_ccw_loadparm_show(struct kset *kset, char *page) | |||
| 375 | { | 373 | { |
| 376 | char loadparm[LOADPARM_LEN + 1] = {}; | 374 | char loadparm[LOADPARM_LEN + 1] = {}; |
| 377 | 375 | ||
| 378 | if (!SCCB_VALID) | 376 | if (!sclp_ipl_info.is_valid) |
| 379 | return sprintf(page, "#unknown#\n"); | 377 | return sprintf(page, "#unknown#\n"); |
| 380 | memcpy(loadparm, SCCB_LOADPARM, LOADPARM_LEN); | 378 | memcpy(loadparm, &sclp_ipl_info.loadparm, LOADPARM_LEN); |
| 381 | EBCASC(loadparm, LOADPARM_LEN); | 379 | EBCASC(loadparm, LOADPARM_LEN); |
| 382 | strstrip(loadparm); | 380 | strstrip(loadparm); |
| 383 | return sprintf(page, "%s\n", loadparm); | 381 | return sprintf(page, "%s\n", loadparm); |
| @@ -910,9 +908,9 @@ static int __init reipl_ccw_init(void) | |||
| 910 | reipl_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN; | 908 | reipl_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN; |
| 911 | reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW; | 909 | reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW; |
| 912 | /* check if read scp info worked and set loadparm */ | 910 | /* check if read scp info worked and set loadparm */ |
| 913 | if (SCCB_VALID) | 911 | if (sclp_ipl_info.is_valid) |
| 914 | memcpy(reipl_block_ccw->ipl_info.ccw.load_param, | 912 | memcpy(reipl_block_ccw->ipl_info.ccw.load_param, |
| 915 | SCCB_LOADPARM, LOADPARM_LEN); | 913 | &sclp_ipl_info.loadparm, LOADPARM_LEN); |
| 916 | else | 914 | else |
| 917 | /* read scp info failed: set empty loadparm (EBCDIC blanks) */ | 915 | /* read scp info failed: set empty loadparm (EBCDIC blanks) */ |
| 918 | memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40, | 916 | memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40, |
| @@ -1007,7 +1005,7 @@ static int __init dump_fcp_init(void) | |||
| 1007 | { | 1005 | { |
| 1008 | int rc; | 1006 | int rc; |
| 1009 | 1007 | ||
| 1010 | if(!(SCCB_FLAG & 0x2) || !SCCB_VALID) | 1008 | if (!sclp_ipl_info.has_dump) |
| 1011 | return 0; /* LDIPL DUMP is not installed */ | 1009 | return 0; /* LDIPL DUMP is not installed */ |
| 1012 | if (!diag308_set_works) | 1010 | if (!diag308_set_works) |
| 1013 | return 0; | 1011 | return 0; |
| @@ -1088,6 +1086,7 @@ static int __init s390_ipl_init(void) | |||
| 1088 | { | 1086 | { |
| 1089 | int rc; | 1087 | int rc; |
| 1090 | 1088 | ||
| 1089 | sclp_get_ipl_info(&sclp_ipl_info); | ||
| 1091 | reipl_probe(); | 1090 | reipl_probe(); |
| 1092 | rc = ipl_init(); | 1091 | rc = ipl_init(); |
| 1093 | if (rc) | 1092 | if (rc) |
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index dbb99d1b6f57..cb5888f79007 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h | |||
| @@ -72,6 +72,13 @@ typedef unsigned int sclp_cmdw_t; | |||
| 72 | 72 | ||
| 73 | typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */ | 73 | typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */ |
| 74 | 74 | ||
| 75 | struct sccb_header { | ||
| 76 | u16 length; | ||
| 77 | u8 function_code; | ||
| 78 | u8 control_mask[3]; | ||
| 79 | u16 response_code; | ||
| 80 | } __attribute__((packed)); | ||
| 81 | |||
| 75 | struct gds_subvector { | 82 | struct gds_subvector { |
| 76 | u8 length; | 83 | u8 length; |
| 77 | u8 key; | 84 | u8 key; |
diff --git a/drivers/s390/char/sclp_info.c b/drivers/s390/char/sclp_info.c index 7bcbe643b087..7d21dbb12fcd 100644 --- a/drivers/s390/char/sclp_info.c +++ b/drivers/s390/char/sclp_info.c | |||
| @@ -11,47 +11,97 @@ | |||
| 11 | #include <asm/sclp.h> | 11 | #include <asm/sclp.h> |
| 12 | #include "sclp.h" | 12 | #include "sclp.h" |
| 13 | 13 | ||
| 14 | struct sclp_readinfo_sccb s390_readinfo_sccb; | 14 | struct sclp_readinfo_sccb { |
| 15 | struct sccb_header header; /* 0-7 */ | ||
| 16 | u16 rnmax; /* 8-9 */ | ||
| 17 | u8 rnsize; /* 10 */ | ||
| 18 | u8 _reserved0[24 - 11]; /* 11-23 */ | ||
| 19 | u8 loadparm[8]; /* 24-31 */ | ||
| 20 | u8 _reserved1[48 - 32]; /* 32-47 */ | ||
| 21 | u64 facilities; /* 48-55 */ | ||
| 22 | u8 _reserved2[91 - 56]; /* 56-90 */ | ||
| 23 | u8 flags; /* 91 */ | ||
| 24 | u8 _reserved3[100 - 92]; /* 92-99 */ | ||
| 25 | u32 rnsize2; /* 100-103 */ | ||
| 26 | u64 rnmax2; /* 104-111 */ | ||
| 27 | u8 _reserved4[4096 - 112]; /* 112-4095 */ | ||
| 28 | } __attribute__((packed, aligned(4096))); | ||
| 29 | |||
| 30 | static struct sclp_readinfo_sccb __initdata early_readinfo_sccb; | ||
| 31 | static int __initdata early_readinfo_sccb_valid; | ||
| 15 | 32 | ||
| 16 | void __init sclp_readinfo_early(void) | 33 | void __init sclp_readinfo_early(void) |
| 17 | { | 34 | { |
| 18 | sclp_cmdw_t command; | ||
| 19 | struct sccb_header *sccb; | ||
| 20 | int ret; | 35 | int ret; |
| 36 | int i; | ||
| 37 | struct sclp_readinfo_sccb *sccb; | ||
| 38 | sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED, | ||
| 39 | SCLP_CMDW_READ_SCP_INFO}; | ||
| 21 | 40 | ||
| 22 | __ctl_set_bit(0, 9); /* enable service signal subclass mask */ | 41 | /* Enable service signal subclass mask. */ |
| 23 | 42 | __ctl_set_bit(0, 9); | |
| 24 | sccb = &s390_readinfo_sccb.header; | 43 | sccb = &early_readinfo_sccb; |
| 25 | command = SCLP_CMDW_READ_SCP_INFO_FORCED; | 44 | for (i = 0; i < ARRAY_SIZE(commands); i++) { |
| 26 | while (1) { | 45 | do { |
| 27 | u16 response; | 46 | memset(sccb, 0, sizeof(*sccb)); |
| 28 | 47 | sccb->header.length = sizeof(*sccb); | |
| 29 | memset(&s390_readinfo_sccb, 0, sizeof(s390_readinfo_sccb)); | 48 | sccb->header.control_mask[2] = 0x80; |
| 30 | sccb->length = sizeof(s390_readinfo_sccb); | 49 | ret = sclp_service_call(commands[i], sccb); |
| 31 | sccb->control_mask[2] = 0x80; | 50 | } while (ret == -EBUSY); |
| 32 | |||
| 33 | ret = sclp_service_call(command, &s390_readinfo_sccb); | ||
| 34 | |||
| 35 | if (ret == -EIO) | ||
| 36 | goto out; | ||
| 37 | if (ret == -EBUSY) | ||
| 38 | continue; | ||
| 39 | 51 | ||
| 52 | if (ret) | ||
| 53 | break; | ||
| 40 | __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT | | 54 | __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT | |
| 41 | PSW_MASK_WAIT | PSW_DEFAULT_KEY); | 55 | PSW_MASK_WAIT | PSW_DEFAULT_KEY); |
| 42 | local_irq_disable(); | 56 | local_irq_disable(); |
| 57 | /* | ||
| 58 | * Contents of the sccb might have changed | ||
| 59 | * therefore a barrier is needed. | ||
| 60 | */ | ||
| 43 | barrier(); | 61 | barrier(); |
| 62 | if (sccb->header.response_code == 0x10) { | ||
| 63 | early_readinfo_sccb_valid = 1; | ||
| 64 | break; | ||
| 65 | } | ||
| 66 | if (sccb->header.response_code != 0x1f0) | ||
| 67 | break; | ||
| 68 | } | ||
| 69 | /* Disable service signal subclass mask again. */ | ||
| 70 | __ctl_clear_bit(0, 9); | ||
| 71 | } | ||
| 44 | 72 | ||
| 45 | response = sccb->response_code; | 73 | unsigned long long __init sclp_memory_detect(void) |
| 74 | { | ||
| 75 | unsigned long long memsize; | ||
| 76 | struct sclp_readinfo_sccb *sccb; | ||
| 46 | 77 | ||
| 47 | if (response == 0x10) | 78 | if (!early_readinfo_sccb_valid) |
| 48 | break; | 79 | return 0; |
| 80 | sccb = &early_readinfo_sccb; | ||
| 81 | if (sccb->rnsize) | ||
| 82 | memsize = sccb->rnsize << 20; | ||
| 83 | else | ||
| 84 | memsize = sccb->rnsize2 << 20; | ||
| 85 | if (sccb->rnmax) | ||
| 86 | memsize *= sccb->rnmax; | ||
| 87 | else | ||
| 88 | memsize *= sccb->rnmax2; | ||
| 89 | return memsize; | ||
| 90 | } | ||
| 49 | 91 | ||
| 50 | if (response != 0x1f0 || command == SCLP_CMDW_READ_SCP_INFO) | 92 | /* |
| 51 | break; | 93 | * This function will be called after sclp_memory_detect(), which gets called |
| 94 | * early from early.c code. Therefore the sccb should have valid contents. | ||
| 95 | */ | ||
| 96 | void __init sclp_get_ipl_info(struct sclp_ipl_info *info) | ||
| 97 | { | ||
| 98 | struct sclp_readinfo_sccb *sccb; | ||
| 52 | 99 | ||
| 53 | command = SCLP_CMDW_READ_SCP_INFO; | 100 | if (!early_readinfo_sccb_valid) |
| 54 | } | 101 | return; |
| 55 | out: | 102 | sccb = &early_readinfo_sccb; |
| 56 | __ctl_clear_bit(0, 9); /* disable service signal subclass mask */ | 103 | info->is_valid = 1; |
| 104 | if (sccb->flags & 0x2) | ||
| 105 | info->has_dump = 1; | ||
| 106 | memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN); | ||
| 57 | } | 107 | } |
diff --git a/include/asm-s390/sclp.h b/include/asm-s390/sclp.h index 21ed64773210..ddfaa8db47be 100644 --- a/include/asm-s390/sclp.h +++ b/include/asm-s390/sclp.h | |||
| @@ -11,29 +11,6 @@ | |||
| 11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
| 12 | #include <asm/chpid.h> | 12 | #include <asm/chpid.h> |
| 13 | 13 | ||
| 14 | struct sccb_header { | ||
| 15 | u16 length; | ||
| 16 | u8 function_code; | ||
| 17 | u8 control_mask[3]; | ||
| 18 | u16 response_code; | ||
| 19 | } __attribute__((packed)); | ||
| 20 | |||
| 21 | #define LOADPARM_LEN 8 | ||
| 22 | |||
| 23 | struct sclp_readinfo_sccb { | ||
| 24 | struct sccb_header header; /* 0-7 */ | ||
| 25 | u16 rnmax; /* 8-9 */ | ||
| 26 | u8 rnsize; /* 10 */ | ||
| 27 | u8 _reserved0[24 - 11]; /* 11-23 */ | ||
| 28 | u8 loadparm[LOADPARM_LEN]; /* 24-31 */ | ||
| 29 | u8 _reserved1[91 - 32]; /* 32-90 */ | ||
| 30 | u8 flags; /* 91 */ | ||
| 31 | u8 _reserved2[100 - 92]; /* 92-99 */ | ||
| 32 | u32 rnsize2; /* 100-103 */ | ||
| 33 | u64 rnmax2; /* 104-111 */ | ||
| 34 | u8 _reserved3[4096 - 112]; /* 112-4095 */ | ||
| 35 | } __attribute__((packed, aligned(4096))); | ||
| 36 | |||
| 37 | #define SCLP_CHP_INFO_MASK_SIZE 32 | 14 | #define SCLP_CHP_INFO_MASK_SIZE 32 |
| 38 | 15 | ||
| 39 | struct sclp_chp_info { | 16 | struct sclp_chp_info { |
| @@ -42,12 +19,21 @@ struct sclp_chp_info { | |||
| 42 | u8 configured[SCLP_CHP_INFO_MASK_SIZE]; | 19 | u8 configured[SCLP_CHP_INFO_MASK_SIZE]; |
| 43 | }; | 20 | }; |
| 44 | 21 | ||
| 45 | extern struct sclp_readinfo_sccb s390_readinfo_sccb; | 22 | #define LOADPARM_LEN 8 |
| 46 | extern void sclp_readinfo_early(void); | 23 | |
| 47 | extern int sclp_sdias_blk_count(void); | 24 | struct sclp_ipl_info { |
| 48 | extern int sclp_sdias_copy(void *dest, int blk_num, int nr_blks); | 25 | int is_valid; |
| 49 | extern int sclp_chp_configure(struct chp_id chpid); | 26 | int has_dump; |
| 50 | extern int sclp_chp_deconfigure(struct chp_id chpid); | 27 | char loadparm[LOADPARM_LEN]; |
| 51 | extern int sclp_chp_read_info(struct sclp_chp_info *info); | 28 | }; |
| 29 | |||
| 30 | void sclp_readinfo_early(void); | ||
| 31 | unsigned long long sclp_memory_detect(void); | ||
| 32 | int sclp_sdias_blk_count(void); | ||
| 33 | int sclp_sdias_copy(void *dest, int blk_num, int nr_blks); | ||
| 34 | int sclp_chp_configure(struct chp_id chpid); | ||
| 35 | int sclp_chp_deconfigure(struct chp_id chpid); | ||
| 36 | int sclp_chp_read_info(struct sclp_chp_info *info); | ||
| 37 | void sclp_get_ipl_info(struct sclp_ipl_info *info); | ||
| 52 | 38 | ||
| 53 | #endif /* _ASM_S390_SCLP_H */ | 39 | #endif /* _ASM_S390_SCLP_H */ |
