On Thu, Jan 23, 2020 at 09:51:11AM +0100, Martin Pieuchot wrote:
> On 23/01/20(Thu) 08:26, Patrick Wildt wrote:
> > Hi,
> > 
> > this is the second attempt of a diff that prepares acpivout(4) to work
> > with the X395.  The previous one broke due to recursive ACPI locking.
> > 
> > So apparently we cannot change the brightness using the acpivout(4) ACPI
> > methods.  Instead we need to call amdgpu(4) to change the brightness.
> > But the brightness key events are still reported by acpivout(4).  That
> > means that we need to seperate the keystroke events from the actual
> > brightness change.
> > 
> > This diff changes the code to always use ws_[gs]et_param instead of just
> > calling the ACPI methods.  This means that the function pointers can
> > point to acpivout(4) or amdgpu(4), it shouldn't matter.
> > 
> > Unfortunately there's an issue with acpivout(4) calling itself.  The
> > keystroke event handler runs with the ACPI lock, so if we call our own
> > function, we try to grab the ACPI lock again and panic.  So, in this
> > diff I check whether we already have it and skip taking it again.
> 
> Why do you need to grab the ACPI lock again?  Can't you assert the lock
> is always taken and use a wrapper in the code path where it isn't?

acpivout_[gs]et_param don't know if they are being called by itself
or by someone else.  I don't need to grab it again, I just need to
have it before calling an ACPI method.  But when acpivout(4) calls
itself, it already has it, so taking it again would break it, as it's
non recursive.

Since it's a global function pointer that hides the implementation, the
caller cannot just take the ACPI lock before calling ws_[gs]et_param.
The caller doesn't know that the implementation needs ACPI.  On my X395
the function set in ws_[gs]et_param have nothing to do with ACPI at all.

