Skip to content
  • Stephen Warren's avatar
    pinctrl: fix and simplify locking · 57b676f9
    Stephen Warren authored and Linus Walleij's avatar Linus Walleij committed
    
    
    There are many problems with the current pinctrl locking:
    
    struct pinctrl_dev's gpio_ranges_lock isn't effective;
    pinctrl_match_gpio_range() only holds this lock while searching for a gpio
    range, but the found range is return and manipulated after releading the
    lock. This could allow pinctrl_remove_gpio_range() for that range while it
    is in use, and the caller may very well delete the range after removing it,
    causing pinctrl code to touch the now-free range object.
    
    Solving this requires the introduction of a higher-level lock, at least
    a lock per pin controller, which both gpio range registration and
    pinctrl_get()/put() will acquire.
    
    There is missing locking on HW programming; pin controllers may pack the
    configuration for different pins/groups/config options/... into one
    register, and hence have to read-modify-write the register. This needs to
    be protected, but currently isn't. Related, a future change will add a
    "complete" op to the pin controller drivers, the idea being that each
    state's programming will be programmed into the pinctrl driver followed
    by the "complete" call, which may e.g. flush a register cache to HW. For
    this to work, it must not be possible to interleave the pinctrl driver
    calls for different devices.
    
    As above, solving this requires the introduction of a higher-level lock,
    at least a lock per pin controller, which will be held for the duration
    of any pinctrl_enable()/disable() call.
    
    However, each pinctrl mapping table entry may affect a different pin
    controller if necessary. Hence, with a per-pin-controller lock, almost
    any pinctrl API may need to acquire multiple locks, one per controller.
    To avoid deadlock, these would need to be acquired in the same order in
    all cases. This is extremely difficult to implement in the case of
    pinctrl_get(), which doesn't know which pin controllers to lock until it
    has parsed the entire mapping table, since it contains somewhat arbitrary
    data.
    
    The simplest solution here is to introduce a single lock that covers all
    pin controllers at once. This will be acquired by all pinctrl APIs.
    
    This then makes struct pinctrl's mutex irrelevant, since that single lock
    will always be held whenever this mutex is currently held.
    
    Signed-off-by: default avatarStephen Warren <swarren@nvidia.com>
    Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
    57b676f9