summaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/sclp.S
blob: ada0c07fe1a8744ecf989093720422cac1429e66 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
/*
 * Mini SCLP driver.
 *
 * Copyright IBM Corp. 2004, 2009
 *
 *   Author(s):	Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>,
 *		Heiko Carstens <heiko.carstens@de.ibm.com>,
 *
 */

#include <linux/linkage.h>
#include <asm/irq.h>

LC_EXT_NEW_PSW		= 0x58			# addr of ext int handler
LC_EXT_NEW_PSW_64	= 0x1b0			# addr of ext int handler 64 bit
LC_EXT_INT_PARAM	= 0x80			# addr of ext int parameter
LC_EXT_INT_CODE		= 0x86			# addr of ext int code
LC_AR_MODE_ID		= 0xa3

#
# Subroutine which waits synchronously until either an external interruption
# or a timeout occurs.
#
# Parameters:
#   R2	= 0 for no timeout, non-zero for timeout in (approximated) seconds
#
# Returns:
#   R2	= 0 on interrupt, 2 on timeout
#   R3	= external interruption parameter if R2=0
#

_sclp_wait_int:
	stm	%r6,%r15,24(%r15)		# save registers
	basr	%r13,0				# get base register
.LbaseS1:
	ahi	%r15,-96			# create stack frame
	la	%r8,LC_EXT_NEW_PSW		# register int handler
	la	%r9,.LextpswS1-.LbaseS1(%r13)
	tm	LC_AR_MODE_ID,1
	jno	.Lesa1
	la	%r8,LC_EXT_NEW_PSW_64		# register int handler 64 bit
	la	%r9,.LextpswS1_64-.LbaseS1(%r13)
.Lesa1:
	mvc	.LoldpswS1-.LbaseS1(16,%r13),0(%r8)
	mvc	0(16,%r8),0(%r9)
	epsw	%r6,%r7				# set current addressing mode
	nill	%r6,0x1				# in new psw (31 or 64 bit mode)
	nilh	%r7,0x8000
	stm	%r6,%r7,0(%r8)
	lhi	%r6,0x0200			# cr mask for ext int (cr0.54)
	ltr	%r2,%r2
	jz	.LsetctS1
	ahi	%r6,0x0800			# cr mask for clock int (cr0.52)
	stck	.LtimeS1-.LbaseS1(%r13)		# initiate timeout
	al	%r2,.LtimeS1-.LbaseS1(%r13)
	st	%r2,.LtimeS1-.LbaseS1(%r13)
	sckc	.LtimeS1-.LbaseS1(%r13)

.LsetctS1:
	stctl	%c0,%c0,.LctlS1-.LbaseS1(%r13)	# enable required interrupts
	l	%r0,.LctlS1-.LbaseS1(%r13)
	lhi	%r1,~(0x200 | 0x800)		# clear old values
	nr	%r1,%r0
	or	%r1,%r6				# set new value
	st	%r1,.LctlS1-.LbaseS1(%r13)
	lctl	%c0,%c0,.LctlS1-.LbaseS1(%r13)
	st	%r0,.LctlS1-.LbaseS1(%r13)
	lhi	%r2,2				# return code for timeout
.LloopS1:
	lpsw	.LwaitpswS1-.LbaseS1(%r13)	# wait until interrupt
.LwaitS1:
	lh	%r7,LC_EXT_INT_CODE
	chi	%r7,EXT_IRQ_CLK_COMP		# timeout?
	je	.LtimeoutS1
	chi	%r7,EXT_IRQ_SERVICE_SIG		# service int?
	jne	.LloopS1
	sr	%r2,%r2
	l	%r3,LC_EXT_INT_PARAM
.LtimeoutS1:
	lctl	%c0,%c0,.LctlS1-.LbaseS1(%r13)	# restore interrupt setting
	# restore old handler
	mvc	0(16,%r8),.LoldpswS1-.LbaseS1(%r13)
	lm	%r6,%r15,120(%r15)		# restore registers
	br	%r14				# return to caller

	.align	8
.LoldpswS1:
	.long	0, 0, 0, 0			# old ext int PSW
.LextpswS1:
	.long	0x00080000, 0x80000000+.LwaitS1	# PSW to handle ext int
.LextpswS1_64:
	.quad	0, .LwaitS1			# PSW to handle ext int, 64 bit
.LwaitpswS1:
	.long	0x010a0000, 0x00000000+.LloopS1	# PSW to wait for ext int
.LtimeS1:
	.quad	0				# current time
