From 3ecadbc42fc0ba66e75a218e353a863ad881b97c Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Thu, 6 Apr 2017 00:02:30 -0700 Subject: qcom: battery: Fix using stale votable pointers The code flow between battery.c and smblib.c could end up with stale references in smblib. This is when if pl_init fails for some reason after creating the votables, while smblib obtains references to them, those references become invalid. Fix this by calling pl_init early in smb2 driver's probe such that if it fails smb2 driver exits early. Also change the name of pl_(de)init() functions to more appropriate name - qcom_batt_(de)init(). Change-Id: I58f79d26e6cc8524e792a23185ff6fc8cfdffa75 Signed-off-by: Harry Yang Signed-off-by: Abhijeet Dharmapurikar --- drivers/power/supply/qcom/battery.c | 28 +++++++++++++++++-------- drivers/power/supply/qcom/battery.h | 17 +++++++++++++++ drivers/power/supply/qcom/smb-lib.c | 41 +++++++++++++++++++++++++++++-------- 3 files changed, 69 insertions(+), 17 deletions(-) create mode 100644 drivers/power/supply/qcom/battery.h diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 539e757d3e99..1df46d120d94 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -930,11 +930,17 @@ static int pl_determine_initial_status(struct pl_data *chip) } #define DEFAULT_RESTRICTED_CURRENT_UA 1000000 -static int pl_init(void) +int qcom_batt_init(void) { struct pl_data *chip; int rc = 0; + /* initialize just once */ + if (the_chip) { + pr_err("was initialized earlier Failing now\n"); + return -EINVAL; + } + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; @@ -1014,7 +1020,9 @@ static int pl_init(void) goto unreg_notifier; } - return rc; + the_chip = chip; + + return 0; unreg_notifier: power_supply_unreg_notifier(&chip->nb); @@ -1031,21 +1039,23 @@ cleanup: return rc; } -static void pl_deinit(void) +void qcom_batt_deinit(void) { struct pl_data *chip = the_chip; + if (chip == NULL) + return; + + cancel_work_sync(&chip->status_change_work); + cancel_delayed_work_sync(&chip->pl_taper_work); + cancel_work_sync(&chip->pl_disable_forever_work); + power_supply_unreg_notifier(&chip->nb); destroy_votable(chip->pl_awake_votable); destroy_votable(chip->pl_disable_votable); destroy_votable(chip->fv_votable); destroy_votable(chip->fcc_votable); wakeup_source_unregister(chip->pl_ws); + the_chip = NULL; kfree(chip); } - -module_init(pl_init); -module_exit(pl_deinit) - -MODULE_DESCRIPTION(""); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/supply/qcom/battery.h b/drivers/power/supply/qcom/battery.h new file mode 100644 index 000000000000..38626e733a09 --- /dev/null +++ b/drivers/power/supply/qcom/battery.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __BATTERY_H +#define __BATTERY_H +int qcom_batt_init(void); +void qcom_batt_deinit(void); +#endif /* __BATTERY_H */ diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index cc83309d3c03..9aa255ae57da 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -19,10 +19,11 @@ #include #include #include +#include #include "smb-lib.h" #include "smb-reg.h" +#include "battery.h" #include "storm-watch.h" -#include #define smblib_err(chg, fmt, ...) \ pr_err("%s: %s: " fmt, chg->name, \ @@ -4268,26 +4269,30 @@ static int smblib_create_votables(struct smb_charger *chg) int rc = 0; chg->fcc_votable = find_votable("FCC"); - if (!chg->fcc_votable) { - rc = -EPROBE_DEFER; + if (chg->fcc_votable == NULL) { + rc = -EINVAL; + smblib_err(chg, "Couldn't find FCC votable rc=%d\n", rc); return rc; } chg->fv_votable = find_votable("FV"); - if (!chg->fv_votable) { - rc = -EPROBE_DEFER; + if (chg->fv_votable == NULL) { + rc = -EINVAL; + smblib_err(chg, "Couldn't find FV votable rc=%d\n", rc); return rc; } chg->usb_icl_votable = find_votable("USB_ICL"); if (!chg->usb_icl_votable) { - rc = -EPROBE_DEFER; + rc = -EINVAL; + smblib_err(chg, "Couldn't find USB_ICL votable rc=%d\n", rc); return rc; } chg->pl_disable_votable = find_votable("PL_DISABLE"); - if (!chg->pl_disable_votable) { - rc = -EPROBE_DEFER; + if (chg->pl_disable_votable == NULL) { + rc = -EINVAL; + smblib_err(chg, "Couldn't find votable PL_DISABLE rc=%d\n", rc); return rc; } vote(chg->pl_disable_votable, PL_INDIRECT_VOTER, true, 0); @@ -4471,6 +4476,14 @@ int smblib_init(struct smb_charger *chg) case PARALLEL_MASTER: chg->qnovo_fcc_ua = -EINVAL; chg->qnovo_fv_uv = -EINVAL; + + rc = qcom_batt_init(); + if (rc < 0) { + smblib_err(chg, "Couldn't init qcom_batt_init rc=%d\n", + rc); + return rc; + } + rc = smblib_create_votables(chg); if (rc < 0) { smblib_err(chg, "Couldn't create votables rc=%d\n", @@ -4502,8 +4515,20 @@ int smblib_deinit(struct smb_charger *chg) { switch (chg->mode) { case PARALLEL_MASTER: + cancel_work_sync(&chg->bms_update_work); + cancel_work_sync(&chg->rdstd_cc2_detach_work); + cancel_delayed_work_sync(&chg->hvdcp_detect_work); + cancel_delayed_work_sync(&chg->step_soc_req_work); + cancel_delayed_work_sync(&chg->clear_hdc_work); + cancel_work_sync(&chg->otg_oc_work); + cancel_work_sync(&chg->vconn_oc_work); + cancel_delayed_work_sync(&chg->otg_ss_done_work); + cancel_delayed_work_sync(&chg->icl_change_work); + cancel_delayed_work_sync(&chg->pl_enable_work); + cancel_work_sync(&chg->legacy_detection_work); power_supply_unreg_notifier(&chg->nb); smblib_destroy_votables(chg); + qcom_batt_deinit(); break; case PARALLEL_SLAVE: break; -- cgit v1.2.3