2 * Copyright IBM Corp. 2015
3 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
6 #include <linux/kernel.h>
7 #include <asm/processor.h>
8 #include <asm/lowcore.h>
9 #include <asm/ebcdic.h>
14 char sclp_early_sccb
[PAGE_SIZE
] __aligned(PAGE_SIZE
) __section(data
);
15 int sclp_init_state
__section(data
) = sclp_init_state_uninitialized
;
17 void sclp_early_wait_irq(void)
19 unsigned long psw_mask
, addr
;
20 psw_t psw_ext_save
, psw_wait
;
21 union ctlreg0 cr0
, cr0_new
;
23 __ctl_store(cr0
.val
, 0, 0);
24 cr0_new
.val
= cr0
.val
& ~CR0_IRQ_SUBCLASS_MASK
;
27 __ctl_load(cr0_new
.val
, 0, 0);
29 psw_ext_save
= S390_lowcore
.external_new_psw
;
30 psw_mask
= __extract_psw();
31 S390_lowcore
.external_new_psw
.mask
= psw_mask
;
32 psw_wait
.mask
= psw_mask
| PSW_MASK_EXT
| PSW_MASK_WAIT
;
33 S390_lowcore
.ext_int_code
= 0;
38 " stg %[addr],%[psw_wait_addr]\n"
39 " stg %[addr],%[psw_ext_addr]\n"
40 " lpswe %[psw_wait]\n"
42 : [addr
] "=&d" (addr
),
43 [psw_wait_addr
] "=Q" (psw_wait
.addr
),
44 [psw_ext_addr
] "=Q" (S390_lowcore
.external_new_psw
.addr
)
45 : [psw_wait
] "Q" (psw_wait
)
47 } while (S390_lowcore
.ext_int_code
!= EXT_IRQ_SERVICE_SIG
);
49 S390_lowcore
.external_new_psw
= psw_ext_save
;
50 __ctl_load(cr0
.val
, 0, 0);
53 int sclp_early_cmd(sclp_cmdw_t cmd
, void *sccb
)
58 raw_local_irq_save(flags
);
59 rc
= sclp_service_call(cmd
, sccb
);
62 sclp_early_wait_irq();
64 raw_local_irq_restore(flags
);
69 struct sccb_header header
;
73 /* Output multi-line text using SCLP Message interface. */
74 static void sclp_early_print_lm(const char *str
, unsigned int len
)
76 unsigned char *ptr
, *end
, ch
;
77 unsigned int count
, offset
;
78 struct write_sccb
*sccb
;
84 sccb
= (struct write_sccb
*) &sclp_early_sccb
;
85 end
= (unsigned char *) sccb
+ sizeof(sclp_early_sccb
) - 1;
86 memset(sccb
, 0, sizeof(*sccb
));
87 ptr
= (unsigned char *) &sccb
->msg
.mdb
.mto
;
90 for (count
= sizeof(*mto
); offset
< len
; count
++) {
92 if ((ch
== 0x0a) || (ptr
+ count
> end
))
94 ptr
[count
] = _ascebc
[ch
];
96 mto
= (struct mto
*) ptr
;
97 memset(mto
, 0, sizeof(*mto
));
100 mto
->line_type_flags
= LNTPFLGS_ENDTEXT
;
102 } while ((offset
< len
) && (ptr
+ sizeof(*mto
) <= end
));
103 len
= ptr
- (unsigned char *) sccb
;
104 sccb
->header
.length
= len
- offsetof(struct write_sccb
, header
);
106 msg
->header
.type
= EVTYP_MSG
;
107 msg
->header
.length
= len
- offsetof(struct write_sccb
, msg
.header
);
109 mdb
->header
.type
= 1;
110 mdb
->header
.tag
= 0xD4C4C240;
111 mdb
->header
.revision_code
= 1;
112 mdb
->header
.length
= len
- offsetof(struct write_sccb
, msg
.mdb
.header
);
114 go
->length
= sizeof(*go
);
116 sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA
, sccb
);
120 struct sccb_header header
;
122 struct evbuf_header header
;
127 /* Output multi-line text using SCLP VT220 interface. */
128 static void sclp_early_print_vt220(const char *str
, unsigned int len
)
130 struct vt220_sccb
*sccb
;
132 sccb
= (struct vt220_sccb
*) &sclp_early_sccb
;
133 if (sizeof(*sccb
) + len
>= sizeof(sclp_early_sccb
))
134 len
= sizeof(sclp_early_sccb
) - sizeof(*sccb
);
135 memset(sccb
, 0, sizeof(*sccb
));
136 memcpy(&sccb
->msg
.data
, str
, len
);
137 sccb
->header
.length
= sizeof(*sccb
) + len
;
138 sccb
->msg
.header
.length
= sizeof(sccb
->msg
) + len
;
139 sccb
->msg
.header
.type
= EVTYP_VT220MSG
;
140 sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA
, sccb
);
143 int sclp_early_set_event_mask(struct init_sccb
*sccb
,
144 unsigned long receive_mask
,
145 unsigned long send_mask
)
147 memset(sccb
, 0, sizeof(*sccb
));
148 sccb
->header
.length
= sizeof(*sccb
);
149 sccb
->mask_length
= sizeof(sccb_mask_t
);
150 sccb
->receive_mask
= receive_mask
;
151 sccb
->send_mask
= send_mask
;
152 if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_MASK
, sccb
))
154 if (sccb
->header
.response_code
!= 0x20)
159 unsigned int sclp_early_con_check_linemode(struct init_sccb
*sccb
)
161 if (!(sccb
->sclp_send_mask
& EVTYP_OPCMD_MASK
))
163 if (!(sccb
->sclp_receive_mask
& (EVTYP_MSG_MASK
| EVTYP_PMSGCMD_MASK
)))
168 static int sclp_early_setup(int disable
, int *have_linemode
, int *have_vt220
)
170 unsigned long receive_mask
, send_mask
;
171 struct init_sccb
*sccb
;
174 *have_linemode
= *have_vt220
= 0;
175 sccb
= (struct init_sccb
*) &sclp_early_sccb
;
176 receive_mask
= disable
? 0 : EVTYP_OPCMD_MASK
;
177 send_mask
= disable
? 0 : EVTYP_VT220MSG_MASK
| EVTYP_MSG_MASK
;
178 rc
= sclp_early_set_event_mask(sccb
, receive_mask
, send_mask
);
181 *have_linemode
= sclp_early_con_check_linemode(sccb
);
182 *have_vt220
= sccb
->send_mask
& EVTYP_VT220MSG_MASK
;
187 * Output one or more lines of text on the SCLP console (VT220 and /
190 void __sclp_early_printk(const char *str
, unsigned int len
)
192 int have_linemode
, have_vt220
;
194 if (sclp_init_state
!= sclp_init_state_uninitialized
)
196 if (sclp_early_setup(0, &have_linemode
, &have_vt220
) != 0)
199 sclp_early_print_lm(str
, len
);
201 sclp_early_print_vt220(str
, len
);
202 sclp_early_setup(1, &have_linemode
, &have_vt220
);
205 void sclp_early_printk(const char *str
)
207 __sclp_early_printk(str
, strlen(str
));