.LctlS1:
	.long	0				# CT0 contents

#
# Subroutine to synchronously issue a service call.
#
# Parameters:
#   R2	= command word
#   R3	= sccb address
#
# Returns:
#   R2	= 0 on success, 1 on failure
#   R3	= sccb response code if R2 = 0
#

_sclp_servc:
	stm	%r6,%r15,24(%r15)		# save registers
	ahi	%r15,-96			# create stack frame
	lr	%r6,%r2				# save command word
	lr	%r7,%r3				# save sccb address
.LretryS2:
	lhi	%r2,1				# error return code
	.insn	rre,0xb2200000,%r6,%r7		# servc
	brc	1,.LendS2			# exit if not operational
	brc	8,.LnotbusyS2			# go on if not busy
	sr	%r2,%r2				# wait until no longer busy
	bras	%r14,_sclp_wait_int
	j	.LretryS2			# retry
.LnotbusyS2:
	sr	%r2,%r2				# wait until result
	bras	%r14,_sclp_wait_int
	sr	%r2,%r2
	lh	%r3,6(%r7)
.LendS2:
	lm	%r6,%r15,120(%r15)		# restore registers
	br	%r14

#
# Subroutine to set up the SCLP interface.
#
# Parameters:
#   R2	= 0 to activate, non-zero to deactivate
#
# Returns:
#   R2	= 0 on success, non-zero on failure
#

_sclp_setup:
	stm	%r6,%r15,24(%r15)		# save registers
	ahi	%r15,-96			# create stack frame
	basr	%r13,0				# get base register
.LbaseS3:
	l	%r6,.LsccbS0-.LbaseS3(%r13)	# prepare init mask sccb
	mvc	0(.LinitendS3-.LinitsccbS3,%r6),.LinitsccbS3-.LbaseS3(%r13)
	ltr	%r2,%r2				# initialization?
	jz	.LdoinitS3			# go ahead
	# clear masks
	xc	.LinitmaskS3-.LinitsccbS3(8,%r6),.LinitmaskS3-.LinitsccbS3(%r6)
.LdoinitS3:
	l	%r2,.LwritemaskS3-.LbaseS3(%r13)# get command word
	lr	%r3,%r6				# get sccb address
	bras	%r14,_sclp_servc		# issue service call
	ltr	%r2,%r2				# servc successful?
	jnz	.LerrorS3
	chi	%r3,0x20			# write mask successful?
	jne	.LerrorS3
	# check masks
	la	%r2,.LinitmaskS3-.LinitsccbS3(%r6)
	l	%r1,0(%r2)			# receive mask ok?
	n	%r1,12(%r2)
	cl	%r1,0(%r2)
	jne	.LerrorS3
	l	%r1,4(%r2)			# send mask ok?
	n	%r1,8(%r2)
	cl	%r1,4(%r2)
	sr	%r2,%r2
	je	.LendS3
.LerrorS3:
	lhi	%r2,1				# error return code
.LendS3:
	lm	%r6,%r15,120(%r15)		# restore registers
	br	%r14
.LwritemaskS3:
	.long	0x00780005			# SCLP command for write mask
.LinitsccbS3:
	.word	.LinitendS3-.LinitsccbS3
	.byte	0,0,0,0
	.word	0
	.word	0
	.word	4
.LinitmaskS3:
	.long	0x80000000
	.long	0x40000000
	.long	0
	.long	0
.LinitendS3:

#
# Subroutine which prints a given text to the SCLP console.
#
# Parameters:
#   R2	= address of nil-terminated ASCII text
#
# Returns:
#   R2	= 0 on success, 1 on failure
#

_sclp_print:
	stm	%r6,%r15,24(%r15)		# save registers
	ahi	%r15,-96			# create stack frame
	basr	%r13,0				# get base register
.LbaseS4:
	l	%r8,.LsccbS0-.LbaseS4(%r13)	# prepare write data sccb
	mvc	0(.LmtoS4-.LwritesccbS4,%r8),.LwritesccbS4-.LbaseS4(%r13)
	la	%r7,.LmtoS4-.LwritesccbS4(%r8)	# current mto addr
	sr	%r0,%r0
	l	%r10,.Lascebc-.LbaseS4(%r13)	# address of translation table
.LinitmtoS4:
	# initialize mto
	mvc	0(.LmtoendS4-.LmtoS4,%r7),.LmtoS4-.LbaseS4(%r13)
	lhi	%r6,.LmtoendS4-.LmtoS4		# current mto length
