Skip to content

Commit c8befdc

Browse files
krzklinusw
authored andcommitted
pinctrl: qcom: lpass-lpi: fix concurrent register updates
The Qualcomm LPASS LPI pin controller driver uses one lock for guarding Read-Modify-Write code for slew rate registers. However the pin configuration and muxing registers have exactly the same RMW code but are not protected. Pin controller framework does not provide locking here, thus it is possible to trigger simultaneous change of pin configuration registers resulting in non-atomic changes. Protect from concurrent access by re-using the same lock used to cover the slew rate register. Using the same lock instead of adding second one will make more sense, once we add support for newer Qualcomm SoC, where slew rate is configured in the same register as pin configuration/muxing. Fixes: 6e261d1 ("pinctrl: qcom: Add sm8250 lpass lpi pinctrl driver") Cc: [email protected] Reviewed-by: Linus Walleij <[email protected]> Signed-off-by: Krzysztof Kozlowski <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Linus Walleij <[email protected]>
1 parent 5872080 commit c8befdc

File tree

1 file changed

+11
-6
lines changed

1 file changed

+11
-6
lines changed

drivers/pinctrl/qcom/pinctrl-lpass-lpi.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ struct lpi_pinctrl {
3232
char __iomem *tlmm_base;
3333
char __iomem *slew_base;
3434
struct clk_bulk_data clks[MAX_LPI_NUM_CLKS];
35-
struct mutex slew_access_lock;
35+
/* Protects from concurrent register updates */
36+
struct mutex lock;
3637
DECLARE_BITMAP(ever_gpio, MAX_NR_GPIO);
3738
const struct lpi_pinctrl_variant_data *data;
3839
};
@@ -103,6 +104,7 @@ static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
103104
if (WARN_ON(i == g->nfuncs))
104105
return -EINVAL;
105106

107+
mutex_lock(&pctrl->lock);
106108
val = lpi_gpio_read(pctrl, pin, LPI_GPIO_CFG_REG);
107109

108110
/*
@@ -128,6 +130,7 @@ static int lpi_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
128130

129131
u32p_replace_bits(&val, i, LPI_GPIO_FUNCTION_MASK);
130132
lpi_gpio_write(pctrl, pin, LPI_GPIO_CFG_REG, val);
133+
mutex_unlock(&pctrl->lock);
131134

132135
return 0;
133136
}
@@ -233,14 +236,14 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group,
233236
if (slew_offset == LPI_NO_SLEW)
234237
break;
235238

236-
mutex_lock(&pctrl->slew_access_lock);
239+
mutex_lock(&pctrl->lock);
237240

238241
sval = ioread32(pctrl->slew_base + LPI_SLEW_RATE_CTL_REG);
239242
sval &= ~(LPI_SLEW_RATE_MASK << slew_offset);
240243
sval |= arg << slew_offset;
241244
iowrite32(sval, pctrl->slew_base + LPI_SLEW_RATE_CTL_REG);
242245

243-
mutex_unlock(&pctrl->slew_access_lock);
246+
mutex_unlock(&pctrl->lock);
244247
break;
245248
default:
246249
return -EINVAL;
@@ -256,6 +259,7 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group,
256259
lpi_gpio_write(pctrl, group, LPI_GPIO_VALUE_REG, val);
257260
}
258261

262+
mutex_lock(&pctrl->lock);
259263
val = lpi_gpio_read(pctrl, group, LPI_GPIO_CFG_REG);
260264

261265
u32p_replace_bits(&val, pullup, LPI_GPIO_PULL_MASK);
@@ -264,6 +268,7 @@ static int lpi_config_set(struct pinctrl_dev *pctldev, unsigned int group,
264268
u32p_replace_bits(&val, output_enabled, LPI_GPIO_OE_MASK);
265269

266270
lpi_gpio_write(pctrl, group, LPI_GPIO_CFG_REG, val);
271+
mutex_unlock(&pctrl->lock);
267272

268273
return 0;
269274
}
@@ -461,7 +466,7 @@ int lpi_pinctrl_probe(struct platform_device *pdev)
461466
pctrl->chip.label = dev_name(dev);
462467
pctrl->chip.can_sleep = false;
463468

464-
mutex_init(&pctrl->slew_access_lock);
469+
mutex_init(&pctrl->lock);
465470

466471
pctrl->ctrl = devm_pinctrl_register(dev, &pctrl->desc, pctrl);
467472
if (IS_ERR(pctrl->ctrl)) {
@@ -483,7 +488,7 @@ int lpi_pinctrl_probe(struct platform_device *pdev)
483488
return 0;
484489

485490
err_pinctrl:
486-
mutex_destroy(&pctrl->slew_access_lock);
491+
mutex_destroy(&pctrl->lock);
487492
clk_bulk_disable_unprepare(MAX_LPI_NUM_CLKS, pctrl->clks);
488493

489494
return ret;
@@ -495,7 +500,7 @@ int lpi_pinctrl_remove(struct platform_device *pdev)
495500
struct lpi_pinctrl *pctrl = platform_get_drvdata(pdev);
496501
int i;
497502

498-
mutex_destroy(&pctrl->slew_access_lock);
503+
mutex_destroy(&pctrl->lock);
499504
clk_bulk_disable_unprepare(MAX_LPI_NUM_CLKS, pctrl->clks);
500505

501506
for (i = 0; i < pctrl->data->npins; i++)

0 commit comments

Comments
 (0)