diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2007-07-10 05:24:09 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-07-10 05:24:42 -0400 |
commit | 05dd25307ca67cbfa0207bbba2e6c79fa97d125b (patch) | |
tree | 4601c5732e71883bffab31a4a786f838e8473f58 /drivers/s390/char | |
parent | bccdbdc9bd7db3a32c14d8a47f1fb66e3de3c92f (diff) |
[S390] sclp: introduce some new interfaces.
Introduce some new interfaces so that random subsystems don't have to
mess around with sclp internal structures.
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/char')
-rw-r--r-- | drivers/s390/char/sclp.h | 7 | ||||
-rw-r--r-- | drivers/s390/char/sclp_info.c | 108 |
2 files changed, 86 insertions, 29 deletions
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 | } |