Blame view

drivers/s390/char/sclp_early.c 7.17 KB
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
1
2
3
4
5
6
7
8
  /*
   * SCLP early driver
   *
   * Copyright IBM Corp. 2013
   */
  
  #define KMSG_COMPONENT "sclp_early"
  #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
acf6a004e   Michael Holzheu   s390/sclp: Move e...
9
  #include <asm/ctl_reg.h>
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
10
11
12
13
  #include <asm/sclp.h>
  #include <asm/ipl.h>
  #include "sclp_sdias.h"
  #include "sclp.h"
acf6a004e   Michael Holzheu   s390/sclp: Move e...
14
15
16
17
18
19
20
  #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 */
cf813db0b   Heiko Carstens   s390/smp: limit n...
21
22
  	u8	_reserved0[16 - 11];	/* 11-15 */
  	u16	ncpurl;			/* 16-17 */
217a44068   Heiko Carstens   KVM: s390/sclp: c...
23
24
  	u16	cpuoff;			/* 18-19 */
  	u8	_reserved7[24 - 20];	/* 20-23 */
acf6a004e   Michael Holzheu   s390/sclp: Move e...
25
26
27
  	u8	loadparm[8];		/* 24-31 */
  	u8	_reserved1[48 - 32];	/* 32-47 */
  	u64	facilities;		/* 48-55 */
570126d37   Michael Mueller   s390/sclp: add sc...
28
29
30
  	u8	_reserved2a[76 - 56];	/* 56-75 */
  	u32	ibc;			/* 76-79 */
  	u8	_reserved2b[84 - 80];	/* 80-83 */
acf6a004e   Michael Holzheu   s390/sclp: Move e...
31
32
33
34
35
36
37
  	u8	fac84;			/* 84 */
  	u8	fac85;			/* 85 */
  	u8	_reserved3[91 - 86];	/* 86-90 */
  	u8	flags;			/* 91 */
  	u8	_reserved4[100 - 92];	/* 92-99 */
  	u32	rnsize2;		/* 100-103 */
  	u64	rnmax2;			/* 104-111 */
cf813db0b   Heiko Carstens   s390/smp: limit n...
38
39
40
  	u8	_reserved5[120 - 112];	/* 112-119 */
  	u16	hcpua;			/* 120-121 */
  	u8	_reserved6[4096 - 122];	/* 122-4095 */
acf6a004e   Michael Holzheu   s390/sclp: Move e...
41
  } __packed __aligned(PAGE_SIZE);
56e57a84a   Hendrik Brueckner   s390/sclp_early: ...
42
  static char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE) __initdata;
52733e015   Hendrik Brueckner   s390/sclp_early: ...
43
44
  static unsigned int sclp_con_has_vt220 __initdata;
  static unsigned int sclp_con_has_linemode __initdata;
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
45
  static unsigned long sclp_hsa_size;
cf813db0b   Heiko Carstens   s390/smp: limit n...
46
  static unsigned int sclp_max_cpu;
333cce91f   Hendrik Brueckner   s390/sclp_early: ...
47
  static struct sclp_ipl_info sclp_ipl_info;
217a44068   Heiko Carstens   KVM: s390/sclp: c...
48
  static unsigned char sclp_siif;
570126d37   Michael Mueller   s390/sclp: add sc...
49
  static u32 sclp_ibc;
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
50

acf6a004e   Michael Holzheu   s390/sclp: Move e...
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
  u64 sclp_facilities;
  u8 sclp_fac84;
  unsigned long long sclp_rzm;
  unsigned long long sclp_rnmax;
  
  static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb)
  {
  	int rc;
  
  	__ctl_set_bit(0, 9);
  	rc = sclp_service_call(cmd, sccb);
  	if (rc)
  		goto out;
  	__load_psw_mask(PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_EA |
  			PSW_MASK_BA | PSW_MASK_EXT | PSW_MASK_WAIT);
  	local_irq_disable();
  out:
  	/* Contents of the sccb might have changed. */
  	barrier();
  	__ctl_clear_bit(0, 9);
  	return rc;
  }
