lkml.org 
[lkml]   [2020]   [Dec]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: [PATCH v2] pwm: bcm2835: Support apply function for atomic configuration
    Hello Sean,

    On Fri, Dec 04, 2020 at 11:38:46AM +0000, Sean Young wrote:
    > On Fri, Dec 04, 2020 at 12:13:26PM +0100, Uwe Kleine-König wrote:
    > > On Fri, Dec 04, 2020 at 08:44:17AM +0000, Sean Young wrote:
    > > > On Fri, Dec 04, 2020 at 12:42:15AM +0100, Lino Sanfilippo wrote:
    > > > > > You're storing an unsigned long long (i.e. 64 bits) in an u32. If
    > > > > > you are sure that this won't discard relevant bits, please explain
    > > > > > this in a comment for the cursory reader.
    > > > >
    > > > > What about an extra check then to make sure that the period has not been truncated,
    > > > > e.g:
    > > > >
    > > > > value = DIV_ROUND_CLOSEST_ULL(state->period, scaler);
    > > > >
    > > > > /* dont accept a period that is too small or has been truncated */
    > > > > if ((value < PERIOD_MIN) ||
    > > > > (value != DIV_ROUND_CLOSEST_ULL(state->period, scaler)))
    > > > > return -EINVAL;
    > > >
    > > > Rather than doing another 64 bit division which is expensive (esp on 32 bit
    > > > kernels), you could assign to u64 and check:
    > > >
    > > > if (value < PERIOD_MIN || value > U32_MAX)
    > > > return -EINVAL;
    > >
    > > Given that value is a u32, value > U32_MAX will never trigger.
    >
    > I meant that value is declared u64 as well ("assign to u64").
    >
    > > Maybe checking period before doing the division is more sensible.
    >
    > That could introduce rounding errors, exactly why PERIOD_MIN was introduced.

    If done correctly it doesn't introduce rounding errors.

    > > > > > Also note that round_closed is probably wrong, as .apply() is
    > > > > > supposed to round down the period to the next achievable period. (But
    > > > > > fixing this has to do done in a separate patch.)
    > > > >
    > > > > According to commit 11fc4edc4 rounding to the closest integer has been introduced
    > > > > to improve precision in case that the pwm controller is used by the pwm-ir-tx driver.
    > > > > I dont know how strong the requirement is to round down the period in apply(), but I
    > > > > can imagine that this may be a good reason to deviate from this rule.
    > > > > (CCing Sean Young who introduced DIV_ROUND_CLOSEST)
    > > >
    > > > There was a problem where the carrier is incorrect for some IR hardware
    > > > which uses a carrier of 455kHz. With periods that small, rounding errors
    > > > do really matter and rounding down might cause problems.
    > > >
    > > > A policy of rounding down the carrier is not the right thing to do
    > > > for pwm-ir-tx, and such a change will probably break pwm-ir-tx in some
    > > > edge cases.
    > >
    > > IMO it's not an option to say: pwm-driver A is used for IR, so A's
    > > .apply uses round-nearest and pwm-driver B is used for $somethingelse,
    > > so B's .apply uses round-down.
    >
    > I'm not saying that one driver should have one it one way and another driver
    > another way.

    I read between your lines that you think that round-nearest is the
    single best strategy, is that right?

    > > To be a sensible API pwm_apply_state
    > > should have a fixed behaviour. I consider round-down the sensible
    > > choice (because it is easier to implmement the other options with this)
    >
    > It's not sensible when it's wrong about half the time.

    So round-nearest which is wrong about the other half is better?
    If you have two consumer drivers and one requires round-nearest and the
    other requires round-down, how would you suggest to implement these two?
    Always adapting the low-level driver depending on which consumer is in
    use sounds wrong. So I conclude that the expectation about the
    implemented rounding behaviour should be the same for all drivers. And
    if your consumer happens to require a different strategy you're either
    out of luck (bad), or we need to expand the PWM API to make this
    possible, probably by implementing a round_state callback that tells the
    caller the resulting state if the given state is applied.

    > Why is is easier to implement?

    If pwm_apply_state (and so pwm_round_state) rounds down, you can achieve
    round-nearest (simplified: Ignoring polarity, just looking for period) using:

    lower_state = pwm_round_state(pwm, target_state);
    upper_state = {
    .period = 2 * target_state.period - lower_state.period,
    ...
    }
    tmp = pwm_round_state(pwm, upper)

    if tmp.period < target_state.period:
    # tmp == lower_state
    return lower_state

    else while tmp.period > target_state.period:
    upper = tmp;
    tmp.period -= 1
    tmp = pwm_round_state(pwm, tmp)

    I admit it is not pretty. But please try to implement it the other way
    around (i.e. pwm_round_state rounding to nearest and search for a
    setting that yields the biggest period not above target.period without
    just trying all steps). I spend a few brain cycles and the corner cases
    are harder. (But maybe I'm not smart enough, so please convince me.)

    Note that with round-nearest there is another complication: Assume a PWM
    that can implement period = 500 µs and period = 1000 µs (and nothing
    inbetween). That corresponds to the frequencies 2000 Hz and 1000 Hz.
    round_nearest for state with period = 700 µs (corresponding to 1428.5714
    Hz) would then pick 500 µs (corresponding to 2000 Hz), right? So is
    round-nearest really what you prefer?

    > > and for consumers like the IR stuff we need to provide some more
    > > functions to allow it selecting a better suited state. Something like:
    > >
    > > pwm_round_state_nearest(pwm, { .period = 2198, .. }, &state)
    > >
    > > which queries the hardwares capabilities and then assigns state.period =
    > > 2200 instead of 2100.
    >
    > This is very elaborate and surely not "easier to implement". Why not just
    > do the right thing in the first place and round-closest?

    I looked through the history of drivers/pwm for commits changing the
    rounding behaviour. I found:

    - 11fc4edc483 which changes bcm2835 from round-down to round-closest
    (I didn't check but given that the driver divides by the result of a
    division the rounding might not always be round-closest.)
    - 12f9ce4a519 which changes pwm-rockchip from round-down to
    round-closest
    (The motivation described in the commit log is wrong today as
    pwm_get_state() gives the last set value, not the result of the
    lowlevel driver's .get_state callback. Also this problem can be fixed
    with drivers implementing round-down by just letting .get_state round
    up. (Which by the way is how I recommend how to implement it when
    reviewing new drivers.))

    Did I miss something?

    For a quick (and maybe unreliable) overview:

    $ git grep -l _CLOSEST drivers/pwm/ | wc -l
    15

    so we might have 15 drivers that round to nearest and the remaining 40
    round down. (I checked a few and didn't find a false diagnose.)

    For me this isn't a clear indication that round-nearest is
    unconditionally better. What is the fact that convinces you that
    round-nearest is better in general?

    > > Where can I find the affected (consumer) driver?
    >
    > So there is the pwm-ir-tx driver. The infrared led is directly connected
    > to the pwm output pin, so that's all there is.

    Ah, found it, drivers/media/rc/pwm-ir-tx.c, thanks.

    Best regards
    Uwe

    --
    Pengutronix e.K. | Uwe Kleine-König |
    Industrial Linux Solutions | https://www.pengutronix.de/ |
    [unhandled content-type:application/pgp-signature]
    \
     
     \ /
      Last update: 2020-12-05 00:31    [W:3.274 / U:0.092 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site