blob: ba004fd43c05ad651275759f51e26fc9fb0b218e [file] [log] [blame]
Heiko Carstens08d07962008-01-26 14:10:56 +01001/*
2 * drivers/s390/char/sclp_cmd.c
3 *
4 * Copyright IBM Corp. 2007
5 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
6 */
7
8#include <linux/completion.h>
9#include <linux/init.h>
10#include <linux/errno.h>
11#include <linux/slab.h>
12#include <linux/string.h>
13#include <asm/sclp.h>
14#include "sclp.h"
15
16#define TAG "sclp_cmd: "
17
18#define SCLP_CMDW_READ_SCP_INFO 0x00020001
19#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
20
21struct read_info_sccb {
22 struct sccb_header header; /* 0-7 */
23 u16 rnmax; /* 8-9 */
24 u8 rnsize; /* 10 */
25 u8 _reserved0[24 - 11]; /* 11-15 */
26 u8 loadparm[8]; /* 24-31 */
27 u8 _reserved1[48 - 32]; /* 32-47 */
28 u64 facilities; /* 48-55 */
29 u8 _reserved2[84 - 56]; /* 56-83 */
30 u8 fac84; /* 84 */
31 u8 _reserved3[91 - 85]; /* 85-90 */
32 u8 flags; /* 91 */
33 u8 _reserved4[100 - 92]; /* 92-99 */
34 u32 rnsize2; /* 100-103 */
35 u64 rnmax2; /* 104-111 */
36 u8 _reserved5[4096 - 112]; /* 112-4095 */
37} __attribute__((packed, aligned(PAGE_SIZE)));
38
39static struct read_info_sccb __initdata early_read_info_sccb;
40static int __initdata early_read_info_sccb_valid;
41
42u64 sclp_facilities;
43static u8 sclp_fac84;
44
45static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb)
46{
47 int rc;
48
49 __ctl_set_bit(0, 9);
50 rc = sclp_service_call(cmd, sccb);
51 if (rc)
52 goto out;
53 __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
54 PSW_MASK_WAIT | PSW_DEFAULT_KEY);
55 local_irq_disable();
56out:
57 /* Contents of the sccb might have changed. */
58 barrier();
59 __ctl_clear_bit(0, 9);
60 return rc;
61}
62
63void __init sclp_read_info_early(void)
64{
65 int rc;
66 int i;
67 struct read_info_sccb *sccb;
68 sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
69 SCLP_CMDW_READ_SCP_INFO};
70
71 sccb = &early_read_info_sccb;
72 for (i = 0; i < ARRAY_SIZE(commands); i++) {
73 do {
74 memset(sccb, 0, sizeof(*sccb));
75 sccb->header.length = sizeof(*sccb);
76 sccb->header.control_mask[2] = 0x80;
77 rc = sclp_cmd_sync_early(commands[i], sccb);
78 } while (rc == -EBUSY);
79
80 if (rc)
81 break;
82 if (sccb->header.response_code == 0x10) {
83 early_read_info_sccb_valid = 1;
84 break;
85 }
86 if (sccb->header.response_code != 0x1f0)
87 break;
88 }
89}
90
91void __init sclp_facilities_detect(void)
92{
93 if (!early_read_info_sccb_valid)
94 return;
95 sclp_facilities = early_read_info_sccb.facilities;
96 sclp_fac84 = early_read_info_sccb.fac84;
97}
98
99unsigned long long __init sclp_memory_detect(void)
100{
101 unsigned long long memsize;
102 struct read_info_sccb *sccb;
103
104 if (!early_read_info_sccb_valid)
105 return 0;
106 sccb = &early_read_info_sccb;
107 if (sccb->rnsize)
108 memsize = sccb->rnsize << 20;
109 else
110 memsize = sccb->rnsize2 << 20;
111 if (sccb->rnmax)
112 memsize *= sccb->rnmax;
113 else
114 memsize *= sccb->rnmax2;
115 return memsize;
116}
117
118/*
119 * This function will be called after sclp_memory_detect(), which gets called
120 * early from early.c code. Therefore the sccb should have valid contents.
121 */
122void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
123{
124 struct read_info_sccb *sccb;
125
126 if (!early_read_info_sccb_valid)
127 return;
128 sccb = &early_read_info_sccb;
129 info->is_valid = 1;
130 if (sccb->flags & 0x2)
131 info->has_dump = 1;
132 memcpy(&info->loadparm, &sccb->loadparm, LOADPARM_LEN);
133}
134
135static void sclp_sync_callback(struct sclp_req *req, void *data)
136{
137 struct completion *completion = data;
138
139 complete(completion);
140}
141
142static int do_sync_request(sclp_cmdw_t cmd, void *sccb)
143{
144 struct completion completion;
145 struct sclp_req *request;
146 int rc;
147
148 request = kzalloc(sizeof(*request), GFP_KERNEL);
149 if (!request)
150 return -ENOMEM;
151 request->command = cmd;
152 request->sccb = sccb;
153 request->status = SCLP_REQ_FILLED;
154 request->callback = sclp_sync_callback;
155 request->callback_data = &completion;
156 init_completion(&completion);
157
158 /* Perform sclp request. */
159 rc = sclp_add_request(request);
160 if (rc)
161 goto out;
162 wait_for_completion(&completion);
163
164 /* Check response. */
165 if (request->status != SCLP_REQ_DONE) {
166 printk(KERN_WARNING TAG "sync request failed "
167 "(cmd=0x%08x, status=0x%02x)\n", cmd, request->status);
168 rc = -EIO;
169 }
170out:
171 kfree(request);
172 return rc;
173}
174
175/*
176 * CPU configuration related functions.
177 */
178
179#define SCLP_CMDW_READ_CPU_INFO 0x00010001
180#define SCLP_CMDW_CONFIGURE_CPU 0x00110001
181#define SCLP_CMDW_DECONFIGURE_CPU 0x00100001
182
183struct read_cpu_info_sccb {
184 struct sccb_header header;
185 u16 nr_configured;
186 u16 offset_configured;
187 u16 nr_standby;
188 u16 offset_standby;
189 u8 reserved[4096 - 16];
190} __attribute__((packed, aligned(PAGE_SIZE)));
191
192static struct read_cpu_info_sccb __initdata early_read_cpu_info_sccb;
193static struct sclp_cpu_info __initdata sclp_cpu_info;
194
195static void sclp_fill_cpu_info(struct sclp_cpu_info *info,
196 struct read_cpu_info_sccb *sccb)
197{
198 char *page = (char *) sccb;
199
200 memset(info, 0, sizeof(*info));
201 info->configured = sccb->nr_configured;
202 info->standby = sccb->nr_standby;
203 info->combined = sccb->nr_configured + sccb->nr_standby;
204 info->has_cpu_type = sclp_fac84 & 0x1;
205 memcpy(&info->cpu, page + sccb->offset_configured,
206 info->combined * sizeof(struct sclp_cpu_entry));
207}
208
209void __init sclp_read_cpu_info_early(void)
210{
211 int rc;
212 struct read_cpu_info_sccb *sccb;
213
214 if (!SCLP_HAS_CPU_INFO)
215 return;
216
217 sccb = &early_read_cpu_info_sccb;
218 do {
219 memset(sccb, 0, sizeof(*sccb));
220 sccb->header.length = sizeof(*sccb);
221 rc = sclp_cmd_sync_early(SCLP_CMDW_READ_CPU_INFO, sccb);
222 } while (rc == -EBUSY);
223
224 if (rc)
225 return;
226 if (sccb->header.response_code != 0x10)
227 return;
228 sclp_fill_cpu_info(&sclp_cpu_info, sccb);
229}
230
231static int __init sclp_get_cpu_info_early(struct sclp_cpu_info *info)
232{
233 if (!SCLP_HAS_CPU_INFO)
234 return -EOPNOTSUPP;
235 *info = sclp_cpu_info;
236 return 0;
237}
238
239static int sclp_get_cpu_info_late(struct sclp_cpu_info *info)
240{
241 int rc;
242 struct read_cpu_info_sccb *sccb;
243
244 if (!SCLP_HAS_CPU_INFO)
245 return -EOPNOTSUPP;
246 sccb = (struct read_cpu_info_sccb *) __get_free_page(GFP_KERNEL
247 | GFP_DMA);
248 if (!sccb)
249 return -ENOMEM;
250 memset(sccb, 0, sizeof(*sccb));
251 sccb->header.length = sizeof(*sccb);
252 rc = do_sync_request(SCLP_CMDW_READ_CPU_INFO, sccb);
253 if (rc)
254 goto out;
255 if (sccb->header.response_code != 0x0010) {
256 printk(KERN_WARNING TAG "readcpuinfo failed "
257 "(response=0x%04x)\n", sccb->header.response_code);
258 rc = -EIO;
259 goto out;
260 }
261 sclp_fill_cpu_info(info, sccb);
262out:
263 free_page((unsigned long) sccb);
264 return rc;
265}
266
267int __init_refok sclp_get_cpu_info(struct sclp_cpu_info *info)
268{
269 if (slab_is_available())
270 return sclp_get_cpu_info_late(info);
271 return sclp_get_cpu_info_early(info);
272}
273
274struct cpu_configure_sccb {
275 struct sccb_header header;
276} __attribute__((packed, aligned(8)));
277
278static int do_cpu_configure(sclp_cmdw_t cmd)
279{
280 struct cpu_configure_sccb *sccb;
281 int rc;
282
283 if (!SCLP_HAS_CPU_RECONFIG)
284 return -EOPNOTSUPP;
285 /*
286 * This is not going to cross a page boundary since we force
287 * kmalloc to have a minimum alignment of 8 bytes on s390.
288 */
289 sccb = kzalloc(sizeof(*sccb), GFP_KERNEL | GFP_DMA);
290 if (!sccb)
291 return -ENOMEM;
292 sccb->header.length = sizeof(*sccb);
293 rc = do_sync_request(cmd, sccb);
294 if (rc)
295 goto out;
296 switch (sccb->header.response_code) {
297 case 0x0020:
298 case 0x0120:
299 break;
300 default:
301 printk(KERN_WARNING TAG "configure cpu failed (cmd=0x%08x, "
302 "response=0x%04x)\n", cmd, sccb->header.response_code);
303 rc = -EIO;
304 break;
305 }
306out:
307 kfree(sccb);
308 return rc;
309}
310
311int sclp_cpu_configure(u8 cpu)
312{
313 return do_cpu_configure(SCLP_CMDW_CONFIGURE_CPU | cpu << 8);
314}
315
316int sclp_cpu_deconfigure(u8 cpu)
317{
318 return do_cpu_configure(SCLP_CMDW_DECONFIGURE_CPU | cpu << 8);
319}