56e57a84a   Hendrik Brueckner   s390/sclp_early: ...
73
  static int __init sclp_read_info_early(struct read_info_sccb *sccb)
acf6a004e   Michael Holzheu   s390/sclp: Move e...
74
  {
333cce91f   Hendrik Brueckner   s390/sclp_early: ...
75
  	int rc, i;
acf6a004e   Michael Holzheu   s390/sclp: Move e...
76
77
  	sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
  				  SCLP_CMDW_READ_SCP_INFO};
acf6a004e   Michael Holzheu   s390/sclp: Move e...
78
79
80
81
82
83
84
85
86
87
88
  	for (i = 0; i < ARRAY_SIZE(commands); i++) {
  		do {
  			memset(sccb, 0, sizeof(*sccb));
  			sccb->header.length = sizeof(*sccb);
  			sccb->header.function_code = 0x80;
  			sccb->header.control_mask[2] = 0x80;
  			rc = sclp_cmd_sync_early(commands[i], sccb);
  		} while (rc == -EBUSY);
  
  		if (rc)
  			break;
333cce91f   Hendrik Brueckner   s390/sclp_early: ...
89
90
  		if (sccb->header.response_code == 0x10)
  			return 0;
acf6a004e   Michael Holzheu   s390/sclp: Move e...
91
92
93
  		if (sccb->header.response_code != 0x1f0)
  			break;
  	}
333cce91f   Hendrik Brueckner   s390/sclp_early: ...
94
  	return -EIO;
acf6a004e   Michael Holzheu   s390/sclp: Move e...
95
  }
5d5de1a06   Hendrik Brueckner   s390/sclp_early: ...
96
  static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
acf6a004e   Michael Holzheu   s390/sclp: Move e...
97
  {
217a44068   Heiko Carstens   KVM: s390/sclp: c...
98
99
  	struct sclp_cpu_entry *cpue;
  	u16 boot_cpu_address, cpu;
56e57a84a   Hendrik Brueckner   s390/sclp_early: ...
100
  	if (sclp_read_info_early(sccb))
acf6a004e   Michael Holzheu   s390/sclp: Move e...
101
  		return;
acf6a004e   Michael Holzheu   s390/sclp: Move e...
102
103
104
105
106
107
108
  	sclp_facilities = sccb->facilities;
  	sclp_fac84 = sccb->fac84;
  	if (sccb->fac85 & 0x02)
  		S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP;
  	sclp_rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
  	sclp_rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
  	sclp_rzm <<= 20;
570126d37   Michael Mueller   s390/sclp: add sc...
109
  	sclp_ibc = sccb->ibc;
333cce91f   Hendrik Brueckner   s390/sclp_early: ...
110

cf813db0b   Heiko Carstens   s390/smp: limit n...
111
112
113
114
115
116
117
118
  	if (!sccb->hcpua) {
  		if (MACHINE_IS_VM)
  			sclp_max_cpu = 64;
  		else
  			sclp_max_cpu = sccb->ncpurl;
  	} else {
  		sclp_max_cpu = sccb->hcpua + 1;
  	}
217a44068   Heiko Carstens   KVM: s390/sclp: c...
119
120
121
122
123
124
125
126
  	boot_cpu_address = stap();
  	cpue = (void *)sccb + sccb->cpuoff;
  	for (cpu = 0; cpu < sccb->ncpurl; cpue++, cpu++) {
  		if (boot_cpu_address != cpue->address)
  			continue;
  		sclp_siif = cpue->siif;
  		break;
  	}
333cce91f   Hendrik Brueckner   s390/sclp_early: ...
127
128
129
130
131
  	/* Save IPL information */
  	sclp_ipl_info.is_valid = 1;
  	if (sccb->flags & 0x2)
  		sclp_ipl_info.has_dump = 1;
  	memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN);
