xref: /openbmc/linux/drivers/tty/hvc/hvsi_lib.c (revision 9cfc5c90)
1 #include <linux/types.h>
2 #include <linux/delay.h>
3 #include <linux/slab.h>
4 #include <linux/console.h>
5 #include <asm/hvsi.h>
6 
7 #include "hvc_console.h"
8 
9 static int hvsi_send_packet(struct hvsi_priv *pv, struct hvsi_header *packet)
10 {
11 	packet->seqno = cpu_to_be16(atomic_inc_return(&pv->seqno));
12 
13 	/* Assumes that always succeeds, works in practice */
14 	return pv->put_chars(pv->termno, (char *)packet, packet->len);
15 }
16 
17 static void hvsi_start_handshake(struct hvsi_priv *pv)
18 {
19 	struct hvsi_query q;
20 
21 	/* Reset state */
22 	pv->established = 0;
23 	atomic_set(&pv->seqno, 0);
24 
25 	pr_devel("HVSI@%x: Handshaking started\n", pv->termno);
26 
27 	/* Send version query */
28 	q.hdr.type = VS_QUERY_PACKET_HEADER;
29 	q.hdr.len = sizeof(struct hvsi_query);
30 	q.verb = cpu_to_be16(VSV_SEND_VERSION_NUMBER);
31 	hvsi_send_packet(pv, &q.hdr);
32 }
33 
34 static int hvsi_send_close(struct hvsi_priv *pv)
35 {
36 	struct hvsi_control ctrl;
37 
38 	pv->established = 0;
39 
40 	ctrl.hdr.type = VS_CONTROL_PACKET_HEADER;
41 	ctrl.hdr.len = sizeof(struct hvsi_control);
42 	ctrl.verb = cpu_to_be16(VSV_CLOSE_PROTOCOL);
43 	return hvsi_send_packet(pv, &ctrl.hdr);
44 }
45 
46 static void hvsi_cd_change(struct hvsi_priv *pv, int cd)
47 {
48 	if (cd)
49 		pv->mctrl |= TIOCM_CD;
50 	else {
51 		pv->mctrl &= ~TIOCM_CD;
52 
53 		/* We copy the existing hvsi driver semantics
54 		 * here which are to trigger a hangup when
55 		 * we get a carrier loss.
56 		 * Closing our connection to the server will
57 		 * do just that.
58 		 */
59 		if (!pv->is_console && pv->opened) {
60 			pr_devel("HVSI@%x Carrier lost, hanging up !\n",
61 				 pv->termno);
62 			hvsi_send_close(pv);
63 		}
64 	}
65 }
66 
67 static void hvsi_got_control(struct hvsi_priv *pv)
68 {
69 	struct hvsi_control *pkt = (struct hvsi_control *)pv->inbuf;
70 
71 	switch (be16_to_cpu(pkt->verb)) {
72 	case VSV_CLOSE_PROTOCOL:
73 		/* We restart the handshaking */
74 		hvsi_start_handshake(pv);
75 		break;
76 	case VSV_MODEM_CTL_UPDATE:
77 		/* Transition of carrier detect */
78 		hvsi_cd_change(pv, be32_to_cpu(pkt->word) & HVSI_TSCD);
79 		break;
80 	}
81 }
82 
83 static void hvsi_got_query(struct hvsi_priv *pv)
84 {
85 	struct hvsi_query *pkt = (struct hvsi_query *)pv->inbuf;
86 	struct hvsi_query_response r;
87 
88 	/* We only handle version queries */
89 	if (be16_to_cpu(pkt->verb) != VSV_SEND_VERSION_NUMBER)
90 		return;
91 
92 	pr_devel("HVSI@%x: Got version query, sending response...\n",
93 		 pv->termno);
94 
95 	/* Send version response */
96 	r.hdr.type = VS_QUERY_RESPONSE_PACKET_HEADER;
97 	r.hdr.len = sizeof(struct hvsi_query_response);
98 	r.verb = cpu_to_be16(VSV_SEND_VERSION_NUMBER);
99 	r.u.version = HVSI_VERSION;
100 	r.query_seqno = pkt->hdr.seqno;
101 	hvsi_send_packet(pv, &r.hdr);
102 
103 	/* Assume protocol is open now */
104 	pv->established = 1;
105 }
106 
107 static void hvsi_got_response(struct hvsi_priv *pv)
108 {
109 	struct hvsi_query_response *r =
110 		(struct hvsi_query_response *)pv->inbuf;
111 
112 	switch(r->verb) {
113 	case VSV_SEND_MODEM_CTL_STATUS:
114 		hvsi_cd_change(pv, be32_to_cpu(r->u.mctrl_word) & HVSI_TSCD);
115 		pv->mctrl_update = 1;
116 		break;
117 	}
118 }
119 
120 static int hvsi_check_packet(struct hvsi_priv *pv)
121 {
122 	u8 len, type;
123 
124 	/* Check header validity. If it's invalid, we ditch
125 	 * the whole buffer and hope we eventually resync
126 	 */
127 	if (pv->inbuf[0] < 0xfc) {
128 		pv->inbuf_len = pv->inbuf_pktlen = 0;
129 		return 0;
130 	}
131 	type = pv->inbuf[0];
132 	len = pv->inbuf[1];
133 
134 	/* Packet incomplete ? */
135 	if (pv->inbuf_len < len)
136 		return 0;
137 
138 	pr_devel("HVSI@%x: Got packet type %x len %d bytes:\n",
139 		 pv->termno, type, len);
140 
141 	/* We have a packet, yay ! Handle it */
142 	switch(type) {
143 	case VS_DATA_PACKET_HEADER:
144 		pv->inbuf_pktlen = len - 4;
145 		pv->inbuf_cur = 4;
146 		return 1;
147 	case VS_CONTROL_PACKET_HEADER:
148 		hvsi_got_control(pv);
149 		break;
150 	case VS_QUERY_PACKET_HEADER:
151 		hvsi_got_query(pv);
152 		break;
153 	case VS_QUERY_RESPONSE_PACKET_HEADER:
154 		hvsi_got_response(pv);
155 		break;
156 	}
157 
158 	/* Swallow packet and retry */
159 	pv->inbuf_len -= len;
160 	memmove(pv->inbuf, &pv->inbuf[len], pv->inbuf_len);
161 	return 1;
162 }
163 
164 static int hvsi_get_packet(struct hvsi_priv *pv)
165 {
166 	/* If we have room in the buffer, ask HV for more */
167 	if (pv->inbuf_len < HVSI_INBUF_SIZE)
168 		pv->inbuf_len += pv->get_chars(pv->termno,
169 					     &pv->inbuf[pv->inbuf_len],
170 					     HVSI_INBUF_SIZE - pv->inbuf_len);
171 	/*
172 	 * If we have at least 4 bytes in the buffer, check for
173 	 * a full packet and retry
174 	 */
175 	if (pv->inbuf_len >= 4)
176 		return hvsi_check_packet(pv);
177 	return 0;
178 }
179 
180 int hvsilib_get_chars(struct hvsi_priv *pv, char *buf, int count)
181 {
182 	unsigned int tries, read = 0;
183 
184 	if (WARN_ON(!pv))
185 		return -ENXIO;
186 
187 	/* If we aren't open, don't do anything in order to avoid races
188 	 * with connection establishment. The hvc core will call this
189 	 * before we have returned from notifier_add(), and we need to
190 	 * avoid multiple users playing with the receive buffer
191 	 */
192 	if (!pv->opened)
193 		return 0;
194 
195 	/* We try twice, once with what data we have and once more
196 	 * after we try to fetch some more from the hypervisor
197 	 */
198 	for (tries = 1; count && tries < 2; tries++) {
199 		/* Consume existing data packet */
200 		if (pv->inbuf_pktlen) {
201 			unsigned int l = min(count, (int)pv->inbuf_pktlen);
202 			memcpy(&buf[read], &pv->inbuf[pv->inbuf_cur], l);
203 			pv->inbuf_cur += l;
204 			pv->inbuf_pktlen -= l;
205 			count -= l;
206 			read += l;
207 		}
208 		if (count == 0)
209 			break;
210 
211 		/* Data packet fully consumed, move down remaning data */
212 		if (pv->inbuf_cur) {
213 			pv->inbuf_len -= pv->inbuf_cur;
214 			memmove(pv->inbuf, &pv->inbuf[pv->inbuf_cur],
215 				pv->inbuf_len);
216 			pv->inbuf_cur = 0;
217 		}
218 
219 		/* Try to get another packet */
220 		if (hvsi_get_packet(pv))
221 			tries--;
222 	}
223 	if (!pv->established) {
224 		pr_devel("HVSI@%x: returning -EPIPE\n", pv->termno);
225 		return -EPIPE;
226 	}
227 	return read;
228 }
229 
230 int hvsilib_put_chars(struct hvsi_priv *pv, const char *buf, int count)
231 {
232 	struct hvsi_data dp;
233 	int rc, adjcount = min(count, HVSI_MAX_OUTGOING_DATA);
234 
235 	if (WARN_ON(!pv))
236 		return -ENODEV;
237 
238 	dp.hdr.type = VS_DATA_PACKET_HEADER;
239 	dp.hdr.len = adjcount + sizeof(struct hvsi_header);
240 	memcpy(dp.data, buf, adjcount);
241 	rc = hvsi_send_packet(pv, &dp.hdr);
242 	if (rc <= 0)
243 		return rc;
244 	return adjcount;
245 }
246 
247 static void maybe_msleep(unsigned long ms)
248 {
249 	/* During early boot, IRQs are disabled, use mdelay */
250 	if (irqs_disabled())
251 		mdelay(ms);
252 	else
253 		msleep(ms);
254 }
255 
256 int hvsilib_read_mctrl(struct hvsi_priv *pv)
257 {
258 	struct hvsi_query q;
259 	int rc, timeout;
260 
261 	pr_devel("HVSI@%x: Querying modem control status...\n",
262 		 pv->termno);
263 
264 	pv->mctrl_update = 0;
265 	q.hdr.type = VS_QUERY_PACKET_HEADER;
266 	q.hdr.len = sizeof(struct hvsi_query);
267 	q.verb = cpu_to_be16(VSV_SEND_MODEM_CTL_STATUS);
268 	rc = hvsi_send_packet(pv, &q.hdr);
269 	if (rc <= 0) {
270 		pr_devel("HVSI@%x: Error %d...\n", pv->termno, rc);
271 		return rc;
272 	}
273 
274 	/* Try for up to 200ms */
275 	for (timeout = 0; timeout < 20; timeout++) {
276 		if (!pv->established)
277 			return -ENXIO;
278 		if (pv->mctrl_update)
279 			return 0;
280 		if (!hvsi_get_packet(pv))
281 			maybe_msleep(10);
282 	}
283 	return -EIO;
284 }
285 
286 int hvsilib_write_mctrl(struct hvsi_priv *pv, int dtr)
287 {
288 	struct hvsi_control ctrl;
289 	unsigned short mctrl;
290 
291 	mctrl = pv->mctrl;
292 	if (dtr)
293 		mctrl |= TIOCM_DTR;
294 	else
295 		mctrl &= ~TIOCM_DTR;
296 	if (mctrl == pv->mctrl)
297 		return 0;
298 	pv->mctrl = mctrl;
299 
300 	pr_devel("HVSI@%x: %s DTR...\n", pv->termno,
301 		 dtr ? "Setting" : "Clearing");
302 
303 	ctrl.hdr.type = VS_CONTROL_PACKET_HEADER,
304 	ctrl.hdr.len = sizeof(struct hvsi_control);
305 	ctrl.verb = cpu_to_be16(VSV_SET_MODEM_CTL);
306 	ctrl.mask = cpu_to_be32(HVSI_TSDTR);
307 	ctrl.word = cpu_to_be32(dtr ? HVSI_TSDTR : 0);
308 	return hvsi_send_packet(pv, &ctrl.hdr);
309 }
310 
311 void hvsilib_establish(struct hvsi_priv *pv)
312 {
313 	int timeout;
314 
315 	pr_devel("HVSI@%x: Establishing...\n", pv->termno);
316 
317 	/* Try for up to 200ms, there can be a packet to
318 	 * start the process waiting for us...
319 	 */
320 	for (timeout = 0; timeout < 20; timeout++) {
321 		if (pv->established)
322 			goto established;
323 		if (!hvsi_get_packet(pv))
324 			maybe_msleep(10);
325 	}
326 
327 	/* Failed, send a close connection packet just
328 	 * in case
329 	 */
330 	pr_devel("HVSI@%x:   ... sending close\n", pv->termno);
331 
332 	hvsi_send_close(pv);
333 
334 	/* Then restart handshake */
335 
336 	pr_devel("HVSI@%x:   ... restarting handshake\n", pv->termno);
337 
338 	hvsi_start_handshake(pv);
339 
340 	pr_devel("HVSI@%x:   ... waiting handshake\n", pv->termno);
341 
342 	/* Try for up to 400ms */
343 	for (timeout = 0; timeout < 40; timeout++) {
344 		if (pv->established)
345 			goto established;
346 		if (!hvsi_get_packet(pv))
347 			maybe_msleep(10);
348 	}
349 
350 	if (!pv->established) {
351 		pr_devel("HVSI@%x: Timeout handshaking, giving up !\n",
352 			 pv->termno);
353 		return;
354 	}
355  established:
356 	/* Query modem control lines */
357 
358 	pr_devel("HVSI@%x:   ... established, reading mctrl\n", pv->termno);
359 
360 	hvsilib_read_mctrl(pv);
361 
362 	/* Set our own DTR */
363 
364 	pr_devel("HVSI@%x:   ... setting mctrl\n", pv->termno);
365 
366 	hvsilib_write_mctrl(pv, 1);
367 
368 	/* Set the opened flag so reads are allowed */
369 	wmb();
370 	pv->opened = 1;
371 }
372 
373 int hvsilib_open(struct hvsi_priv *pv, struct hvc_struct *hp)
374 {
375 	pr_devel("HVSI@%x: open !\n", pv->termno);
376 
377 	/* Keep track of the tty data structure */
378 	pv->tty = tty_port_tty_get(&hp->port);
379 
380 	hvsilib_establish(pv);
381 
382 	return 0;
383 }
384 
385 void hvsilib_close(struct hvsi_priv *pv, struct hvc_struct *hp)
386 {
387 	unsigned long flags;
388 
389 	pr_devel("HVSI@%x: close !\n", pv->termno);
390 
391 	if (!pv->is_console) {
392 		pr_devel("HVSI@%x: Not a console, tearing down\n",
393 			 pv->termno);
394 
395 		/* Clear opened, synchronize with khvcd */
396 		spin_lock_irqsave(&hp->lock, flags);
397 		pv->opened = 0;
398 		spin_unlock_irqrestore(&hp->lock, flags);
399 
400 		/* Clear our own DTR */
401 		if (!pv->tty || (pv->tty->termios.c_cflag & HUPCL))
402 			hvsilib_write_mctrl(pv, 0);
403 
404 		/* Tear down the connection */
405 		hvsi_send_close(pv);
406 	}
407 
408 	tty_kref_put(pv->tty);
409 	pv->tty = NULL;
410 }
411 
412 void hvsilib_init(struct hvsi_priv *pv,
413 		  int (*get_chars)(uint32_t termno, char *buf, int count),
414 		  int (*put_chars)(uint32_t termno, const char *buf,
415 				   int count),
416 		  int termno, int is_console)
417 {
418 	memset(pv, 0, sizeof(*pv));
419 	pv->get_chars = get_chars;
420 	pv->put_chars = put_chars;
421 	pv->termno = termno;
422 	pv->is_console = is_console;
423 }
424