From: sashiko-bot@kernel.org
To: "Fenglin Wu" <fenglin.wu@oss.qualcomm.com>
Cc: conor+dt@kernel.org, devicetree@vger.kernel.org, robh@kernel.org
Subject: Re: [PATCH 4/4] pinctrl: qcom: spmi-gpio: Add level-shifter function support
Date: Wed, 27 May 2026 11:36:41 +0000 [thread overview]
Message-ID: <20260527113641.D6E281F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260527-pinctrl-level-shifter-v1-4-1965461d0a7c@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] Out-of-bounds array access on the `pmic_gpio_functions` array when reading pin configurations from debugfs.
- [High] Applying pin configurations to a level-shifter group incorrectly re-enables the disabled GPIO pads and writes out-of-bounds function values, corrupting hardware mode control registers.
- [High] The driver fails to properly defer probing if the command DB (`cmd-db`) is not yet initialized.
- [High] The unconditional registration of level shifters breaks the probe sequence for existing devices that do not utilize them.
--
commit 0ccd51f9c406d2406a12a93ef3944f4bac8c5bdb
Author: Fenglin Wu <fenglin.wu@oss.qualcomm.com>
pinctrl: qcom: spmi-gpio: Add level-shifter function support
This commit introduces support for bidirectional level shifter modules
(BIDIR_LVL_SHIFTER) to the SPMI GPIO driver. It adds a new "level-shifter"
function to manage GPIO pairs that share physical pins with the level shifter,
controlling their state via RPMh.
> diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
> index f159c56784b4f..d0144dbb7cfc8 100644
> --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
> +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
[ ... ]
> @@ -137,6 +144,7 @@ enum pmic_gpio_func_index {
> PMIC_GPIO_FUNC_INDEX_DTEST2,
> PMIC_GPIO_FUNC_INDEX_DTEST3,
> PMIC_GPIO_FUNC_INDEX_DTEST4,
> + PMIC_GPIO_FUNC_INDEX_LEVEL_SHIFTER,
> };
[Severity: High]
Does this code cause an out-of-bounds array access when reading pin
configurations from debugfs?
If a pin is configured as a level-shifter and its pad is enabled, reading the
pin's debugfs node will index pmic_gpio_functions[10] (or [12] for non-LV/MV
subtypes due to the DTEST offset). Since PMIC_GPIO_FUNC_INDEX_LEVEL_SHIFTER was
added to the enum but pmic_gpio_functions was not updated, it seems this could
result in an out-of-bounds read that can crash the kernel or leak memory.
[ ... ]
> @@ -705,7 +835,25 @@ static int pmic_gpio_pinconf_group_set(struct pinctrl_dev *pctldev,
> if (!group)
> return -EINVAL;
>
> - /* Iterate over all pins in the group and apply config to each */
> + /* Handle group-level LS_ENABLE before iterating per-pin configs */
> + for (i = 0; i < nconfs; i++) {
> + if (pinconf_to_config_param(configs[i]) != PMIC_GPIO_CONF_LS_ENABLE)
> + continue;
> +
> + if (!group->data) {
> + dev_err(state->dev,
> + "qcom,1p2v-1p8v-ls-en is only valid for level-shifter groups\n");
> + return -EINVAL;
> + }
> +
> + ret = pmic_gpio_set_ls_rpmh(state,
> + (struct ls_pingroup_data *)group->data,
> + !!pinconf_to_config_argument(configs[i]));
> + if (ret < 0)
> + return ret;
> + }
> +
> + /* Apply per-pin configs to each pin in the group */
> for (i = 0; i < group->grp.npins; i++) {
> pin = group->grp.pins[i];
>
> + ret = pmic_gpio_pinconf_pin_set(pctldev, pin, configs, nconfs);
> + if (ret < 0)
> + return ret;
> }
[Severity: High]
Can applying pin configurations to a level-shifter group incorrectly re-enable
the disabled GPIO pads and write out-of-bounds function values?
In pmic_gpio_set_mux(), level-shifter pins correctly have their pads disabled.
However, when group-level pin configurations are applied
(e.g., qcom,1p2v-1p8v-ls-en), pmic_gpio_pinconf_group_set() delegates to
pmic_gpio_pinconf_pin_set().
The per-pin function unconditionally sets pad->is_enabled = true and writes it
to PMIC_GPIO_REG_EN_CTL, re-enabling the pads. Furthermore, it shifts
pad->function (10) left by 1 (PMIC_GPIO_REG_MODE_FUNCTION_SHIFT), which
overflows the 3-bit mode mask and overwrites adjacent bits in
PMIC_GPIO_REG_MODE_CTL.
[ ... ]
> @@ -1177,6 +1333,96 @@ static const struct irq_chip spmi_gpio_irq_chip = {
> GPIOCHIP_IRQ_RESOURCE_HELPERS,
> };
>
> +/**
> + * pmic_gpio_register_level_shifters() - Register level-shifter groups and function
> + * @state: PMIC GPIO state
> + * @hw_data: Hardware-specific data containing level-shifter configurations
> + *
> + * This function registers level-shifter support by:
> + * 1. Getting RPMh device reference and PMIC ID from device tree
> + * 2. Registering each level-shifter pair as a multi-pin group
> + * 3. Getting RPMh addresses from cmd_db for each level-shifter
> + * 4. Registering the level-shifter function once with all valid groups
> + *
> + * Return: 0 on success, negative error code on failure
> + */
> +static int pmic_gpio_register_level_shifters(struct pmic_gpio_state *state,
> + const struct pmic_gpio_hw_data *hw_data)
> +{
> + struct device *dev = state->dev;
> + const char **ls_group_names;
> + int ret, i;
> +
> + /* Get RPMh device reference for level shifter control */
> + state->rpmh_dev = rpmh_get_ctrlr_dev(dev);
> + if (IS_ERR(state->rpmh_dev))
> + return dev_err_probe(dev, PTR_ERR(state->rpmh_dev),
> + "Level shifter needs rpmh device\n");
> +
> + /* Get PMIC ID from device tree for RPMh resource name composition */
> + ret = of_property_read_string(dev->of_node, "qcom,pmic-id",
> + &state->pmic_id);
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "get qcom,pmic-id failed for rpmh resource\n");
[Severity: High]
Does the unconditional registration of level shifters break the probe sequence
for existing devices that do not utilize them?
pmic_gpio_probe() unconditionally invokes pmic_gpio_register_level_shifters()
for any device matching qcom,pmh0101-gpio. If rpmh_get_ctrlr_dev(),
qcom,pmic-id property parsing, or cmd_db_read_addr() fails, the function
returns an error that aborts the entire GPIO controller probe. Existing devices
do not possess the newly introduced qcom,rpmh or qcom,pmic-id properties,
causing them to encounter a fatal -ENODEV during probe.
> +
> + /* Allocate array to hold all level-shifter group names */
> + ls_group_names = devm_kcalloc(dev, hw_data->num_ls,
> + sizeof(*ls_group_names), GFP_KERNEL);
> + if (!ls_group_names)
> + return -ENOMEM;
> +
> + /* Register each level-shifter pair as a multi-pin group */
> + for (i = 0; i < hw_data->num_ls; i++) {
> + struct ls_config *ls = &hw_data->ls_config[i];
> + struct ls_pingroup_data *ls_group_data;
> + char rpmh_resource_name[32];
> +
> + /* Allocate ls_pingroup_data for this level shifter */
> + ls_group_data = devm_kzalloc(dev, sizeof(*ls_group_data),
> + GFP_KERNEL);
> + if (!ls_group_data)
> + return -ENOMEM;
> +
> + ls_group_data->config = ls;
> +
> + /* Compose RPMh resource name and get address from cmd_db */
> + if (state->pmic_id && ls->rpmh_prefix) {
> + snprintf(rpmh_resource_name,
> + sizeof(rpmh_resource_name),
> + "%s%s", ls->rpmh_prefix, state->pmic_id);
> + ls_group_data->level_shifter_addr =
> + cmd_db_read_addr(rpmh_resource_name);
> + if (!ls_group_data->level_shifter_addr)
> + return dev_err_probe(dev, -ENODEV,
> + "RPMh resource %s not found in cmd_db\n",
> + rpmh_resource_name);
[Severity: High]
Does this code fail to properly defer probing if the command DB (cmd-db) is
not yet initialized?
If the command database is not yet ready, cmd_db_read_addr() swallows the
-EPROBE_DEFER error and returns 0. The driver misinterprets this 0 as a missing
resource and returns a permanent -ENODEV via dev_err_probe(). The driver must
explicitly check cmd_db_ready() to correctly defer probing. Otherwise, it races
with cmd-db initialization and breaks on early probes.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260527-pinctrl-level-shifter-v1-0-1965461d0a7c@oss.qualcomm.com?part=4
prev parent reply other threads:[~2026-05-27 11:36 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-27 9:22 [PATCH 0/4] pinctrl: qcom: spmi-gpio: Add bidirectional level-shifter function support Fenglin Wu
2026-05-27 9:22 ` [PATCH 1/4] soc: qcom: rpmh: Allow non-child devices to issue write commands Fenglin Wu
2026-05-27 9:53 ` sashiko-bot
2026-05-27 9:22 ` [PATCH 2/4] dt-bindings: pinctrl: qcom,pmic-gpio: Add level-shifter function Fenglin Wu
2026-05-27 10:12 ` sashiko-bot
2026-05-27 9:22 ` [PATCH 3/4] pinctrl: qcom: spmi-gpio: Rearchitect for flexible group support Fenglin Wu
2026-05-27 10:59 ` sashiko-bot
2026-05-27 9:22 ` [PATCH 4/4] pinctrl: qcom: spmi-gpio: Add level-shifter function support Fenglin Wu
2026-05-27 11:36 ` sashiko-bot [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260527113641.D6E281F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=fenglin.wu@oss.qualcomm.com \
--cc=robh@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox