vldcp(4/sparc64), magma(4) and spif(4) kqfilter

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

vldcp(4/sparc64), magma(4) and spif(4) kqfilter

Martin Pieuchot
Diff below implements kqfilter for the 3 remaining drivers in the tree,
that I could find, supporting poll(2) but not kqueue(2).

magma(4) and spif(4) call seltrue() so their diff is trivial.

This change is required to be able to switch poll(2) and select(2) to
use the *kqfilter() handlers on sparc64.  If one values coherency, it
also makes sense on its own.

ok?

Index: arch/sparc64//dev/vldcp.c
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/dev/vldcp.c,v
retrieving revision 1.19
diff -u -p -r1.19 vldcp.c
--- arch/sparc64//dev/vldcp.c 19 Dec 2019 12:04:38 -0000 1.19
+++ arch/sparc64//dev/vldcp.c 20 May 2020 09:21:20 -0000
@@ -70,6 +70,11 @@ struct vldcp_softc {
 
 int vldcp_match(struct device *, void *, void *);
 void vldcp_attach(struct device *, struct device *, void *);
+void filt_vldcprdetach(struct knote *);
+void filt_vldcpwdetach(struct knote *);
+int filt_vldcpread(struct knote *, long);
+int filt_vldcpwrite(struct knote *, long);
+int vldcpkqfilter(dev_t, struct knote *);
 
 struct cfattach vldcp_ca = {
  sizeof(struct vldcp_softc), vldcp_match, vldcp_attach
@@ -614,4 +619,122 @@ vldcppoll(dev_t dev, int events, struct
  }
  splx(s);
  return revents;
+}
+
+void
+filt_vldcprdetach(struct knote *kn)
+{
+ struct vldcp_softc *sc = (void *)kn->kn_hook;
+ int s;
+
+ s = spltty();
+ klist_remove(&sc->sc_rsel.si_note, kn);
+ splx(s);
+}
+
+void
+filt_vldcpwdetach(struct knote *kn)
+{
+ struct vldcp_softc *sc = (void *)kn->kn_hook;
+ int s;
+
+ s = spltty();
+ klist_remove(&sc->sc_wsel.si_note, kn);
+ splx(s);
+}
+
+int
+filt_vldcpread(struct knote *kn, long hint)
+{
+ struct vldcp_softc *sc = (void *)kn->kn_hook;
+ struct ldc_conn *lc = &sc->sc_lc;
+ uint64_t head, tail, avail, state;
+ int s, err;
+
+ s = spltty();
+ err = hv_ldc_rx_get_state(lc->lc_id, &head, &tail, &state);
+ if (err == 0 && state == LDC_CHANNEL_UP && head != tail) {
+ avail = (head - tail) / sizeof(struct ldc_pkt) +
+    lc->lc_rxq->lq_nentries - 1;
+ avail %= lc->lc_rxq->lq_nentries;
+ kn->kn_data = avail;
+ } else {
+ cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino,
+    INTR_ENABLED);
+ }
+ splx(s);
+
+ return (kn->kn_data > 0);
+}
+
+int
+filt_vldcwrite(struct knote *kn, long hint)
+{
+ struct vldcp_softc *sc = (void *)kn->kn_hook;
+ struct ldc_conn *lc = &sc->sc_lc;
+ uint64_t head, tail, avail, state;
+ int s, err;
+
+ s = spltty();
+ err = hv_ldc_tx_get_state(lc->lc_id, &head, &tail, &state);
+ if (err == 0 && state == LDC_CHANNEL_UP && head != tail) {
+ avail = (head - tail) / sizeof(struct ldc_pkt) +
+    lc->lc_rxq->lq_nentries - 1;
+ avail %= lc->lc_rxq->lq_nentries;
+ kn->kn_data = avail;
+ } else {
+ cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino,
+    INTR_ENABLED);
+ }
+ splx(s);
+
+ return (kn->kn_data > 0);
+}
+
+const struct filterops vldcpread_filtops = {
+ .f_flags = FILTEROP_ISFD,
+ .f_attach = NULL,
+ .f_detach = filt_vldcprdetach,
+ .f_event = filt_vldcpread,
+};
+
+const struct filterops vldcpwrite_filtops = {
+ .f_flags = FILTEROP_ISFD,
+ .f_attach = NULL,
+ .f_detach = filt_vldcpwdetach,
+ .f_event = filt_vldcwrite,
+};
+
+int
+vldcpkqfilter(dev_t dev, struct knote *kn)
+{
+ struct vldcp_softc *sc;
+ struct klist *klist;
+ int s;
+
+ sc = vldcp_lookup(dev);
+ if (sc == NULL)
+ return (ENXIO);
+
+ switch (kn->kn_filter) {
+ case EVFILT_READ:
+ klist = &sc->sc_rsel.si_note;
+ kn->kn_fop = &vldcpread_filtops;
+ break;
+ case EVFILT_WRITE:
+ klist = &sc->sc_wsel.si_note;
+ kn->kn_fop = &vldcpwrite_filtops;
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
+ kn->kn_hook = sc;
+
+ s = spltty();
+ klist_insert(klist, kn);
+ splx(s);
+
+ return (0);
 }
Index: arch/sparc64//include/conf.h
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/include/conf.h,v
retrieving revision 1.25
diff -u -p -r1.25 conf.h
--- arch/sparc64//include/conf.h 13 May 2020 08:10:03 -0000 1.25
+++ arch/sparc64//include/conf.h 20 May 2020 09:15:55 -0000
@@ -64,7 +64,8 @@ cdev_decl(vdsp);
 #define cdev_gen_init(c,n) { \
  dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
  dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) nullop, \
- 0, dev_init(c,n,poll), (dev_type_mmap((*))) enodev }
+ 0, dev_init(c,n,poll), (dev_type_mmap((*))) enodev, \
+ 0, 0, dev_init(c,n,kqfilter) }
 
 cdev_decl(cn);
 
