power: smb5-lib: Fix race conditions for typec power role

Currently power_role is accessed by set_prop and get_prop
functions of typec_power_role without any locking mechanism,
there can be a scenario where both function calls were invoked
simultaneously and power_role variable is not correctly
updated, and it leads to enumeration issues when connected to PC.

Fix it by adding locking mechanism to power_role.

Change-Id: I4f5dc38a9536b535510dc2b112712a5cbd2b3f84
Signed-off-by: Kavya Nunna <knunna@codeaurora.org>
This commit is contained in:
Kavya Nunna 2021-03-10 12:16:48 +05:30
commit c28831d054

View file

@ -3915,18 +3915,20 @@ int smblib_get_prop_typec_power_role(struct smb_charger *chg, int *val)
return 0;
}
spin_lock(&chg->typec_pr_lock);
rc = smblib_read(chg, TYPE_C_MODE_CFG_REG, &ctrl);
if (rc < 0) {
smblib_err(chg, "Couldn't read TYPE_C_MODE_CFG_REG rc=%d\n",
rc);
return rc;
goto unlock;
}
smblib_dbg(chg, PR_REGISTER, "TYPE_C_MODE_CFG_REG = 0x%02x\n",
ctrl);
if (ctrl & TYPEC_DISABLE_CMD_BIT) {
*val = QTI_POWER_SUPPLY_TYPEC_PR_NONE;
return rc;
goto unlock;
}
switch (ctrl & (EN_SRC_ONLY_BIT | EN_SNK_ONLY_BIT)) {
@ -3943,10 +3945,14 @@ int smblib_get_prop_typec_power_role(struct smb_charger *chg, int *val)
*val = QTI_POWER_SUPPLY_TYPEC_PR_NONE;
smblib_err(chg, "unsupported power role 0x%02lx\n",
ctrl & (EN_SRC_ONLY_BIT | EN_SNK_ONLY_BIT));
return -EINVAL;
rc = -EINVAL;
goto unlock;
}
chg->power_role = *val;
unlock:
spin_unlock(&chg->typec_pr_lock);
return rc;
}
@ -4557,6 +4563,8 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg, int val)
if (chg->connector_type == QTI_POWER_SUPPLY_CONNECTOR_MICRO_USB)
return 0;
spin_lock(&chg->typec_pr_lock);
smblib_dbg(chg, PR_MISC, "power role change: %d --> %d!",
chg->power_role, val);
@ -4564,7 +4572,7 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg, int val)
if (chg->power_role == val && chg->power_role != QTI_POWER_SUPPLY_TYPEC_PR_NONE) {
smblib_dbg(chg, PR_MISC, "power role already in %d, ignore!",
chg->power_role);
return 0;
goto unlock;
}
typec_mode = smblib_get_prop_typec_mode(chg);
@ -4590,7 +4598,6 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg, int val)
smblib_dbg(chg, PR_MISC, "snk_attached = %d, src_attached = %d, is_pr_lock = %d\n",
snk_attached, src_attached, is_pr_lock);
cancel_delayed_work(&chg->pr_lock_clear_work);
spin_lock(&chg->typec_pr_lock);
if (!chg->pr_lock_in_progress && is_pr_lock) {
smblib_dbg(chg, PR_MISC, "disable type-c interrupts for power role locking\n");
smblib_typec_irq_config(chg, false);
@ -4602,7 +4609,6 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg, int val)
}
chg->pr_lock_in_progress = is_pr_lock;
spin_unlock(&chg->typec_pr_lock);
switch (val) {
case QTI_POWER_SUPPLY_TYPEC_PR_NONE:
@ -4619,7 +4625,8 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg, int val)
break;
default:
smblib_err(chg, "power role %d not supported\n", val);
return -EINVAL;
rc = -EINVAL;
goto unlock;
}
rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
@ -4628,10 +4635,13 @@ int smblib_set_prop_typec_power_role(struct smb_charger *chg, int val)
if (rc < 0) {
smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n",
power_role, rc);
return rc;
goto unlock;
}
chg->power_role = val;
unlock:
spin_unlock(&chg->typec_pr_lock);
return rc;
}