DF-4653 / fix.diff
--- a/sys/dev/misc/puc/puc.c +++ b/sys/dev/misc/puc/puc.c @@ -88,6 +88,7 @@ #include <sys/conf.h> #include <sys/malloc.h> #include <sys/rman.h> +#include <cpu/cpufunc.h> /* cpu_ccfence() */ #include <bus/pci/pcireg.h> #include <bus/pci/pcivar.h> @@ -405,6 +406,7 @@ ilr_mask = sc->ilr_enabled ? puc_ilr_read(sc) : 0xffffffff; for (i = 0; i < PUC_MAX_PORTS; i++) if (sc->sc_ports[i].ihand != NULL && + sc->sc_ports[i].ihandarg != NULL && ((ilr_mask >> i) & 0x00000001)) (sc->sc_ports[i].ihand)(sc->sc_ports[i].ihandarg); } @@ -688,8 +690,12 @@ if (sc->sc_ports[i].dev == child) { if (sc->sc_ports[i].ihand != NULL) return (ENXIO); - sc->sc_ports[i].ihand = ihand; + /* Publish the argument BEFORE the handler: puc_intr + * gates on ihand alone, so ihandarg must become + * visible no later than ihand. */ sc->sc_ports[i].ihandarg = arg; + cpu_ccfence(); + sc->sc_ports[i].ihand = ihand; KKASSERT(serializer == NULL); /* not handled yet XXX */ *cookiep = arg; return (0); @@ -708,7 +714,10 @@ sc = (struct puc_softc *)device_get_softc(dev); for (i = 0; PUC_PORT_VALID(sc->sc_desc, i); i++) { if (sc->sc_ports[i].dev == child) { + /* Retract the handler BEFORE the argument (inverse + * of the setup publication order). */ sc->sc_ports[i].ihand = NULL; + cpu_ccfence(); sc->sc_ports[i].ihandarg = NULL; return (0); } |