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