1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/types.h>
3 #include <linux/delay.h>
4 #include <linux/slab.h>
5 #include <linux/console.h>
8 #include "hvc_console.h"
10 static int hvsi_send_packet(struct hvsi_priv
*pv
, struct hvsi_header
*packet
)
12 packet
->seqno
= cpu_to_be16(atomic_inc_return(&pv
->seqno
));
14 /* Assumes that always succeeds, works in practice */
15 return pv
->put_chars(pv
->termno
, (char *)packet
, packet
->len
);
18 static void hvsi_start_handshake(struct hvsi_priv
*pv
)
24 atomic_set(&pv
->seqno
, 0);
26 pr_devel("HVSI@%x: Handshaking started\n", pv
->termno
);
28 /* Send version query */
29 q
.hdr
.type
= VS_QUERY_PACKET_HEADER
;
30 q
.hdr
.len
= sizeof(struct hvsi_query
);
31 q
.verb
= cpu_to_be16(VSV_SEND_VERSION_NUMBER
);
32 hvsi_send_packet(pv
, &q
.hdr
);
35 static int hvsi_send_close(struct hvsi_priv
*pv
)
37 struct hvsi_control ctrl
;
41 ctrl
.hdr
.type
= VS_CONTROL_PACKET_HEADER
;
42 ctrl
.hdr
.len
= sizeof(struct hvsi_control
);
43 ctrl
.verb
= cpu_to_be16(VSV_CLOSE_PROTOCOL
);
44 return hvsi_send_packet(pv
, &ctrl
.hdr
);
47 static void hvsi_cd_change(struct hvsi_priv
*pv
, int cd
)
50 pv
->mctrl
|= TIOCM_CD
;
52 pv
->mctrl
&= ~TIOCM_CD
;
54 /* We copy the existing hvsi driver semantics
55 * here which are to trigger a hangup when
56 * we get a carrier loss.
57 * Closing our connection to the server will
60 if (!pv
->is_console
&& pv
->opened
) {
61 pr_devel("HVSI@%x Carrier lost, hanging up !\n",
68 static void hvsi_got_control(struct hvsi_priv
*pv
)
70 struct hvsi_control
*pkt
= (struct hvsi_control
*)pv
->inbuf
;
72 switch (be16_to_cpu(pkt
->verb
)) {
73 case VSV_CLOSE_PROTOCOL
:
74 /* We restart the handshaking */
75 hvsi_start_handshake(pv
);
77 case VSV_MODEM_CTL_UPDATE
:
78 /* Transition of carrier detect */
79 hvsi_cd_change(pv
, be32_to_cpu(pkt
->word
) & HVSI_TSCD
);
84 static void hvsi_got_query(struct hvsi_priv
*pv
)
86 struct hvsi_query
*pkt
= (struct hvsi_query
*)pv
->inbuf
;
87 struct hvsi_query_response r
;
89 /* We only handle version queries */
90 if (be16_to_cpu(pkt
->verb
) != VSV_SEND_VERSION_NUMBER
)
93 pr_devel("HVSI@%x: Got version query, sending response...\n",
96 /* Send version response */
97 r
.hdr
.type
= VS_QUERY_RESPONSE_PACKET_HEADER
;
98 r
.hdr
.len
= sizeof(struct hvsi_query_response
);
99 r
.verb
= cpu_to_be16(VSV_SEND_VERSION_NUMBER
);
100 r
.u
.version
= HVSI_VERSION
;
101 r
.query_seqno
= pkt
->hdr
.seqno
;
102 hvsi_send_packet(pv
, &r
.hdr
);
104 /* Assume protocol is open now */
108 static void hvsi_got_response(struct hvsi_priv
*pv
)
110 struct hvsi_query_response
*r
=
111 (struct hvsi_query_response
*)pv
->inbuf
;
114 case VSV_SEND_MODEM_CTL_STATUS
:
115 hvsi_cd_change(pv
, be32_to_cpu(r
->u
.mctrl_word
) & HVSI_TSCD
);
116 pv
->mctrl_update
= 1;
121 static int hvsi_check_packet(struct hvsi_priv
*pv
)
125 /* Check header validity. If it's invalid, we ditch
126 * the whole buffer and hope we eventually resync
128 if (pv
->inbuf
[0] < 0xfc) {
129 pv
->inbuf_len
= pv
->inbuf_pktlen
= 0;
135 /* Packet incomplete ? */
136 if (pv
->inbuf_len
< len
)
139 pr_devel("HVSI@%x: Got packet type %x len %d bytes:\n",
140 pv
->termno
, type
, len
);
142 /* We have a packet, yay ! Handle it */
144 case VS_DATA_PACKET_HEADER
:
145 pv
->inbuf_pktlen
= len
- 4;
148 case VS_CONTROL_PACKET_HEADER
:
149 hvsi_got_control(pv
);
151 case VS_QUERY_PACKET_HEADER
:
154 case VS_QUERY_RESPONSE_PACKET_HEADER
:
155 hvsi_got_response(pv
);
159 /* Swallow packet and retry */
160 pv
->inbuf_len
-= len
;
161 memmove(pv
->inbuf
, &pv
->inbuf
[len
], pv
->inbuf_len
);
165 static int hvsi_get_packet(struct hvsi_priv
*pv
)
167 /* If we have room in the buffer, ask HV for more */
168 if (pv
->inbuf_len
< HVSI_INBUF_SIZE
)
169 pv
->inbuf_len
+= pv
->get_chars(pv
->termno
,
170 &pv
->inbuf
[pv
->inbuf_len
],
171 HVSI_INBUF_SIZE
- pv
->inbuf_len
);
173 * If we have at least 4 bytes in the buffer, check for
174 * a full packet and retry
176 if (pv
->inbuf_len
>= 4)
177 return hvsi_check_packet(pv
);
181 int hvsilib_get_chars(struct hvsi_priv
*pv
, char *buf
, int count
)
183 unsigned int tries
, read
= 0;
188 /* If we aren't open, don't do anything in order to avoid races
189 * with connection establishment. The hvc core will call this
190 * before we have returned from notifier_add(), and we need to
191 * avoid multiple users playing with the receive buffer
196 /* We try twice, once with what data we have and once more
197 * after we try to fetch some more from the hypervisor
199 for (tries
= 1; count
&& tries
< 2; tries
++) {
200 /* Consume existing data packet */
201 if (pv
->inbuf_pktlen
) {
202 unsigned int l
= min(count
, (int)pv
->inbuf_pktlen
);
203 memcpy(&buf
[read
], &pv
->inbuf
[pv
->inbuf_cur
], l
);
205 pv
->inbuf_pktlen
-= l
;
212 /* Data packet fully consumed, move down remaning data */
214 pv
->inbuf_len
-= pv
->inbuf_cur
;
215 memmove(pv
->inbuf
, &pv
->inbuf
[pv
->inbuf_cur
],
220 /* Try to get another packet */
221 if (hvsi_get_packet(pv
))
224 if (!pv
->established
) {
225 pr_devel("HVSI@%x: returning -EPIPE\n", pv
->termno
);
231 int hvsilib_put_chars(struct hvsi_priv
*pv
, const char *buf
, int count
)
234 int rc
, adjcount
= min(count
, HVSI_MAX_OUTGOING_DATA
);
239 dp
.hdr
.type
= VS_DATA_PACKET_HEADER
;
240 dp
.hdr
.len
= adjcount
+ sizeof(struct hvsi_header
);
241 memcpy(dp
.data
, buf
, adjcount
);
242 rc
= hvsi_send_packet(pv
, &dp
.hdr
);
248 static void maybe_msleep(unsigned long ms
)
250 /* During early boot, IRQs are disabled, use mdelay */
257 int hvsilib_read_mctrl(struct hvsi_priv
*pv
)
262 pr_devel("HVSI@%x: Querying modem control status...\n",
265 pv
->mctrl_update
= 0;
266 q
.hdr
.type
= VS_QUERY_PACKET_HEADER
;
267 q
.hdr
.len
= sizeof(struct hvsi_query
);
268 q
.verb
= cpu_to_be16(VSV_SEND_MODEM_CTL_STATUS
);
269 rc
= hvsi_send_packet(pv
, &q
.hdr
);
271 pr_devel("HVSI@%x: Error %d...\n", pv
->termno
, rc
);
275 /* Try for up to 200ms */
276 for (timeout
= 0; timeout
< 20; timeout
++) {
277 if (!pv
->established
)
279 if (pv
->mctrl_update
)
281 if (!hvsi_get_packet(pv
))
287 int hvsilib_write_mctrl(struct hvsi_priv
*pv
, int dtr
)
289 struct hvsi_control ctrl
;
290 unsigned short mctrl
;
297 if (mctrl
== pv
->mctrl
)
301 pr_devel("HVSI@%x: %s DTR...\n", pv
->termno
,
302 dtr
? "Setting" : "Clearing");
304 ctrl
.hdr
.type
= VS_CONTROL_PACKET_HEADER
,
305 ctrl
.hdr
.len
= sizeof(struct hvsi_control
);
306 ctrl
.verb
= cpu_to_be16(VSV_SET_MODEM_CTL
);
307 ctrl
.mask
= cpu_to_be32(HVSI_TSDTR
);
308 ctrl
.word
= cpu_to_be32(dtr
? HVSI_TSDTR
: 0);
309 return hvsi_send_packet(pv
, &ctrl
.hdr
);
312 void hvsilib_establish(struct hvsi_priv
*pv
)
316 pr_devel("HVSI@%x: Establishing...\n", pv
->termno
);
318 /* Try for up to 200ms, there can be a packet to
319 * start the process waiting for us...
321 for (timeout
= 0; timeout
< 20; timeout
++) {
324 if (!hvsi_get_packet(pv
))
328 /* Failed, send a close connection packet just
331 pr_devel("HVSI@%x: ... sending close\n", pv
->termno
);
335 /* Then restart handshake */
337 pr_devel("HVSI@%x: ... restarting handshake\n", pv
->termno
);
339 hvsi_start_handshake(pv
);
341 pr_devel("HVSI@%x: ... waiting handshake\n", pv
->termno
);
343 /* Try for up to 400ms */
344 for (timeout
= 0; timeout
< 40; timeout
++) {
347 if (!hvsi_get_packet(pv
))
351 if (!pv
->established
) {
352 pr_devel("HVSI@%x: Timeout handshaking, giving up !\n",
357 /* Query modem control lines */
359 pr_devel("HVSI@%x: ... established, reading mctrl\n", pv
->termno
);
361 hvsilib_read_mctrl(pv
);
363 /* Set our own DTR */
365 pr_devel("HVSI@%x: ... setting mctrl\n", pv
->termno
);
367 hvsilib_write_mctrl(pv
, 1);
369 /* Set the opened flag so reads are allowed */
374 int hvsilib_open(struct hvsi_priv
*pv
, struct hvc_struct
*hp
)
376 pr_devel("HVSI@%x: open !\n", pv
->termno
);
378 /* Keep track of the tty data structure */
379 pv
->tty
= tty_port_tty_get(&hp
->port
);
381 hvsilib_establish(pv
);
386 void hvsilib_close(struct hvsi_priv
*pv
, struct hvc_struct
*hp
)
390 pr_devel("HVSI@%x: close !\n", pv
->termno
);
392 if (!pv
->is_console
) {
393 pr_devel("HVSI@%x: Not a console, tearing down\n",
396 /* Clear opened, synchronize with khvcd */
397 spin_lock_irqsave(&hp
->lock
, flags
);
399 spin_unlock_irqrestore(&hp
->lock
, flags
);
401 /* Clear our own DTR */
402 if (!pv
->tty
|| (pv
->tty
->termios
.c_cflag
& HUPCL
))
403 hvsilib_write_mctrl(pv
, 0);
405 /* Tear down the connection */
409 tty_kref_put(pv
->tty
);
413 void hvsilib_init(struct hvsi_priv
*pv
,
414 int (*get_chars
)(uint32_t termno
, char *buf
, int count
),
415 int (*put_chars
)(uint32_t termno
, const char *buf
,
417 int termno
, int is_console
)
419 memset(pv
, 0, sizeof(*pv
));
420 pv
->get_chars
= get_chars
;
421 pv
->put_chars
= put_chars
;
423 pv
->is_console
= is_console
;