Index: dev/sbus/magma.c
===================================================================
RCS file: /cvs/src/sys/dev/sbus/magma.c,v
retrieving revision 1.31
diff -u -p -r1.31 magma.c
--- dev/sbus/magma.c 18 Feb 2020 00:12:08 -0000 1.31
+++ dev/sbus/magma.c 20 May 2020 09:15:55 -0000
@@ -1340,6 +1340,7 @@ mtty_param(struct tty *tp, struct termio
  * mbppwrite write to mbpp
  * mbppioctl do ioctl on mbpp
  * mbpppoll do poll on mbpp
+ * mbppkqfilter kqueue on mbpp
  * mbpp_rw general rw routine
  * mbpp_timeout rw timeout
  * mbpp_start rw start after delay
@@ -1513,6 +1514,12 @@ int
 mbpppoll(dev_t dev, int events, struct proc *p)
 {
  return (seltrue(dev, events, p));
+}
+
+int
+mbppkqfilter(dev_t dev, struct knote *kn)
+{
+ return (seltrue_kqfilter(dev, kn));
 }
 
 int
Index: dev/sbus/spif.c
===================================================================
RCS file: /cvs/src/sys/dev/sbus/spif.c,v
retrieving revision 1.23
diff -u -p -r1.23 spif.c
--- dev/sbus/spif.c 19 Jul 2019 00:17:15 -0000 1.23
+++ dev/sbus/spif.c 20 May 2020 09:15:55 -0000
@@ -91,6 +91,7 @@ int sbppwrite(dev_t, struct uio *, int);
 int sbpp_rw(dev_t, struct uio *);
 int spifppcintr(void *);
 int sbpppoll(dev_t, int, struct proc *);
+int sbppkqfilter(dev_t, struct knote *);
 int sbppioctl(dev_t, u_long, caddr_t, int, struct proc *);
 
 struct cfattach spif_ca = {
@@ -1043,6 +1044,11 @@ int
 sbpppoll(dev_t dev, int events, struct proc *p)
 {
  return (seltrue(dev, events, p));
+}
+int
+sbppkqfilter(dev_t dev, struct knote *kn)
+{
+ return (seltrue_kqfilter(dev, kn));
 }
 
 int

Reply | Threaded
Open this post in threaded view
|

Re: vldcp(4/sparc64), magma(4) and spif(4) kqfilter

Mark Kettenis
> Date: Wed, 20 May 2020 11:33:24 +0200
> From: Martin Pieuchot <[hidden email]>
>
> Diff below implements kqfilter for the 3 remaining drivers in the tree,
> that I could find, supporting poll(2) but not kqueue(2).
>
> magma(4) and spif(4) call seltrue() so their diff is trivial.
>
> This change is required to be able to switch poll(2) and select(2) to
> use the *kqfilter() handlers on sparc64.  If one values coherency, it
> also makes sense on its own.
>
> ok?

Nope.  The filt_vldcwrite() implementation is defenitely wrong as it
looks at the rx queue instead of the tx queue.

But even then, I'm not sure if this is doing the right thing.  Si the
way the code enables interrupts compatible with kqueue(2)?  In the
current implementation, enabling interrupts is closely tied to the
selrecord() call and disabling interrupts happens at the same time as
the selwakeup().

It really is hard to tell for me to tell what is supposed to happen
here since there is no kqueue(9) that documents how this is supposed to
work.


> Index: arch/sparc64//dev/vldcp.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/sparc64/dev/vldcp.c,v
> retrieving revision 1.19
> diff -u -p -r1.19 vldcp.c
> --- arch/sparc64//dev/vldcp.c 19 Dec 2019 12:04:38 -0000 1.19
> +++ arch/sparc64//dev/vldcp.c 20 May 2020 09:21:20 -0000
> @@ -70,6 +70,11 @@ struct vldcp_softc {
>  
>  int vldcp_match(struct device *, void *, void *);
>  void vldcp_attach(struct device *, struct device *, void *);
> +void filt_vldcprdetach(struct knote *);
> +void filt_vldcpwdetach(struct knote *);
> +int filt_vldcpread(struct knote *, long);
> +int filt_vldcpwrite(struct knote *, long);
> +int vldcpkqfilter(dev_t, struct knote *);
>  
>  struct cfattach vldcp_ca = {
>   sizeof(struct vldcp_softc), vldcp_match, vldcp_attach
> @@ -614,4 +619,122 @@ vldcppoll(dev_t dev, int events, struct
>   }
>   splx(s);
>   return revents;
> +}
> +
> +void
> +filt_vldcprdetach(struct knote *kn)
> +{
> + struct vldcp_softc *sc = (void *)kn->kn_hook;
> + int s;
> +
> + s = spltty();
> + klist_remove(&sc->sc_rsel.si_note, kn);
> + splx(s);
> +}
> +
> +void
> +filt_vldcpwdetach(struct knote *kn)
> +{
> + struct vldcp_softc *sc = (void *)kn->kn_hook;
> + int s;
> +
> + s = spltty();
> + klist_remove(&sc->sc_wsel.si_note, kn);
> + splx(s);
> +}
> +
> +int
> +filt_vldcpread(struct knote *kn, long hint)
> +{
> + struct vldcp_softc *sc = (void *)kn->kn_hook;
> + struct ldc_conn *lc = &sc->sc_lc;
> + uint64_t head, tail, avail, state;
> + int s, err;
> +
> + s = spltty();
> + err = hv_ldc_rx_get_state(lc->lc_id, &head, &tail, &state);
> + if (err == 0 && state == LDC_CHANNEL_UP && head != tail) {
> + avail = (head - tail) / sizeof(struct ldc_pkt) +
> +    lc->lc_rxq->lq_nentries - 1;
> + avail %= lc->lc_rxq->lq_nentries;
> + kn->kn_data = avail;
> + } else {
> + cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino,
> +    INTR_ENABLED);
> + }
> + splx(s);
> +
> + return (kn->kn_data > 0);
> +}
> +
> +int
> +filt_vldcwrite(struct knote *kn, long hint)
> +{
> + struct vldcp_softc *sc = (void *)kn->kn_hook;
> + struct ldc_conn *lc = &sc->sc_lc;
> + uint64_t head, tail, avail, state;
> + int s, err;
> +
> + s = spltty();
> + err = hv_ldc_tx_get_state(lc->lc_id, &head, &tail, &state);
> + if (err == 0 && state == LDC_CHANNEL_UP && head != tail) {
> + avail = (head - tail) / sizeof(struct ldc_pkt) +
> +    lc->lc_rxq->lq_nentries - 1;
> + avail %= lc->lc_rxq->lq_nentries;
> + kn->kn_data = avail;
> + } else {
> + cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino,
> +    INTR_ENABLED);
> + }
> + splx(s);
> +
> + return (kn->kn_data > 0);
> +}
> +
> +const struct filterops vldcpread_filtops = {
> + .f_flags = FILTEROP_ISFD,
> + .f_attach = NULL,
> + .f_detach = filt_vldcprdetach,
> + .f_event = filt_vldcpread,
> +};
> +
> +const struct filterops vldcpwrite_filtops = {
> + .f_flags = FILTEROP_ISFD,
> + .f_attach = NULL,
> + .f_detach = filt_vldcpwdetach,
> + .f_event = filt_vldcwrite,
> +};
> +
> +int
> +vldcpkqfilter(dev_t dev, struct knote *kn)
> +{
> + struct vldcp_softc *sc;
> + struct klist *klist;
> + int s;
> +
> + sc = vldcp_lookup(dev);
> + if (sc == NULL)
> + return (ENXIO);
> +
> + switch (kn->kn_filter) {
> + case EVFILT_READ:
> + klist = &sc->sc_rsel.si_note;
> + kn->kn_fop = &vldcpread_filtops;
> + break;
> + case EVFILT_WRITE:
> + klist = &sc->sc_wsel.si_note;
> + kn->kn_fop = &vldcpwrite_filtops;
> + break;
> +
> + default:
> + return (EINVAL);
> + }
> +
> + kn->kn_hook = sc;
> +
> + s = spltty();
> + klist_insert(klist, kn);
> + splx(s);
> +
> + return (0);
>  }
> Index: arch/sparc64//include/conf.h
> ===================================================================
> RCS file: /cvs/src/sys/arch/sparc64/include/conf.h,v
> retrieving revision 1.25
> diff -u -p -r1.25 conf.h
> --- arch/sparc64//include/conf.h 13 May 2020 08:10:03 -0000 1.25
> +++ arch/sparc64//include/conf.h 20 May 2020 09:15:55 -0000
> @@ -64,7 +64,8 @@ cdev_decl(vdsp);
>  #define cdev_gen_init(c,n) { \
>   dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
>   dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) nullop, \
> - 0, dev_init(c,n,poll), (dev_type_mmap((*))) enodev }
> + 0, dev_init(c,n,poll), (dev_type_mmap((*))) enodev, \
> + 0, 0, dev_init(c,n,kqfilter) }
>  
>  cdev_decl(cn);
>  
> Index: dev/sbus/magma.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/sbus/magma.c,v
> retrieving revision 1.31
> diff -u -p -r1.31 magma.c
> --- dev/sbus/magma.c 18 Feb 2020 00:12:08 -0000 1.31
> +++ dev/sbus/magma.c 20 May 2020 09:15:55 -0000
> @@ -1340,6 +1340,7 @@ mtty_param(struct tty *tp, struct termio
>   * mbppwrite write to mbpp
>   * mbppioctl do ioctl on mbpp
>   * mbpppoll do poll on mbpp
> + * mbppkqfilter kqueue on mbpp
>   * mbpp_rw general rw routine
>   * mbpp_timeout rw timeout
>   * mbpp_start rw start after delay
> @@ -1513,6 +1514,12 @@ int
>  mbpppoll(dev_t dev, int events, struct proc *p)
>  {
>   return (seltrue(dev, events, p));
> +}
> +
> +int
> +mbppkqfilter(dev_t dev, struct knote *kn)
> +{
> + return (seltrue_kqfilter(dev, kn));
>  }
>  
>  int
> Index: dev/sbus/spif.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/sbus/spif.c,v
> retrieving revision 1.23
> diff -u -p -r1.23 spif.c
> --- dev/sbus/spif.c 19 Jul 2019 00:17:15 -0000 1.23
> +++ dev/sbus/spif.c 20 May 2020 09:15:55 -0000
> @@ -91,6 +91,7 @@ int sbppwrite(dev_t, struct uio *, int);
>  int sbpp_rw(dev_t, struct uio *);
>  int spifppcintr(void *);
>  int sbpppoll(dev_t, int, struct proc *);
> +int sbppkqfilter(dev_t, struct knote *);
>  int sbppioctl(dev_t, u_long, caddr_t, int, struct proc *);
>  
>  struct cfattach spif_ca = {
> @@ -1043,6 +1044,11 @@ int
>  sbpppoll(dev_t dev, int events, struct proc *p)
>  {
>   return (seltrue(dev, events, p));
> +}
> +int
> +sbppkqfilter(dev_t dev, struct knote *kn)
> +{
> + return (seltrue_kqfilter(dev, kn));
>  }
>  
>  int
>
>

Reply | Threaded
Open this post in threaded view
|

Re: vldcp(4/sparc64), magma(4) and spif(4) kqfilter

Martin Pieuchot
On 20/05/20(Wed) 12:18, Mark Kettenis wrote:

> > Date: Wed, 20 May 2020 11:33:24 +0200
> > From: Martin Pieuchot <[hidden email]>
> >
> > Diff below implements kqfilter for the 3 remaining drivers in the tree,
> > that I could find, supporting poll(2) but not kqueue(2).
> >
> > magma(4) and spif(4) call seltrue() so their diff is trivial.
> >
> > This change is required to be able to switch poll(2) and select(2) to
> > use the *kqfilter() handlers on sparc64.  If one values coherency, it
> > also makes sense on its own.
> >
> > ok?
>
> Nope.  The filt_vldcwrite() implementation is defenitely wrong as it
> looks at the rx queue instead of the tx queue.

Diff below fixed the cbus_intr_setenabled() line and `avail' calculation.
Is it what you were pointing?

> But even then, I'm not sure if this is doing the right thing.  Si the
> way the code enables interrupts compatible with kqueue(2)?  In the
> current implementation, enabling interrupts is closely tied to the
> selrecord() call and disabling interrupts happens at the same time as
> the selwakeup().

When a kevent is registered to a kqueue, the corresponding filter
function, pointed by `f_event', is called.  This is similar to calling
`fo_poll' inside pollscan() before going to sleep.

When `f_event' returns a non-0 value, an allocated descriptor representing
the event, `kn' (or knote), is put in the kqueue.

If this didn't happen when the kevent has been registered, either via
kevent(2) or by calling kqueue_register() inside sys_ppoll(), it might
happen when selwakeup() occurs.  Because selwakeup() calls knote().

To my understanding this does the same, did I miss anything?

> It really is hard to tell for me to tell what is supposed to happen
> here since there is no kqueue(9) that documents how this is supposed to
> work.

Agreed, that's why it is important to discuss and build knowledge :)

Index: arch/sparc64/dev/vldcp.c
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/dev/vldcp.c,v
retrieving revision 1.19
diff -u -p -r1.19 vldcp.c
--- arch/sparc64/dev/vldcp.c 19 Dec 2019 12:04:38 -0000 1.19
+++ arch/sparc64/dev/vldcp.c 20 May 2020 12:37:27 -0000
@@ -70,6 +70,11 @@ struct vldcp_softc {
 
 int vldcp_match(struct device *, void *, void *);
 void vldcp_attach(struct device *, struct device *, void *);
+void filt_vldcprdetach(struct knote *);
+void filt_vldcpwdetach(struct knote *);
+int filt_vldcpread(struct knote *, long);
+int filt_vldcpwrite(struct knote *, long);
+int vldcpkqfilter(dev_t, struct knote *);
 
 struct cfattach vldcp_ca = {
  sizeof(struct vldcp_softc), vldcp_match, vldcp_attach
@@ -614,4 +619,122 @@ vldcppoll(dev_t dev, int events, struct
  }
  splx(s);
  return revents;
+}
+
+void
+filt_vldcprdetach(struct knote *kn)
+{
+ struct vldcp_softc *sc = (void *)kn->kn_hook;
+ int s;
+
+ s = spltty();
+ klist_remove(&sc->sc_rsel.si_note, kn);
+ splx(s);
+}
+
+void
+filt_vldcpwdetach(struct knote *kn)
+{
+ struct vldcp_softc *sc = (void *)kn->kn_hook;
+ int s;
+
+ s = spltty();
+ klist_remove(&sc->sc_wsel.si_note, kn);
+ splx(s);
+}
+
+int
+filt_vldcpread(struct knote *kn, long hint)
+{
+ struct vldcp_softc *sc = (void *)kn->kn_hook;
+ struct ldc_conn *lc = &sc->sc_lc;
+ uint64_t head, tail, avail, state;
+ int s, err;
+
+ s = spltty();
+ err = hv_ldc_rx_get_state(lc->lc_id, &head, &tail, &state);
+ if (err == 0 && state == LDC_CHANNEL_UP && head != tail) {
+ avail = (head - tail) / sizeof(struct ldc_pkt) +
+    lc->lc_rxq->lq_nentries - 1;
+ avail %= lc->lc_rxq->lq_nentries;
+ kn->kn_data = avail;
+ } else {
+ cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino,
+    INTR_ENABLED);
+ }
+ splx(s);
+
+ return (kn->kn_data > 0);
+}
+
+int
+filt_vldcwrite(struct knote *kn, long hint)
+{
+ struct vldcp_softc *sc = (void *)kn->kn_hook;
+ struct ldc_conn *lc = &sc->sc_lc;
+ uint64_t head, tail, avail, state;
+ int s, err;
+
+ s = spltty();
+ err = hv_ldc_tx_get_state(lc->lc_id, &head, &tail, &state);
+ if (err == 0 && state == LDC_CHANNEL_UP && head != tail) {
+ avail = (head - tail) / sizeof(struct ldc_pkt) +
+    lc->lc_txq->lq_nentries - 1;
+ avail %= lc->lc_txq->lq_nentries;
+ kn->kn_data = avail;
+ } else {
+ cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino,
+    INTR_ENABLED);
+ }
+ splx(s);
+
+ return (kn->kn_data > 0);
+}
+
+const struct filterops vldcpread_filtops = {
+ .f_flags = FILTEROP_ISFD,
+ .f_attach = NULL,
+ .f_detach = filt_vldcprdetach,
+ .f_event = filt_vldcpread,
+};
+
+const struct filterops vldcpwrite_filtops = {
+ .f_flags = FILTEROP_ISFD,
+ .f_attach = NULL,
+ .f_detach = filt_vldcpwdetach,
+ .f_event = filt_vldcwrite,
+};
+
+int
+vldcpkqfilter(dev_t dev, struct knote *kn)
+{
+ struct vldcp_softc *sc;
+ struct klist *klist;
+ int s;
+
+ sc = vldcp_lookup(dev);
+ if (sc == NULL)
+ return (ENXIO);
+
+ switch (kn->kn_filter) {
+ case EVFILT_READ:
+ klist = &sc->sc_rsel.si_note;
+ kn->kn_fop = &vldcpread_filtops;
+ break;
+ case EVFILT_WRITE:
+ klist = &sc->sc_wsel.si_note;
+ kn->kn_fop = &vldcpwrite_filtops;
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
+ kn->kn_hook = sc;
+
+ s = spltty();
+ klist_insert(klist, kn);
+ splx(s);
+
+ return (0);
 }
Index: arch/sparc64/include/conf.h
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/include/conf.h,v
retrieving revision 1.25
diff -u -p -r1.25 conf.h
--- arch/sparc64/include/conf.h 13 May 2020 08:10:03 -0000 1.25
+++ arch/sparc64/include/conf.h 20 May 2020 09:15:55 -0000
@@ -64,7 +64,8 @@ cdev_decl(vdsp);
 #define cdev_gen_init(c,n) { \
  dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
  dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) nullop, \
- 0, dev_init(c,n,poll), (dev_type_mmap((*))) enodev }
+ 0, dev_init(c,n,poll), (dev_type_mmap((*))) enodev, \
+ 0, 0, dev_init(c,n,kqfilter) }
 
 cdev_decl(cn);
 
Index: dev/sbus/magma.c
===================================================================
RCS file: /cvs/src/sys/dev/sbus/magma.c,v
retrieving revision 1.31
diff -u -p -r1.31 magma.c
--- dev/sbus/magma.c 18 Feb 2020 00:12:08 -0000 1.31
+++ dev/sbus/magma.c 20 May 2020 09:15:55 -0000
@@ -1340,6 +1340,7 @@ mtty_param(struct tty *tp, struct termio
  * mbppwrite write to mbpp
  * mbppioctl do ioctl on mbpp
  * mbpppoll do poll on mbpp
+ * mbppkqfilter kqueue on mbpp
  * mbpp_rw general rw routine
  * mbpp_timeout rw timeout
  * mbpp_start rw start after delay
@@ -1513,6 +1514,12 @@ int
 mbpppoll(dev_t dev, int events, struct proc *p)
 {
  return (seltrue(dev, events, p));
+}
+
+int
+mbppkqfilter(dev_t dev, struct knote *kn)
+{
+ return (seltrue_kqfilter(dev, kn));
 }
 
 int
Index: dev/sbus/spif.c
===================================================================
RCS file: /cvs/src/sys/dev/sbus/spif.c,v
retrieving revision 1.23
diff -u -p -r1.23 spif.c
--- dev/sbus/spif.c 19 Jul 2019 00:17:15 -0000 1.23
+++ dev/sbus/spif.c 20 May 2020 09:15:55 -0000
@@ -91,6 +91,7 @@ int sbppwrite(dev_t, struct uio *, int);
 int sbpp_rw(dev_t, struct uio *);
 int spifppcintr(void *);
 int sbpppoll(dev_t, int, struct proc *);
+int sbppkqfilter(dev_t, struct knote *);
 int sbppioctl(dev_t, u_long, caddr_t, int, struct proc *);
 
 struct cfattach spif_ca = {
@@ -1043,6 +1044,11 @@ int
 sbpppoll(dev_t dev, int events, struct proc *p)
 {
  return (seltrue(dev, events, p));
+}
+int
+sbppkqfilter(dev_t dev, struct knote *kn)
+{
+ return (seltrue_kqfilter(dev, kn));
 }
 
 int

Reply | Threaded
Open this post in threaded view
|

Re: vldcp(4/sparc64), magma(4) and spif(4) kqfilter

Mark Kettenis
> Date: Wed, 20 May 2020 14:39:05 +0200
> From: Martin Pieuchot <[hidden email]>
> Cc: [hidden email]
> Content-Type: text/plain; charset=utf-8
> Content-Disposition: inline
>
> On 20/05/20(Wed) 12:18, Mark Kettenis wrote:
> > > Date: Wed, 20 May 2020 11:33:24 +0200
> > > From: Martin Pieuchot <[hidden email]>
> > >
> > > Diff below implements kqfilter for the 3 remaining drivers in the tree,
> > > that I could find, supporting poll(2) but not kqueue(2).
> > >
> > > magma(4) and spif(4) call seltrue() so their diff is trivial.
> > >
> > > This change is required to be able to switch poll(2) and select(2) to
> > > use the *kqfilter() handlers on sparc64.  If one values coherency, it
> > > also makes sense on its own.
> > >
> > > ok?
> >
> > Nope.  The filt_vldcwrite() implementation is defenitely wrong as it
> > looks at the rx queue instead of the tx queue.
>
> Diff below fixed the cbus_intr_setenabled() line and `avail' calculation.
> Is it what you were pointing?

Yes.  But I think it still isn't right.  See below.

Are we allowed to make up what these functions return in kn->kn_data?
Since this device only allows reading and writing complete packets,
counting packets instead of bytes probably makes sense.

> > But even then, I'm not sure if this is doing the right thing.  Si the
> > way the code enables interrupts compatible with kqueue(2)?  In the
> > current implementation, enabling interrupts is closely tied to the
> > selrecord() call and disabling interrupts happens at the same time as
> > the selwakeup().
>
> When a kevent is registered to a kqueue, the corresponding filter
> function, pointed by `f_event', is called.  This is similar to calling
> `fo_poll' inside pollscan() before going to sleep.

I guess it has to because if there is something to read/write it
shouldn't go to sleep ;).  Does this mean kn->kn_data should be set to
0 where we enable the interrupt?

> When `f_event' returns a non-0 value, an allocated descriptor representing
> the event, `kn' (or knote), is put in the kqueue.
>
> If this didn't happen when the kevent has been registered, either via
> kevent(2) or by calling kqueue_register() inside sys_ppoll(), it might
> happen when selwakeup() occurs.  Because selwakeup() calls knote().
>
> To my understanding this does the same, did I miss anything?

You tell me ;).

> > It really is hard to tell for me to tell what is supposed to happen
> > here since there is no kqueue(9) that documents how this is supposed to
> > work.
>
> Agreed, that's why it is important to discuss and build knowledge :)
>
> Index: arch/sparc64/dev/vldcp.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/sparc64/dev/vldcp.c,v
> retrieving revision 1.19
> diff -u -p -r1.19 vldcp.c
> --- arch/sparc64/dev/vldcp.c 19 Dec 2019 12:04:38 -0000 1.19
> +++ arch/sparc64/dev/vldcp.c 20 May 2020 12:37:27 -0000
> @@ -70,6 +70,11 @@ struct vldcp_softc {
>  
>  int vldcp_match(struct device *, void *, void *);
>  void vldcp_attach(struct device *, struct device *, void *);
> +void filt_vldcprdetach(struct knote *);
> +void filt_vldcpwdetach(struct knote *);
> +int filt_vldcpread(struct knote *, long);
> +int filt_vldcpwrite(struct knote *, long);
> +int vldcpkqfilter(dev_t, struct knote *);
>  
>  struct cfattach vldcp_ca = {
>   sizeof(struct vldcp_softc), vldcp_match, vldcp_attach
> @@ -614,4 +619,122 @@ vldcppoll(dev_t dev, int events, struct
>   }
>   splx(s);
>   return revents;
> +}
> +
> +void
> +filt_vldcprdetach(struct knote *kn)
> +{
> + struct vldcp_softc *sc = (void *)kn->kn_hook;
> + int s;
> +
> + s = spltty();
> + klist_remove(&sc->sc_rsel.si_note, kn);
> + splx(s);
> +}
> +
> +void
> +filt_vldcpwdetach(struct knote *kn)
> +{
> + struct vldcp_softc *sc = (void *)kn->kn_hook;
> + int s;
> +
> + s = spltty();
> + klist_remove(&sc->sc_wsel.si_note, kn);
> + splx(s);
> +}
> +
> +int
> +filt_vldcpread(struct knote *kn, long hint)
> +{
> + struct vldcp_softc *sc = (void *)kn->kn_hook;
> + struct ldc_conn *lc = &sc->sc_lc;
> + uint64_t head, tail, avail, state;
> + int s, err;
> +
> + s = spltty();
> + err = hv_ldc_rx_get_state(lc->lc_id, &head, &tail, &state);
> + if (err == 0 && state == LDC_CHANNEL_UP && head != tail) {
> + avail = (head - tail) / sizeof(struct ldc_pkt) +
> +    lc->lc_rxq->lq_nentries - 1;

This needs to be

                avail = (tail - head) / sizeof(struct ldc_pkt) +
                    lc->lc_rxq->lq_nentries;

I think the -1 here would be wrong.  If tail is 1 entry ahead of head,
there is 1 packet of data to read.

> + avail %= lc->lc_rxq->lq_nentries;
> + kn->kn_data = avail;
> + } else {
> + cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino,
> +    INTR_ENABLED);

kn->kn_data = 0?

> + }
> + splx(s);
> +
> + return (kn->kn_data > 0);
> +}
> +
> +int
> +filt_vldcwrite(struct knote *kn, long hint)
> +{
> + struct vldcp_softc *sc = (void *)kn->kn_hook;
> + struct ldc_conn *lc = &sc->sc_lc;
> + uint64_t head, tail, avail, state;
> + int s, err;
> +
> + s = spltty();
> + err = hv_ldc_tx_get_state(lc->lc_id, &head, &tail, &state);
> + if (err == 0 && state == LDC_CHANNEL_UP && head != tail) {
> + avail = (head - tail) / sizeof(struct ldc_pkt) +
> +    lc->lc_txq->lq_nentries - 1;

This one is right I believe.  The -1 is needed here since we don't
allow the head pointer to become equal to the tail so effectively we
can't use the "last" entry in the queue.

Yes, I think that means the current poll implementation is broken for
writes.  Currently we only poll for reading (POLLIN).

> + avail %= lc->lc_txq->lq_nentries;
> + kn->kn_data = avail;
> + } else {
> + cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino,
> +    INTR_ENABLED);
> + }
> + splx(s);
> +
> + return (kn->kn_data > 0);
> +}
> +
> +const struct filterops vldcpread_filtops = {
> + .f_flags = FILTEROP_ISFD,
> + .f_attach = NULL,
> + .f_detach = filt_vldcprdetach,
> + .f_event = filt_vldcpread,
> +};
> +
> +const struct filterops vldcpwrite_filtops = {
> + .f_flags = FILTEROP_ISFD,
> + .f_attach = NULL,
> + .f_detach = filt_vldcpwdetach,
> + .f_event = filt_vldcwrite,
> +};
> +
> +int
> +vldcpkqfilter(dev_t dev, struct knote *kn)
> +{
> + struct vldcp_softc *sc;
> + struct klist *klist;
> + int s;
> +
> + sc = vldcp_lookup(dev);
> + if (sc == NULL)
> + return (ENXIO);
> +
> + switch (kn->kn_filter) {
> + case EVFILT_READ:
> + klist = &sc->sc_rsel.si_note;
> + kn->kn_fop = &vldcpread_filtops;
> + break;
> + case EVFILT_WRITE:
> + klist = &sc->sc_wsel.si_note;
> + kn->kn_fop = &vldcpwrite_filtops;
> + break;
> +
> + default:
> + return (EINVAL);
> + }
> +
> + kn->kn_hook = sc;
> +
> + s = spltty();
> + klist_insert(klist, kn);
> + splx(s);
> +
> + return (0);
>  }
> Index: arch/sparc64/include/conf.h
> ===================================================================
> RCS file: /cvs/src/sys/arch/sparc64/include/conf.h,v
> retrieving revision 1.25
> diff -u -p -r1.25 conf.h
> --- arch/sparc64/include/conf.h 13 May 2020 08:10:03 -0000 1.25
> +++ arch/sparc64/include/conf.h 20 May 2020 09:15:55 -0000
> @@ -64,7 +64,8 @@ cdev_decl(vdsp);
>  #define cdev_gen_init(c,n) { \
>   dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
>   dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) nullop, \
> - 0, dev_init(c,n,poll), (dev_type_mmap((*))) enodev }
> + 0, dev_init(c,n,poll), (dev_type_mmap((*))) enodev, \
> + 0, 0, dev_init(c,n,kqfilter) }
>  
>  cdev_decl(cn);
>  
> Index: dev/sbus/magma.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/sbus/magma.c,v
> retrieving revision 1.31
> diff -u -p -r1.31 magma.c
> --- dev/sbus/magma.c 18 Feb 2020 00:12:08 -0000 1.31
> +++ dev/sbus/magma.c 20 May 2020 09:15:55 -0000
> @@ -1340,6 +1340,7 @@ mtty_param(struct tty *tp, struct termio
>   * mbppwrite write to mbpp
>   * mbppioctl do ioctl on mbpp
>   * mbpppoll do poll on mbpp
> + * mbppkqfilter kqueue on mbpp
>   * mbpp_rw general rw routine
>   * mbpp_timeout rw timeout
>   * mbpp_start rw start after delay
> @@ -1513,6 +1514,12 @@ int
>  mbpppoll(dev_t dev, int events, struct proc *p)
>  {
>   return (seltrue(dev, events, p));
> +}
> +
> +int
> +mbppkqfilter(dev_t dev, struct knote *kn)
> +{
> + return (seltrue_kqfilter(dev, kn));
>  }
>  
>  int
> Index: dev/sbus/spif.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/sbus/spif.c,v
> retrieving revision 1.23
> diff -u -p -r1.23 spif.c
> --- dev/sbus/spif.c 19 Jul 2019 00:17:15 -0000 1.23
> +++ dev/sbus/spif.c 20 May 2020 09:15:55 -0000
> @@ -91,6 +91,7 @@ int sbppwrite(dev_t, struct uio *, int);
>  int sbpp_rw(dev_t, struct uio *);
>  int spifppcintr(void *);
>  int sbpppoll(dev_t, int, struct proc *);
> +int sbppkqfilter(dev_t, struct knote *);
>  int sbppioctl(dev_t, u_long, caddr_t, int, struct proc *);
>  
>  struct cfattach spif_ca = {
> @@ -1043,6 +1044,11 @@ int
>  sbpppoll(dev_t dev, int events, struct proc *p)
>  {
>   return (seltrue(dev, events, p));
> +}
> +int
> +sbppkqfilter(dev_t dev, struct knote *kn)
> +{
> + return (seltrue_kqfilter(dev, kn));
>  }
>  
>  int
>

Reply | Threaded
Open this post in threaded view
|

Re: vldcp(4/sparc64), magma(4) and spif(4) kqfilter

Martin Pieuchot
On 21/05/20(Thu) 14:44, Mark Kettenis wrote:

> > Date: Wed, 20 May 2020 14:39:05 +0200
> > From: Martin Pieuchot <[hidden email]>
> > Cc: [hidden email]
> > [...]
> > Diff below fixed the cbus_intr_setenabled() line and `avail' calculation.
> > Is it what you were pointing?
>
> Yes.  But I think it still isn't right.  See below.
>
> Are we allowed to make up what these functions return in kn->kn_data?
> Since this device only allows reading and writing complete packets,
> counting packets instead of bytes probably makes sense.

What is written in `kn_data' will be available to userland in the `data'
field of the corresponding "struct kevent" exchanged via kevent(2).  It
is described as a "Filter-specific data value".

To implement poll(2)/select(2) on top of kqfilter* routines the value
doesn't matter, these interfaces only need to know if something can be
read or written, not how much.

So if you believe that counting packets make more sense, could you tell
which calculation I should use or maybe it's easier for you to modify the
routines once in tree?

> > When a kevent is registered to a kqueue, the corresponding filter
> > function, pointed by `f_event', is called.  This is similar to calling
> > `fo_poll' inside pollscan() before going to sleep.
>
> I guess it has to because if there is something to read/write it
> shouldn't go to sleep ;).  Does this mean kn->kn_data should be set to
> 0 where we enable the interrupt?

The first time a filter is called with a newly allocated descriptor,
`kn_data' is already cleared.  The existing kqfilters are inconsistent
when it comes to set kn_data to 0 and which value to test in the return
statement.

These 2 behaviors matter for events that stay on the queue after having
being triggered.

I haven't investigated this part of the handlers yet.  This question is
also related to the EV_CLEAR flag that one can set in events in userland.

For the proposed poll(2)/select(2) diff it doesn't matter because events
are always allocated & freed for every syscall.  However this question
should be answered if we want to implement lazy removal & reuse of
descriptors.

Diff below removes the "-1" as suggested.  Is it ok to commit it and
address your other questions, which apply to all kq filters, later?

Index: arch/sparc64/dev/vldcp.c
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/dev/vldcp.c,v
retrieving revision 1.19
diff -u -p -r1.19 vldcp.c
--- arch/sparc64/dev/vldcp.c 19 Dec 2019 12:04:38 -0000 1.19
+++ arch/sparc64/dev/vldcp.c 23 May 2020 10:38:08 -0000
@@ -70,6 +70,11 @@ struct vldcp_softc {
 
 int vldcp_match(struct device *, void *, void *);
 void vldcp_attach(struct device *, struct device *, void *);
+void filt_vldcprdetach(struct knote *);
+void filt_vldcpwdetach(struct knote *);
+int filt_vldcpread(struct knote *, long);
+int filt_vldcpwrite(struct knote *, long);
+int vldcpkqfilter(dev_t, struct knote *);
 
 struct cfattach vldcp_ca = {
  sizeof(struct vldcp_softc), vldcp_match, vldcp_attach
@@ -614,4 +619,122 @@ vldcppoll(dev_t dev, int events, struct
  }
  splx(s);
  return revents;
+}
+
+void
+filt_vldcprdetach(struct knote *kn)
+{
+ struct vldcp_softc *sc = (void *)kn->kn_hook;
+ int s;
+
+ s = spltty();
+ klist_remove(&sc->sc_rsel.si_note, kn);
+ splx(s);
+}
+
+void
+filt_vldcpwdetach(struct knote *kn)
+{
+ struct vldcp_softc *sc = (void *)kn->kn_hook;
+ int s;
+
+ s = spltty();
+ klist_remove(&sc->sc_wsel.si_note, kn);
+ splx(s);
+}
+
+int
+filt_vldcpread(struct knote *kn, long hint)
+{
+ struct vldcp_softc *sc = (void *)kn->kn_hook;
+ struct ldc_conn *lc = &sc->sc_lc;
+ uint64_t head, tail, avail, state;
+ int s, err;
+
+ s = spltty();
+ err = hv_ldc_rx_get_state(lc->lc_id, &head, &tail, &state);
+ if (err == 0 && state == LDC_CHANNEL_UP && head != tail) {
+ avail = (head - tail) / sizeof(struct ldc_pkt) +
+    lc->lc_rxq->lq_nentries;
+ avail %= lc->lc_rxq->lq_nentries;
+ kn->kn_data = avail;
+ } else {
+ cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino,
+    INTR_ENABLED);
+ }
+ splx(s);
+
+ return (kn->kn_data > 0);
+}
+
+int
+filt_vldcwrite(struct knote *kn, long hint)
+{
+ struct vldcp_softc *sc = (void *)kn->kn_hook;
+ struct ldc_conn *lc = &sc->sc_lc;
+ uint64_t head, tail, avail, state;
+ int s, err;
+
+ s = spltty();
+ err = hv_ldc_tx_get_state(lc->lc_id, &head, &tail, &state);
+ if (err == 0 && state == LDC_CHANNEL_UP && head != tail) {
+ avail = (head - tail) / sizeof(struct ldc_pkt) +
+    lc->lc_txq->lq_nentries - 1;
+ avail %= lc->lc_txq->lq_nentries;
+ kn->kn_data = avail;
+ } else {
+ cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino,
+    INTR_ENABLED);
+ }
+ splx(s);
+
+ return (kn->kn_data > 0);
+}
+
+const struct filterops vldcpread_filtops = {
+ .f_flags = FILTEROP_ISFD,
+ .f_attach = NULL,
+ .f_detach = filt_vldcprdetach,
+ .f_event = filt_vldcpread,
+};
+
+const struct filterops vldcpwrite_filtops = {
+ .f_flags = FILTEROP_ISFD,
+ .f_attach = NULL,
+ .f_detach = filt_vldcpwdetach,
+ .f_event = filt_vldcwrite,
+};
+
+int
+vldcpkqfilter(dev_t dev, struct knote *kn)
+{
+ struct vldcp_softc *sc;
+ struct klist *klist;
+ int s;
+
+ sc = vldcp_lookup(dev);
+ if (sc == NULL)
+ return (ENXIO);
+
+ switch (kn->kn_filter) {
+ case EVFILT_READ:
+ klist = &sc->sc_rsel.si_note;
+ kn->kn_fop = &vldcpread_filtops;
+ break;
+ case EVFILT_WRITE:
+ klist = &sc->sc_wsel.si_note;
+ kn->kn_fop = &vldcpwrite_filtops;
+ break;
+
+ default:
+ return (EINVAL);
+ }
+
+ kn->kn_hook = sc;
+
+ s = spltty();
+ klist_insert(klist, kn);
+ splx(s);
+
+ return (0);
 }
Index: arch/sparc64/include/conf.h
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/include/conf.h,v
retrieving revision 1.25
diff -u -p -r1.25 conf.h
--- arch/sparc64/include/conf.h 13 May 2020 08:10:03 -0000 1.25
+++ arch/sparc64/include/conf.h 20 May 2020 09:15:55 -0000
@@ -64,7 +64,8 @@ cdev_decl(vdsp);
 #define cdev_gen_init(c,n) { \
  dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
  dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) nullop, \
- 0, dev_init(c,n,poll), (dev_type_mmap((*))) enodev }
+ 0, dev_init(c,n,poll), (dev_type_mmap((*))) enodev, \
+ 0, 0, dev_init(c,n,kqfilter) }
 
 cdev_decl(cn);
 

Reply | Threaded
Open this post in threaded view
|

Re: vldcp(4/sparc64), magma(4) and spif(4) kqfilter

Mark Kettenis
> Date: Sat, 23 May 2020 12:42:04 +0200
> From: Martin Pieuchot <[hidden email]>
>
> On 21/05/20(Thu) 14:44, Mark Kettenis wrote:
> > > Date: Wed, 20 May 2020 14:39:05 +0200
> > > From: Martin Pieuchot <[hidden email]>
> > > Cc: [hidden email]
> > > [...]
> > > Diff below fixed the cbus_intr_setenabled() line and `avail' calculation.
> > > Is it what you were pointing?
> >
> > Yes.  But I think it still isn't right.  See below.
> >
> > Are we allowed to make up what these functions return in kn->kn_data?
> > Since this device only allows reading and writing complete packets,
> > counting packets instead of bytes probably makes sense.
>
> What is written in `kn_data' will be available to userland in the `data'
> field of the corresponding "struct kevent" exchanged via kevent(2).  It
> is described as a "Filter-specific data value".

Which for EVFILT_READ and EVFILT_WRITE is dependent on the actual
device so it can be packets instead of bytes.

>
> To implement poll(2)/select(2) on top of kqfilter* routines the value
> doesn't matter, these interfaces only need to know if something can be
> read or written, not how much.
>
> So if you believe that counting packets make more sense, could you tell
> which calculation I should use or maybe it's easier for you to modify the
> routines once in tree?

You're already counting packets.

> > > When a kevent is registered to a kqueue, the corresponding filter
> > > function, pointed by `f_event', is called.  This is similar to calling
> > > `fo_poll' inside pollscan() before going to sleep.
> >
> > I guess it has to because if there is something to read/write it
> > shouldn't go to sleep ;).  Does this mean kn->kn_data should be set to
> > 0 where we enable the interrupt?
>
> The first time a filter is called with a newly allocated descriptor,
> `kn_data' is already cleared.  The existing kqfilters are inconsistent
> when it comes to set kn_data to 0 and which value to test in the return
> statement.

ok

> These 2 behaviors matter for events that stay on the queue after having
> being triggered.
>
> I haven't investigated this part of the handlers yet.  This question is
> also related to the EV_CLEAR flag that one can set in events in userland.
>
> For the proposed poll(2)/select(2) diff it doesn't matter because events
> are always allocated & freed for every syscall.  However this question
> should be answered if we want to implement lazy removal & reuse of
> descriptors.

In general I think we shouldn't add any new filters in this process
that are "wrong".  As this will come back to bite us later.  That
said, this device is special and not expected to be used by random
ports so fixing things later is much easier.

> Diff below removes the "-1" as suggested.  Is it ok to commit it and
> address your other questions, which apply to all kq filters, later?

There is one fix you missed, see below.

With that change, ok kettenis@

> Index: arch/sparc64/dev/vldcp.c
> ===================================================================
> RCS file: /cvs/src/sys/arch/sparc64/dev/vldcp.c,v
> retrieving revision 1.19
> diff -u -p -r1.19 vldcp.c
> --- arch/sparc64/dev/vldcp.c 19 Dec 2019 12:04:38 -0000 1.19
> +++ arch/sparc64/dev/vldcp.c 23 May 2020 10:38:08 -0000
> @@ -70,6 +70,11 @@ struct vldcp_softc {
>  
>  int vldcp_match(struct device *, void *, void *);
>  void vldcp_attach(struct device *, struct device *, void *);
> +void filt_vldcprdetach(struct knote *);
> +void filt_vldcpwdetach(struct knote *);
> +int filt_vldcpread(struct knote *, long);
> +int filt_vldcpwrite(struct knote *, long);
> +int vldcpkqfilter(dev_t, struct knote *);
>  
>  struct cfattach vldcp_ca = {
>   sizeof(struct vldcp_softc), vldcp_match, vldcp_attach
> @@ -614,4 +619,122 @@ vldcppoll(dev_t dev, int events, struct
>   }
>   splx(s);
>   return revents;
> +}
> +
> +void
> +filt_vldcprdetach(struct knote *kn)
> +{
> + struct vldcp_softc *sc = (void *)kn->kn_hook;
> + int s;
> +
> + s = spltty();
> + klist_remove(&sc->sc_rsel.si_note, kn);
> + splx(s);
> +}
> +
> +void
> +filt_vldcpwdetach(struct knote *kn)
> +{
> + struct vldcp_softc *sc = (void *)kn->kn_hook;
> + int s;
> +
> + s = spltty();
> + klist_remove(&sc->sc_wsel.si_note, kn);
> + splx(s);
> +}
> +
> +int
> +filt_vldcpread(struct knote *kn, long hint)
> +{
> + struct vldcp_softc *sc = (void *)kn->kn_hook;
> + struct ldc_conn *lc = &sc->sc_lc;
> + uint64_t head, tail, avail, state;
> + int s, err;
> +
> + s = spltty();
> + err = hv_ldc_rx_get_state(lc->lc_id, &head, &tail, &state);
> + if (err == 0 && state == LDC_CHANNEL_UP && head != tail) {
> + avail = (head - tail) / sizeof(struct ldc_pkt) +
> +    lc->lc_rxq->lq_nentries;

                avail = (tail - head) / sizeof(struct ldc_pkt) +
                    lc->lc_rxq->lq_nentries;

> + avail %= lc->lc_rxq->lq_nentries;
> + kn->kn_data = avail;
> + } else {
> + cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino,
> +    INTR_ENABLED);
> + }
> + splx(s);
> +
> + return (kn->kn_data > 0);
> +}
> +
> +int
> +filt_vldcwrite(struct knote *kn, long hint)
> +{
> + struct vldcp_softc *sc = (void *)kn->kn_hook;
> + struct ldc_conn *lc = &sc->sc_lc;
> + uint64_t head, tail, avail, state;
> + int s, err;
> +
> + s = spltty();
> + err = hv_ldc_tx_get_state(lc->lc_id, &head, &tail, &state);
> + if (err == 0 && state == LDC_CHANNEL_UP && head != tail) {
> + avail = (head - tail) / sizeof(struct ldc_pkt) +
> +    lc->lc_txq->lq_nentries - 1;
> + avail %= lc->lc_txq->lq_nentries;
> + kn->kn_data = avail;
> + } else {
> + cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino,
> +    INTR_ENABLED);
> + }
> + splx(s);
> +
> + return (kn->kn_data > 0);
> +}
> +
> +const struct filterops vldcpread_filtops = {
> + .f_flags = FILTEROP_ISFD,
> + .f_attach = NULL,
> + .f_detach = filt_vldcprdetach,
> + .f_event = filt_vldcpread,
> +};
> +
> +const struct filterops vldcpwrite_filtops = {
> + .f_flags = FILTEROP_ISFD,
> + .f_attach = NULL,
> + .f_detach = filt_vldcpwdetach,
> + .f_event = filt_vldcwrite,
> +};
> +
> +int
> +vldcpkqfilter(dev_t dev, struct knote *kn)
> +{
> + struct vldcp_softc *sc;
> + struct klist *klist;
> + int s;
> +
> + sc = vldcp_lookup(dev);
> + if (sc == NULL)
> + return (ENXIO);
> +
> + switch (kn->kn_filter) {
> + case EVFILT_READ:
> + klist = &sc->sc_rsel.si_note;
> + kn->kn_fop = &vldcpread_filtops;
> + break;
> + case EVFILT_WRITE:
> + klist = &sc->sc_wsel.si_note;
> + kn->kn_fop = &vldcpwrite_filtops;
> + break;
> +
> + default:
> + return (EINVAL);
> + }
> +
> + kn->kn_hook = sc;
> +
> + s = spltty();
> + klist_insert(klist, kn);
> + splx(s);
> +
> + return (0);
>  }
> Index: arch/sparc64/include/conf.h
> ===================================================================
> RCS file: /cvs/src/sys/arch/sparc64/include/conf.h,v
> retrieving revision 1.25
> diff -u -p -r1.25 conf.h
> --- arch/sparc64/include/conf.h 13 May 2020 08:10:03 -0000 1.25
> +++ arch/sparc64/include/conf.h 20 May 2020 09:15:55 -0000
> @@ -64,7 +64,8 @@ cdev_decl(vdsp);
>  #define cdev_gen_init(c,n) { \
>   dev_init(c,n,open), dev_init(c,n,close), dev_init(c,n,read), \
>   dev_init(c,n,write), dev_init(c,n,ioctl), (dev_type_stop((*))) nullop, \
> - 0, dev_init(c,n,poll), (dev_type_mmap((*))) enodev }
> + 0, dev_init(c,n,poll), (dev_type_mmap((*))) enodev, \
> + 0, 0, dev_init(c,n,kqfilter) }
>  
>  cdev_decl(cn);
>  
>