2 * Copyright IBM Corp. 2015
3 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
5 #include <linux/kernel.h>
6 #include <asm/ebcdic.h>
8 #include <asm/lowcore.h>
9 #include <asm/processor.h>
12 static char _sclp_work_area
[4096] __aligned(PAGE_SIZE
);
14 static void _sclp_wait_int(void)
16 unsigned long cr0
, cr0_new
, psw_mask
, addr
;
17 psw_t psw_ext_save
, psw_wait
;
19 __ctl_store(cr0
, 0, 0);
20 cr0_new
= cr0
| 0x200;
21 __ctl_load(cr0_new
, 0, 0);
23 psw_ext_save
= S390_lowcore
.external_new_psw
;
24 psw_mask
= __extract_psw() & (PSW_MASK_EA
| PSW_MASK_BA
);
25 S390_lowcore
.external_new_psw
.mask
= psw_mask
;
26 psw_wait
.mask
= psw_mask
| PSW_MASK_EXT
| PSW_MASK_WAIT
;
27 S390_lowcore
.ext_int_code
= 0;
32 " stg %[addr],%[psw_wait_addr]\n"
33 " stg %[addr],%[psw_ext_addr]\n"
34 " lpswe %[psw_wait]\n"
36 : [addr
] "=&d" (addr
),
37 [psw_wait_addr
] "=Q" (psw_wait
.addr
),
38 [psw_ext_addr
] "=Q" (S390_lowcore
.external_new_psw
.addr
)
39 : [psw_wait
] "Q" (psw_wait
)
41 } while (S390_lowcore
.ext_int_code
!= EXT_IRQ_SERVICE_SIG
);
43 __ctl_load(cr0
, 0, 0);
44 S390_lowcore
.external_new_psw
= psw_ext_save
;
47 static int _sclp_servc(unsigned int cmd
, char *sccb
)
53 " .insn rre,0xb2200000,%1,%2\n"
55 : "=d" (cc
) : "d" (cmd
), "a" (sccb
)
62 return (*(unsigned short *)(sccb
+ 6) == 0x20) ? 0 : -EIO
;
65 static int _sclp_setup(int disable
)
67 static unsigned char init_sccb
[] = {
69 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
72 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
77 memcpy(_sclp_work_area
, init_sccb
, 28);
78 masks
= (unsigned int *)(_sclp_work_area
+ 12);
82 rc
= _sclp_servc(0x00780005, _sclp_work_area
);
85 if ((masks
[0] & masks
[3]) != masks
[0] ||
86 (masks
[1] & masks
[2]) != masks
[1])
91 static int _sclp_print(const char *str
)
93 static unsigned char write_head
[] = {
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 2 */
99 0x02, 0x00, 0x00, 0x00, /* 10 */
103 0xd4, 0xc4, 0xc2, 0x40, /* 18 */
104 0x00, 0x00, 0x00, 0x01, /* 22 */
108 0x00, 0x00, 0x00, 0x00, /* 30 */
109 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 34 */
110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 42 */
111 0x00, 0x00, 0x00, 0x00, /* 50 */
113 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 56 */
114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 64 */
115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 72 */
118 static unsigned char write_mto
[] = {
123 0x00, 0x00, 0x00, 0x00 /* 6 */
125 unsigned char *ptr
, ch
;
128 memcpy(_sclp_work_area
, write_head
, sizeof(write_head
));
129 ptr
= _sclp_work_area
+ sizeof(write_head
);
131 memcpy(ptr
, write_mto
, sizeof(write_mto
));
132 for (count
= sizeof(write_mto
); (ch
= *str
++) != 0; count
++) {
135 ptr
[count
] = _ascebc
[ch
];
137 /* Update length fields in mto, mdb, evbuf and sccb */
138 *(unsigned short *) ptr
= count
;
139 *(unsigned short *)(_sclp_work_area
+ 14) += count
;
140 *(unsigned short *)(_sclp_work_area
+ 8) += count
;
141 *(unsigned short *)(_sclp_work_area
+ 0) += count
;
145 /* SCLP write data */
146 return _sclp_servc(0x00760005, _sclp_work_area
);
149 int _sclp_print_early(const char *str
)
156 rc
= _sclp_print(str
);
159 return _sclp_setup(1);