> Date: Wed, 20 May 2020 14:39:05 +0200 > From: Martin Pieuchot <m...@openbsd.org> > Cc: tech@openbsd.org > 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 <m...@openbsd.org> > > > > > > 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 >