Home | History | Annotate | Line # | Download | only in virtio
viocon.c revision 1.5.4.3
      1  1.5.4.3    martin /*	$NetBSD: viocon.c,v 1.5.4.3 2024/10/02 18:20:48 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.3    martin __KERNEL_RCSID(0, "$NetBSD: viocon.c,v 1.5.4.3 2024/10/02 18:20:48 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 
    226  1.5.4.1    martin 	if (virtio_child_attach_finish(vsc, sc->sc_vqs, nvqs,
    227  1.5.4.1    martin 	    /*config_change*/NULL, /*req_flags*/0) != 0)
    228      1.1  riastrad 		goto err;
    229      1.1  riastrad 
    230  1.5.4.2    martin 	viocon_rx_fill(sc->sc_ports[0]);
    231  1.5.4.2    martin 
    232      1.1  riastrad 	return;
    233      1.1  riastrad err:
    234  1.5.4.1    martin 	kmem_free(sc->sc_vqs, nvqs * sizeof(sc->sc_vqs[0]));
    235      1.1  riastrad 	kmem_free(sc->sc_ports, maxports * sizeof(sc->sc_ports[0]));
    236      1.1  riastrad 	virtio_child_attach_failed(vsc);
    237      1.1  riastrad }
    238      1.1  riastrad 
    239      1.1  riastrad int
    240      1.1  riastrad viocon_port_create(struct viocon_softc *sc, int portidx)
    241      1.1  riastrad {
    242      1.1  riastrad 	struct virtio_softc *vsc = sc->sc_virtio;
    243      1.1  riastrad 	int rxidx, txidx, allocsize, nsegs;
    244      1.1  riastrad 	char name[6];
    245      1.1  riastrad 	struct viocon_port *vp;
    246      1.1  riastrad 	void *kva;
    247      1.1  riastrad 	struct tty *tp;
    248      1.1  riastrad 
    249      1.1  riastrad 	vp = kmem_zalloc(sizeof(*vp), KM_SLEEP);
    250      1.1  riastrad 	if (vp == NULL)
    251      1.1  riastrad 		return ENOMEM;
    252      1.1  riastrad 	sc->sc_ports[portidx] = vp;
    253      1.1  riastrad 	vp->vp_sc = sc;
    254      1.1  riastrad 	DPRINTF("%s: vp: %p\n", __func__, vp);
    255      1.1  riastrad 
    256  1.5.4.1    martin 	rxidx = (portidx * VIOCON_PORT_NQS) + VIOCON_PORT_RX;
    257  1.5.4.1    martin 	txidx = (portidx * VIOCON_PORT_NQS) + VIOCON_PORT_TX;
    258      1.1  riastrad 
    259      1.1  riastrad 	snprintf(name, sizeof(name), "p%drx", portidx);
    260  1.5.4.1    martin 	virtio_init_vq_vqdone(vsc, &sc->sc_vqs[rxidx], rxidx,
    261  1.5.4.1    martin 	    viocon_rx_intr);
    262  1.5.4.1    martin 	if (virtio_alloc_vq(vsc, &sc->sc_vqs[rxidx], BUFSIZE, 1,
    263      1.1  riastrad 	    name) != 0) {
    264      1.1  riastrad 		printf("\nCan't alloc %s virtqueue\n", name);
    265      1.1  riastrad 		goto err;
    266      1.1  riastrad 	}
    267      1.1  riastrad 	vp->vp_rx = &sc->sc_vqs[rxidx];
    268      1.1  riastrad 	vp->vp_si = softint_establish(SOFTINT_SERIAL, viocon_rx_soft, vp);
    269      1.1  riastrad 	DPRINTF("%s: rx: %p\n", __func__, vp->vp_rx);
    270      1.1  riastrad 
    271      1.1  riastrad 	snprintf(name, sizeof(name), "p%dtx", portidx);
    272  1.5.4.1    martin 	virtio_init_vq_vqdone(vsc, &sc->sc_vqs[txidx], txidx,
    273  1.5.4.1    martin 	    viocon_tx_intr);
    274  1.5.4.1    martin 	if (virtio_alloc_vq(vsc, &sc->sc_vqs[txidx], BUFSIZE, 1,
    275      1.1  riastrad 	    name) != 0) {
    276      1.1  riastrad 		printf("\nCan't alloc %s virtqueue\n", name);
    277      1.1  riastrad 		goto err;
    278      1.1  riastrad 	}
    279      1.1  riastrad 	vp->vp_tx = &sc->sc_vqs[txidx];
    280      1.1  riastrad 	DPRINTF("%s: tx: %p\n", __func__, vp->vp_tx);
    281      1.1  riastrad 
    282      1.1  riastrad 	allocsize = (vp->vp_rx->vq_num + vp->vp_tx->vq_num) * BUFSIZE;
    283      1.1  riastrad 
    284      1.1  riastrad 	if (bus_dmamap_create(virtio_dmat(vsc), allocsize, 1, allocsize, 0,
    285      1.1  riastrad 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &vp->vp_dmamap) != 0)
    286      1.1  riastrad 		goto err;
    287      1.1  riastrad 	if (bus_dmamem_alloc(virtio_dmat(vsc), allocsize, 8, 0, &vp->vp_dmaseg,
    288      1.1  riastrad 	    1, &nsegs, BUS_DMA_NOWAIT) != 0)
    289      1.1  riastrad 		goto err;
    290      1.1  riastrad 	if (bus_dmamem_map(virtio_dmat(vsc), &vp->vp_dmaseg, nsegs,
    291      1.1  riastrad 	    allocsize, &kva, BUS_DMA_NOWAIT) != 0)
    292      1.1  riastrad 		goto err;
    293      1.1  riastrad 	memset(kva, 0, allocsize);
    294      1.1  riastrad 	if (bus_dmamap_load(virtio_dmat(vsc), vp->vp_dmamap, kva,
    295      1.1  riastrad 	    allocsize, NULL, BUS_DMA_NOWAIT) != 0)
    296      1.1  riastrad 		goto err;
    297      1.1  riastrad 	vp->vp_rx_buf = (unsigned char *)kva;
    298      1.1  riastrad 	/*
    299      1.1  riastrad 	 * XXX use only a small circular tx buffer instead of many BUFSIZE buffers?
    300      1.1  riastrad 	 */
    301      1.1  riastrad 	vp->vp_tx_buf = vp->vp_rx_buf + vp->vp_rx->vq_num * BUFSIZE;
    302      1.1  riastrad 
    303      1.1  riastrad 	if (virtio_features(vsc) & VIRTIO_CONSOLE_F_SIZE) {
    304      1.1  riastrad 		vp->vp_cols = virtio_read_device_config_2(vsc,
    305      1.1  riastrad 		    VIRTIO_CONSOLE_COLS);
    306      1.1  riastrad 		vp->vp_rows = virtio_read_device_config_2(vsc,
    307      1.1  riastrad 		    VIRTIO_CONSOLE_ROWS);
    308      1.1  riastrad 	}
    309      1.1  riastrad 
    310      1.1  riastrad 	tp = ttymalloc(1000000);
    311      1.1  riastrad 	tp->t_oproc = vioconstart;
    312      1.1  riastrad 	tp->t_param = vioconparam;
    313      1.1  riastrad 	tp->t_hwiflow = vioconhwiflow;
    314      1.2  riastrad 	tp->t_dev = VIOCONDEV(device_unit(sc->sc_dev), portidx);
    315      1.1  riastrad 	vp->vp_tty = tp;
    316      1.1  riastrad 	DPRINTF("%s: tty: %p\n", __func__, tp);
    317      1.1  riastrad 
    318      1.1  riastrad 	virtio_start_vq_intr(vsc, vp->vp_rx);
    319      1.1  riastrad 	virtio_start_vq_intr(vsc, vp->vp_tx);
    320      1.1  riastrad 
    321      1.1  riastrad 	return 0;
    322      1.1  riastrad err:
    323      1.1  riastrad 	panic("%s failed", __func__);
    324      1.1  riastrad 	return -1;
    325      1.1  riastrad }
    326      1.1  riastrad 
    327      1.1  riastrad int
    328      1.1  riastrad viocon_tx_drain(struct viocon_port *vp, struct virtqueue *vq)
    329      1.1  riastrad {
    330      1.1  riastrad 	struct virtio_softc *vsc = vq->vq_owner;
    331      1.1  riastrad 	int ndone = 0, len, slot;
    332      1.1  riastrad 
    333      1.1  riastrad 	splassert(IPL_TTY);
    334      1.1  riastrad 	while (virtio_dequeue(vsc, vq, &slot, &len) == 0) {
    335      1.1  riastrad 		bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap,
    336      1.1  riastrad 		    vp->vp_tx_buf - vp->vp_rx_buf + slot * BUFSIZE, BUFSIZE,
    337      1.4  riastrad 		    BUS_DMASYNC_POSTWRITE);
    338      1.1  riastrad 		virtio_dequeue_commit(vsc, vq, slot);
    339      1.1  riastrad 		ndone++;
    340      1.1  riastrad 	}
    341      1.1  riastrad 	return ndone;
    342      1.1  riastrad }
    343      1.1  riastrad 
    344      1.1  riastrad int
    345      1.1  riastrad viocon_tx_intr(struct virtqueue *vq)
    346      1.1  riastrad {
    347      1.1  riastrad 	struct virtio_softc *vsc = vq->vq_owner;
    348      1.1  riastrad 	struct viocon_softc *sc = device_private(virtio_child(vsc));
    349      1.1  riastrad 	int ndone = 0;
    350      1.1  riastrad 	int portidx = (vq->vq_index - 1) / 2;
    351      1.1  riastrad 	struct viocon_port *vp = sc->sc_ports[portidx];
    352      1.1  riastrad 	struct tty *tp = vp->vp_tty;
    353      1.1  riastrad 
    354      1.1  riastrad 	splassert(IPL_TTY);
    355      1.1  riastrad 	ndone = viocon_tx_drain(vp, vq);
    356      1.1  riastrad 	if (ndone && ISSET(tp->t_state, TS_BUSY)) {
    357      1.1  riastrad 		CLR(tp->t_state, TS_BUSY);
    358      1.1  riastrad 		(*tp->t_linesw->l_start)(tp);
    359      1.1  riastrad 	}
    360      1.1  riastrad 
    361      1.1  riastrad 	return 1;
    362      1.1  riastrad }
    363      1.1  riastrad 
    364      1.1  riastrad void
    365      1.1  riastrad viocon_rx_fill(struct viocon_port *vp)
    366      1.1  riastrad {
    367      1.1  riastrad 	struct virtqueue *vq = vp->vp_rx;
    368      1.1  riastrad 	struct virtio_softc *vsc = vp->vp_sc->sc_virtio;
    369      1.1  riastrad 	int r, slot, ndone = 0;
    370      1.1  riastrad 
    371      1.1  riastrad 	while ((r = virtio_enqueue_prep(vsc, vq, &slot)) == 0) {
    372      1.1  riastrad 		if (virtio_enqueue_reserve(vsc, vq, slot, 1) != 0)
    373      1.1  riastrad 			break;
    374      1.1  riastrad 		bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap, slot * BUFSIZE,
    375      1.1  riastrad 		    BUFSIZE, BUS_DMASYNC_PREREAD);
    376      1.1  riastrad 		virtio_enqueue_p(vsc, vq, slot, vp->vp_dmamap, slot * BUFSIZE,
    377      1.1  riastrad 		    BUFSIZE, 0);
    378      1.1  riastrad 		virtio_enqueue_commit(vsc, vq, slot, 0);
    379      1.1  riastrad 		ndone++;
    380      1.1  riastrad 	}
    381  1.5.4.3    martin 	KASSERTMSG(r == 0 || r == EAGAIN, "r=%d", r);
    382      1.1  riastrad 	if (ndone > 0)
    383      1.1  riastrad 		virtio_notify(vsc, vq);
    384      1.1  riastrad }
    385      1.1  riastrad 
    386      1.1  riastrad int
    387      1.1  riastrad viocon_rx_intr(struct virtqueue *vq)
    388      1.1  riastrad {
    389      1.1  riastrad 	struct virtio_softc *vsc = vq->vq_owner;
    390      1.1  riastrad 	struct viocon_softc *sc = device_private(virtio_child(vsc));
    391      1.1  riastrad 	int portidx = (vq->vq_index - 1) / 2;
    392      1.1  riastrad 	struct viocon_port *vp = sc->sc_ports[portidx];
    393      1.1  riastrad 
    394      1.1  riastrad 	softint_schedule(vp->vp_si);
    395      1.1  riastrad 	return 1;
    396      1.1  riastrad }
    397      1.1  riastrad 
    398      1.1  riastrad void
    399      1.1  riastrad viocon_rx_soft(void *arg)
    400      1.1  riastrad {
    401      1.1  riastrad 	struct viocon_port *vp = arg;
    402      1.1  riastrad 	struct virtqueue *vq = vp->vp_rx;
    403      1.1  riastrad 	struct virtio_softc *vsc = vq->vq_owner;
    404      1.1  riastrad 	struct tty *tp = vp->vp_tty;
    405      1.1  riastrad 	int slot, len, i;
    406      1.1  riastrad 	u_char *p;
    407      1.1  riastrad 
    408      1.1  riastrad 	while (!vp->vp_iflow && virtio_dequeue(vsc, vq, &slot, &len) == 0) {
    409      1.1  riastrad 		bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap,
    410      1.1  riastrad 		    slot * BUFSIZE, BUFSIZE, BUS_DMASYNC_POSTREAD);
    411      1.1  riastrad 		p = vp->vp_rx_buf + slot * BUFSIZE;
    412      1.1  riastrad 		for (i = 0; i < len; i++)
    413      1.1  riastrad 			(*tp->t_linesw->l_rint)(*p++, tp);
    414      1.1  riastrad 		virtio_dequeue_commit(vsc, vq, slot);
    415      1.1  riastrad 	}
    416      1.1  riastrad 
    417      1.1  riastrad 	viocon_rx_fill(vp);
    418      1.1  riastrad 
    419      1.1  riastrad 	return;
    420      1.1  riastrad }
    421      1.1  riastrad 
    422      1.1  riastrad void
    423      1.1  riastrad vioconstart(struct tty *tp)
    424      1.1  riastrad {
    425      1.1  riastrad 	struct viocon_softc *sc = dev2sc(tp->t_dev);
    426      1.1  riastrad 	struct virtio_softc *vsc;
    427      1.1  riastrad 	struct viocon_port *vp = dev2port(tp->t_dev);
    428      1.1  riastrad 	struct virtqueue *vq;
    429      1.1  riastrad 	u_char *buf;
    430      1.1  riastrad 	int s, cnt, slot, ret, ndone;
    431      1.1  riastrad 
    432      1.1  riastrad 	vsc = sc->sc_virtio;
    433      1.1  riastrad 	vq = vp->vp_tx;
    434      1.1  riastrad 
    435      1.1  riastrad 	s = spltty();
    436      1.1  riastrad 
    437      1.1  riastrad 	ndone = viocon_tx_drain(vp, vq);
    438      1.1  riastrad 	if (ISSET(tp->t_state, TS_BUSY)) {
    439      1.1  riastrad 		if (ndone > 0)
    440      1.1  riastrad 			CLR(tp->t_state, TS_BUSY);
    441      1.1  riastrad 		else
    442      1.1  riastrad 			goto out;
    443      1.1  riastrad 	}
    444      1.1  riastrad 	if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP))
    445      1.1  riastrad 		goto out;
    446      1.1  riastrad 
    447      1.1  riastrad 	if (tp->t_outq.c_cc == 0)
    448      1.1  riastrad 		goto out;
    449      1.1  riastrad 	ndone = 0;
    450      1.1  riastrad 
    451      1.1  riastrad 	while (tp->t_outq.c_cc > 0) {
    452      1.1  riastrad 		ret = virtio_enqueue_prep(vsc, vq, &slot);
    453      1.1  riastrad 		if (ret == EAGAIN) {
    454      1.1  riastrad 			SET(tp->t_state, TS_BUSY);
    455      1.1  riastrad 			break;
    456      1.1  riastrad 		}
    457  1.5.4.3    martin 		KASSERTMSG(ret == 0, "ret=%d", ret);
    458      1.1  riastrad 		ret = virtio_enqueue_reserve(vsc, vq, slot, 1);
    459  1.5.4.3    martin 		KASSERTMSG(ret == 0, "ret=%d", ret);
    460      1.1  riastrad 		buf = vp->vp_tx_buf + slot * BUFSIZE;
    461      1.1  riastrad 		cnt = q_to_b(&tp->t_outq, buf, BUFSIZE);
    462      1.1  riastrad 		bus_dmamap_sync(virtio_dmat(vsc), vp->vp_dmamap,
    463      1.1  riastrad 		    vp->vp_tx_buf - vp->vp_rx_buf + slot * BUFSIZE, cnt,
    464      1.1  riastrad 		    BUS_DMASYNC_PREWRITE);
    465      1.1  riastrad 		virtio_enqueue_p(vsc, vq, slot, vp->vp_dmamap,
    466      1.1  riastrad 		    vp->vp_tx_buf - vp->vp_rx_buf + slot * BUFSIZE, cnt, 1);
    467      1.1  riastrad 		virtio_enqueue_commit(vsc, vq, slot, 0);
    468      1.1  riastrad 		ndone++;
    469      1.1  riastrad 	}
    470      1.1  riastrad 	if (ndone > 0)
    471      1.1  riastrad 		virtio_notify(vsc, vq);
    472      1.1  riastrad 	ttwakeupwr(tp);
    473      1.1  riastrad out:
    474      1.1  riastrad 	splx(s);
    475      1.1  riastrad }
    476      1.1  riastrad 
    477      1.1  riastrad int
    478      1.1  riastrad vioconhwiflow(struct tty *tp, int stop)
    479      1.1  riastrad {
    480      1.1  riastrad 	struct viocon_port *vp = dev2port(tp->t_dev);
    481      1.1  riastrad 	int s;
    482      1.1  riastrad 
    483      1.1  riastrad 	s = spltty();
    484      1.1  riastrad 	vp->vp_iflow = stop;
    485      1.1  riastrad 	if (stop) {
    486      1.1  riastrad 		virtio_stop_vq_intr(vp->vp_sc->sc_virtio, vp->vp_rx);
    487      1.1  riastrad 	} else {
    488      1.1  riastrad 		virtio_start_vq_intr(vp->vp_sc->sc_virtio, vp->vp_rx);
    489      1.1  riastrad 		softint_schedule(vp->vp_si);
    490      1.1  riastrad 	}
    491      1.1  riastrad 	splx(s);
    492      1.1  riastrad 	return 1;
    493      1.1  riastrad }
    494      1.1  riastrad 
    495      1.1  riastrad int
    496      1.1  riastrad vioconparam(struct tty *tp, struct termios *t)
    497      1.1  riastrad {
    498      1.1  riastrad 	tp->t_ispeed = t->c_ispeed;
    499      1.1  riastrad 	tp->t_ospeed = t->c_ospeed;
    500      1.1  riastrad 	tp->t_cflag = t->c_cflag;
    501      1.1  riastrad 
    502      1.1  riastrad 	vioconstart(tp);
    503      1.1  riastrad 	return 0;
    504      1.1  riastrad }
    505      1.1  riastrad 
    506      1.1  riastrad int
    507      1.1  riastrad vioconopen(dev_t dev, int flag, int mode, struct lwp *l)
    508      1.1  riastrad {
    509      1.1  riastrad 	int unit = VIOCONUNIT(dev);
    510      1.1  riastrad 	int port = VIOCONPORT(dev);
    511      1.1  riastrad 	struct viocon_softc *sc;
    512      1.1  riastrad 	struct viocon_port *vp;
    513      1.1  riastrad 	struct tty *tp;
    514      1.1  riastrad 	int s, error;
    515      1.1  riastrad 
    516      1.1  riastrad 	sc = device_lookup_private(&viocon_cd, unit);
    517      1.1  riastrad 	if (sc == NULL)
    518      1.1  riastrad 		return (ENXIO);
    519      1.1  riastrad 	if (!device_is_active(sc->sc_dev))
    520      1.1  riastrad 		return (ENXIO);
    521      1.1  riastrad 
    522      1.1  riastrad 	s = spltty();
    523      1.1  riastrad 	if (port >= sc->sc_max_ports) {
    524      1.1  riastrad 		splx(s);
    525      1.1  riastrad 		return (ENXIO);
    526      1.1  riastrad 	}
    527      1.1  riastrad 	vp = sc->sc_ports[port];
    528      1.1  riastrad 	tp = vp->vp_tty;
    529      1.1  riastrad #ifdef NOTYET
    530      1.1  riastrad 	vp->vp_guest_open = 1;
    531      1.1  riastrad #endif
    532      1.1  riastrad 	splx(s);
    533      1.1  riastrad 
    534      1.1  riastrad 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
    535      1.1  riastrad 		return (EBUSY);
    536      1.1  riastrad 
    537      1.1  riastrad 	s = spltty();
    538      1.1  riastrad 	if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
    539      1.1  riastrad 		ttychars(tp);
    540      1.1  riastrad 		tp->t_ispeed = 1000000;
    541      1.1  riastrad 		tp->t_ospeed = 1000000;
    542      1.1  riastrad 		tp->t_cflag = TTYDEF_CFLAG|CLOCAL|CRTSCTS;
    543      1.1  riastrad 		tp->t_iflag = TTYDEF_IFLAG;
    544      1.1  riastrad 		tp->t_oflag = TTYDEF_OFLAG;
    545      1.1  riastrad 		tp->t_lflag = TTYDEF_LFLAG;
    546      1.1  riastrad 		if (vp->vp_cols != 0) {
    547      1.1  riastrad 			tp->t_winsize.ws_col = vp->vp_cols;
    548      1.1  riastrad 			tp->t_winsize.ws_row = vp->vp_rows;
    549      1.1  riastrad 		}
    550      1.1  riastrad 
    551      1.1  riastrad 		vioconparam(tp, &tp->t_termios);
    552      1.1  riastrad 		ttsetwater(tp);
    553      1.1  riastrad 	}
    554      1.1  riastrad 	splx(s);
    555      1.1  riastrad 
    556      1.1  riastrad 	error = (*tp->t_linesw->l_open)(dev, tp);
    557      1.1  riastrad 	return error;
    558      1.1  riastrad }
    559      1.1  riastrad 
    560      1.1  riastrad int
    561      1.1  riastrad vioconclose(dev_t dev, int flag, int mode, struct lwp *l)
    562      1.1  riastrad {
    563      1.1  riastrad 	struct viocon_port *vp = dev2port(dev);
    564      1.1  riastrad 	struct tty *tp = vp->vp_tty;
    565      1.1  riastrad 	int s;
    566      1.1  riastrad 
    567      1.1  riastrad 	if (!ISSET(tp->t_state, TS_ISOPEN))
    568      1.1  riastrad 		return 0;
    569      1.1  riastrad 
    570      1.1  riastrad 	(*tp->t_linesw->l_close)(tp, flag);
    571      1.1  riastrad 	s = spltty();
    572      1.1  riastrad #ifdef NOTYET
    573      1.1  riastrad 	vp->vp_guest_open = 0;
    574      1.1  riastrad #endif
    575      1.1  riastrad 	CLR(tp->t_state, TS_BUSY | TS_FLUSH);
    576      1.1  riastrad 	ttyclose(tp);
    577      1.1  riastrad 	splx(s);
    578      1.1  riastrad 
    579      1.1  riastrad 	return 0;
    580      1.1  riastrad }
    581      1.1  riastrad 
    582      1.1  riastrad int
    583      1.1  riastrad vioconread(dev_t dev, struct uio *uio, int flag)
    584      1.1  riastrad {
    585      1.1  riastrad 	struct viocon_port *vp = dev2port(dev);
    586      1.1  riastrad 	struct tty *tp = vp->vp_tty;
    587      1.1  riastrad 
    588      1.1  riastrad 	return (*tp->t_linesw->l_read)(tp, uio, flag);
    589      1.1  riastrad }
    590      1.1  riastrad 
    591      1.1  riastrad int
    592      1.1  riastrad vioconwrite(dev_t dev, struct uio *uio, int flag)
    593      1.1  riastrad {
    594      1.1  riastrad 	struct viocon_port *vp = dev2port(dev);
    595      1.1  riastrad 	struct tty *tp = vp->vp_tty;
    596      1.1  riastrad 
    597      1.1  riastrad 	return (*tp->t_linesw->l_write)(tp, uio, flag);
    598      1.1  riastrad }
    599      1.1  riastrad 
    600      1.1  riastrad struct tty *
    601      1.1  riastrad viocontty(dev_t dev)
    602      1.1  riastrad {
    603      1.1  riastrad 	struct viocon_port *vp = dev2port(dev);
    604      1.1  riastrad 
    605      1.1  riastrad 	return vp->vp_tty;
    606      1.1  riastrad }
    607      1.1  riastrad 
    608      1.1  riastrad void
    609      1.1  riastrad vioconstop(struct tty *tp, int flag)
    610      1.1  riastrad {
    611      1.1  riastrad 	int s;
    612      1.1  riastrad 
    613      1.1  riastrad 	s = spltty();
    614      1.1  riastrad 	if (ISSET(tp->t_state, TS_BUSY))
    615      1.1  riastrad 		if (!ISSET(tp->t_state, TS_TTSTOP))
    616      1.1  riastrad 			SET(tp->t_state, TS_FLUSH);
    617      1.1  riastrad 	splx(s);
    618      1.1  riastrad }
    619      1.1  riastrad 
    620      1.1  riastrad int
    621      1.1  riastrad vioconioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    622      1.1  riastrad {
    623      1.1  riastrad 	struct viocon_port *vp = dev2port(dev);
    624      1.1  riastrad 	struct tty *tp;
    625      1.1  riastrad 	int error1, error2;
    626      1.1  riastrad 
    627      1.1  riastrad 	tp = vp->vp_tty;
    628      1.1  riastrad 
    629      1.1  riastrad 	error1 = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
    630      1.1  riastrad 	if (error1 >= 0)
    631      1.1  riastrad 		return error1;
    632      1.1  riastrad 	error2 = ttioctl(tp, cmd, data, flag, l);
    633      1.1  riastrad 	if (error2 >= 0)
    634      1.1  riastrad 		return error2;
    635      1.1  riastrad 	return ENOTTY;
    636      1.1  riastrad }
    637