acf6a004e   Michael Holzheu   s390/sclp: Move e...
132
133
134
135
  }
  
  bool __init sclp_has_linemode(void)
  {
52733e015   Hendrik Brueckner   s390/sclp_early: ...
136
  	return !!sclp_con_has_linemode;
acf6a004e   Michael Holzheu   s390/sclp: Move e...
137
138
139
140
  }
  
  bool __init sclp_has_vt220(void)
  {
52733e015   Hendrik Brueckner   s390/sclp_early: ...
141
  	return !!sclp_con_has_vt220;
acf6a004e   Michael Holzheu   s390/sclp: Move e...
142
143
144
145
146
147
148
149
150
151
152
  }
  
  unsigned long long sclp_get_rnmax(void)
  {
  	return sclp_rnmax;
  }
  
  unsigned long long sclp_get_rzm(void)
  {
  	return sclp_rzm;
  }
cf813db0b   Heiko Carstens   s390/smp: limit n...
153
154
155
156
  unsigned int sclp_get_max_cpu(void)
  {
  	return sclp_max_cpu;
  }
217a44068   Heiko Carstens   KVM: s390/sclp: c...
157
158
159
160
161
  int sclp_has_siif(void)
  {
  	return sclp_siif;
  }
  EXPORT_SYMBOL(sclp_has_siif);
570126d37   Michael Mueller   s390/sclp: add sc...
162
163
164
165
166
  unsigned int sclp_get_ibc(void)
  {
  	return sclp_ibc;
  }
  EXPORT_SYMBOL(sclp_get_ibc);
acf6a004e   Michael Holzheu   s390/sclp: Move e...
167
168
  /*
   * This function will be called after sclp_facilities_detect(), which gets
333cce91f   Hendrik Brueckner   s390/sclp_early: ...
169
170
   * called from early.c code. The sclp_facilities_detect() function retrieves
   * and saves the IPL information.
acf6a004e   Michael Holzheu   s390/sclp: Move e...
171
172
173
   */
  void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
  {
333cce91f   Hendrik Brueckner   s390/sclp_early: ...
174
  	*info = sclp_ipl_info;
acf6a004e   Michael Holzheu   s390/sclp: Move e...
175
  }
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  static int __init sclp_cmd_early(sclp_cmdw_t cmd, void *sccb)
  {
  	int rc;
  
  	do {
  		rc = sclp_cmd_sync_early(cmd, sccb);
  	} while (rc == -EBUSY);
  
  	if (rc)
  		return -EIO;
  	if (((struct sccb_header *) sccb)->response_code != 0x0020)
  		return -EIO;
  	return 0;
  }
  
  static void __init sccb_init_eq_size(struct sdias_sccb *sccb)
  {
  	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;
  }
5d5de1a06   Hendrik Brueckner   s390/sclp_early: ...
203
204
  static int __init sclp_set_event_mask(struct init_sccb *sccb,
  				      unsigned long receive_mask,
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
205
206
  				      unsigned long send_mask)
  {
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
207
208
209
210
211
212
213
  	memset(sccb, 0, sizeof(*sccb));
  	sccb->header.length = sizeof(*sccb);
  	sccb->mask_length = sizeof(sccb_mask_t);
  	sccb->receive_mask = receive_mask;
  	sccb->send_mask = send_mask;
  	return sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_MASK, sccb);
  }
5d5de1a06   Hendrik Brueckner   s390/sclp_early: ...
214
  static long __init sclp_hsa_size_init(struct sdias_sccb *sccb)
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
215
  {
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
216
217
218
  	sccb_init_eq_size(sccb);
  	if (sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_DATA, sccb))
  		return -EIO;
9499934f7   Michael Holzheu   s390/sclp_early: ...
219
220
221
  	if (sccb->evbuf.blk_cnt == 0)
  		return 0;
  	return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
222
  }
