xref: /openbsd/sys/arch/sparc64/dev/vldcp.c (revision 5a38ef86)
1 /*	$OpenBSD: vldcp.c,v 1.22 2021/10/24 17:05:04 mpi Exp $	*/
2 /*
3  * Copyright (c) 2009, 2012 Mark Kettenis
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/conf.h>
20 #include <sys/device.h>
21 #include <sys/malloc.h>
22 #include <sys/poll.h>
23 #include <sys/proc.h>
24 #include <sys/systm.h>
25 
26 #include <machine/autoconf.h>
27 #include <machine/hypervisor.h>
28 #include <machine/mdesc.h>
29 
30 #include <uvm/uvm_extern.h>
31 
32 #include <sparc64/dev/cbusvar.h>
33 #include <sparc64/dev/ldcvar.h>
34 
35 #ifdef VLDCP_DEBUG
36 #define DPRINTF(x)	printf x
37 #else
38 #define DPRINTF(x)
39 #endif
40 
41 #include <sys/ioccom.h>
42 
43 struct hv_io {
44 	uint64_t	hi_cookie;
45 	void		*hi_addr;
46 	size_t		hi_len;
47 };
48 
49 #define HVIOCREAD	_IOW('h', 0, struct hv_io)
50 #define HVIOCWRITE	_IOW('h', 1, struct hv_io)
51 
52 #define VLDCP_TX_ENTRIES	128
53 #define VLDCP_RX_ENTRIES	128
54 
55 struct vldcp_softc {
56 	struct device	sc_dv;
57 	bus_space_tag_t	sc_bustag;
58 	bus_dma_tag_t	sc_dmatag;
59 
60 	uint64_t	sc_tx_ino;
61 	uint64_t	sc_rx_ino;
62 	void		*sc_tx_ih;
63 	void		*sc_rx_ih;
64 
65 	struct ldc_conn	sc_lc;
66 
67 	struct selinfo	sc_rsel;
68 	struct selinfo	sc_wsel;
69 };
70 
71 int	vldcp_match(struct device *, void *, void *);
72 void	vldcp_attach(struct device *, struct device *, void *);
73 void	filt_vldcprdetach(struct knote *);
74 void	filt_vldcpwdetach(struct knote *);
75 int	filt_vldcpread(struct knote *, long);
76 int	filt_vldcpwrite(struct knote *, long);
77 int	vldcpkqfilter(dev_t, struct knote *);
78 
79 const struct cfattach vldcp_ca = {
80 	sizeof(struct vldcp_softc), vldcp_match, vldcp_attach
81 };
82 
83 struct cfdriver vldcp_cd = {
84 	NULL, "vldcp", DV_DULL
85 };
86 
87 int	vldcp_tx_intr(void *);
88 int	vldcp_rx_intr(void *);
89 
90 /*
91  * We attach to certain well-known channels.  These are assigned fixed
92  * device minor device numbers through their index in the table below.
93  * So "hvctl" gets minor 0, "spds" gets minor 1, etc. etc.
94  *
95  * We also attach to the domain services channels.  These are named
96  * "ldom-<guestname>" and get assigned a device minor starting at
97  * VLDC_LDOM_OFFSET.
98  */
99 #define VLDC_NUM_SERVICES	64
100 #define VLDC_LDOM_OFFSET	32
101 int vldc_num_ldoms;
102 
103 struct vldc_svc {
104 	const char *vs_name;
105 	struct vldcp_softc *vs_sc;
106 };
107 
108 struct vldc_svc vldc_svc[VLDC_NUM_SERVICES] = {
109 	{ "hvctl" },
110 	{ "spds" },
111 	{ NULL }
112 };
113 
114 int
115 vldcp_match(struct device *parent, void *match, void *aux)
116 {
117 	struct cbus_attach_args *ca = aux;
118 	struct vldc_svc *svc;
119 
120 	for (svc = vldc_svc; svc->vs_name != NULL; svc++)
121 		if (strcmp(ca->ca_name, svc->vs_name) == 0)
122 			return (1);
123 
124 	if (strncmp(ca->ca_name, "ldom-", 5) == 0 &&
125 	    strcmp(ca->ca_name, "ldom-primary") != 0)
126 		return (1);
127 
128 	return (0);
129 }
130 
131 void
132 vldcp_attach(struct device *parent, struct device *self, void *aux)
133 {
134 	struct vldcp_softc *sc = (struct vldcp_softc *)self;
135 	struct cbus_attach_args *ca = aux;
136 	struct vldc_svc *svc;
137 	struct ldc_conn *lc;
138 
139 	sc->sc_bustag = ca->ca_bustag;
140 	sc->sc_dmatag = ca->ca_dmatag;
141 	sc->sc_tx_ino = ca->ca_tx_ino;
142 	sc->sc_rx_ino = ca->ca_rx_ino;
143 
144 	printf(": ivec 0x%llx, 0x%llx", sc->sc_tx_ino, sc->sc_rx_ino);
145 
146 	/*
147 	 * Un-configure queues before registering interrupt handlers,
148 	 * such that we dont get any stale LDC packets or events.
149 	 */
150 	hv_ldc_tx_qconf(ca->ca_id, 0, 0);
151 	hv_ldc_rx_qconf(ca->ca_id, 0, 0);
152 
153 	sc->sc_tx_ih = bus_intr_establish(ca->ca_bustag, sc->sc_tx_ino,
154 	    IPL_TTY, 0, vldcp_tx_intr, sc, sc->sc_dv.dv_xname);
155 	sc->sc_rx_ih = bus_intr_establish(ca->ca_bustag, sc->sc_rx_ino,
156 	    IPL_TTY, 0, vldcp_rx_intr, sc, sc->sc_dv.dv_xname);
157 	if (sc->sc_tx_ih == NULL || sc->sc_rx_ih == NULL) {
158 		printf(", can't establish interrupt\n");
159 		return;
160 	}
161 
162 	lc = &sc->sc_lc;
163 	lc->lc_id = ca->ca_id;
164 	lc->lc_sc = sc;
165 
166 	lc->lc_txq = ldc_queue_alloc(sc->sc_dmatag, VLDCP_TX_ENTRIES);
167 	if (lc->lc_txq == NULL) {
168 		printf(", can't allocate tx queue\n");
169 		return;
170 	}
171 
172 	lc->lc_rxq = ldc_queue_alloc(sc->sc_dmatag, VLDCP_RX_ENTRIES);
173 	if (lc->lc_rxq == NULL) {
174 		printf(", can't allocate rx queue\n");
175 		goto free_txqueue;
176 	}
177 	lc->lc_rx_state = LDC_CHANNEL_INIT;
178 
179 	for (svc = vldc_svc; svc->vs_name != NULL; svc++) {
180 		if (strcmp(ca->ca_name, svc->vs_name) == 0) {
181 			svc->vs_sc = sc;
182 			break;
183 		}
184 	}
185 
186 	if (strncmp(ca->ca_name, "ldom-", 5) == 0 &&
187 	    strcmp(ca->ca_name, "ldom-primary") != 0) {
188 		int minor = VLDC_LDOM_OFFSET + vldc_num_ldoms++;
189 		if (minor < nitems(vldc_svc))
190 			vldc_svc[minor].vs_sc = sc;
191 	}
192 
193 	printf(" channel \"%s\"\n", ca->ca_name);
194 	return;
195 
196 #if 0
197 free_rxqueue:
198 	ldc_queue_free(sc->sc_dmatag, lc->lc_rxq);
199 #endif
200 free_txqueue:
201 	ldc_queue_free(sc->sc_dmatag, lc->lc_txq);
202 }
203 
204 int
205 vldcp_tx_intr(void *arg)
206 {
207 	struct vldcp_softc *sc = arg;
208 	struct ldc_conn *lc = &sc->sc_lc;
209 	uint64_t tx_head, tx_tail, tx_state;
210 	int err;
211 
212 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
213 	if (err != H_EOK) {
214 		printf("%s: hv_ldc_tx_get_state %d\n", __func__, err);
215 		return (0);
216 	}
217 
218 	if (tx_state != lc->lc_tx_state) {
219 		switch (tx_state) {
220 		case LDC_CHANNEL_DOWN:
221 			DPRINTF(("%s: Tx link down\n", __func__));
222 			break;
223 		case LDC_CHANNEL_UP:
224 			DPRINTF(("%s: Tx link up\n", __func__));
225 			break;
226 		case LDC_CHANNEL_RESET:
227 			DPRINTF(("%s: Tx link reset\n", __func__));
228 			break;
229 		}
230 		lc->lc_tx_state = tx_state;
231 	}
232 
233 	cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, INTR_DISABLED);
234 	selwakeup(&sc->sc_wsel);
235 	wakeup(lc->lc_txq);
236 	return (1);
237 }
238 
239 int
240 vldcp_rx_intr(void *arg)
241 {
242 	struct vldcp_softc *sc = arg;
243 	struct ldc_conn *lc = &sc->sc_lc;
244 	uint64_t rx_head, rx_tail, rx_state;
245 	int err;
246 
247 	err = hv_ldc_rx_get_state(lc->lc_id, &rx_head, &rx_tail, &rx_state);
248 	if (err != H_EOK) {
249 		printf("%s: hv_ldc_rx_get_state %d\n", __func__, err);
250 		return (0);
251 	}
252 
253 	if (rx_state != lc->lc_rx_state) {
254 		switch (rx_state) {
255 		case LDC_CHANNEL_DOWN:
256 			DPRINTF(("%s: Rx link down\n", __func__));
257 			if (rx_head == rx_tail)
258 				break;
259 			/* Discard and ack pending I/O. */
260 			DPRINTF(("setting rx qhead to %llx\n", rx_tail));
261 			err = hv_ldc_rx_set_qhead(lc->lc_id, rx_tail);
262 			if (err == H_EOK)
263 				break;
264 			printf("%s: hv_ldc_rx_set_qhead %d\n", __func__, err);
265 			break;
266 		case LDC_CHANNEL_UP:
267 			DPRINTF(("%s: Rx link up\n", __func__));
268 			break;
269 		case LDC_CHANNEL_RESET:
270 			DPRINTF(("%s: Rx link reset\n", __func__));
271 			if (rx_head == rx_tail)
272 				break;
273 			/* Discard and ack pending I/O. */
274 			DPRINTF(("setting rx qhead to %llx\n", rx_tail));
275 			err = hv_ldc_rx_set_qhead(lc->lc_id, rx_tail);
276 			if (err == H_EOK)
277 				break;
278 			printf("%s: hv_ldc_rx_set_qhead %d\n", __func__, err);
279 			break;
280 		}
281 		lc->lc_rx_state = rx_state;
282 		cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino,
283 		    INTR_DISABLED);
284 		selwakeup(&sc->sc_rsel);
285 		wakeup(lc->lc_rxq);
286 		return (1);
287 	}
288 
289 	if (rx_head == rx_tail)
290 		return (0);
291 
292 	cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, INTR_DISABLED);
293 	selwakeup(&sc->sc_rsel);
294 	wakeup(lc->lc_rxq);
295 	return (1);
296 }
297 
298 cdev_decl(vldcp);
299 struct vldcp_softc *vldcp_lookup(dev_t);
300 
301 struct vldcp_softc *
302 vldcp_lookup(dev_t dev)
303 {
304 	struct vldcp_softc *sc = NULL;
305 
306 	if (minor(dev) < nitems(vldc_svc))
307 		sc = vldc_svc[minor(dev)].vs_sc;
308 
309 	if (sc)
310 		device_ref(&sc->sc_dv);
311 
312 	return (sc);
313 }
314 
315 int
316 vldcpopen(dev_t dev, int flag, int mode, struct proc *p)
317 {
318 	struct vldcp_softc *sc;
319 	struct ldc_conn *lc;
320 	uint64_t rx_head, rx_tail, rx_state;
321 	int err;
322 
323 	sc = vldcp_lookup(dev);
324 	if (sc == NULL)
325 		return (ENXIO);
326 	lc = &sc->sc_lc;
327 
328 	err = hv_ldc_tx_qconf(lc->lc_id,
329 	    lc->lc_txq->lq_map->dm_segs[0].ds_addr, lc->lc_txq->lq_nentries);
330 	if (err != H_EOK)
331 		printf("%s: hv_ldc_tx_qconf %d\n", __func__, err);
332 
333 	err = hv_ldc_rx_qconf(lc->lc_id,
334 	    lc->lc_rxq->lq_map->dm_segs[0].ds_addr, lc->lc_rxq->lq_nentries);
335 	if (err != H_EOK)
336 		printf("%s: hv_ldc_rx_qconf %d\n", __func__, err);
337 
338 	/* Clear a pending channel reset.  */
339 	err = hv_ldc_rx_get_state(lc->lc_id, &rx_head, &rx_tail, &rx_state);
340 	if (err != H_EOK)
341 		printf("%s: hv_ldc_rx_get_state %d\n", __func__, err);
342 
343 	device_unref(&sc->sc_dv);
344 	return (0);
345 }
346 
347 int
348 vldcpclose(dev_t dev, int flag, int mode, struct proc *p)
349 {
350 	struct vldcp_softc *sc;
351 
352 	sc = vldcp_lookup(dev);
353 	if (sc == NULL)
354 		return (ENXIO);
355 
356 	cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, INTR_DISABLED);
357 	cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, INTR_DISABLED);
358 
359 	hv_ldc_tx_qconf(sc->sc_lc.lc_id, 0, 0);
360 	hv_ldc_rx_qconf(sc->sc_lc.lc_id, 0, 0);
361 
362 	device_unref(&sc->sc_dv);
363 	return (0);
364 }
365 
366 int
367 vldcpread(dev_t dev, struct uio *uio, int ioflag)
368 {
369 	struct vldcp_softc *sc;
370 	struct ldc_conn *lc;
371 	uint64_t rx_head, rx_tail, rx_state;
372 	int err, ret;
373 	int s;
374 
375 	sc = vldcp_lookup(dev);
376 	if (sc == NULL)
377 		return (ENXIO);
378 	lc = &sc->sc_lc;
379 
380 	if (uio->uio_resid != 64) {
381 		device_unref(&sc->sc_dv);
382 		return (EINVAL);
383 	}
384 
385 	s = spltty();
386 retry:
387 	err = hv_ldc_rx_get_state(lc->lc_id, &rx_head, &rx_tail, &rx_state);
388 	if (err != H_EOK) {
389 		splx(s);
390 		printf("%s: hv_ldc_rx_get_state %d\n", __func__, err);
391 		device_unref(&sc->sc_dv);
392 		return (EIO);
393 	}
394 
395 	DPRINTF(("rx head %llx, rx tail %llx, state %lld\n", rx_head, rx_tail, rx_state));
396 
397 	if (rx_state != LDC_CHANNEL_UP) {
398 		splx(s);
399 		device_unref(&sc->sc_dv);
400 		return (EIO);
401 	}
402 
403 	if (rx_head == rx_tail) {
404 		cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino,
405 		    INTR_ENABLED);
406 		ret = tsleep_nsec(lc->lc_rxq, PWAIT | PCATCH, "hvrd", INFSLP);
407 		if (ret) {
408 			splx(s);
409 			device_unref(&sc->sc_dv);
410 			return (ret);
411 		}
412 		goto retry;
413 	}
414 
415 	ret = uiomove(lc->lc_rxq->lq_va + rx_head, 64, uio);
416 
417 	rx_head += 64;
418 	rx_head &= ((lc->lc_rxq->lq_nentries * 64) - 1);
419 	err = hv_ldc_rx_set_qhead(lc->lc_id, rx_head);
420 	if (err != H_EOK)
421 		printf("%s: hv_ldc_rx_set_qhead %d\n", __func__, err);
422 
423 	splx(s);
424 	device_unref(&sc->sc_dv);
425 	return (ret);
426 }
427 
428 int
429 vldcpwrite(dev_t dev, struct uio *uio, int ioflag)
430 {
431 	struct vldcp_softc *sc;
432 	struct ldc_conn *lc;
433 	uint64_t tx_head, tx_tail, tx_state;
434 	uint64_t next_tx_tail;
435 	int err, ret;
436 	int s;
437 
438 	sc = vldcp_lookup(dev);
439 	if (sc == NULL)
440 		return (ENXIO);
441 	lc = &sc->sc_lc;
442 
443 	if (uio->uio_resid != 64) {
444 		device_unref(&sc->sc_dv);
445 		return (EINVAL);
446 	}
447 
448 	s = spltty();
449 retry:
450 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
451 	if (err != H_EOK) {
452 		splx(s);
453 		printf("%s: hv_ldc_tx_get_state %d\n", __func__, err);
454 		device_unref(&sc->sc_dv);
455 		return (EIO);
456 	}
457 
458 	if (tx_state != LDC_CHANNEL_UP) {
459 		splx(s);
460 		device_unref(&sc->sc_dv);
461 		return (EIO);
462 	}
463 
464 	DPRINTF(("tx head %llx, tx tail %llx\n", tx_head, tx_tail));
465 
466 	next_tx_tail = tx_tail + 64;
467 	next_tx_tail &= ((lc->lc_txq->lq_nentries * 64) - 1);
468 
469 	if (tx_head == next_tx_tail) {
470 		cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino,
471 		    INTR_ENABLED);
472 		ret = tsleep_nsec(lc->lc_txq, PWAIT | PCATCH, "hvwr", INFSLP);
473 		if (ret) {
474 			splx(s);
475 			device_unref(&sc->sc_dv);
476 			return (ret);
477 		}
478 		goto retry;
479 	}
480 	splx(s);
481 
482 	ret = uiomove(lc->lc_txq->lq_va + tx_tail, 64, uio);
483 
484 	err = hv_ldc_tx_set_qtail(lc->lc_id, next_tx_tail);
485 	if (err != H_EOK) {
486 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
487 		device_unref(&sc->sc_dv);
488 		return (EIO);
489 	}
490 
491 	device_unref(&sc->sc_dv);
492 	return (ret);
493 }
494 
495 int
496 vldcpioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
497 {
498 	struct vldcp_softc *sc;
499 	struct ldc_conn *lc;
500 	struct hv_io *hi = (struct hv_io *)data;
501 	paddr_t pa, offset;
502 	psize_t nbytes;
503 	caddr_t buf;
504 	size_t size;
505 	int err;
506 
507 	sc = vldcp_lookup(dev);
508 	if (sc == NULL)
509 		return (ENXIO);
510 	lc = &sc->sc_lc;
511 
512 	switch (cmd) {
513 	case HVIOCREAD:
514 	case HVIOCWRITE:
515 		break;
516 	default:
517 		device_unref(&sc->sc_dv);
518 		return (ENOTTY);
519 	}
520 
521 	buf = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
522 
523 	switch(cmd) {
524 	case HVIOCREAD:
525 		size = hi->hi_len;
526 		offset = 0;
527 		while (size > 0) {
528 			pmap_extract(pmap_kernel(), (vaddr_t)buf, &pa);
529 			nbytes = min(PAGE_SIZE, size);
530 			err = hv_ldc_copy(lc->lc_id, LDC_COPY_IN,
531 			    hi->hi_cookie + offset, pa, nbytes, &nbytes);
532 			if (err != H_EOK) {
533 				printf("hv_ldc_copy %d\n", err);
534 				free(buf, M_DEVBUF, 0);
535 				device_unref(&sc->sc_dv);
536 				return (EINVAL);
537 			}
538 			err = copyout(buf, (caddr_t)hi->hi_addr + offset, nbytes);
539 			if (err) {
540 				free(buf, M_DEVBUF, 0);
541 				device_unref(&sc->sc_dv);
542 				return (err);
543 			}
544 			size -= nbytes;
545 			offset += nbytes;
546 		}
547 		break;
548 	case HVIOCWRITE:
549 		size = hi->hi_len;
550 		offset = 0;
551 		while (size > 0) {
552 			pmap_extract(pmap_kernel(), (vaddr_t)buf, &pa);
553 			nbytes = min(PAGE_SIZE, size);
554 			err = copyin((caddr_t)hi->hi_addr + offset, buf, nbytes);
555 			if (err) {
556 				free(buf, M_DEVBUF, 0);
557 				device_unref(&sc->sc_dv);
558 				return (err);
559 			}
560 			err = hv_ldc_copy(lc->lc_id, LDC_COPY_OUT,
561 			    hi->hi_cookie + offset, pa, nbytes, &nbytes);
562 			if (err != H_EOK) {
563 				printf("hv_ldc_copy %d\n", err);
564 				free(buf, M_DEVBUF, 0);
565 				device_unref(&sc->sc_dv);
566 				return (EINVAL);
567 			}
568 			size -= nbytes;
569 			offset += nbytes;
570 		}
571 		break;
572 
573 	}
574 
575 	free(buf, M_DEVBUF, 0);
576 
577 	device_unref(&sc->sc_dv);
578 	return (0);
579 }
580 
581 int
582 vldcppoll(dev_t dev, int events, struct proc *p)
583 {
584 	struct vldcp_softc *sc;
585 	struct ldc_conn *lc;
586 	uint64_t head, tail, state;
587 	int revents = 0;
588 	int s, err;
589 
590 	sc = vldcp_lookup(dev);
591 	if (sc == NULL)
592 		return (POLLERR);
593 	lc = &sc->sc_lc;
594 
595 	s = spltty();
596 	if (events & (POLLIN | POLLRDNORM)) {
597 		err = hv_ldc_rx_get_state(lc->lc_id, &head, &tail, &state);
598 
599 		if (err == 0 && state == LDC_CHANNEL_UP && head != tail)
600 			revents |= events & (POLLIN | POLLRDNORM);
601 	}
602 	if (events & (POLLOUT | POLLWRNORM)) {
603 		err = hv_ldc_tx_get_state(lc->lc_id, &head, &tail, &state);
604 
605 		if (err == 0 && state == LDC_CHANNEL_UP && head != tail)
606 			revents |= events & (POLLOUT | POLLWRNORM);
607 	}
608 	if (revents == 0) {
609 		if (events & (POLLIN | POLLRDNORM)) {
610 			cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino,
611 			    INTR_ENABLED);
612 			selrecord(p, &sc->sc_rsel);
613 		}
614 		if (events & (POLLOUT | POLLWRNORM)) {
615 			cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino,
616 			    INTR_ENABLED);
617 			selrecord(p, &sc->sc_wsel);
618 		}
619 	}
620 	splx(s);
621 	return revents;
622 }
623 
624 void
625 filt_vldcprdetach(struct knote *kn)
626 {
627 	struct vldcp_softc *sc = (void *)kn->kn_hook;
628 	int s;
629 
630 	s = spltty();
631 	klist_remove_locked(&sc->sc_rsel.si_note, kn);
632 	splx(s);
633 }
634 
635 void
636 filt_vldcpwdetach(struct knote *kn)
637 {
638 	struct vldcp_softc *sc = (void *)kn->kn_hook;
639 	int s;
640 
641 	s = spltty();
642 	klist_remove_locked(&sc->sc_wsel.si_note, kn);
643 	splx(s);
644 }
645 
646 int
647 filt_vldcpread(struct knote *kn, long hint)
648 {
649 	struct vldcp_softc *sc = (void *)kn->kn_hook;
650 	struct ldc_conn *lc = &sc->sc_lc;
651 	uint64_t head, tail, avail, state;
652 	int s, err;
653 
654 	s = spltty();
655 	err = hv_ldc_rx_get_state(lc->lc_id, &head, &tail, &state);
656 	if (err == 0 && state == LDC_CHANNEL_UP && head != tail) {
657 		avail = (tail - head) / sizeof(struct ldc_pkt) +
658 		    lc->lc_rxq->lq_nentries;
659 		avail %= lc->lc_rxq->lq_nentries;
660 		kn->kn_data = avail;
661 	} else {
662 		cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino,
663 		    INTR_ENABLED);
664 	}
665 	splx(s);
666 
667 	return (kn->kn_data > 0);
668 }
669 
670 int
671 filt_vldcwrite(struct knote *kn, long hint)
672 {
673 	struct vldcp_softc *sc = (void *)kn->kn_hook;
674 	struct ldc_conn *lc = &sc->sc_lc;
675 	uint64_t head, tail, avail, state;
676 	int s, err;
677 
678 	s = spltty();
679 	err = hv_ldc_tx_get_state(lc->lc_id, &head, &tail, &state);
680 	if (err == 0 && state == LDC_CHANNEL_UP && head != tail) {
681 		avail = (head - tail) / sizeof(struct ldc_pkt) +
682 		    lc->lc_txq->lq_nentries - 1;
683 		avail %= lc->lc_txq->lq_nentries;
684 		kn->kn_data = avail;
685 	} else {
686 		cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino,
687 		    INTR_ENABLED);
688 	}
689 	splx(s);
690 
691 	return (kn->kn_data > 0);
692 }
693 
694 const struct filterops vldcpread_filtops = {
695 	.f_flags	= FILTEROP_ISFD,
696 	.f_attach	= NULL,
697 	.f_detach	= filt_vldcprdetach,
698 	.f_event	= filt_vldcpread,
699 };
700 
701 const struct filterops vldcpwrite_filtops = {
702 	.f_flags	= FILTEROP_ISFD,
703 	.f_attach	= NULL,
704 	.f_detach	= filt_vldcpwdetach,
705 	.f_event	= filt_vldcwrite,
706 };
707 
708 int
709 vldcpkqfilter(dev_t dev, struct knote *kn)
710 {
711 	struct vldcp_softc *sc;
712 	struct klist *klist;
713 	int s;
714 
715 	sc = vldcp_lookup(dev);
716 	if (sc == NULL)
717 		return (ENXIO);
718 
719 	switch (kn->kn_filter) {
720 	case EVFILT_READ:
721 		klist = &sc->sc_rsel.si_note;
722 		kn->kn_fop = &vldcpread_filtops;
723 		break;
724 	case EVFILT_WRITE:
725 		klist = &sc->sc_wsel.si_note;
726 		kn->kn_fop = &vldcpwrite_filtops;
727 		break;
728 
729 	default:
730 		return (EINVAL);
731 	}
732 
733 	kn->kn_hook = sc;
734 
735 	s = spltty();
736 	klist_insert_locked(klist, kn);
737 	splx(s);
738 
739 	return (0);
740 }
741