Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / tty / hvc / hvsi_lib.c
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 }