5d5de1a06   Hendrik Brueckner   s390/sclp_early: ...
223
  static long __init sclp_hsa_copy_wait(struct sccb_header *sccb)
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
224
  {
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
225
226
227
228
  	memset(sccb, 0, PAGE_SIZE);
  	sccb->length = PAGE_SIZE;
  	if (sclp_cmd_early(SCLP_CMDW_READ_EVENT_DATA, sccb))
  		return -EIO;
9499934f7   Michael Holzheu   s390/sclp_early: ...
229
230
  	if (((struct sdias_sccb *) sccb)->evbuf.blk_cnt == 0)
  		return 0;
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
231
232
233
234
235
236
237
  	return (((struct sdias_sccb *) sccb)->evbuf.blk_cnt - 1) * PAGE_SIZE;
  }
  
  unsigned long sclp_get_hsa_size(void)
  {
  	return sclp_hsa_size;
  }
5d5de1a06   Hendrik Brueckner   s390/sclp_early: ...
238
  static void __init sclp_hsa_size_detect(void *sccb)
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
239
240
241
242
  {
  	long size;
  
  	/* First try synchronous interface (LPAR) */
5d5de1a06   Hendrik Brueckner   s390/sclp_early: ...
243
  	if (sclp_set_event_mask(sccb, 0, 0x40000010))
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
244
  		return;
5d5de1a06   Hendrik Brueckner   s390/sclp_early: ...
245
  	size = sclp_hsa_size_init(sccb);
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
246
247
248
249
250
  	if (size < 0)
  		return;
  	if (size != 0)
  		goto out;
  	/* Then try asynchronous interface (z/VM) */
5d5de1a06   Hendrik Brueckner   s390/sclp_early: ...
251
  	if (sclp_set_event_mask(sccb, 0x00000010, 0x40000010))
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
252
  		return;
5d5de1a06   Hendrik Brueckner   s390/sclp_early: ...
253
  	size = sclp_hsa_size_init(sccb);
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
254
255
  	if (size < 0)
  		return;
5d5de1a06   Hendrik Brueckner   s390/sclp_early: ...
256
  	size = sclp_hsa_copy_wait(sccb);
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
257
258
259
  	if (size < 0)
  		return;
  out:
e657d8fe2   Michael Holzheu   s390/sclp: Determ...
260
261
  	sclp_hsa_size = size;
  }
7b50da53f   Michael Holzheu   s390/sclp: Consol...
262

52733e015   Hendrik Brueckner   s390/sclp_early: ...
263
264
  static unsigned int __init sclp_con_check_linemode(struct init_sccb *sccb)
  {
ea61a579a   Martin Schwidefsky   s390/sclp: reduce...
265
  	if (!(sccb->sclp_send_mask & EVTYP_OPCMD_MASK))
52733e015   Hendrik Brueckner   s390/sclp_early: ...
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  		return 0;
  	if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK)))
  		return 0;
  	return 1;
  }
  
  static void __init sclp_console_detect(struct init_sccb *sccb)
  {
  	if (sccb->header.response_code != 0x20)
  		return;
  
  	if (sccb->sclp_send_mask & EVTYP_VT220MSG_MASK)
  		sclp_con_has_vt220 = 1;
  
  	if (sclp_con_check_linemode(sccb))
  		sclp_con_has_linemode = 1;
  }
7b50da53f   Michael Holzheu   s390/sclp: Consol...
283
284
  void __init sclp_early_detect(void)
  {
5d5de1a06   Hendrik Brueckner   s390/sclp_early: ...
285
286
287
288
  	void *sccb = &sccb_early;
  
  	sclp_facilities_detect(sccb);
  	sclp_hsa_size_detect(sccb);
52733e015   Hendrik Brueckner   s390/sclp_early: ...
289
290
291
292
  
  	/* Turn off SCLP event notifications.  Also save remote masks in the
  	 * sccb.  These are sufficient to detect sclp console capabilities.
  	 */
5d5de1a06   Hendrik Brueckner   s390/sclp_early: ...
293
  	sclp_set_event_mask(sccb, 0, 0);
52733e015   Hendrik Brueckner   s390/sclp_early: ...
294
  	sclp_console_detect(sccb);
7b50da53f   Michael Holzheu   s390/sclp: Consol...
295
  }