1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright IBM Corp. 2015
4 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
7 #include <linux/kernel.h>
8 #include <asm/processor.h>
9 #include <asm/lowcore.h>
10 #include <asm/ebcdic.h>
15 char sclp_early_sccb
[PAGE_SIZE
] __aligned(PAGE_SIZE
) __section(.data
);
16 int sclp_init_state
__section(.data
) = sclp_init_state_uninitialized
;
18 void sclp_early_wait_irq(void)
20 unsigned long psw_mask
, addr
;
21 psw_t psw_ext_save
, psw_wait
;
22 union ctlreg0 cr0
, cr0_new
;
24 __ctl_store(cr0
.val
, 0, 0);
25 cr0_new
.val
= cr0
.val
& ~CR0_IRQ_SUBCLASS_MASK
;
28 __ctl_load(cr0_new
.val
, 0, 0);
30 psw_ext_save
= S390_lowcore
.external_new_psw
;
31 psw_mask
= __extract_psw();
32 S390_lowcore
.external_new_psw
.mask
= psw_mask
;
33 psw_wait
.mask
= psw_mask
| PSW_MASK_EXT
| PSW_MASK_WAIT
;
34 S390_lowcore
.ext_int_code
= 0;
39 " stg %[addr],%[psw_wait_addr]\n"
40 " stg %[addr],%[psw_ext_addr]\n"
41 " lpswe %[psw_wait]\n"
43 : [addr
] "=&d" (addr
),
44 [psw_wait_addr
] "=Q" (psw_wait
.addr
),
45 [psw_ext_addr
] "=Q" (S390_lowcore
.external_new_psw
.addr
)
46 : [psw_wait
] "Q" (psw_wait
)
48 } while (S390_lowcore
.ext_int_code
!= EXT_IRQ_SERVICE_SIG
);
50 S390_lowcore
.external_new_psw
= psw_ext_save
;
51 __ctl_load(cr0
.val
, 0, 0);
54 int sclp_early_cmd(sclp_cmdw_t cmd
, void *sccb
)
59 raw_local_irq_save(flags
);
60 rc
= sclp_service_call(cmd
, sccb
);
63 sclp_early_wait_irq();
65 raw_local_irq_restore(flags
);
70 struct sccb_header header
;
74 /* Output multi-line text using SCLP Message interface. */
75 static void sclp_early_print_lm(const char *str
, unsigned int len
)
77 unsigned char *ptr
, *end
, ch
;
78 unsigned int count
, offset
;
79 struct write_sccb
*sccb
;
85 sccb
= (struct write_sccb
*) &sclp_early_sccb
;
86 end
= (unsigned char *) sccb
+ sizeof(sclp_early_sccb
) - 1;
87 memset(sccb
, 0, sizeof(*sccb
));
88 ptr
= (unsigned char *) &sccb
->msg
.mdb
.mto
;
91 for (count
= sizeof(*mto
); offset
< len
; count
++) {
93 if ((ch
== 0x0a) || (ptr
+ count
> end
))
95 ptr
[count
] = _ascebc
[ch
];
97 mto
= (struct mto
*) ptr
;
98 memset(mto
, 0, sizeof(*mto
));
101 mto
->line_type_flags
= LNTPFLGS_ENDTEXT
;
103 } while ((offset
< len
) && (ptr
+ sizeof(*mto
) <= end
));
104 len
= ptr
- (unsigned char *) sccb
;
105 sccb
->header
.length
= len
- offsetof(struct write_sccb
, header
);
107 msg
->header
.type
= EVTYP_MSG
;
108 msg
->header
.length
= len
- offsetof(struct write_sccb
, msg
.header
);
110 mdb
->header
.type
= 1;
111 mdb
->header
.tag
= 0xD4C4C240;
112 mdb
->header
.revision_code
= 1;
113 mdb
->header
.length
= len
- offsetof(struct write_sccb
, msg
.mdb
.header
);
115 go
->length
= sizeof(*go
);
117 sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA
, sccb
);
121 struct sccb_header header
;
123 struct evbuf_header header
;
128 /* Output multi-line text using SCLP VT220 interface. */
129 static void sclp_early_print_vt220(const char *str
, unsigned int len
)
131 struct vt220_sccb
*sccb
;
133 sccb
= (struct vt220_sccb
*) &sclp_early_sccb
;
134 if (sizeof(*sccb
) + len
>= sizeof(sclp_early_sccb
))
135 len
= sizeof(sclp_early_sccb
) - sizeof(*sccb
);
136 memset(sccb
, 0, sizeof(*sccb
));
137 memcpy(&sccb
->msg
.data
, str
, len
);
138 sccb
->header
.length
= sizeof(*sccb
) + len
;
139 sccb
->msg
.header
.length
= sizeof(sccb
->msg
) + len
;
140 sccb
->msg
.header
.type
= EVTYP_VT220MSG
;
141 sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA
, sccb
);
144 int sclp_early_set_event_mask(struct init_sccb
*sccb
,
145 unsigned long receive_mask
,
146 unsigned long send_mask
)
148 memset(sccb
, 0, sizeof(*sccb
));
149 sccb
->header
.length
= sizeof(*sccb
);
150 sccb
->mask_length
= sizeof(sccb_mask_t
);
151 sccb
->receive_mask
= receive_mask
;
152 sccb
->send_mask
= send_mask
;
153 if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_MASK
, sccb
))
155 if (sccb
->header
.response_code
!= 0x20)
160 unsigned int sclp_early_con_check_linemode(struct init_sccb
*sccb
)
162 if (!(sccb
->sclp_send_mask
& EVTYP_OPCMD_MASK
))
164 if (!(sccb
->sclp_receive_mask
& (EVTYP_MSG_MASK
| EVTYP_PMSGCMD_MASK
)))
169 static int sclp_early_setup(int disable
, int *have_linemode
, int *have_vt220
)
171 unsigned long receive_mask
, send_mask
;
172 struct init_sccb
*sccb
;
175 *have_linemode
= *have_vt220
= 0;
176 sccb
= (struct init_sccb
*) &sclp_early_sccb
;
177 receive_mask
= disable
? 0 : EVTYP_OPCMD_MASK
;
178 send_mask
= disable
? 0 : EVTYP_VT220MSG_MASK
| EVTYP_MSG_MASK
;
179 rc
= sclp_early_set_event_mask(sccb
, receive_mask
, send_mask
);
182 *have_linemode
= sclp_early_con_check_linemode(sccb
);
183 *have_vt220
= sccb
->send_mask
& EVTYP_VT220MSG_MASK
;
188 * Output one or more lines of text on the SCLP console (VT220 and /
191 void __sclp_early_printk(const char *str
, unsigned int len
)
193 int have_linemode
, have_vt220
;
195 if (sclp_init_state
!= sclp_init_state_uninitialized
)
197 if (sclp_early_setup(0, &have_linemode
, &have_vt220
) != 0)
200 sclp_early_print_lm(str
, len
);
202 sclp_early_print_vt220(str
, len
);
203 sclp_early_setup(1, &have_linemode
, &have_vt220
);
206 void sclp_early_printk(const char *str
)
208 __sclp_early_printk(str
, strlen(str
));