.LloopS4:
	ic	%r0,0(%r2)			# get character
	ahi	%r2,1
	ltr	%r0,%r0				# end of string?
	jz	.LfinalizemtoS4
	chi	%r0,0x0a			# end of line (NL)?
	jz	.LfinalizemtoS4
	stc	%r0,0(%r6,%r7)			# copy to mto
	la	%r11,0(%r6,%r7)
	tr	0(1,%r11),0(%r10)		# translate to EBCDIC
	ahi	%r6,1
	j	.LloopS4
.LfinalizemtoS4:
	sth	%r6,0(%r7)			# update mto length
	lh	%r9,.LmdbS4-.LwritesccbS4(%r8)	# update mdb length
	ar	%r9,%r6
	sth	%r9,.LmdbS4-.LwritesccbS4(%r8)
	lh	%r9,.LevbufS4-.LwritesccbS4(%r8)# update evbuf length
	ar	%r9,%r6
	sth	%r9,.LevbufS4-.LwritesccbS4(%r8)
	lh	%r9,0(%r8)			# update sccb length
	ar	%r9,%r6
	sth	%r9,0(%r8)
	ar	%r7,%r6				# update current mto address
	ltr	%r0,%r0				# more characters?
	jnz	.LinitmtoS4
	l	%r2,.LwritedataS4-.LbaseS4(%r13)# write data
	lr	%r3,%r8
	bras	%r14,_sclp_servc
	ltr	%r2,%r2				# servc successful?
	jnz	.LendS4
	chi	%r3,0x20			# write data successful?
	je	.LendS4
	lhi	%r2,1				# error return code
.LendS4:
	lm	%r6,%r15,120(%r15)		# restore registers
	br	%r14

#
# Function which prints a given text to the SCLP console.
#
# Parameters:
#   R2	= address of nil-terminated ASCII text
#
# Returns:
#   R2	= 0 on success, 1 on failure
#

ENTRY(_sclp_print_early)
	stm	%r6,%r15,24(%r15)		# save registers
	ahi	%r15,-96			# create stack frame
	tm	LC_AR_MODE_ID,1
	jno	.Lesa2
	ahi	%r15,-80
	stmh	%r6,%r15,96(%r15)		# store upper register halves
	basr	%r13,0
	lmh	%r0,%r15,.Lzeroes-.(%r13)	# clear upper register halves
.Lesa2:
	lr	%r10,%r2			# save string pointer
	lhi	%r2,0
	bras	%r14,_sclp_setup		# enable console
	ltr	%r2,%r2
	jnz	.LendS5
	lr	%r2,%r10
	bras	%r14,_sclp_print		# print string
	ltr	%r2,%r2
	jnz	.LendS5
	lhi	%r2,1
	bras	%r14,_sclp_setup		# disable console
.LendS5:
	tm	LC_AR_MODE_ID,1
	jno	.Lesa3
	lgfr	%r2,%r2				# sign extend return value
	lmh	%r6,%r15,96(%r15)		# restore upper register halves
	ahi	%r15,80
.Lesa3:
	lm	%r6,%r15,120(%r15)		# restore registers
	br	%r14
.Lzeroes:
	.fill	64,4,0

.LwritedataS4:
	.long	0x00760005			# SCLP command for write data
.LwritesccbS4:
	# sccb
	.word	.LmtoS4-.LwritesccbS4
	.byte	0
	.byte	0,0,0
	.word	0

	# evbuf
.LevbufS4:
	.word	.LmtoS4-.LevbufS4
	.byte	0x02
	.byte	0
	.word	0

.LmdbS4:
	# mdb
	.word	.LmtoS4-.LmdbS4
	.word	1
	.long	0xd4c4c240
	.long	1

	# go
.LgoS4:
	.word	.LmtoS4-.LgoS4
	.word	1
	.long	0
	.byte	0,0,0,0,0,0,0,0
	.byte	0,0,0
	.byte	0
	.byte	0,0,0,0,0,0,0
	.byte	0
	.word	0
	.byte	0,0,0,0,0,0,0,0,0,0
	.byte	0,0,0,0,0,0,0,0
	.byte	0,0,0,0,0,0,0,0

.LmtoS4:
	.word	.LmtoendS4-.LmtoS4
	.word	4
	.word	0x1000
	.byte	0
	.byte	0,0,0
.LmtoendS4:

	# Global constants
.LsccbS0:
	.long	_sclp_work_area
.Lascebc:
	.long	_ascebc

.section .data,"aw",@progbits
	.balign 4096
_sclp_work_area:
	.fill	4096
.previous