Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pinctrl: Fix the clean up on pinconf_apply_setting failure

When some client does devm_pinctrl_get() followed by
pinctrl_select_state() that does pinmux first successfully and later
during config setting it sets the wrong drive strenght to the pin due to
which pinconf_apply_setting fails. Currently, on failure during config
setting is implemented as if pinmux has failed for one of the pin but
that does not seem right and need to undo the pinmux for all the pin if
config setting fails.

Current commit does a bit refactor to reuse the code and tries to clean
up mux setting on config setting failure.

Signed-off-by: Mukesh Ojha <mukesh.ojha@oss.qualcomm.com>
Link: https://lore.kernel.org/20241224084441.515870-1-mukesh.ojha@oss.qualcomm.com
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

authored by

Mukesh Ojha and committed by
Linus Walleij
001d7ef8 e4ee0acf

+30 -20
+30 -20
drivers/pinctrl/core.c
··· 1256 1256 DL_FLAG_AUTOREMOVE_CONSUMER); 1257 1257 } 1258 1258 1259 + static void pinctrl_cond_disable_mux_setting(struct pinctrl_state *state, 1260 + struct pinctrl_setting *target_setting) 1261 + { 1262 + struct pinctrl_setting *setting; 1263 + 1264 + list_for_each_entry(setting, &state->settings, node) { 1265 + if (target_setting && (&setting->node == &target_setting->node)) 1266 + break; 1267 + 1268 + if (setting->type == PIN_MAP_TYPE_MUX_GROUP) 1269 + pinmux_disable_setting(setting); 1270 + } 1271 + } 1272 + 1259 1273 /** 1260 1274 * pinctrl_commit_state() - select/activate/program a pinctrl state to HW 1261 1275 * @p: the pinctrl handle for the device that requests configuration ··· 1277 1263 */ 1278 1264 static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state) 1279 1265 { 1280 - struct pinctrl_setting *setting, *setting2; 1266 + struct pinctrl_setting *setting; 1281 1267 struct pinctrl_state *old_state = READ_ONCE(p->state); 1282 1268 int ret; 1283 1269 ··· 1288 1274 * still owned by the new state will be re-acquired by the call 1289 1275 * to pinmux_enable_setting() in the loop below. 1290 1276 */ 1291 - list_for_each_entry(setting, &old_state->settings, node) { 1292 - if (setting->type != PIN_MAP_TYPE_MUX_GROUP) 1293 - continue; 1294 - pinmux_disable_setting(setting); 1295 - } 1277 + pinctrl_cond_disable_mux_setting(old_state, NULL); 1296 1278 } 1297 1279 1298 1280 p->state = NULL; ··· 1332 1322 } 1333 1323 1334 1324 if (ret < 0) { 1335 - goto unapply_new_state; 1325 + goto unapply_mux_setting; 1336 1326 } 1337 1327 1338 1328 /* Do not link hogs (circular dependency) */ ··· 1344 1334 1345 1335 return 0; 1346 1336 1337 + unapply_mux_setting: 1338 + pinctrl_cond_disable_mux_setting(state, NULL); 1339 + goto restore_old_state; 1340 + 1347 1341 unapply_new_state: 1348 1342 dev_err(p->dev, "Error applying setting, reverse things back\n"); 1349 1343 1350 - list_for_each_entry(setting2, &state->settings, node) { 1351 - if (&setting2->node == &setting->node) 1352 - break; 1353 - /* 1354 - * All we can do here is pinmux_disable_setting. 1355 - * That means that some pins are muxed differently now 1356 - * than they were before applying the setting (We can't 1357 - * "unmux a pin"!), but it's not a big deal since the pins 1358 - * are free to be muxed by another apply_setting. 1359 - */ 1360 - if (setting2->type == PIN_MAP_TYPE_MUX_GROUP) 1361 - pinmux_disable_setting(setting2); 1362 - } 1344 + /* 1345 + * All we can do here is pinmux_disable_setting. 1346 + * That means that some pins are muxed differently now 1347 + * than they were before applying the setting (We can't 1348 + * "unmux a pin"!), but it's not a big deal since the pins 1349 + * are free to be muxed by another apply_setting. 1350 + */ 1351 + pinctrl_cond_disable_mux_setting(state, setting); 1363 1352 1353 + restore_old_state: 1364 1354 /* There's no infinite recursive loop here because p->state is NULL */ 1365 1355 if (old_state) 1366 1356 pinctrl_select_state(p, old_state);