Home | History | Annotate | Line # | Download | only in virtio
viocon.c revision 1.5.4.1
      1  1.5.4.1    martin /*	$NetBSD: viocon.c,v 1.5.4.1 2023/05/13 10:56:10 martin Exp $	*/
      2      1.1  riastrad /*	$OpenBSD: viocon.c,v 1.8 2021/11/05 11:38:29 mpi Exp $	*/
      3      1.1  riastrad 
      4      1.1  riastrad /*
      5      1.1  riastrad  * Copyright (c) 2013-2015 Stefan Fritsch <sf (at) sfritsch.de>
      6      1.1  riastrad  *
      7      1.1  riastrad  * Permission to use, copy, modify, and distribute this software for any
      8      1.1  riastrad  * purpose with or without fee is hereby granted, provided that the above
      9      1.1  riastrad  * copyright notice and this permission notice appear in all copies.
     10      1.1  riastrad  *
     11      1.1  riastrad  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     12      1.1  riastrad  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13      1.1  riastrad  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     14      1.1  riastrad  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15      1.1  riastrad  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16      1.1  riastrad  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     17      1.1  riastrad  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18      1.1  riastrad  */
     19      1.1  riastrad 
     20      1.1  riastrad #include <sys/cdefs.h>
     21  1.5.4.1    martin __KERNEL_RCSID(0, "$NetBSD: viocon.c,v 1.5.4.1 2023/05/13 10:56:10 martin Exp $");
     22      1.1  riastrad 
     23      1.1  riastrad #include <sys/param.h>
     24      1.1  riastrad #include <sys/types.h>
     25      1.1  riastrad 
     26      1.1  riastrad #include <sys/bus.h>
     27      1.1  riastrad #include <sys/conf.h>
     28      1.1  riastrad #include <sys/device.h>
     29      1.1  riastrad #include <sys/kauth.h>
     30      1.1  riastrad #include <sys/kernel.h>
     31      1.1  riastrad #include <sys/kmem.h>
     32      1.1  riastrad #include <sys/lwp.h>
     33      1.1  riastrad #include <sys/systm.h>
     34      1.1  riastrad #include <sys/tty.h>
     35      1.1  riastrad 
     36      1.1  riastrad #include <dev/pci/virtioreg.h>
     37      1.1  riastrad #include <dev/pci/virtiovar.h>
     38      1.1  riastrad 
     39      1.1  riastrad #include "ioconf.h"
     40      1.1  riastrad 
     41      1.1  riastrad /* OpenBSD compat shims */
     42      1.1  riastrad #define	ttymalloc(speed)	tty_alloc()
     43      1.1  riastrad #define	splassert(ipl)		__nothing
     44      1.1  riastrad #define	virtio_notify(vsc, vq)	virtio_enqueue_commit(vsc, vq, -1, true)
     45      1.1  riastrad #define	ttwakeupwr(tp)		__nothing
     46      1.1  riastrad 
     47      1.1  riastrad /* features */
     48      1.1  riastrad #define	VIRTIO_CONSOLE_F_SIZE		(1ULL<<0)
     49      1.1  riastrad #define	VIRTIO_CONSOLE_F_MULTIPORT	(1ULL<<1)
     50      1.1  riastrad #define	VIRTIO_CONSOLE_F_EMERG_WRITE 	(1ULL<<2)
     51      1.1  riastrad 
     52      1.1  riastrad /* config space */
     53      1.1  riastrad #define VIRTIO_CONSOLE_COLS		0	/* 16 bits */
     54      1.1  riastrad #define VIRTIO_CONSOLE_ROWS		2	/* 16 bits */
     55      1.1  riastrad #define VIRTIO_CONSOLE_MAX_NR_PORTS	4	/* 32 bits */
     56      1.1  riastrad #define VIRTIO_CONSOLE_EMERG_WR		8	/* 32 bits */
     57      1.1  riastrad 
     58      1.1  riastrad #define VIOCON_DEBUG	0
     59      1.1  riastrad 
     60      1.1  riastrad #if VIOCON_DEBUG
     61      1.1  riastrad #define DPRINTF(x...) printf(x)
     62      1.1  riastrad #else
     63      1.1  riastrad #define DPRINTF(x...)
     64      1.1  riastrad #endif
     65      1.1  riastrad 
     66      1.1  riastrad #define	VIRTIO_CONSOLE_FLAG_BITS					      \
     67      1.1  riastrad 	VIRTIO_COMMON_FLAG_BITS						      \
     68      1.1  riastrad 	"b\x00" "SIZE\0"						      \
     69      1.1  riastrad 	"b\x01" "MULTIPORT\0"						      \
     70      1.1  riastrad 	"b\x02" "EMERG_WRITE\0"
     71      1.1  riastrad 
     72      1.1  riastrad struct virtio_console_control {
     73      1.1  riastrad 	uint32_t id;	/* Port number */
     74      1.1  riastrad 
     75      1.1  riastrad #define	VIRTIO_CONSOLE_DEVICE_READY	0
     76      1.1  riastrad #define	VIRTIO_CONSOLE_PORT_ADD		1
     77      1.1  riastrad #define	VIRTIO_CONSOLE_PORT_REMOVE	2
     78      1.1  riastrad #define	VIRTIO_CONSOLE_PORT_READY	3
     79      1.1  riastrad #define	VIRTIO_CONSOLE_CONSOLE_PORT	4
     80      1.1  riastrad #define	VIRTIO_CONSOLE_RESIZE		5
     81      1.1  riastrad #define	VIRTIO_CONSOLE_PORT_OPEN	6
     82      1.1  riastrad #define	VIRTIO_CONSOLE_PORT_NAME	7
     83      1.1  riastrad 	uint16_t event;
     84      1.1  riastrad 
     85      1.1  riastrad 	uint16_t value;
     86      1.1  riastrad };
     87      1.1  riastrad 
     88      1.1  riastrad struct virtio_console_control_resize {
     89      1.1  riastrad 	/* yes, the order is different than in config space */
     90      1.1  riastrad 	uint16_t rows;
     91      1.1  riastrad 	uint16_t cols;
     92      1.1  riastrad };
     93      1.1  riastrad 
     94      1.1  riastrad #define	BUFSIZE		128
     95      1.1  riastrad 
     96      1.2  riastrad #define	VIOCONDEV(u,p)	makedev(cdevsw_lookup_major(&viocon_cdevsw),	      \
     97      1.2  riastrad 			    ((u) << 4) | (p))
     98      1.1  riastrad #define VIOCONUNIT(x)	(minor(x) >> 4)
     99      1.1  riastrad #define VIOCONPORT(x)	(minor(x) & 0x0f)
    100      1.1  riastrad 
    101      1.1  riastrad struct viocon_port {
    102      1.1  riastrad 	struct viocon_softc	*vp_sc;
    103      1.1  riastrad 	struct virtqueue	*vp_rx;
    104      1.1  riastrad 	struct virtqueue	*vp_tx;
    105      1.1  riastrad 	void			*vp_si;
    106      1.1  riastrad 	struct tty		*vp_tty;
    107      1.1  riastrad 	const char 		*vp_name;
    108      1.1  riastrad 	bus_dma_segment_t	 vp_dmaseg;
    109      1.1  riastrad 	bus_dmamap_t		 vp_dmamap;
    110      1.1  riastrad #ifdef NOTYET
    111      1.1  riastrad 	unsigned int		 vp_host_open:1;	/* XXX needs F_MULTIPORT */
    112      1.1  riastrad 	unsigned int		 vp_guest_open:1;	/* XXX needs F_MULTIPORT */
    113      1.1  riastrad 	unsigned int		 vp_is_console:1;	/* XXX needs F_MULTIPORT */
    114      1.1  riastrad #endif
    115      1.1  riastrad 	unsigned int		 vp_iflow:1;		/* rx flow control */
    116      1.1  riastrad 	uint16_t		 vp_rows;
    117      1.1  riastrad 	uint16_t		 vp_cols;
    118      1.1  riastrad 	u_char			*vp_rx_buf;
    119      1.1  riastrad 	u_char			*vp_tx_buf;
    120      1.1  riastrad };
    121      1.1  riastrad 
    122      1.1  riastrad struct viocon_softc {
    123      1.1  riastrad 	struct device		*sc_dev;
    124      1.1  riastrad 	struct virtio_softc	*sc_virtio;
    125      1.1  riastrad 	struct virtqueue	*sc_vqs;
    126  1.5.4.1    martin #define VIOCON_PORT_RX	0
    127  1.5.4.1    martin #define VIOCON_PORT_TX	1
    128  1.5.4.1    martin #define VIOCON_PORT_NQS	2
    129      1.1  riastrad 
    130      1.1  riastrad 	struct virtqueue        *sc_c_vq_rx;
    131      1.1  riastrad 	struct virtqueue        *sc_c_vq_tx;
    132      1.1  riastrad 
    133      1.1  riastrad 	unsigned int		 sc_max_ports;
    134      1.1  riastrad 	struct viocon_port	**sc_ports;
    135      1.1  riastrad };
    136      1.1  riastrad 
    137      1.1  riastrad int	viocon_match(struct device *, struct cfdata *, void *);
    138      1.1  riastrad void	viocon_attach(struct device *, struct device *, void *);
    139      1.1  riastrad int	viocon_tx_intr(struct virtqueue *);
    140      1.1  riastrad int	viocon_tx_drain(struct viocon_port *, struct virtqueue *vq);
    141      1.1  riastrad int	viocon_rx_intr(struct virtqueue *);
    142      1.1  riastrad void	viocon_rx_soft(void *);
    143      1.1  riastrad void	viocon_rx_fill(struct viocon_port *);
    144      1.1  riastrad int	viocon_port_create(struct viocon_softc *, int);
    145      1.1  riastrad void	vioconstart(struct tty *);
    146      1.1  riastrad int	vioconhwiflow(struct tty *, int);
    147      1.1  riastrad int	vioconparam(struct tty *, struct termios *);
    148      1.1  riastrad int	vioconopen(dev_t, int, int, struct lwp *);
    149      1.1  riastrad int	vioconclose(dev_t, int, int, struct lwp *);
    150      1.1  riastrad int	vioconread(dev_t, struct uio *, int);
    151      1.1  riastrad int	vioconwrite(dev_t, struct uio *, int);
    152      1.1  riastrad void	vioconstop(struct tty *, int);
    153      1.1  riastrad int	vioconioctl(dev_t, u_long, void *, int, struct lwp *);
    154      1.1  riastrad struct tty	*viocontty(dev_t dev);
    155      1.1  riastrad 
    156      1.1  riastrad CFATTACH_DECL_NEW(viocon, sizeof(struct viocon_softc),
    157      1.1  riastrad     viocon_match, viocon_attach, /*detach*/NULL, /*activate*/NULL);
    158      1.1  riastrad 
    159      1.1  riastrad const struct cdevsw viocon_cdevsw = {
    160      1.1  riastrad 	.d_open = vioconopen,
    161      1.1  riastrad 	.d_close = vioconclose,
    162      1.1  riastrad 	.d_read = vioconread,
    163      1.1  riastrad 	.d_write = vioconwrite,
    164      1.1  riastrad 	.d_ioctl = vioconioctl,
    165      1.1  riastrad 	.d_stop = vioconstop,
    166      1.1  riastrad 	.d_tty = viocontty,
    167      1.1  riastrad 	.d_poll = nopoll,	/* XXX */
    168      1.1  riastrad 	.d_mmap = nommap,
    169      1.1  riastrad 	.d_kqfilter = ttykqfilter,
    170      1.1  riastrad 	.d_discard = nodiscard,
    171      1.1  riastrad 	.d_flag = D_TTY,
    172      1.1  riastrad };
    173      1.1  riastrad 
    174      1.1  riastrad static inline struct viocon_softc *
    175      1.1  riastrad dev2sc(dev_t dev)
    176      1.1  riastrad {
    177      1.1  riastrad 	return device_lookup_private(&viocon_cd, VIOCONUNIT(dev));
    178      1.1  riastrad }
    179      1.1  riastrad 
    180      1.1  riastrad static inline struct viocon_port *
    181      1.1  riastrad dev2port(dev_t dev)
    182      1.1  riastrad {
    183      1.1  riastrad 	return dev2sc(dev)->sc_ports[VIOCONPORT(dev)];
    184      1.1  riastrad }
    185      1.1  riastrad 
    186      1.1  riastrad int viocon_match(struct device *parent, struct cfdata *match, void *aux)
    187      1.1  riastrad {
    188      1.1  riastrad 	struct virtio_attach_args *va = aux;
    189      1.1  riastrad 	if (va->sc_childdevid == VIRTIO_DEVICE_ID_CONSOLE)
    190      1.1  riastrad 		return 1;
    191      1.1  riastrad 	return 0;
    192      1.1  riastrad }
    193      1.1  riastrad 
    194      1.1  riastrad void
    195      1.1  riastrad viocon_attach(struct device *parent, struct device *self, void *aux)
    196      1.1  riastrad {
    197      1.1  riastrad 	struct viocon_softc *sc = device_private(self);
    198      1.1  riastrad 	struct virtio_softc *vsc = device_private(parent);
    199      1.1  riastrad 	int maxports = 1;
    200  1.5.4.1    martin 	size_t nvqs;
    201      1.1  riastrad 
    202      1.1  riastrad 	sc->sc_dev = self;
    203      1.1  riastrad 	if (virtio_child(vsc) != NULL) {
    204      1.1  riastrad 		aprint_error(": parent %s already has a child\n",
    205      1.1  riastrad 		    device_xname(parent));
    206      1.1  riastrad 		return;
    207      1.1  riastrad 	}
    208      1.1  riastrad 	sc->sc_virtio = vsc;
    209      1.1  riastrad 	sc->sc_max_ports = maxports;
    210  1.5.4.1    martin 	nvqs = VIOCON_PORT_NQS * maxports;
    211      1.1  riastrad 
    212  1.5.4.1    martin 	sc->sc_vqs = kmem_zalloc(nvqs * sizeof(sc->sc_vqs[0]),
    213      1.1  riastrad 	    KM_SLEEP);
    214      1.1  riastrad 	sc->sc_ports = kmem_zalloc(maxports * sizeof(sc->sc_ports[0]),
    215      1.1  riastrad 	    KM_SLEEP);
    216      1.1  riastrad 
    217  1.5.4.1    martin 	virtio_child_attach_start(vsc, self, IPL_TTY,
    218  1.5.4.1    martin 	    /*req_features*/VIRTIO_CONSOLE_F_SIZE, VIRTIO_CONSOLE_FLAG_BITS);
    219      1.1  riastrad 
    220      1.1  riastrad 	DPRINTF("%s: softc: %p\n", __func__, sc);
    221      1.1  riastrad 	if (viocon_port_create(sc, 0) != 0) {
    222      1.1  riastrad 		printf("\n%s: viocon_port_create failed\n", __func__);
    223      1.1  riastrad 		goto err;
    224      1.1  riastrad 	}
    225      1.1  riastrad 	viocon_rx_fill(sc->sc_ports[0]);
    226      1.1  riastrad 
    227  1.5.4.1    martin 	if (virtio_child_attach_finish(vsc, sc->sc_vqs, nvqs,
    228  1.5.4.1    martin 	    /*config_change*/NULL, /*req_flags*/0) != 0)
    229      1.1  riastrad 		goto err;
    230      1.1  riastrad 
    231      1.1  riastrad 	return;
    232      1.1  riastrad err:
    233  1.5.4.1    martin 	kmem_free(sc->sc_vqs, nvqs * sizeof(sc->sc_vqs[0]));
    234      1.1  riastrad 	kmem_free(sc->sc_ports, maxports * sizeof(sc->sc_ports[0]));
    235      1.1  riastrad 	virtio_child_attach_failed(vsc);
    236      1.1  riastrad }
    237      1.1  riastrad 
    238      1.1  riastrad int
    239      1.1  riastrad viocon_port_create(struct viocon_softc *sc, int portidx)
    240      1.1  riastrad {
    241      1.1  riastrad 	struct virtio_softc *vsc = sc->sc_virtio;
    242      1.1  riastrad 	int rxidx, txidx, allocsize, nsegs;
    243      1.1  riastrad 	char name[6];
    244      1.1  riastrad 	struct viocon_port *vp;
    245      1.1  riastrad 	void *kva;
    246      1.1  riastrad 	struct tty *tp;
    247      1.1  riastrad 
    248      1.1  riastrad 	vp = kmem_zalloc(sizeof(*vp), KM_SLEEP);
    249      1.1  riastrad 	if (vp == NULL)
    250      1.1  riastrad 		return ENOMEM;
    251      1.1  riastrad 	sc->sc_ports[portidx] = vp;
    252      1.1  riastrad 	vp->vp_sc = sc;
    253      1.1  riastrad 	DPRINTF("%s: vp: %p\n", __func__, vp);
    254      1.1  riastrad 
    255  1.5.4.1    martin 	rxidx = (portidx * VIOCON_PORT_NQS) + VIOCON_PORT_RX;
    256  1.5.4.1    martin 	txidx = (portidx * VIOCON_PORT_NQS) + VIOCON_PORT_TX;
    257      1.1  riastrad 
    258      1.1  riastrad 	snprintf(name, sizeof(name), "p%drx", portidx);
    259  1.5.4.1    martin 	virtio_init_vq_vqdone(vsc, &sc->sc_vqs[rxidx], rxidx,
    260  1.5.4.1    martin 	    viocon_rx_intr);
    261  1.5.4.1    martin 	if (virtio_alloc_vq(vsc, &sc->sc_vqs[rxidx], BUFSIZE, 1,
    262      1.1  riastrad 	    name) != 0) {
    263      1.1  riastrad 		printf("\nCan't alloc %s virtqueue\n", name);
    264      1.1  riastrad 		goto err;
    265      1.1  riastrad 	}
    266      1.1  riastrad 	vp->vp_rx = &sc->sc_vqs[rxidx];
    267      1.1  riastrad 	vp->vp_si = softint_establish(SOFTINT_SERIAL, viocon_rx_soft, vp);
    268      1.1  riastrad 	DPRINTF("%s: rx: %p\n", __func__, vp->vp_rx);
    269      1.1  riastrad 
    270      1.1  riastrad 	snprintf(name, sizeof(name), "p%dtx", portidx);
    271  1.5.4.1    martin 	virtio_init_vq_vqdone(vsc, &sc->sc_vqs[txidx], txidx,
    272  1.5.4.1    martin 	    viocon_tx_intr);
    273  1.5.4.1    martin 	if (virtio_alloc_vq(vsc, &sc->sc_vqs[txidx], BUFSIZE, 1,
    274      1.1  riastrad 	    name) != 0) {
    275      1.1  riastrad 		printf("\nCan't alloc %s virtqueue\n", name);
    276      1.1  riastrad 		goto err;
    277      1.1  riastrad 	}
    278      1.1  riastrad 	vp->vp_tx = &sc->sc_vqs[txidx];
    279      1.1  riastrad 	DPRINTF("%s: tx: %p\n", __func__, vp->vp_tx);
    280      1.1  riastrad 
    281      1.1  riastrad 	allocsize = (vp->vp_rx->vq_num + vp->vp_tx->vq_num) * BUFSIZE;
    282      1.1  riastrad 
    283      1.1  riastrad 	if (bus_dmamap_create(virtio_dmat(vsc), allocsize, 1, allocsize, 0,
    284      1.1  riastrad 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &vp->vp_dmamap) != 0)
    285      1.1  riastrad 		goto err;
    286      1.1  riastrad 	if (bus_dmamem_alloc(virtio_dmat(vsc), allocsize, 8, 0, &vp->vp_dmaseg,
    287      1.1  riastrad 	    1, &nsegs, BUS_DMA_NOWAIT) != 0)
    288      1.1  riastrad 		goto err;
    289      1.1  riastrad 	if (bus_dmamem_map(virtio_dmat(vsc), &vp->vp_dmaseg, nsegs,
    290      1.1  riastrad 	    allocsize, &kva, BUS_DMA_NOWAIT) != 0)
    291      1.1  riastrad 		goto err;
    292      1.1  riastrad 	memset(kva, 0, allocsize);
    293      1.1  riastrad 	if (bus_dmamap_load(virtio_dmat(vsc), vp->vp_dmamap, kva,
    294      1.1  riastrad 	    allocsize, NULL, BUS_DMA_NOWAIT) != 0)
    295      1.1  riastrad 		goto err;
    296      1.1  riastrad 	vp->vp_rx_buf = (unsigned char *)kva;
    297      1.1  riastrad 	/*
    298      1.1  riastrad 	 * XXX use only a small circular tx buffer instead of many BUFSIZE buffers?
    299      1.1  riastrad 	 */
    300      1.1  riastrad 	vp->vp_tx_buf = vp->vp_rx_buf + vp->vp_rx->vq_num * BUFSIZE;
    301      1.1  riastrad 
    302      1.1  riastrad 	if (virtio_features(vsc) & VIRTIO_CONSOLE_F_SIZE) {
    303      1.1  riastrad 		vp->vp_cols = virtio_read_device_config_2(vsc,
    304      1.1  riastrad 		    VIRTIO_CONSOLE_COLS);
    305      1.1  riastrad 		vp->vp_rows = virtio_read_device_config_2(vsc,
    306      1.1  riastrad 		    VIRTIO_CONSOLE_ROWS);
    307      1.1  riastrad 	}
    308      1.1  riastrad 
    309      1.1  riastrad 	tp = ttymalloc(1000000);
    310      1.1  riastrad 	tp->t_oproc = vioconstart;
    311      1.1  riastrad 	tp->t_param = vioconparam;
    312      1.1  riastrad 	tp->t_hwiflow = vioconhwiflow;
    313      1.2  riastrad 	tp->t_dev = VIOCONDEV(device_unit(sc->sc_dev), portidx);
    314      1.1  riastrad 	vp->vp_tty = tp;
    315      1.1  riastrad 	DPRINTF("%s: tty: %p\n", __func__, tp);
    316      1.1  riastrad 
    317      1.1  riastrad 	virtio_start_vq_intr(vsc, vp->vp_rx);
    318      1.1  riastrad 	virtio_start_vq_intr(vsc, vp->vp_tx);
    319      1.1  riastrad 
    320      1.1  riastrad 	return 0;
    321      1.1  riastrad err:
    322      1.1  riastrad 	panic("%s failed", __func__);
    323      1.1  riastrad 	return -1;
    324      1.1  riastrad }
    325      1.1  riastrad 
    326      1.1  riastrad int
    327      1.1  riastrad viocon_tx_drain(struct viocon_port *vp, struct virtqueue *vq)
    328      1.1  riastrad {
    329      1.1  riastrad 	struct virtio_softc *vsc = vq->vq_owner;
    330      1.1  riastrad 	int ndone = 0, len, slot;
    331      1.1  riastrad 
    332      1.1  riastrad 	splassert(IPL_TTY);
    333      1.1  riastrad 	while (virtio_dequeue(vsc, vq, &slot, &len) == 0) {
    334      1.1  riastrad 		bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap,
    335      1.1  riastrad 		    vp->vp_tx_buf - vp->vp_rx_buf + slot * BUFSIZE, BUFSIZE,
    336      1.4  riastrad 		    BUS_DMASYNC_POSTWRITE);
    337      1.1  riastrad 		virtio_dequeue_commit(vsc, vq, slot);
    338      1.1  riastrad 		ndone++;
    339      1.1  riastrad 	}
    340      1.1  riastrad 	return ndone;
    341      1.1  riastrad }
    342      1.1  riastrad 
    343      1.1  riastrad int
    344      1.1  riastrad viocon_tx_intr(struct virtqueue *vq)
    345      1.1  riastrad {
    346      1.1  riastrad 	struct virtio_softc *vsc = vq->vq_owner;
    347      1.1  riastrad 	struct viocon_softc *sc = device_private(virtio_child(vsc));
    348      1.1  riastrad 	int ndone = 0;
    349      1.1  riastrad 	int portidx = (vq->vq_index - 1) / 2;
    350      1.1  riastrad 	struct viocon_port *vp = sc->sc_ports[portidx];
    351      1.1  riastrad 	struct tty *tp = vp->vp_tty;
    352      1.1  riastrad 
    353      1.1  riastrad 	splassert(IPL_TTY);
    354      1.1  riastrad 	ndone = viocon_tx_drain(vp, vq);
    355      1.1  riastrad 	if (ndone && ISSET(tp->t_state, TS_BUSY)) {
    356      1.1  riastrad 		CLR(tp->t_state, TS_BUSY);
    357      1.1  riastrad 		(*tp->t_linesw->l_start)(tp);
    358      1.1  riastrad 	}
    359      1.1  riastrad 
    360      1.1  riastrad 	return 1;
    361      1.1  riastrad }
    362      1.1  riastrad 
    363      1.1  riastrad void
    364      1.1  riastrad viocon_rx_fill(struct viocon_port *vp)
    365      1.1  riastrad {
    366      1.1  riastrad 	struct virtqueue *vq = vp->vp_rx;
    367      1.1  riastrad 	struct virtio_softc *vsc = vp->vp_sc->sc_virtio;
    368      1.1  riastrad 	int r, slot, ndone = 0;
    369      1.1  riastrad 
    370      1.1  riastrad 	while ((r = virtio_enqueue_prep(vsc, vq, &slot)) == 0) {
    371      1.1  riastrad 		if (virtio_enqueue_reserve(vsc, vq, slot, 1) != 0)
    372      1.1  riastrad 			break;
    373      1.1  riastrad 		bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap, slot * BUFSIZE,
    374      1.1  riastrad 		    BUFSIZE, BUS_DMASYNC_PREREAD);
    375      1.1  riastrad 		virtio_enqueue_p(vsc, vq, slot, vp->vp_dmamap, slot * BUFSIZE,
    376      1.1  riastrad 		    BUFSIZE, 0);
    377      1.1  riastrad 		virtio_enqueue_commit(vsc, vq, slot, 0);
    378      1.1  riastrad 		ndone++;
    379      1.1  riastrad 	}
    380      1.1  riastrad 	KASSERT(r == 0 || r == EAGAIN);
    381      1.1  riastrad 	if (ndone > 0)
    382      1.1  riastrad 		virtio_notify(vsc, vq);
    383      1.1  riastrad }
    384      1.1  riastrad 
    385      1.1  riastrad int
    386      1.1  riastrad viocon_rx_intr(struct virtqueue *vq)
    387      1.1  riastrad {
    388      1.1  riastrad 	struct virtio_softc *vsc = vq->vq_owner;
    389      1.1  riastrad 	struct viocon_softc *sc = device_private(virtio_child(vsc));
    390      1.1  riastrad 	int portidx = (vq->vq_index - 1) / 2;
    391      1.1  riastrad 	struct viocon_port *vp = sc->sc_ports[portidx];
    392      1.1  riastrad 
    393      1.1  riastrad 	softint_schedule(vp->vp_si);
    394      1.1  riastrad 	return 1;
    395      1.1  riastrad }
    396      1.1  riastrad 
    397      1.1  riastrad void
    398      1.1  riastrad viocon_rx_soft(void *arg)
    399      1.1  riastrad {
    400      1.1  riastrad 	struct viocon_port *vp = arg;
    401      1.1  riastrad 	struct virtqueue *vq = vp->vp_rx;
    402      1.1  riastrad 	struct virtio_softc *vsc = vq->vq_owner;
    403      1.1  riastrad 	struct tty *tp = vp->vp_tty;
    404      1.1  riastrad 	int slot, len, i;
    405      1.1  riastrad 	u_char *p;
    406      1.1  riastrad 
    407      1.1  riastrad 	while (!vp->vp_iflow && virtio_dequeue(vsc, vq, &slot, &len) == 0) {
    408      1.1  riastrad 		bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap,
    409      1.1  riastrad 		    slot * BUFSIZE, BUFSIZE, BUS_DMASYNC_POSTREAD);
    410      1.1  riastrad 		p = vp->vp_rx_buf + slot * BUFSIZE;
    411      1.1  riastrad 		for (i = 0; i < len; i++)
    412      1.1  riastrad 			(*tp->t_linesw->l_rint)(*p++, tp);
    413      1.1  riastrad 		virtio_dequeue_commit(vsc, vq, slot);
    414      1.1  riastrad 	}
    415      1.1  riastrad 
    416      1.1  riastrad 	viocon_rx_fill(vp);
    417      1.1  riastrad 
    418      1.1  riastrad 	return;
    419      1.1  riastrad }
    420      1.1  riastrad 
    421      1.1  riastrad void
    422      1.1  riastrad vioconstart(struct tty *tp)
    423      1.1  riastrad {
    424      1.1  riastrad 	struct viocon_softc *sc = dev2sc(tp->t_dev);
    425      1.1  riastrad 	struct virtio_softc *vsc;
    426      1.1  riastrad 	struct viocon_port *vp = dev2port(tp->t_dev);
    427      1.1  riastrad 	struct virtqueue *vq;
    428      1.1  riastrad 	u_char *buf;
    429      1.1  riastrad 	int s, cnt, slot, ret, ndone;
    430      1.1  riastrad 
    431      1.1  riastrad 	vsc = sc->sc_virtio;
    432      1.1  riastrad 	vq = vp->vp_tx;
    433      1.1  riastrad 
    434      1.1  riastrad 	s = spltty();
    435      1.1  riastrad 
    436      1.1  riastrad 	ndone = viocon_tx_drain(vp, vq);
    437      1.1  riastrad 	if (ISSET(tp->t_state, TS_BUSY)) {
    438      1.1  riastrad 		if (ndone > 0)
    439      1.1  riastrad 			CLR(tp->t_state, TS_BUSY);
    440      1.1  riastrad 		else
    441      1.1  riastrad 			goto out;
    442      1.1  riastrad 	}
    443      1.1  riastrad 	if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP))
    444      1.1  riastrad 		goto out;
    445      1.1  riastrad 
    446      1.1  riastrad 	if (tp->t_outq.c_cc == 0)
    447      1.1  riastrad 		goto out;
    448      1.1  riastrad 	ndone = 0;
    449      1.1  riastrad 
    450      1.1  riastrad 	while (tp->t_outq.c_cc > 0) {
    451      1.1  riastrad 		ret = virtio_enqueue_prep(vsc, vq, &slot);
    452      1.1  riastrad 		if (ret == EAGAIN) {
    453      1.1  riastrad 			SET(tp->t_state, TS_BUSY);
    454      1.1  riastrad 			break;
    455      1.1  riastrad 		}
    456      1.1  riastrad 		KASSERT(ret == 0);
    457      1.1  riastrad 		ret = virtio_enqueue_reserve(vsc, vq, slot, 1);
    458      1.1  riastrad 		KASSERT(ret == 0);
    459      1.1  riastrad 		buf = vp->vp_tx_buf + slot * BUFSIZE;
    460      1.1  riastrad 		cnt = q_to_b(&tp->t_outq, buf, BUFSIZE);
    461      1.1  riastrad 		bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap,
    462      1.1  riastrad 		    vp->vp_tx_buf - vp->vp_rx_buf + slot * BUFSIZE, cnt,
    463      1.1  riastrad 		    BUS_DMASYNC_PREWRITE);
    464      1.1  riastrad 		virtio_enqueue_p(vsc, vq, slot, vp->vp_dmamap,
    465      1.1  riastrad 		    vp->vp_tx_buf - vp->vp_rx_buf + slot * BUFSIZE, cnt, 1);
    466      1.1  riastrad 		virtio_enqueue_commit(vsc, vq, slot, 0);
    467      1.1  riastrad 		ndone++;
    468      1.1  riastrad 	}
    469      1.1  riastrad 	if (ndone > 0)
    470      1.1  riastrad 		virtio_notify(vsc, vq);
    471      1.1  riastrad 	ttwakeupwr(tp);
    472      1.1  riastrad out:
    473      1.1  riastrad 	splx(s);
    474      1.1  riastrad }
    475      1.1  riastrad 
    476      1.1  riastrad int
    477      1.1  riastrad vioconhwiflow(struct tty *tp, int stop)
    478      1.1  riastrad {
    479      1.1  riastrad 	struct viocon_port *vp = dev2port(tp->t_dev);
    480      1.1  riastrad 	int s;
    481      1.1  riastrad 
    482      1.1  riastrad 	s = spltty();
    483      1.1  riastrad 	vp->vp_iflow = stop;
    484      1.1  riastrad 	if (stop) {
    485      1.1  riastrad 		virtio_stop_vq_intr(vp->vp_sc->sc_virtio, vp->vp_rx);
    486      1.1  riastrad 	} else {
    487      1.1  riastrad 		virtio_start_vq_intr(vp->vp_sc->sc_virtio, vp->vp_rx);
    488      1.1  riastrad 		softint_schedule(vp->vp_si);
    489      1.1  riastrad 	}
    490      1.1  riastrad 	splx(s);
    491      1.1  riastrad 	return 1;
    492      1.1  riastrad }
    493      1.1  riastrad 
    494      1.1  riastrad int
    495      1.1  riastrad vioconparam(struct tty *tp, struct termios *t)
    496      1.1  riastrad {
    497      1.1  riastrad 	tp->t_ispeed = t->c_ispeed;
    498      1.1  riastrad 	tp->t_ospeed = t->c_ospeed;
    499      1.1  riastrad 	tp->t_cflag = t->c_cflag;
    500      1.1  riastrad 
    501      1.1  riastrad 	vioconstart(tp);
    502      1.1  riastrad 	return 0;
    503      1.1  riastrad }
    504      1.1  riastrad 
    505      1.1  riastrad int
    506      1.1  riastrad vioconopen(dev_t dev, int flag, int mode, struct lwp *l)
    507      1.1  riastrad {
    508      1.1  riastrad 	int unit = VIOCONUNIT(dev);
    509      1.1  riastrad 	int port = VIOCONPORT(dev);
    510      1.1  riastrad 	struct viocon_softc *sc;
    511      1.1  riastrad 	struct viocon_port *vp;
    512      1.1  riastrad 	struct tty *tp;
    513      1.1  riastrad 	int s, error;
    514      1.1  riastrad 
    515      1.1  riastrad 	sc = device_lookup_private(&viocon_cd, unit);
    516      1.1  riastrad 	if (sc == NULL)
    517      1.1  riastrad 		return (ENXIO);
    518      1.1  riastrad 	if (!device_is_active(sc->sc_dev))
    519      1.1  riastrad 		return (ENXIO);
    520      1.1  riastrad 
    521      1.1  riastrad 	s = spltty();
    522      1.1  riastrad 	if (port >= sc->sc_max_ports) {
    523      1.1  riastrad 		splx(s);
    524      1.1  riastrad 		return (ENXIO);
    525      1.1  riastrad 	}
    526      1.1  riastrad 	vp = sc->sc_ports[port];
    527      1.1  riastrad 	tp = vp->vp_tty;
    528      1.1  riastrad #ifdef NOTYET
    529      1.1  riastrad 	vp->vp_guest_open = 1;
    530      1.1  riastrad #endif
    531      1.1  riastrad 	splx(s);
    532      1.1  riastrad 
    533      1.1  riastrad 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
    534      1.1  riastrad 		return (EBUSY);
    535      1.1  riastrad 
    536      1.1  riastrad 	s = spltty();
    537      1.1  riastrad 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    538      1.1  riastrad 		ttychars(tp);
    539      1.1  riastrad 		tp->t_ispeed = 1000000;
    540      1.1  riastrad 		tp->t_ospeed = 1000000;
    541      1.1  riastrad 		tp->t_cflag = TTYDEF_CFLAG|CLOCAL|CRTSCTS;
    542      1.1  riastrad 		tp->t_iflag = TTYDEF_IFLAG;
    543      1.1  riastrad 		tp->t_oflag = TTYDEF_OFLAG;
    544      1.1  riastrad 		tp->t_lflag = TTYDEF_LFLAG;
    545      1.1  riastrad 		if (vp->vp_cols != 0) {
    546      1.1  riastrad 			tp->t_winsize.ws_col = vp->vp_cols;
    547      1.1  riastrad 			tp->t_winsize.ws_row = vp->vp_rows;
    548      1.1  riastrad 		}
    549      1.1  riastrad 
    550      1.1  riastrad 		vioconparam(tp, &tp->t_termios);
    551      1.1  riastrad 		ttsetwater(tp);
    552      1.1  riastrad 	}
    553      1.1  riastrad 	splx(s);
    554      1.1  riastrad 
    555      1.1  riastrad 	error = (*tp->t_linesw->l_open)(dev, tp);
    556      1.1  riastrad 	return error;
    557      1.1  riastrad }
    558      1.1  riastrad 
    559      1.1  riastrad int
    560      1.1  riastrad vioconclose(dev_t dev, int flag, int mode, struct lwp *l)
    561      1.1  riastrad {
    562      1.1  riastrad 	struct viocon_port *vp = dev2port(dev);
    563      1.1  riastrad 	struct tty *tp = vp->vp_tty;
    564      1.1  riastrad 	int s;
    565      1.1  riastrad 
    566      1.1  riastrad 	if (!ISSET(tp->t_state, TS_ISOPEN))
    567      1.1  riastrad 		return 0;
    568      1.1  riastrad 
    569      1.1  riastrad 	(*tp->t_linesw->l_close)(tp, flag);
    570      1.1  riastrad 	s = spltty();
    571      1.1  riastrad #ifdef NOTYET
    572      1.1  riastrad 	vp->vp_guest_open = 0;
    573      1.1  riastrad #endif
    574      1.1  riastrad 	CLR(tp->t_state, TS_BUSY | TS_FLUSH);
    575      1.1  riastrad 	ttyclose(tp);
    576      1.1  riastrad 	splx(s);
    577      1.1  riastrad 
    578      1.1  riastrad 	return 0;
    579      1.1  riastrad }
    580      1.1  riastrad 
    581      1.1  riastrad int
    582      1.1  riastrad vioconread(dev_t dev, struct uio *uio, int flag)
    583      1.1  riastrad {
    584      1.1  riastrad 	struct viocon_port *vp = dev2port(dev);
    585      1.1  riastrad 	struct tty *tp = vp->vp_tty;
    586      1.1  riastrad 
    587      1.1  riastrad 	return (*tp->t_linesw->l_read)(tp, uio, flag);
    588      1.1  riastrad }
    589      1.1  riastrad 
    590      1.1  riastrad int
    591      1.1  riastrad vioconwrite(dev_t dev, struct uio *uio, int flag)
    592      1.1  riastrad {
    593      1.1  riastrad 	struct viocon_port *vp = dev2port(dev);
    594      1.1  riastrad 	struct tty *tp = vp->vp_tty;
    595      1.1  riastrad 
    596      1.1  riastrad 	return (*tp->t_linesw->l_write)(tp, uio, flag);
    597      1.1  riastrad }
    598      1.1  riastrad 
    599      1.1  riastrad struct tty *
    600      1.1  riastrad viocontty(dev_t dev)
    601      1.1  riastrad {
    602      1.1  riastrad 	struct viocon_port *vp = dev2port(dev);
    603      1.1  riastrad 
    604      1.1  riastrad 	return vp->vp_tty;
    605      1.1  riastrad }
    606      1.1  riastrad 
    607      1.1  riastrad void
    608      1.1  riastrad vioconstop(struct tty *tp, int flag)
    609      1.1  riastrad {
    610      1.1  riastrad 	int s;
    611      1.1  riastrad 
    612      1.1  riastrad 	s = spltty();
    613      1.1  riastrad 	if (ISSET(tp->t_state, TS_BUSY))
    614      1.1  riastrad 		if (!ISSET(tp->t_state, TS_TTSTOP))
    615      1.1  riastrad 			SET(tp->t_state, TS_FLUSH);
    616      1.1  riastrad 	splx(s);
    617      1.1  riastrad }
    618      1.1  riastrad 
    619      1.1  riastrad int
    620      1.1  riastrad vioconioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    621      1.1  riastrad {
    622      1.1  riastrad 	struct viocon_port *vp = dev2port(dev);
    623      1.1  riastrad 	struct tty *tp;
    624      1.1  riastrad 	int error1, error2;
    625      1.1  riastrad 
    626      1.1  riastrad 	tp = vp->vp_tty;
    627      1.1  riastrad 
    628      1.1  riastrad 	error1 = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
    629      1.1  riastrad 	if (error1 >= 0)
    630      1.1  riastrad 		return error1;
    631      1.1  riastrad 	error2 = ttioctl(tp, cmd, data, flag, l);
    632      1.1  riastrad 	if (error2 >= 0)
    633      1.1  riastrad 		return error2;
    634      1.1  riastrad 	return ENOTTY;
    635      1.1  riastrad }
    636