Heiko Carstens | d90cbd4 | 2009-06-12 10:26:24 +0200 | [diff] [blame] | 1 | /* |
| 2 | * Mini SCLP driver. |
| 3 | * |
Heiko Carstens | a53c8fa | 2012-07-20 11:15:04 +0200 | [diff] [blame] | 4 | * Copyright IBM Corp. 2004, 2009 |
Heiko Carstens | d90cbd4 | 2009-06-12 10:26:24 +0200 | [diff] [blame] | 5 | * |
| 6 | * Author(s): Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>, |
| 7 | * Heiko Carstens <heiko.carstens@de.ibm.com>, |
| 8 | * |
| 9 | */ |
| 10 | |
Jan Glauber | 144d634 | 2011-07-24 10:48:19 +0200 | [diff] [blame] | 11 | #include <linux/linkage.h> |
| 12 | |
Heiko Carstens | d90cbd4 | 2009-06-12 10:26:24 +0200 | [diff] [blame] | 13 | LC_EXT_NEW_PSW = 0x58 # addr of ext int handler |
Martin Schwidefsky | 1844c9b | 2010-02-26 22:37:53 +0100 | [diff] [blame] | 14 | LC_EXT_NEW_PSW_64 = 0x1b0 # addr of ext int handler 64 bit |
Heiko Carstens | d90cbd4 | 2009-06-12 10:26:24 +0200 | [diff] [blame] | 15 | LC_EXT_INT_PARAM = 0x80 # addr of ext int parameter |
| 16 | LC_EXT_INT_CODE = 0x86 # addr of ext int code |
Martin Schwidefsky | 1844c9b | 2010-02-26 22:37:53 +0100 | [diff] [blame] | 17 | LC_AR_MODE_ID = 0xa3 |
Heiko Carstens | d90cbd4 | 2009-06-12 10:26:24 +0200 | [diff] [blame] | 18 | |
| 19 | # |
| 20 | # Subroutine which waits synchronously until either an external interruption |
| 21 | # or a timeout occurs. |
| 22 | # |
| 23 | # Parameters: |
| 24 | # R2 = 0 for no timeout, non-zero for timeout in (approximated) seconds |
| 25 | # |
| 26 | # Returns: |
| 27 | # R2 = 0 on interrupt, 2 on timeout |
| 28 | # R3 = external interruption parameter if R2=0 |
| 29 | # |
| 30 | |
Heiko Carstens | d90cbd4 | 2009-06-12 10:26:24 +0200 | [diff] [blame] | 31 | _sclp_wait_int: |
| 32 | stm %r6,%r15,24(%r15) # save registers |
| 33 | basr %r13,0 # get base register |
| 34 | .LbaseS1: |
| 35 | ahi %r15,-96 # create stack frame |
| 36 | la %r8,LC_EXT_NEW_PSW # register int handler |
Martin Schwidefsky | 1844c9b | 2010-02-26 22:37:53 +0100 | [diff] [blame] | 37 | la %r9,.LextpswS1-.LbaseS1(%r13) |
| 38 | #ifdef CONFIG_64BIT |
| 39 | tm LC_AR_MODE_ID,1 |
| 40 | jno .Lesa1 |
| 41 | la %r8,LC_EXT_NEW_PSW_64 # register int handler 64 bit |
| 42 | la %r9,.LextpswS1_64-.LbaseS1(%r13) |
| 43 | .Lesa1: |
| 44 | #endif |
| 45 | mvc .LoldpswS1-.LbaseS1(16,%r13),0(%r8) |
| 46 | mvc 0(16,%r8),0(%r9) |
Heiko Carstens | 99e639b | 2012-10-31 17:14:39 +0100 | [diff] [blame] | 47 | #ifdef CONFIG_64BIT |
| 48 | epsw %r6,%r7 # set current addressing mode |
| 49 | nill %r6,0x1 # in new psw (31 or 64 bit mode) |
| 50 | nilh %r7,0x8000 |
| 51 | stm %r6,%r7,0(%r8) |
| 52 | #endif |
Heiko Carstens | d90cbd4 | 2009-06-12 10:26:24 +0200 | [diff] [blame] | 53 | lhi %r6,0x0200 # cr mask for ext int (cr0.54) |
| 54 | ltr %r2,%r2 |
| 55 | jz .LsetctS1 |
| 56 | ahi %r6,0x0800 # cr mask for clock int (cr0.52) |
| 57 | stck .LtimeS1-.LbaseS1(%r13) # initiate timeout |
| 58 | al %r2,.LtimeS1-.LbaseS1(%r13) |
| 59 | st %r2,.LtimeS1-.LbaseS1(%r13) |
| 60 | sckc .LtimeS1-.LbaseS1(%r13) |
| 61 | |
| 62 | .LsetctS1: |
| 63 | stctl %c0,%c0,.LctlS1-.LbaseS1(%r13) # enable required interrupts |
| 64 | l %r0,.LctlS1-.LbaseS1(%r13) |
| 65 | lhi %r1,~(0x200 | 0x800) # clear old values |
| 66 | nr %r1,%r0 |
| 67 | or %r1,%r6 # set new value |
| 68 | st %r1,.LctlS1-.LbaseS1(%r13) |
| 69 | lctl %c0,%c0,.LctlS1-.LbaseS1(%r13) |
| 70 | st %r0,.LctlS1-.LbaseS1(%r13) |
| 71 | lhi %r2,2 # return code for timeout |
| 72 | .LloopS1: |
| 73 | lpsw .LwaitpswS1-.LbaseS1(%r13) # wait until interrupt |
| 74 | .LwaitS1: |
| 75 | lh %r7,LC_EXT_INT_CODE |
| 76 | chi %r7,0x1004 # timeout? |
| 77 | je .LtimeoutS1 |
| 78 | chi %r7,0x2401 # service int? |
| 79 | jne .LloopS1 |
| 80 | sr %r2,%r2 |
| 81 | l %r3,LC_EXT_INT_PARAM |
| 82 | .LtimeoutS1: |
| 83 | lctl %c0,%c0,.LctlS1-.LbaseS1(%r13) # restore interrupt setting |
| 84 | # restore old handler |
Martin Schwidefsky | 1844c9b | 2010-02-26 22:37:53 +0100 | [diff] [blame] | 85 | mvc 0(16,%r8),.LoldpswS1-.LbaseS1(%r13) |
Heiko Carstens | d90cbd4 | 2009-06-12 10:26:24 +0200 | [diff] [blame] | 86 | lm %r6,%r15,120(%r15) # restore registers |
| 87 | br %r14 # return to caller |
| 88 | |
| 89 | .align 8 |
| 90 | .LoldpswS1: |
Martin Schwidefsky | 1844c9b | 2010-02-26 22:37:53 +0100 | [diff] [blame] | 91 | .long 0, 0, 0, 0 # old ext int PSW |
Heiko Carstens | d90cbd4 | 2009-06-12 10:26:24 +0200 | [diff] [blame] | 92 | .LextpswS1: |
| 93 | .long 0x00080000, 0x80000000+.LwaitS1 # PSW to handle ext int |
Martin Schwidefsky | 1844c9b | 2010-02-26 22:37:53 +0100 | [diff] [blame] | 94 | #ifdef CONFIG_64BIT |
| 95 | .LextpswS1_64: |
Heiko Carstens | 99e639b | 2012-10-31 17:14:39 +0100 | [diff] [blame] | 96 | .quad 0, .LwaitS1 # PSW to handle ext int, 64 bit |
Martin Schwidefsky | 1844c9b | 2010-02-26 22:37:53 +0100 | [diff] [blame] | 97 | #endif |
Heiko Carstens | d90cbd4 | 2009-06-12 10:26:24 +0200 | [diff] [blame] | 98 | .LwaitpswS1: |
| 99 | .long 0x010a0000, 0x00000000+.LloopS1 # PSW to wait for ext int |
| 100 | .LtimeS1: |
| 101 | .quad 0 # current time |
| 102 | .LctlS1: |
| 103 | .long 0 # CT0 contents |
| 104 | |
| 105 | # |
| 106 | # Subroutine to synchronously issue a service call. |
| 107 | # |
| 108 | # Parameters: |
| 109 | # R2 = command word |
| 110 | # R3 = sccb address |
| 111 | # |
| 112 | # Returns: |
| 113 | # R2 = 0 on success, 1 on failure |
| 114 | # R3 = sccb response code if R2 = 0 |
| 115 | # |
| 116 | |
| 117 | _sclp_servc: |
| 118 | stm %r6,%r15,24(%r15) # save registers |
| 119 | ahi %r15,-96 # create stack frame |
| 120 | lr %r6,%r2 # save command word |
| 121 | lr %r7,%r3 # save sccb address |
| 122 | .LretryS2: |
| 123 | lhi %r2,1 # error return code |
| 124 | .insn rre,0xb2200000,%r6,%r7 # servc |
| 125 | brc 1,.LendS2 # exit if not operational |
| 126 | brc 8,.LnotbusyS2 # go on if not busy |
| 127 | sr %r2,%r2 # wait until no longer busy |
| 128 | bras %r14,_sclp_wait_int |
| 129 | j .LretryS2 # retry |
| 130 | .LnotbusyS2: |
| 131 | sr %r2,%r2 # wait until result |
| 132 | bras %r14,_sclp_wait_int |
| 133 | sr %r2,%r2 |
| 134 | lh %r3,6(%r7) |
| 135 | .LendS2: |
| 136 | lm %r6,%r15,120(%r15) # restore registers |
| 137 | br %r14 |
| 138 | |
| 139 | # |
| 140 | # Subroutine to set up the SCLP interface. |
| 141 | # |
| 142 | # Parameters: |
| 143 | # R2 = 0 to activate, non-zero to deactivate |
| 144 | # |
| 145 | # Returns: |
| 146 | # R2 = 0 on success, non-zero on failure |
| 147 | # |
| 148 | |
| 149 | _sclp_setup: |
| 150 | stm %r6,%r15,24(%r15) # save registers |
| 151 | ahi %r15,-96 # create stack frame |
| 152 | basr %r13,0 # get base register |
| 153 | .LbaseS3: |
| 154 | l %r6,.LsccbS0-.LbaseS3(%r13) # prepare init mask sccb |
| 155 | mvc 0(.LinitendS3-.LinitsccbS3,%r6),.LinitsccbS3-.LbaseS3(%r13) |
| 156 | ltr %r2,%r2 # initialization? |
| 157 | jz .LdoinitS3 # go ahead |
| 158 | # clear masks |
| 159 | xc .LinitmaskS3-.LinitsccbS3(8,%r6),.LinitmaskS3-.LinitsccbS3(%r6) |
| 160 | .LdoinitS3: |
| 161 | l %r2,.LwritemaskS3-.LbaseS3(%r13)# get command word |
| 162 | lr %r3,%r6 # get sccb address |
| 163 | bras %r14,_sclp_servc # issue service call |
| 164 | ltr %r2,%r2 # servc successful? |
| 165 | jnz .LerrorS3 |
| 166 | chi %r3,0x20 # write mask successful? |
| 167 | jne .LerrorS3 |
| 168 | # check masks |
| 169 | la %r2,.LinitmaskS3-.LinitsccbS3(%r6) |
| 170 | l %r1,0(%r2) # receive mask ok? |
| 171 | n %r1,12(%r2) |
| 172 | cl %r1,0(%r2) |
| 173 | jne .LerrorS3 |
| 174 | l %r1,4(%r2) # send mask ok? |
| 175 | n %r1,8(%r2) |
| 176 | cl %r1,4(%r2) |
| 177 | sr %r2,%r2 |
| 178 | je .LendS3 |
| 179 | .LerrorS3: |
| 180 | lhi %r2,1 # error return code |
| 181 | .LendS3: |
| 182 | lm %r6,%r15,120(%r15) # restore registers |
| 183 | br %r14 |
| 184 | .LwritemaskS3: |
| 185 | .long 0x00780005 # SCLP command for write mask |
| 186 | .LinitsccbS3: |
| 187 | .word .LinitendS3-.LinitsccbS3 |
| 188 | .byte 0,0,0,0 |
| 189 | .word 0 |
| 190 | .word 0 |
| 191 | .word 4 |
| 192 | .LinitmaskS3: |
| 193 | .long 0x80000000 |
| 194 | .long 0x40000000 |
| 195 | .long 0 |
| 196 | .long 0 |
| 197 | .LinitendS3: |
| 198 | |
| 199 | # |
| 200 | # Subroutine which prints a given text to the SCLP console. |
| 201 | # |
| 202 | # Parameters: |
| 203 | # R2 = address of nil-terminated ASCII text |
| 204 | # |
| 205 | # Returns: |
| 206 | # R2 = 0 on success, 1 on failure |
| 207 | # |
| 208 | |
| 209 | _sclp_print: |
| 210 | stm %r6,%r15,24(%r15) # save registers |
| 211 | ahi %r15,-96 # create stack frame |
| 212 | basr %r13,0 # get base register |
| 213 | .LbaseS4: |
| 214 | l %r8,.LsccbS0-.LbaseS4(%r13) # prepare write data sccb |
| 215 | mvc 0(.LmtoS4-.LwritesccbS4,%r8),.LwritesccbS4-.LbaseS4(%r13) |
| 216 | la %r7,.LmtoS4-.LwritesccbS4(%r8) # current mto addr |
| 217 | sr %r0,%r0 |
| 218 | l %r10,.Lascebc-.LbaseS4(%r13) # address of translation table |
| 219 | .LinitmtoS4: |
| 220 | # initialize mto |
| 221 | mvc 0(.LmtoendS4-.LmtoS4,%r7),.LmtoS4-.LbaseS4(%r13) |
| 222 | lhi %r6,.LmtoendS4-.LmtoS4 # current mto length |
| 223 | .LloopS4: |
| 224 | ic %r0,0(%r2) # get character |
| 225 | ahi %r2,1 |
| 226 | ltr %r0,%r0 # end of string? |
| 227 | jz .LfinalizemtoS4 |
Peter Oberparleiter | 98f6d1a | 2013-06-05 15:51:57 +0200 | [diff] [blame] | 228 | chi %r0,0x0a # end of line (NL)? |
Heiko Carstens | d90cbd4 | 2009-06-12 10:26:24 +0200 | [diff] [blame] | 229 | jz .LfinalizemtoS4 |
| 230 | stc %r0,0(%r6,%r7) # copy to mto |
| 231 | la %r11,0(%r6,%r7) |
| 232 | tr 0(1,%r11),0(%r10) # translate to EBCDIC |
| 233 | ahi %r6,1 |
| 234 | j .LloopS4 |
| 235 | .LfinalizemtoS4: |
| 236 | sth %r6,0(%r7) # update mto length |
| 237 | lh %r9,.LmdbS4-.LwritesccbS4(%r8) # update mdb length |
| 238 | ar %r9,%r6 |
| 239 | sth %r9,.LmdbS4-.LwritesccbS4(%r8) |
| 240 | lh %r9,.LevbufS4-.LwritesccbS4(%r8)# update evbuf length |
| 241 | ar %r9,%r6 |
| 242 | sth %r9,.LevbufS4-.LwritesccbS4(%r8) |
| 243 | lh %r9,0(%r8) # update sccb length |
| 244 | ar %r9,%r6 |
| 245 | sth %r9,0(%r8) |
Daniel Mack | 3ad2f3f | 2010-02-03 08:01:28 +0800 | [diff] [blame] | 246 | ar %r7,%r6 # update current mto address |
Heiko Carstens | d90cbd4 | 2009-06-12 10:26:24 +0200 | [diff] [blame] | 247 | ltr %r0,%r0 # more characters? |
| 248 | jnz .LinitmtoS4 |
| 249 | l %r2,.LwritedataS4-.LbaseS4(%r13)# write data |
| 250 | lr %r3,%r8 |
| 251 | bras %r14,_sclp_servc |
| 252 | ltr %r2,%r2 # servc successful? |
| 253 | jnz .LendS4 |
| 254 | chi %r3,0x20 # write data successful? |
| 255 | je .LendS4 |
| 256 | lhi %r2,1 # error return code |
| 257 | .LendS4: |
| 258 | lm %r6,%r15,120(%r15) # restore registers |
| 259 | br %r14 |
| 260 | |
| 261 | # |
| 262 | # Function which prints a given text to the SCLP console. |
| 263 | # |
| 264 | # Parameters: |
| 265 | # R2 = address of nil-terminated ASCII text |
| 266 | # |
| 267 | # Returns: |
| 268 | # R2 = 0 on success, 1 on failure |
| 269 | # |
| 270 | |
Jan Glauber | 144d634 | 2011-07-24 10:48:19 +0200 | [diff] [blame] | 271 | ENTRY(_sclp_print_early) |
Heiko Carstens | d90cbd4 | 2009-06-12 10:26:24 +0200 | [diff] [blame] | 272 | stm %r6,%r15,24(%r15) # save registers |
| 273 | ahi %r15,-96 # create stack frame |
Martin Schwidefsky | 1844c9b | 2010-02-26 22:37:53 +0100 | [diff] [blame] | 274 | #ifdef CONFIG_64BIT |
| 275 | tm LC_AR_MODE_ID,1 |
| 276 | jno .Lesa2 |
| 277 | ahi %r15,-80 |
| 278 | stmh %r6,%r15,96(%r15) # store upper register halves |
| 279 | .Lesa2: |
| 280 | #endif |
Heiko Carstens | d90cbd4 | 2009-06-12 10:26:24 +0200 | [diff] [blame] | 281 | lr %r10,%r2 # save string pointer |
| 282 | lhi %r2,0 |
| 283 | bras %r14,_sclp_setup # enable console |
| 284 | ltr %r2,%r2 |
| 285 | jnz .LendS5 |
| 286 | lr %r2,%r10 |
| 287 | bras %r14,_sclp_print # print string |
| 288 | ltr %r2,%r2 |
| 289 | jnz .LendS5 |
| 290 | lhi %r2,1 |
| 291 | bras %r14,_sclp_setup # disable console |
| 292 | .LendS5: |
Martin Schwidefsky | 1844c9b | 2010-02-26 22:37:53 +0100 | [diff] [blame] | 293 | #ifdef CONFIG_64BIT |
| 294 | tm LC_AR_MODE_ID,1 |
| 295 | jno .Lesa3 |
| 296 | lmh %r6,%r15,96(%r15) # store upper register halves |
| 297 | ahi %r15,80 |
| 298 | .Lesa3: |
| 299 | #endif |
Heiko Carstens | d90cbd4 | 2009-06-12 10:26:24 +0200 | [diff] [blame] | 300 | lm %r6,%r15,120(%r15) # restore registers |
| 301 | br %r14 |
| 302 | |
| 303 | .LwritedataS4: |
| 304 | .long 0x00760005 # SCLP command for write data |
| 305 | .LwritesccbS4: |
| 306 | # sccb |
| 307 | .word .LmtoS4-.LwritesccbS4 |
| 308 | .byte 0 |
| 309 | .byte 0,0,0 |
| 310 | .word 0 |
| 311 | |
| 312 | # evbuf |
| 313 | .LevbufS4: |
| 314 | .word .LmtoS4-.LevbufS4 |
| 315 | .byte 0x02 |
| 316 | .byte 0 |
| 317 | .word 0 |
| 318 | |
| 319 | .LmdbS4: |
| 320 | # mdb |
| 321 | .word .LmtoS4-.LmdbS4 |
| 322 | .word 1 |
| 323 | .long 0xd4c4c240 |
| 324 | .long 1 |
| 325 | |
| 326 | # go |
| 327 | .LgoS4: |
| 328 | .word .LmtoS4-.LgoS4 |
| 329 | .word 1 |
| 330 | .long 0 |
| 331 | .byte 0,0,0,0,0,0,0,0 |
| 332 | .byte 0,0,0 |
| 333 | .byte 0 |
| 334 | .byte 0,0,0,0,0,0,0 |
| 335 | .byte 0 |
| 336 | .word 0 |
| 337 | .byte 0,0,0,0,0,0,0,0,0,0 |
| 338 | .byte 0,0,0,0,0,0,0,0 |
| 339 | .byte 0,0,0,0,0,0,0,0 |
| 340 | |
| 341 | .LmtoS4: |
| 342 | .word .LmtoendS4-.LmtoS4 |
| 343 | .word 4 |
| 344 | .word 0x1000 |
| 345 | .byte 0 |
| 346 | .byte 0,0,0 |
| 347 | .LmtoendS4: |
| 348 | |
| 349 | # Global constants |
| 350 | .LsccbS0: |
| 351 | .long _sclp_work_area |
| 352 | .Lascebc: |
| 353 | .long _ascebc |
Heiko Carstens | d90cbd4 | 2009-06-12 10:26:24 +0200 | [diff] [blame] | 354 | |
Michael Holzheu | 1aaf179 | 2009-09-22 22:58:53 +0200 | [diff] [blame] | 355 | .section .data,"aw",@progbits |
Heiko Carstens | d90cbd4 | 2009-06-12 10:26:24 +0200 | [diff] [blame] | 356 | .balign 4096 |
| 357 | _sclp_work_area: |
| 358 | .fill 4096 |
| 359 | .previous |