> > I'm sure this looks ugly, and I'm wondering if it's too ugly.  If it is
> > indeed too ugly, I hope you'll also provide another idea how we can work
> > around it.
> > More testing would be appreciated.
> > 
> > Thanks,
> > Patrick
> > 
> > diff --git a/sys/dev/acpi/acpivout.c b/sys/dev/acpi/acpivout.c
> > index 58e8e3d431c..f3de0c582fb 100644
> > --- a/sys/dev/acpi/acpivout.c
> > +++ b/sys/dev/acpi/acpivout.c
> > @@ -66,6 +66,7 @@ void      acpivout_brightness_cycle(struct acpivout_softc 
> > *);
> >  void       acpivout_brightness_step(struct acpivout_softc *, int);
> >  void       acpivout_brightness_zero(struct acpivout_softc *);
> >  int        acpivout_get_brightness(struct acpivout_softc *);
> > +int        acpivout_select_brightness(struct acpivout_softc *, int);
> >  int        acpivout_find_brightness(struct acpivout_softc *, int);
> >  void       acpivout_set_brightness(struct acpivout_softc *, int);
> >  void       acpivout_get_bcl(struct acpivout_softc *);
> > @@ -124,6 +125,9 @@ acpivout_notify(struct aml_node *node, int notify, void 
> > *arg)
> >  {
> >     struct acpivout_softc *sc = arg;
> >  
> > +   if (ws_get_param == NULL || ws_set_param == NULL)
> > +           return (0);
> > +
> >     switch (notify) {
> >     case NOTIFY_BRIGHTNESS_CYCLE:
> >             acpivout_brightness_cycle(sc);
> > @@ -151,12 +155,13 @@ acpivout_notify(struct aml_node *node, int notify, 
> > void *arg)
> >  void
> >  acpivout_brightness_cycle(struct acpivout_softc *sc)
> >  {
> > -   int     cur_level;
> > +   struct wsdisplay_param dp;
> >  
> > -   if (sc->sc_bcl_len == 0)
> > +   dp.param = WSDISPLAYIO_PARAM_BRIGHTNESS;
> > +   if (ws_get_param(&dp))
> >             return;
> > -   cur_level = acpivout_get_brightness(sc);
> > -   if (cur_level == sc->sc_bcl[sc->sc_bcl_len - 1])
> > +
> > +   if (dp.curval == dp.max)
> >             acpivout_brightness_zero(sc);
> >     else
> >             acpivout_brightness_step(sc, 1);
> > @@ -165,33 +170,45 @@ acpivout_brightness_cycle(struct acpivout_softc *sc)
> >  void
> >  acpivout_brightness_step(struct acpivout_softc *sc, int dir)
> >  {
> > -   int level, nindex;
> > +   struct wsdisplay_param dp;
> > +   int delta, new;
> >  
> > -   if (sc->sc_bcl_len == 0)
> > -           return;
> > -   level = acpivout_get_brightness(sc);
> > -   if (level == -1)
> > +   dp.param = WSDISPLAYIO_PARAM_BRIGHTNESS;
> > +   if (ws_get_param(&dp))
> >             return;
> >  
> > -   nindex = acpivout_find_brightness(sc, level + (dir * BRIGHTNESS_STEP));
> > -   if (sc->sc_bcl[nindex] == level) {
> > -           if (dir == 1 && (nindex + 1 < sc->sc_bcl_len))
> > -                   nindex++;
> > -           else if (dir == -1 && (nindex - 1 >= 0))
> > -                   nindex--;
> > +   new = dp.curval;
> > +   delta = ((dp.max - dp.min) * BRIGHTNESS_STEP) / 100;
> > +   if (dir > 0) {
> > +           if (delta > dp.max - dp.curval)
> > +                   new = dp.max;
> > +           else
> > +                   new += delta;
> > +   } else if (dir < 0) {
> > +           if (delta > dp.curval - dp.min)
> > +                   new = dp.min;
> > +           else
> > +                   new -= delta;
> >     }
> > -   if (sc->sc_bcl[nindex] == level)
> > +
> > +   if (dp.curval == new)
> >             return;
> >  
> > -   acpivout_set_brightness(sc, sc->sc_bcl[nindex]);
> > +   dp.curval = new;
> > +   ws_set_param(&dp);
> >  }
> >  
> >  void
> >  acpivout_brightness_zero(struct acpivout_softc *sc)
> >  {
> > -   if (sc->sc_bcl_len == 0)
> > +   struct wsdisplay_param dp;
> > +
> > +   dp.param = WSDISPLAYIO_PARAM_BRIGHTNESS;
> > +   if (ws_get_param(&dp))
> >             return;
> > -   acpivout_set_brightness(sc, sc->sc_bcl[0]);
> > +
> > +   dp.curval = dp.min;
> > +   ws_set_param(&dp);
> >  }
> >  
> >  int
> > @@ -211,6 +228,26 @@ acpivout_get_brightness(struct acpivout_softc *sc)
> >     return (level);
> >  }
> >  
> > +int
> > +acpivout_select_brightness(struct acpivout_softc *sc, int nlevel)
> > +{
> > +   int nindex, level;
> > +
> > +   level = acpivout_get_brightness(sc);
> > +   if (level == -1)
> > +           return level;
> > +
> > +   nindex = acpivout_find_brightness(sc, nlevel);
> > +   if (sc->sc_bcl[nindex] == level) {
> > +           if (nlevel > level && (nindex + 1 < sc->sc_bcl_len))
> > +                   nindex++;
> > +           else if (nlevel < level && (nindex - 1 >= 0))
> > +                   nindex--;
> > +   }
> > +
> > +   return nindex;
> > +}
> > +
> >  int
> >  acpivout_find_brightness(struct acpivout_softc *sc, int level)
> >  {
> > @@ -290,7 +327,7 @@ int
> >  acpivout_get_param(struct wsdisplay_param *dp)
> >  {
> >     struct acpivout_softc   *sc = NULL;
> > -   int i;
> > +   int i, needlock;
> >  
> >     switch (dp->param) {
> >     case WSDISPLAYIO_PARAM_BRIGHTNESS:
> > @@ -304,10 +341,13 @@ acpivout_get_param(struct wsdisplay_param *dp)
> >             }
> >             if (sc != NULL && sc->sc_bcl_len != 0) {
> >                     dp->min = 0;
> > -                   dp->max =  sc->sc_bcl[sc->sc_bcl_len - 1];
> > -                   rw_enter_write(&sc->sc_acpi->sc_lck);
> > +                   dp->max = sc->sc_bcl[sc->sc_bcl_len - 1];
> > +                   needlock = rw_status(&sc->sc_acpi->sc_lck) != RW_WRITE;
> > +                   if (needlock)
> > +                           rw_enter_write(&sc->sc_acpi->sc_lck);
> >                     dp->curval = acpivout_get_brightness(sc);
> > -                   rw_exit_write(&sc->sc_acpi->sc_lck);
> > +                   if (needlock)
> > +                           rw_exit_write(&sc->sc_acpi->sc_lck);
> >                     if (dp->curval != -1)
> >                             return 0;
> >             }
> > @@ -321,7 +361,7 @@ int
> >  acpivout_set_param(struct wsdisplay_param *dp)
> >  {
> >     struct acpivout_softc   *sc = NULL;
> > -   int i, nindex;
> > +   int i, nindex, needlock;
> >  
> >     switch (dp->param) {
> >     case WSDISPLAYIO_PARAM_BRIGHTNESS:
> > @@ -334,10 +374,14 @@ acpivout_set_param(struct wsdisplay_param *dp)
> >                             break;
> >             }
> >             if (sc != NULL && sc->sc_bcl_len != 0) {
> > -                   rw_enter_write(&sc->sc_acpi->sc_lck);
> > -                   nindex = acpivout_find_brightness(sc, dp->curval);
> > -                   acpivout_set_brightness(sc, sc->sc_bcl[nindex]);
> > -                   rw_exit_write(&sc->sc_acpi->sc_lck);
> > +                   needlock = rw_status(&sc->sc_acpi->sc_lck) != RW_WRITE;
> > +                   if (needlock)
> > +                           rw_enter_write(&sc->sc_acpi->sc_lck);
> > +                   nindex = acpivout_select_brightness(sc, dp->curval);
> > +                   if (nindex != -1)
> > +                           acpivout_set_brightness(sc, sc->sc_bcl[nindex]);
> > +                   if (needlock)
> > +                           rw_exit_write(&sc->sc_acpi->sc_lck);
> >                     return 0;
> >             }
> >             return -1;
> > 
> 

Reply via email to