mirror of
https://github.com/torvalds/linux.git
synced 2026-09-29 04:22:03 +02:00
pinctrl: generic: serialise pinctrl_generic_dt_node_to_map()
pinctrl_generic_add_group() documents that the caller must take care of
locking, and pinmux_generic_add_function() needs it too, but
pinctrl_generic_dt_node_to_map() calls them without holding
pctldev->mutex, and the core caller in create_pinctrl() does not take it
either.
The driver core calls pinctrl_bind_pins() before probing a device, so
two devices that reference the same pin controller can run
pinctrl_generic_dt_node_to_map() on one pctldev at the same time.
Both `add` functions take the new selector from pctldev->num_groups or
pctldev->num_functions, and radix_tree_insert() at that index.
Two racing callers can read the same selector before either
has inserted, so the second insert collides and fails:
k1-pinctrl d401e000.pinctrl:
error -EEXIST: error adding function pcie2-0-cfg
k1-pinctrl d401e000.pinctrl:
does not have pin group pcie0-0-cfg.pcie0-0-pins
leaving one consumer without its pin configuration.
This was hit on a SpacemiT K3 board, where PCIe devices probe in parallel
against the single shared pin controller.
Take pctldev->mutex across the whole function, so that the groups and the
function referring are in a single critical section.
Fixes: 43722575e5 ("pinctrl: add generic functions + pins mapper")
Signed-off-by: Sarah Emery <sarah.emery@canonical.com>
Signed-off-by: Linus Walleij <linusw@kernel.org>
This commit is contained in:
parent
692f32609a
commit
51ae996594
|
|
@ -3,8 +3,10 @@
|
|||
#define pr_fmt(fmt) "generic pinconfig core: " fmt
|
||||
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
|
@ -196,6 +198,8 @@ static int pinctrl_generic_dt_node_to_map(struct pinctrl_dev *pctldev,
|
|||
int ngroups = 0;
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&pctldev->mutex);
|
||||
|
||||
*maps = NULL;
|
||||
*num_maps = 0;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user