Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/types.h>
0003 #include <linux/delay.h>
0004 #include <linux/slab.h>
0005 #include <linux/console.h>
0006 #include <asm/hvsi.h>
0007 
0008 #include "hvc_console.h"
0009 
0010 static int hvsi_send_packet(struct hvsi_priv *pv, struct hvsi_header *packet)
0011 {
0012     packet->seqno = cpu_to_be16(atomic_inc_return(&pv->seqno));
0013 
0014     /* Assumes that always succeeds, works in practice */
0015     return pv->put_chars(pv->termno, (char *)packet, packet->len);
0016 }
0017 
0018 static void hvsi_start_handshake(struct hvsi_priv *pv)
0019 {
0020     struct hvsi_query q;
0021 
0022     /* Reset state */
0023     pv->established = 0;
0024     atomic_set(&pv->seqno, 0);
0025 
0026     pr_devel("HVSI@%x: Handshaking started\n", pv->termno);
0027 
0028     /* Send version query */
0029     q.hdr.type = VS_QUERY_PACKET_HEADER;
0030     q.hdr.len = sizeof(struct hvsi_query);
0031     q.verb = cpu_to_be16(VSV_SEND_VERSION_NUMBER);
0032     hvsi_send_packet(pv, &q.hdr);
0033 }
0034 
0035 static int hvsi_send_close(struct hvsi_priv *pv)
0036 {
0037     struct hvsi_control ctrl;
0038 
0039     pv->established = 0;
0040 
0041     ctrl.hdr.type = VS_CONTROL_PACKET_HEADER;
0042     ctrl.hdr.len = sizeof(struct hvsi_control);
0043     ctrl.verb = cpu_to_be16(VSV_CLOSE_PROTOCOL);
0044     return hvsi_send_packet(pv, &ctrl.hdr);
0045 }
0046 
0047 static void hvsi_cd_change(struct hvsi_priv *pv, int cd)
0048 {
0049     if (cd)
0050         pv->mctrl |= TIOCM_CD;
0051     else {
0052         pv->mctrl &= ~TIOCM_CD;
0053 
0054         /* We copy the existing hvsi driver semantics
0055          * here which are to trigger a hangup when
0056          * we get a carrier loss.
0057          * Closing our connection to the server will
0058          * do just that.
0059          */
0060         if (!pv->is_console && pv->opened) {
0061             pr_devel("HVSI@%x Carrier lost, hanging up !\n",
0062                  pv->termno);
0063             hvsi_send_close(pv);
0064         }
0065     }
0066 }
0067 
0068 static void hvsi_got_control(struct hvsi_priv *pv)
0069 {
0070     struct hvsi_control *pkt = (struct hvsi_control *)pv->inbuf;
0071 
0072     switch (be16_to_cpu(pkt->verb)) {
0073     case VSV_CLOSE_PROTOCOL:
0074         /* We restart the handshaking */
0075         hvsi_start_handshake(pv);
0076         break;
0077     case VSV_MODEM_CTL_UPDATE:
0078         /* Transition of carrier detect */
0079         hvsi_cd_change(pv, be32_to_cpu(pkt->word) & HVSI_TSCD);
0080         break;
0081     }
0082 }
0083 
0084 static void hvsi_got_query(struct hvsi_priv *pv)
0085 {
0086     struct hvsi_query *pkt = (struct hvsi_query *)pv->inbuf;
0087     struct hvsi_query_response r;
0088 
0089     /* We only handle version queries */
0090     if (be16_to_cpu(pkt->verb) != VSV_SEND_VERSION_NUMBER)
0091         return;
0092 
0093     pr_devel("HVSI@%x: Got version query, sending response...\n",
0094          pv->termno);
0095 
0096     /* Send version response */
0097     r.hdr.type = VS_QUERY_RESPONSE_PACKET_HEADER;
0098     r.hdr.len = sizeof(struct hvsi_query_response);
0099     r.verb = cpu_to_be16(VSV_SEND_VERSION_NUMBER);
0100     r.u.version = HVSI_VERSION;
0101     r.query_seqno = pkt->hdr.seqno;
0102     hvsi_send_packet(pv, &r.hdr);
0103 
0104     /* Assume protocol is open now */
0105     pv->established = 1;
0106 }
0107 
0108 static void hvsi_got_response(struct hvsi_priv *pv)
0109 {
0110     struct hvsi_query_response *r =
0111         (struct hvsi_query_response *)pv->inbuf;
0112 
0113     switch(r->verb) {
0114     case VSV_SEND_MODEM_CTL_STATUS:
0115         hvsi_cd_change(pv, be32_to_cpu(r->u.mctrl_word) & HVSI_TSCD);
0116         pv->mctrl_update = 1;
0117         break;
0118     }
0119 }
0120 
0121 static int hvsi_check_packet(struct hvsi_priv *pv)
0122 {
0123     u8 len, type;
0124 
0125     /* Check header validity. If it's invalid, we ditch
0126      * the whole buffer and hope we eventually resync
0127      */
0128     if (pv->inbuf[0] < 0xfc) {
0129         pv->inbuf_len = pv->inbuf_pktlen = 0;
0130         return 0;
0131     }
0132     type = pv->inbuf[0];
0133     len = pv->inbuf[1];
0134 
0135     /* Packet incomplete ? */
0136     if (pv->inbuf_len < len)
0137         return 0;
0138 
0139     pr_devel("HVSI@%x: Got packet type %x len %d bytes:\n",
0140          pv->termno, type, len);
0141 
0142     /* We have a packet, yay ! Handle it */
0143     switch(type) {
0144     case VS_DATA_PACKET_HEADER:
0145         pv->inbuf_pktlen = len - 4;
0146         pv->inbuf_cur = 4;
0147         return 1;
0148     case VS_CONTROL_PACKET_HEADER:
0149         hvsi_got_control(pv);
0150         break;
0151     case VS_QUERY_PACKET_HEADER:
0152         hvsi_got_query(pv);
0153         break;
0154     case VS_QUERY_RESPONSE_PACKET_HEADER:
0155         hvsi_got_response(pv);
0156         break;
0157     }
0158 
0159     /* Swallow packet and retry */
0160     pv->inbuf_len -= len;
0161     memmove(pv->inbuf, &pv->inbuf[len], pv->inbuf_len);
0162     return 1;
0163 }
0164 
0165 static int hvsi_get_packet(struct hvsi_priv *pv)
0166 {
0167     /* If we have room in the buffer, ask HV for more */
0168     if (pv->inbuf_len < HVSI_INBUF_SIZE)
0169         pv->inbuf_len += pv->get_chars(pv->termno,
0170                          &pv->inbuf[pv->inbuf_len],
0171                          HVSI_INBUF_SIZE - pv->inbuf_len);
0172     /*
0173      * If we have at least 4 bytes in the buffer, check for
0174      * a full packet and retry
0175      */
0176     if (pv->inbuf_len >= 4)
0177         return hvsi_check_packet(pv);
0178     return 0;
0179 }
0180 
0181 int hvsilib_get_chars(struct hvsi_priv *pv, char *buf, int count)
0182 {
0183     unsigned int tries, read = 0;
0184 
0185     if (WARN_ON(!pv))
0186         return -ENXIO;
0187 
0188     /* If we aren't open, don't do anything in order to avoid races
0189      * with connection establishment. The hvc core will call this
0190      * before we have returned from notifier_add(), and we need to
0191      * avoid multiple users playing with the receive buffer
0192      */
0193     if (!pv->opened)
0194         return 0;
0195 
0196     /* We try twice, once with what data we have and once more
0197      * after we try to fetch some more from the hypervisor
0198      */
0199     for (tries = 1; count && tries < 2; tries++) {
0200         /* Consume existing data packet */
0201         if (pv->inbuf_pktlen) {
0202             unsigned int l = min(count, (int)pv->inbuf_pktlen);
0203             memcpy(&buf[read], &pv->inbuf[pv->inbuf_cur], l);
0204             pv->inbuf_cur += l;
0205             pv->inbuf_pktlen -= l;
0206             count -= l;
0207             read += l;
0208         }
0209         if (count == 0)
0210             break;
0211 
0212         /* Data packet fully consumed, move down remaning data */
0213         if (pv->inbuf_cur) {
0214             pv->inbuf_len -= pv->inbuf_cur;
0215             memmove(pv->inbuf, &pv->inbuf[pv->inbuf_cur],
0216                 pv->inbuf_len);
0217             pv->inbuf_cur = 0;
0218         }
0219 
0220         /* Try to get another packet */
0221         if (hvsi_get_packet(pv))
0222             tries--;
0223     }
0224     if (!pv->established) {
0225         pr_devel("HVSI@%x: returning -EPIPE\n", pv->termno);
0226         return -EPIPE;
0227     }
0228     return read;
0229 }
0230 
0231 int hvsilib_put_chars(struct hvsi_priv *pv, const char *buf, int count)
0232 {
0233     struct hvsi_data dp;
0234     int rc, adjcount = min(count, HVSI_MAX_OUTGOING_DATA);
0235 
0236     if (WARN_ON(!pv))
0237         return -ENODEV;
0238 
0239     dp.hdr.type = VS_DATA_PACKET_HEADER;
0240     dp.hdr.len = adjcount + sizeof(struct hvsi_header);
0241     memcpy(dp.data, buf, adjcount);
0242     rc = hvsi_send_packet(pv, &dp.hdr);
0243     if (rc <= 0)
0244         return rc;
0245     return adjcount;
0246 }
0247 
0248 static void maybe_msleep(unsigned long ms)
0249 {
0250     /* During early boot, IRQs are disabled, use mdelay */
0251     if (irqs_disabled())
0252         mdelay(ms);
0253     else
0254         msleep(ms);
0255 }
0256 
0257 int hvsilib_read_mctrl(struct hvsi_priv *pv)
0258 {
0259     struct hvsi_query q;
0260     int rc, timeout;
0261 
0262     pr_devel("HVSI@%x: Querying modem control status...\n",
0263          pv->termno);
0264 
0265     pv->mctrl_update = 0;
0266     q.hdr.type = VS_QUERY_PACKET_HEADER;
0267     q.hdr.len = sizeof(struct hvsi_query);
0268     q.verb = cpu_to_be16(VSV_SEND_MODEM_CTL_STATUS);
0269     rc = hvsi_send_packet(pv, &q.hdr);
0270     if (rc <= 0) {
0271         pr_devel("HVSI@%x: Error %d...\n", pv->termno, rc);
0272         return rc;
0273     }
0274 
0275     /* Try for up to 200ms */
0276     for (timeout = 0; timeout < 20; timeout++) {
0277         if (!pv->established)
0278             return -ENXIO;
0279         if (pv->mctrl_update)
0280             return 0;
0281         if (!hvsi_get_packet(pv))
0282             maybe_msleep(10);
0283     }
0284     return -EIO;
0285 }
0286 
0287 int hvsilib_write_mctrl(struct hvsi_priv *pv, int dtr)
0288 {
0289     struct hvsi_control ctrl;
0290     unsigned short mctrl;
0291 
0292     mctrl = pv->mctrl;
0293     if (dtr)
0294         mctrl |= TIOCM_DTR;
0295     else
0296         mctrl &= ~TIOCM_DTR;
0297     if (mctrl == pv->mctrl)
0298         return 0;
0299     pv->mctrl = mctrl;
0300 
0301     pr_devel("HVSI@%x: %s DTR...\n", pv->termno,
0302          dtr ? "Setting" : "Clearing");
0303 
0304     ctrl.hdr.type = VS_CONTROL_PACKET_HEADER,
0305     ctrl.hdr.len = sizeof(struct hvsi_control);
0306     ctrl.verb = cpu_to_be16(VSV_SET_MODEM_CTL);
0307     ctrl.mask = cpu_to_be32(HVSI_TSDTR);
0308     ctrl.word = cpu_to_be32(dtr ? HVSI_TSDTR : 0);
0309     return hvsi_send_packet(pv, &ctrl.hdr);
0310 }
0311 
0312 void hvsilib_establish(struct hvsi_priv *pv)
0313 {
0314     int timeout;
0315 
0316     pr_devel("HVSI@%x: Establishing...\n", pv->termno);
0317 
0318     /* Try for up to 200ms, there can be a packet to
0319      * start the process waiting for us...
0320      */
0321     for (timeout = 0; timeout < 20; timeout++) {
0322         if (pv->established)
0323             goto established;
0324         if (!hvsi_get_packet(pv))
0325             maybe_msleep(10);
0326     }
0327 
0328     /* Failed, send a close connection packet just
0329      * in case
0330      */
0331     pr_devel("HVSI@%x:   ... sending close\n", pv->termno);
0332 
0333     hvsi_send_close(pv);
0334 
0335     /* Then restart handshake */
0336 
0337     pr_devel("HVSI@%x:   ... restarting handshake\n", pv->termno);
0338 
0339     hvsi_start_handshake(pv);
0340 
0341     pr_devel("HVSI@%x:   ... waiting handshake\n", pv->termno);
0342 
0343     /* Try for up to 400ms */
0344     for (timeout = 0; timeout < 40; timeout++) {
0345         if (pv->established)
0346             goto established;
0347         if (!hvsi_get_packet(pv))
0348             maybe_msleep(10);
0349     }
0350 
0351     if (!pv->established) {
0352         pr_devel("HVSI@%x: Timeout handshaking, giving up !\n",
0353              pv->termno);
0354         return;
0355     }
0356  established:
0357     /* Query modem control lines */
0358 
0359     pr_devel("HVSI@%x:   ... established, reading mctrl\n", pv->termno);
0360 
0361     hvsilib_read_mctrl(pv);
0362 
0363     /* Set our own DTR */
0364 
0365     pr_devel("HVSI@%x:   ... setting mctrl\n", pv->termno);
0366 
0367     hvsilib_write_mctrl(pv, 1);
0368 
0369     /* Set the opened flag so reads are allowed */
0370     wmb();
0371     pv->opened = 1;
0372 }
0373 
0374 int hvsilib_open(struct hvsi_priv *pv, struct hvc_struct *hp)
0375 {
0376     pr_devel("HVSI@%x: open !\n", pv->termno);
0377 
0378     /* Keep track of the tty data structure */
0379     pv->tty = tty_port_tty_get(&hp->port);
0380 
0381     hvsilib_establish(pv);
0382 
0383     return 0;
0384 }
0385 
0386 void hvsilib_close(struct hvsi_priv *pv, struct hvc_struct *hp)
0387 {
0388     unsigned long flags;
0389 
0390     pr_devel("HVSI@%x: close !\n", pv->termno);
0391 
0392     if (!pv->is_console) {
0393         pr_devel("HVSI@%x: Not a console, tearing down\n",
0394              pv->termno);
0395 
0396         /* Clear opened, synchronize with khvcd */
0397         spin_lock_irqsave(&hp->lock, flags);
0398         pv->opened = 0;
0399         spin_unlock_irqrestore(&hp->lock, flags);
0400 
0401         /* Clear our own DTR */
0402         if (!pv->tty || (pv->tty->termios.c_cflag & HUPCL))
0403             hvsilib_write_mctrl(pv, 0);
0404 
0405         /* Tear down the connection */
0406         hvsi_send_close(pv);
0407     }
0408 
0409     tty_kref_put(pv->tty);
0410     pv->tty = NULL;
0411 }
0412 
0413 void hvsilib_init(struct hvsi_priv *pv,
0414           int (*get_chars)(uint32_t termno, char *buf, int count),
0415           int (*put_chars)(uint32_t termno, const char *buf,
0416                    int count),
0417           int termno, int is_console)
0418 {
0419     memset(pv, 0, sizeof(*pv));
0420     pv->get_chars = get_chars;
0421     pv->put_chars = put_chars;
0422     pv->termno = termno;
0423     pv->is_console = is_console;
0424 }