--- /dev/null
+From 45eaf45dfa4850df16bc2e8e7903d89021137f40 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.de>
+Date: Wed, 29 Oct 2014 08:49:50 +1100
+Subject: md: Always set RECOVERY_NEEDED when clearing RECOVERY_FROZEN
+
+From: NeilBrown <neilb@suse.de>
+
+commit 45eaf45dfa4850df16bc2e8e7903d89021137f40 upstream.
+
+md_check_recovery will skip any recovery and also clear
+MD_RECOVERY_NEEDED if MD_RECOVERY_FROZEN is set.
+So when we clear _FROZEN, we must set _NEEDED and ensure that
+md_check_recovery gets run.
+Otherwise we could miss out on something that is needed.
+
+In particular, this can make it impossible to remove a
+failed device from an array is the 'recovery-needed' processing
+didn't happen.
+Suitable for stable kernels since 3.13.
+
+Reported-and-tested-by: Joe Lawrence <joe.lawrence@stratus.com>
+Fixes: 30b8feb730f9b9b3c5de02580897da03f59b6b16
+Signed-off-by: NeilBrown <neilb@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/md/md.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/md/md.c
++++ b/drivers/md/md.c
+@@ -5333,6 +5333,7 @@ static int md_set_readonly(struct mddev
+ printk("md: %s still in use.\n",mdname(mddev));
+ if (did_freeze) {
+ clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
++ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ md_wakeup_thread(mddev->thread);
+ }
+ err = -EBUSY;
+@@ -5347,6 +5348,8 @@ static int md_set_readonly(struct mddev
+ mddev->ro = 1;
+ set_disk_ro(mddev->gendisk, 1);
+ clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
++ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
++ md_wakeup_thread(mddev->thread);
+ sysfs_notify_dirent_safe(mddev->sysfs_state);
+ err = 0;
+ }
+@@ -5390,6 +5393,7 @@ static int do_md_stop(struct mddev * mdd
+ mutex_unlock(&mddev->open_mutex);
+ if (did_freeze) {
+ clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
++ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ md_wakeup_thread(mddev->thread);
+ }
+ return -EBUSY;
--- /dev/null
+From f8ebf7a8ca35dde321f0cd385fee6f1950609367 Mon Sep 17 00:00:00 2001
+From: Trond Myklebust <trond.myklebust@primarydata.com>
+Date: Fri, 17 Oct 2014 23:02:52 +0300
+Subject: NFS: Don't try to reclaim delegation open state if recovery failed
+
+From: Trond Myklebust <trond.myklebust@primarydata.com>
+
+commit f8ebf7a8ca35dde321f0cd385fee6f1950609367 upstream.
+
+If state recovery failed, then we should not attempt to reclaim delegated
+state.
+
+http://lkml.kernel.org/r/CAN-5tyHwG=Cn2Q9KsHWadewjpTTy_K26ee+UnSvHvG4192p-Xw@mail.gmail.com
+Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfs/delegation.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/fs/nfs/delegation.c
++++ b/fs/nfs/delegation.c
+@@ -109,6 +109,8 @@ again:
+ continue;
+ if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
+ continue;
++ if (!nfs4_valid_open_stateid(state))
++ continue;
+ if (!nfs4_stateid_match(&state->stateid, stateid))
+ continue;
+ get_nfs_open_context(ctx);
--- /dev/null
+From 16caf5b6101d03335b386e77e9e14136f989be87 Mon Sep 17 00:00:00 2001
+From: Jan Kara <jack@suse.cz>
+Date: Thu, 23 Oct 2014 14:02:47 +0200
+Subject: nfs: Fix use of uninitialized variable in nfs_getattr()
+
+From: Jan Kara <jack@suse.cz>
+
+commit 16caf5b6101d03335b386e77e9e14136f989be87 upstream.
+
+Variable 'err' needn't be initialized when nfs_getattr() uses it to
+check whether it should call generic_fillattr() or not. That can result
+in spurious error returns. Initialize 'err' properly.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfs/inode.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/nfs/inode.c
++++ b/fs/nfs/inode.c
+@@ -592,7 +592,7 @@ int nfs_getattr(struct vfsmount *mnt, st
+ {
+ struct inode *inode = dentry->d_inode;
+ int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME;
+- int err;
++ int err = 0;
+
+ trace_nfs_getattr_enter(inode);
+ /* Flush out writes to the server in order to update c/mtime. */
--- /dev/null
+From 4dfd4f7af0afd201706ad186352ca423b0f17d4b Mon Sep 17 00:00:00 2001
+From: Trond Myklebust <trond.myklebust@primarydata.com>
+Date: Fri, 17 Oct 2014 15:10:25 +0300
+Subject: NFSv4: Ensure that we remove NFSv4.0 delegations when state has expired
+
+From: Trond Myklebust <trond.myklebust@primarydata.com>
+
+commit 4dfd4f7af0afd201706ad186352ca423b0f17d4b upstream.
+
+NFSv4.0 does not have TEST_STATEID/FREE_STATEID functionality, so
+unlike NFSv4.1, the recovery procedure when stateids have expired or
+have been revoked requires us to just forget the delegation.
+
+http://lkml.kernel.org/r/CAN-5tyHwG=Cn2Q9KsHWadewjpTTy_K26ee+UnSvHvG4192p-Xw@mail.gmail.com
+Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfs/nfs4proc.c | 24 +++++++++++++++++++++++-
+ 1 file changed, 23 insertions(+), 1 deletion(-)
+
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -2034,6 +2034,28 @@ static int nfs4_open_expired(struct nfs4
+ return ret;
+ }
+
++static void nfs_finish_clear_delegation_stateid(struct nfs4_state *state)
++{
++ nfs_remove_bad_delegation(state->inode);
++ write_seqlock(&state->seqlock);
++ nfs4_stateid_copy(&state->stateid, &state->open_stateid);
++ write_sequnlock(&state->seqlock);
++ clear_bit(NFS_DELEGATED_STATE, &state->flags);
++}
++
++static void nfs40_clear_delegation_stateid(struct nfs4_state *state)
++{
++ if (rcu_access_pointer(NFS_I(state->inode)->delegation) != NULL)
++ nfs_finish_clear_delegation_stateid(state);
++}
++
++static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
++{
++ /* NFSv4.0 doesn't allow for delegation recovery on open expire */
++ nfs40_clear_delegation_stateid(state);
++ return nfs4_open_expired(sp, state);
++}
++
+ #if defined(CONFIG_NFS_V4_1)
+ static void nfs41_clear_delegation_stateid(struct nfs4_state *state)
+ {
+@@ -8255,7 +8277,7 @@ static const struct nfs4_state_recovery_
+ static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {
+ .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
+ .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
+- .recover_open = nfs4_open_expired,
++ .recover_open = nfs40_open_expired,
+ .recover_lock = nfs4_lock_expired,
+ .establish_clid = nfs4_init_clientid,
+ };
--- /dev/null
+From 869f9dfa4d6d57b79e0afc3af14772c2a023eeb1 Mon Sep 17 00:00:00 2001
+From: Trond Myklebust <trond.myklebust@primarydata.com>
+Date: Mon, 10 Nov 2014 18:43:56 -0500
+Subject: NFSv4: Fix races between nfs_remove_bad_delegation() and delegation return
+
+From: Trond Myklebust <trond.myklebust@primarydata.com>
+
+commit 869f9dfa4d6d57b79e0afc3af14772c2a023eeb1 upstream.
+
+Any attempt to call nfs_remove_bad_delegation() while a delegation is being
+returned is currently a no-op. This means that we can end up looping
+forever in nfs_end_delegation_return() if something causes the delegation
+to be revoked.
+This patch adds a mechanism whereby the state recovery code can communicate
+to the delegation return code that the delegation is no longer valid and
+that it should not be used when reclaiming state.
+It also changes the return value for nfs4_handle_delegation_recall_error()
+to ensure that nfs_end_delegation_return() does not reattempt the lock
+reclaim before state recovery is done.
+
+http://lkml.kernel.org/r/CAN-5tyHwG=Cn2Q9KsHWadewjpTTy_K26ee+UnSvHvG4192p-Xw@mail.gmail.com
+Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfs/delegation.c | 23 +++++++++++++++++++++--
+ fs/nfs/delegation.h | 1 +
+ fs/nfs/nfs4proc.c | 2 +-
+ 3 files changed, 23 insertions(+), 3 deletions(-)
+
+--- a/fs/nfs/delegation.c
++++ b/fs/nfs/delegation.c
+@@ -179,7 +179,11 @@ static int nfs_do_return_delegation(stru
+ {
+ int res = 0;
+
+- res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid, issync);
++ if (!test_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
++ res = nfs4_proc_delegreturn(inode,
++ delegation->cred,
++ &delegation->stateid,
++ issync);
+ nfs_free_delegation(delegation);
+ return res;
+ }
+@@ -366,11 +370,13 @@ static int nfs_end_delegation_return(str
+ {
+ struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
+ struct nfs_inode *nfsi = NFS_I(inode);
+- int err;
++ int err = 0;
+
+ if (delegation == NULL)
+ return 0;
+ do {
++ if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
++ break;
+ err = nfs_delegation_claim_opens(inode, &delegation->stateid);
+ if (!issync || err != -EAGAIN)
+ break;
+@@ -591,10 +597,23 @@ static void nfs_client_mark_return_unuse
+ rcu_read_unlock();
+ }
+
++static void nfs_revoke_delegation(struct inode *inode)
++{
++ struct nfs_delegation *delegation;
++ rcu_read_lock();
++ delegation = rcu_dereference(NFS_I(inode)->delegation);
++ if (delegation != NULL) {
++ set_bit(NFS_DELEGATION_REVOKED, &delegation->flags);
++ nfs_mark_return_delegation(NFS_SERVER(inode), delegation);
++ }
++ rcu_read_unlock();
++}
++
+ void nfs_remove_bad_delegation(struct inode *inode)
+ {
+ struct nfs_delegation *delegation;
+
++ nfs_revoke_delegation(inode);
+ delegation = nfs_inode_detach_delegation(inode);
+ if (delegation) {
+ nfs_inode_find_state_and_recover(inode, &delegation->stateid);
+--- a/fs/nfs/delegation.h
++++ b/fs/nfs/delegation.h
+@@ -31,6 +31,7 @@ enum {
+ NFS_DELEGATION_RETURN_IF_CLOSED,
+ NFS_DELEGATION_REFERENCED,
+ NFS_DELEGATION_RETURNING,
++ NFS_DELEGATION_REVOKED,
+ };
+
+ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -1587,7 +1587,7 @@ static int nfs4_handle_delegation_recall
+ nfs_inode_find_state_and_recover(state->inode,
+ stateid);
+ nfs4_schedule_stateid_recovery(server, state);
+- return 0;
++ return -EAGAIN;
+ case -NFS4ERR_DELAY:
+ case -NFS4ERR_GRACE:
+ set_bit(NFS_DELEGATED_STATE, &state->flags);
--- /dev/null
+From 0c116cadd94b16b30b1dd90d38b2784d9b39b01a Mon Sep 17 00:00:00 2001
+From: Trond Myklebust <trond.myklebust@primarydata.com>
+Date: Wed, 12 Nov 2014 14:44:49 -0500
+Subject: NFSv4.1: nfs41_clear_delegation_stateid shouldn't trust NFS_DELEGATED_STATE
+
+From: Trond Myklebust <trond.myklebust@primarydata.com>
+
+commit 0c116cadd94b16b30b1dd90d38b2784d9b39b01a upstream.
+
+This patch removes the assumption made previously, that we only need to
+check the delegation stateid when it matches the stateid on a cached
+open.
+
+If we believe that we hold a delegation for this file, then we must assume
+that its stateid may have been revoked or expired too. If we don't test it
+then our state recovery process may end up caching open/lock state in a
+situation where it should not.
+We therefore rename the function nfs41_clear_delegation_stateid as
+nfs41_check_delegation_stateid, and change it to always run through the
+delegation stateid test and recovery process as outlined in RFC5661.
+
+http://lkml.kernel.org/r/CAN-5tyHwG=Cn2Q9KsHWadewjpTTy_K26ee+UnSvHvG4192p-Xw@mail.gmail.com
+Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfs/nfs4proc.c | 42 +++++++++++++++++-------------------------
+ 1 file changed, 17 insertions(+), 25 deletions(-)
+
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -2057,45 +2057,37 @@ static int nfs40_open_expired(struct nfs
+ }
+
+ #if defined(CONFIG_NFS_V4_1)
+-static void nfs41_clear_delegation_stateid(struct nfs4_state *state)
++static void nfs41_check_delegation_stateid(struct nfs4_state *state)
+ {
+ struct nfs_server *server = NFS_SERVER(state->inode);
+- nfs4_stateid *stateid = &state->stateid;
++ nfs4_stateid stateid;
+ struct nfs_delegation *delegation;
+- struct rpc_cred *cred = NULL;
+- int status = -NFS4ERR_BAD_STATEID;
+-
+- /* If a state reset has been done, test_stateid is unneeded */
+- if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
+- return;
++ struct rpc_cred *cred;
++ int status;
+
+ /* Get the delegation credential for use by test/free_stateid */
+ rcu_read_lock();
+ delegation = rcu_dereference(NFS_I(state->inode)->delegation);
+- if (delegation != NULL &&
+- nfs4_stateid_match(&delegation->stateid, stateid)) {
+- cred = get_rpccred(delegation->cred);
+- rcu_read_unlock();
+- status = nfs41_test_stateid(server, stateid, cred);
+- trace_nfs4_test_delegation_stateid(state, NULL, status);
+- } else
++ if (delegation == NULL) {
+ rcu_read_unlock();
++ return;
++ }
++
++ nfs4_stateid_copy(&stateid, &delegation->stateid);
++ cred = get_rpccred(delegation->cred);
++ rcu_read_unlock();
++ status = nfs41_test_stateid(server, &stateid, cred);
++ trace_nfs4_test_delegation_stateid(state, NULL, status);
+
+ if (status != NFS_OK) {
+ /* Free the stateid unless the server explicitly
+ * informs us the stateid is unrecognized. */
+ if (status != -NFS4ERR_BAD_STATEID)
+- nfs41_free_stateid(server, stateid, cred);
+- nfs_remove_bad_delegation(state->inode);
+-
+- write_seqlock(&state->seqlock);
+- nfs4_stateid_copy(&state->stateid, &state->open_stateid);
+- write_sequnlock(&state->seqlock);
+- clear_bit(NFS_DELEGATED_STATE, &state->flags);
++ nfs41_free_stateid(server, &stateid, cred);
++ nfs_finish_clear_delegation_stateid(state);
+ }
+
+- if (cred != NULL)
+- put_rpccred(cred);
++ put_rpccred(cred);
+ }
+
+ /**
+@@ -2139,7 +2131,7 @@ static int nfs41_open_expired(struct nfs
+ {
+ int status;
+
+- nfs41_clear_delegation_stateid(state);
++ nfs41_check_delegation_stateid(state);
+ status = nfs41_check_open_stateid(state);
+ if (status != NFS_OK)
+ status = nfs4_open_expired(sp, state);
--- /dev/null
+From 21e863b233553998737e1b506c823a00bf012e00 Mon Sep 17 00:00:00 2001
+From: Krzysztof Kozlowski <k.kozlowski@samsung.com>
+Date: Wed, 15 Oct 2014 16:25:10 +0200
+Subject: power: bq2415x_charger: Fix memory leak on DTS parsing error
+
+From: Krzysztof Kozlowski <k.kozlowski@samsung.com>
+
+commit 21e863b233553998737e1b506c823a00bf012e00 upstream.
+
+Memory allocated for 'name' was leaking if required binding properties
+were not present.
+
+The memory for 'name' was allocated early at probe with kasprintf(). It
+was freed in error paths executed before and after parsing DTS but not
+in that error path.
+
+Fix the error path for parsing device tree properties.
+
+Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
+Fixes: faffd234cf85 ("bq2415x_charger: Add DT support")
+Signed-off-by: Sebastian Reichel <sre@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/power/bq2415x_charger.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/drivers/power/bq2415x_charger.c
++++ b/drivers/power/bq2415x_charger.c
+@@ -1609,27 +1609,27 @@ static int bq2415x_probe(struct i2c_clie
+ ret = of_property_read_u32(np, "ti,current-limit",
+ &bq->init_data.current_limit);
+ if (ret)
+- return ret;
++ goto error_2;
+ ret = of_property_read_u32(np, "ti,weak-battery-voltage",
+ &bq->init_data.weak_battery_voltage);
+ if (ret)
+- return ret;
++ goto error_2;
+ ret = of_property_read_u32(np, "ti,battery-regulation-voltage",
+ &bq->init_data.battery_regulation_voltage);
+ if (ret)
+- return ret;
++ goto error_2;
+ ret = of_property_read_u32(np, "ti,charge-current",
+ &bq->init_data.charge_current);
+ if (ret)
+- return ret;
++ goto error_2;
+ ret = of_property_read_u32(np, "ti,termination-current",
+ &bq->init_data.termination_current);
+ if (ret)
+- return ret;
++ goto error_2;
+ ret = of_property_read_u32(np, "ti,resistor-sense",
+ &bq->init_data.resistor_sense);
+ if (ret)
+- return ret;
++ goto error_2;
+ } else {
+ memcpy(&bq->init_data, pdata, sizeof(bq->init_data));
+ }
--- /dev/null
+From 0eaf437aa14949d2230aeab7364f4ab47901304a Mon Sep 17 00:00:00 2001
+From: Krzysztof Kozlowski <k.kozlowski@samsung.com>
+Date: Wed, 15 Oct 2014 16:25:09 +0200
+Subject: power: bq2415x_charger: Properly handle ENODEV from power_supply_get_by_phandle
+
+From: Krzysztof Kozlowski <k.kozlowski@samsung.com>
+
+commit 0eaf437aa14949d2230aeab7364f4ab47901304a upstream.
+
+The power_supply_get_by_phandle() on error returns ENODEV or NULL.
+The driver later expects obtained pointer to power supply to be
+valid or NULL. If it is not NULL then it dereferences it in
+bq2415x_notifier_call() which would lead to dereferencing ENODEV-value
+pointer.
+
+Properly handle the power_supply_get_by_phandle() error case by
+replacing error value with NULL. This indicates that usb charger
+detection won't be used.
+
+Fix also memory leak of 'name' if power_supply_get_by_phandle() fails
+with NULL and probe should defer.
+
+Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
+Fixes: faffd234cf85 ("bq2415x_charger: Add DT support")
+[small fix regarding the missing ti,usb-charger-detection info message]
+Signed-off-by: Sebastian Reichel <sre@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/power/bq2415x_charger.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+--- a/drivers/power/bq2415x_charger.c
++++ b/drivers/power/bq2415x_charger.c
+@@ -1579,8 +1579,15 @@ static int bq2415x_probe(struct i2c_clie
+ if (np) {
+ bq->notify_psy = power_supply_get_by_phandle(np, "ti,usb-charger-detection");
+
+- if (!bq->notify_psy)
+- return -EPROBE_DEFER;
++ if (IS_ERR(bq->notify_psy)) {
++ dev_info(&client->dev,
++ "no 'ti,usb-charger-detection' property (err=%ld)\n",
++ PTR_ERR(bq->notify_psy));
++ bq->notify_psy = NULL;
++ } else if (!bq->notify_psy) {
++ ret = -EPROBE_DEFER;
++ goto error_2;
++ }
+ }
+ else if (pdata->notify_device)
+ bq->notify_psy = power_supply_get_by_name(pdata->notify_device);
--- /dev/null
+From cdaf3e15385d3232b52287e50692506f8fd01a09 Mon Sep 17 00:00:00 2001
+From: Krzysztof Kozlowski <k.kozlowski@samsung.com>
+Date: Mon, 13 Oct 2014 15:34:31 +0200
+Subject: power: charger-manager: Fix accessing invalidated power supply after charger unbind
+
+From: Krzysztof Kozlowski <k.kozlowski@samsung.com>
+
+commit cdaf3e15385d3232b52287e50692506f8fd01a09 upstream.
+
+The charger manager obtained in probe references to power supplies for
+all chargers with power_supply_get_by_name() for later usage. However
+if such charger driver was removed then this reference would point to
+old power supply (from driver which was removed).
+
+This lead to accessing invalid memory which could be observed with:
+$ echo "max77693-charger" > /sys/bus/platform/drivers/max77693-charger/unbind
+$ grep . /sys/devices/virtual/power_supply/battery/charger.0/*
+$ grep . /sys/devices/virtual/power_supply/battery/*
+[ 15.339817] Unable to handle kernel paging request at virtual address 0001c12c
+[ 15.346187] pgd = edd08000
+[ 15.348814] [0001c12c] *pgd=6dce2831, *pte=00000000, *ppte=00000000
+[ 15.355075] Internal error: Oops: 80000007 [#1] PREEMPT SMP ARM
+[ 15.360967] Modules linked in:
+[ 15.364010] CPU: 2 PID: 1388 Comm: grep Not tainted 3.17.0-next-20141007-00027-ga95e761db1b0 #245
+[ 15.372859] task: ee03ad00 ti: edcf6000 task.ti: edcf6000
+[ 15.378241] PC is at 0x1c12c
+[ 15.381113] LR is at is_ext_pwr_online+0x30/0x6c
+[ 15.385706] pc : [<0001c12c>] lr : [<c0339fc4>] psr: a0000013
+[ 15.385706] sp : edcf7e88 ip : 00000000 fp : 00000000
+[ 15.397161] r10: eeb02c08 r9 : c04b1f84 r8 : eeb02c00
+[ 15.402369] r7 : edc69a10 r6 : eea6ac10 r5 : eea6ac10 r4 : 00000004
+[ 15.408878] r3 : 0001c12c r2 : edcf7e8c r1 : 00000004 r0 : ee914418
+[ 15.415390] Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
+[ 15.422506] Control: 10c5387d Table: 6dd0804a DAC: 00000015
+[ 15.428236] Process grep (pid: 1388, stack limit = 0xedcf6240)
+[ 15.434050] Stack: (0xedcf7e88 to 0xedcf8000)
+[ 15.438395] 7e80: ee03ad00 00000000 edcf7f80 eea6aca8 edcf7ec4 c033b7b0
+[ 15.446554] 7ea0: 00000001 ee1cc3f0 00000004 c06e1e44 eebdc000 c06e1e44 eeb02c00 c0337144
+[ 15.454713] 7ec0: ee2dac68 c005cffc ee1cc3c0 c06e1e44 00000fff 00001000 eebdc000 c0278ca8
+[ 15.462872] 7ee0: c0278c8c ee1cc3c0 eeb7ce00 c014422c edcf7f20 00008000 ee1cc3c0 ee9a48c0
+[ 15.471030] 7f00: 00000001 00000001 edcf7f80 c0142d94 c0142d70 c01060f4 00021000 ee1cc3f0
+[ 15.479190] 7f20: 00000000 00000000 c06a2150 eebdc000 2e7ec000 ee9a48c0 00008000 00021000
+[ 15.487349] 7f40: edcf7f80 00008000 edcf6000 00021000 00021000 c00e39a4 00000000 ee9a48c0
+[ 15.495508] 7f60: 00004000 00000000 00000000 ee9a48c0 ee9a48c0 00008000 00021000 c00e3aa0
+[ 15.503668] 7f80: 00000000 00000000 0001f2e0 0001f2e0 00021000 00001000 00000003 c000f364
+[ 15.511826] 7fa0: 00000000 c000f1a0 0001f2e0 00021000 00000003 00021000 00008000 00000000
+[ 15.519986] 7fc0: 0001f2e0 00021000 00001000 00000003 00000001 000205e8 00000000 00021000
+[ 15.528145] 7fe0: 00008000 bebbe910 0000a7ad b6edc49c 60000010 00000003 aaaaaaaa aaaaaaaa
+[ 15.536320] [<c0339fc4>] (is_ext_pwr_online) from [<c033b7b0>] (charger_get_property+0x170/0x314)
+[ 15.545164] [<c033b7b0>] (charger_get_property) from [<c0337144>] (power_supply_show_property+0x48/0x20c)
+[ 15.554719] [<c0337144>] (power_supply_show_property) from [<c0278ca8>] (dev_attr_show+0x1c/0x48)
+[ 15.563577] [<c0278ca8>] (dev_attr_show) from [<c014422c>] (sysfs_kf_seq_show+0x84/0x104)
+[ 15.571725] [<c014422c>] (sysfs_kf_seq_show) from [<c0142d94>] (kernfs_seq_show+0x24/0x28)
+[ 15.579973] [<c0142d94>] (kernfs_seq_show) from [<c01060f4>] (seq_read+0x1b0/0x484)
+[ 15.587614] [<c01060f4>] (seq_read) from [<c00e39a4>] (vfs_read+0x88/0x144)
+[ 15.594552] [<c00e39a4>] (vfs_read) from [<c00e3aa0>] (SyS_read+0x40/0x8c)
+[ 15.601417] [<c00e3aa0>] (SyS_read) from [<c000f1a0>] (ret_fast_syscall+0x0/0x48)
+[ 15.608877] Code: bad PC value
+[ 15.611991] ---[ end trace a88fcc95208db283 ]---
+
+The charger-manager should get reference to charger power supply on
+each use of get_property callback.
+
+Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
+Fixes: 3bb3dbbd56ea ("power_supply: Add initial Charger-Manager driver")
+Signed-off-by: Sebastian Reichel <sre@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/power/charger-manager.c | 64 ++++++++++++++++++++--------------
+ include/linux/power/charger-manager.h | 2 -
+ 2 files changed, 39 insertions(+), 27 deletions(-)
+
+--- a/drivers/power/charger-manager.c
++++ b/drivers/power/charger-manager.c
+@@ -118,10 +118,17 @@ static bool is_batt_present(struct charg
+ present = true;
+ break;
+ case CM_CHARGER_STAT:
+- for (i = 0; cm->charger_stat[i]; i++) {
+- ret = cm->charger_stat[i]->get_property(
+- cm->charger_stat[i],
+- POWER_SUPPLY_PROP_PRESENT, &val);
++ for (i = 0; cm->desc->psy_charger_stat[i]; i++) {
++ psy = power_supply_get_by_name(
++ cm->desc->psy_charger_stat[i]);
++ if (!psy) {
++ dev_err(cm->dev, "Cannot find power supply \"%s\"\n",
++ cm->desc->psy_charger_stat[i]);
++ continue;
++ }
++
++ ret = psy->get_property(psy, POWER_SUPPLY_PROP_PRESENT,
++ &val);
+ if (ret == 0 && val.intval) {
+ present = true;
+ break;
+@@ -144,14 +151,20 @@ static bool is_batt_present(struct charg
+ static bool is_ext_pwr_online(struct charger_manager *cm)
+ {
+ union power_supply_propval val;
++ struct power_supply *psy;
+ bool online = false;
+ int i, ret;
+
+ /* If at least one of them has one, it's yes. */
+- for (i = 0; cm->charger_stat[i]; i++) {
+- ret = cm->charger_stat[i]->get_property(
+- cm->charger_stat[i],
+- POWER_SUPPLY_PROP_ONLINE, &val);
++ for (i = 0; cm->desc->psy_charger_stat[i]; i++) {
++ psy = power_supply_get_by_name(cm->desc->psy_charger_stat[i]);
++ if (!psy) {
++ dev_err(cm->dev, "Cannot find power supply \"%s\"\n",
++ cm->desc->psy_charger_stat[i]);
++ continue;
++ }
++
++ ret = psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &val);
+ if (ret == 0 && val.intval) {
+ online = true;
+ break;
+@@ -196,6 +209,7 @@ static bool is_charging(struct charger_m
+ {
+ int i, ret;
+ bool charging = false;
++ struct power_supply *psy;
+ union power_supply_propval val;
+
+ /* If there is no battery, it cannot be charged */
+@@ -203,17 +217,22 @@ static bool is_charging(struct charger_m
+ return false;
+
+ /* If at least one of the charger is charging, return yes */
+- for (i = 0; cm->charger_stat[i]; i++) {
++ for (i = 0; cm->desc->psy_charger_stat[i]; i++) {
+ /* 1. The charger sholuld not be DISABLED */
+ if (cm->emergency_stop)
+ continue;
+ if (!cm->charger_enabled)
+ continue;
+
++ psy = power_supply_get_by_name(cm->desc->psy_charger_stat[i]);
++ if (!psy) {
++ dev_err(cm->dev, "Cannot find power supply \"%s\"\n",
++ cm->desc->psy_charger_stat[i]);
++ continue;
++ }
++
+ /* 2. The charger should be online (ext-power) */
+- ret = cm->charger_stat[i]->get_property(
+- cm->charger_stat[i],
+- POWER_SUPPLY_PROP_ONLINE, &val);
++ ret = psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &val);
+ if (ret) {
+ dev_warn(cm->dev, "Cannot read ONLINE value from %s\n",
+ cm->desc->psy_charger_stat[i]);
+@@ -226,9 +245,7 @@ static bool is_charging(struct charger_m
+ * 3. The charger should not be FULL, DISCHARGING,
+ * or NOT_CHARGING.
+ */
+- ret = cm->charger_stat[i]->get_property(
+- cm->charger_stat[i],
+- POWER_SUPPLY_PROP_STATUS, &val);
++ ret = psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &val);
+ if (ret) {
+ dev_warn(cm->dev, "Cannot read STATUS value from %s\n",
+ cm->desc->psy_charger_stat[i]);
+@@ -1772,15 +1789,12 @@ static int charger_manager_probe(struct
+ while (desc->psy_charger_stat[i])
+ i++;
+
+- cm->charger_stat = devm_kzalloc(&pdev->dev,
+- sizeof(struct power_supply *) * i, GFP_KERNEL);
+- if (!cm->charger_stat)
+- return -ENOMEM;
+-
++ /* Check if charger's supplies are present at probe */
+ for (i = 0; desc->psy_charger_stat[i]; i++) {
+- cm->charger_stat[i] = power_supply_get_by_name(
+- desc->psy_charger_stat[i]);
+- if (!cm->charger_stat[i]) {
++ struct power_supply *psy;
++
++ psy = power_supply_get_by_name(desc->psy_charger_stat[i]);
++ if (!psy) {
+ dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n",
+ desc->psy_charger_stat[i]);
+ return -ENODEV;
+@@ -2102,8 +2116,8 @@ static bool find_power_supply(struct cha
+ int i;
+ bool found = false;
+
+- for (i = 0; cm->charger_stat[i]; i++) {
+- if (psy == cm->charger_stat[i]) {
++ for (i = 0; cm->desc->psy_charger_stat[i]; i++) {
++ if (!strcmp(psy->name, cm->desc->psy_charger_stat[i])) {
+ found = true;
+ break;
+ }
+--- a/include/linux/power/charger-manager.h
++++ b/include/linux/power/charger-manager.h
+@@ -253,8 +253,6 @@ struct charger_manager {
+ struct device *dev;
+ struct charger_desc *desc;
+
+- struct power_supply **charger_stat;
+-
+ #ifdef CONFIG_THERMAL
+ struct thermal_zone_device *tzd_batt;
+ #endif
--- /dev/null
+From bdbe81445407644492b9ac69a24d35e3202d773b Mon Sep 17 00:00:00 2001
+From: Krzysztof Kozlowski <k.kozlowski@samsung.com>
+Date: Mon, 13 Oct 2014 15:34:30 +0200
+Subject: power: charger-manager: Fix accessing invalidated power supply after fuel gauge unbind
+
+From: Krzysztof Kozlowski <k.kozlowski@samsung.com>
+
+commit bdbe81445407644492b9ac69a24d35e3202d773b upstream.
+
+The charger manager obtained reference to fuel gauge power supply in probe
+with power_supply_get_by_name() for later usage. However if fuel gauge
+driver was removed and re-added then this reference would point to old
+power supply (from driver which was removed).
+
+This lead to accessing old (and probably invalid) memory which could be
+observed with:
+$ echo "12-0036" > /sys/bus/i2c/drivers/max17042/unbind
+$ echo "12-0036" > /sys/bus/i2c/drivers/max17042/bind
+$ cat /sys/devices/virtual/power_supply/battery/capacity
+[ 240.480084] INFO: task cat:1393 blocked for more than 120 seconds.
+[ 240.484799] Not tainted 3.17.0-next-20141007-00028-ge60b6dd79570 #203
+[ 240.491782] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
+[ 240.499589] cat D c0469530 0 1393 1 0x00000000
+[ 240.505947] [<c0469530>] (__schedule) from [<c0469d3c>] (schedule_preempt_disabled+0x14/0x20)
+[ 240.514449] [<c0469d3c>] (schedule_preempt_disabled) from [<c046af08>] (mutex_lock_nested+0x1bc/0x458)
+[ 240.523736] [<c046af08>] (mutex_lock_nested) from [<c0287a98>] (regmap_read+0x30/0x60)
+[ 240.531647] [<c0287a98>] (regmap_read) from [<c032238c>] (max17042_get_property+0x2e8/0x350)
+[ 240.540055] [<c032238c>] (max17042_get_property) from [<c03247d8>] (charger_get_property+0x264/0x348)
+[ 240.549252] [<c03247d8>] (charger_get_property) from [<c0320764>] (power_supply_show_property+0x48/0x1e0)
+[ 240.558808] [<c0320764>] (power_supply_show_property) from [<c027308c>] (dev_attr_show+0x1c/0x48)
+[ 240.567664] [<c027308c>] (dev_attr_show) from [<c0141fb0>] (sysfs_kf_seq_show+0x84/0x104)
+[ 240.575814] [<c0141fb0>] (sysfs_kf_seq_show) from [<c0140b18>] (kernfs_seq_show+0x24/0x28)
+[ 240.584061] [<c0140b18>] (kernfs_seq_show) from [<c0104574>] (seq_read+0x1b0/0x484)
+[ 240.591702] [<c0104574>] (seq_read) from [<c00e1e24>] (vfs_read+0x88/0x144)
+[ 240.598640] [<c00e1e24>] (vfs_read) from [<c00e1f20>] (SyS_read+0x40/0x8c)
+[ 240.605507] [<c00e1f20>] (SyS_read) from [<c000e760>] (ret_fast_syscall+0x0/0x48)
+[ 240.612952] 4 locks held by cat/1393:
+[ 240.616589] #0: (&p->lock){+.+.+.}, at: [<c01043f4>] seq_read+0x30/0x484
+[ 240.623414] #1: (&of->mutex){+.+.+.}, at: [<c01417dc>] kernfs_seq_start+0x1c/0x8c
+[ 240.631086] #2: (s_active#31){++++.+}, at: [<c01417e4>] kernfs_seq_start+0x24/0x8c
+[ 240.638777] #3: (&map->mutex){+.+...}, at: [<c0287a98>] regmap_read+0x30/0x60
+
+The charger-manager should get reference to fuel gauge power supply on
+each use of get_property callback. The thermal zone 'tzd' field of
+power supply should not be used because of the same reason.
+
+Additionally this change solves also the issue with nested
+thermal_zone_get_temp() calls and related false lockdep positive for
+deadlock for thermal zone's mutex [1]. When fuel gauge is used as source of
+temperature then the charger manager forwards its get_temp calls to fuel
+gauge thermal zone. So actually different mutexes are used (one for
+charger manager thermal zone and second for fuel gauge thermal zone) but
+for lockdep this is one class of mutex.
+
+The recursion is removed by retrieving temperature through power
+supply's get_property().
+
+In case external thermal zone is used ('cm-thermal-zone' property is
+present in DTS) the recursion does not exist. Charger manager simply
+exports POWER_SUPPLY_PROP_TEMP_AMBIENT property (instead of
+POWER_SUPPLY_PROP_TEMP) thus no thermal zone is created for this power
+supply.
+
+[1] https://lkml.org/lkml/2014/10/6/309
+
+Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
+Fixes: 3bb3dbbd56ea ("power_supply: Add initial Charger-Manager driver")
+Signed-off-by: Sebastian Reichel <sre@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/power/charger-manager.c | 99 ++++++++++++++++++++++++----------
+ include/linux/power/charger-manager.h | 1
+ 2 files changed, 71 insertions(+), 29 deletions(-)
+
+--- a/drivers/power/charger-manager.c
++++ b/drivers/power/charger-manager.c
+@@ -97,6 +97,7 @@ static struct charger_global_desc *g_des
+ static bool is_batt_present(struct charger_manager *cm)
+ {
+ union power_supply_propval val;
++ struct power_supply *psy;
+ bool present = false;
+ int i, ret;
+
+@@ -107,7 +108,11 @@ static bool is_batt_present(struct charg
+ case CM_NO_BATTERY:
+ break;
+ case CM_FUEL_GAUGE:
+- ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
++ psy = power_supply_get_by_name(cm->desc->psy_fuel_gauge);
++ if (!psy)
++ break;
++
++ ret = psy->get_property(psy,
+ POWER_SUPPLY_PROP_PRESENT, &val);
+ if (ret == 0 && val.intval)
+ present = true;
+@@ -167,12 +172,14 @@ static bool is_ext_pwr_online(struct cha
+ static int get_batt_uV(struct charger_manager *cm, int *uV)
+ {
+ union power_supply_propval val;
++ struct power_supply *fuel_gauge;
+ int ret;
+
+- if (!cm->fuel_gauge)
++ fuel_gauge = power_supply_get_by_name(cm->desc->psy_fuel_gauge);
++ if (!fuel_gauge)
+ return -ENODEV;
+
+- ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
++ ret = fuel_gauge->get_property(fuel_gauge,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW, &val);
+ if (ret)
+ return ret;
+@@ -248,6 +255,7 @@ static bool is_full_charged(struct charg
+ {
+ struct charger_desc *desc = cm->desc;
+ union power_supply_propval val;
++ struct power_supply *fuel_gauge;
+ int ret = 0;
+ int uV;
+
+@@ -255,11 +263,15 @@ static bool is_full_charged(struct charg
+ if (!is_batt_present(cm))
+ return false;
+
+- if (cm->fuel_gauge && desc->fullbatt_full_capacity > 0) {
++ fuel_gauge = power_supply_get_by_name(cm->desc->psy_fuel_gauge);
++ if (!fuel_gauge)
++ return false;
++
++ if (desc->fullbatt_full_capacity > 0) {
+ val.intval = 0;
+
+ /* Not full if capacity of fuel gauge isn't full */
+- ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
++ ret = fuel_gauge->get_property(fuel_gauge,
+ POWER_SUPPLY_PROP_CHARGE_FULL, &val);
+ if (!ret && val.intval > desc->fullbatt_full_capacity)
+ return true;
+@@ -273,10 +285,10 @@ static bool is_full_charged(struct charg
+ }
+
+ /* Full, if the capacity is more than fullbatt_soc */
+- if (cm->fuel_gauge && desc->fullbatt_soc > 0) {
++ if (desc->fullbatt_soc > 0) {
+ val.intval = 0;
+
+- ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
++ ret = fuel_gauge->get_property(fuel_gauge,
+ POWER_SUPPLY_PROP_CAPACITY, &val);
+ if (!ret && val.intval >= desc->fullbatt_soc)
+ return true;
+@@ -551,6 +563,20 @@ static int check_charging_duration(struc
+ return ret;
+ }
+
++static int cm_get_battery_temperature_by_psy(struct charger_manager *cm,
++ int *temp)
++{
++ struct power_supply *fuel_gauge;
++
++ fuel_gauge = power_supply_get_by_name(cm->desc->psy_fuel_gauge);
++ if (!fuel_gauge)
++ return -ENODEV;
++
++ return fuel_gauge->get_property(fuel_gauge,
++ POWER_SUPPLY_PROP_TEMP,
++ (union power_supply_propval *)temp);
++}
++
+ static int cm_get_battery_temperature(struct charger_manager *cm,
+ int *temp)
+ {
+@@ -560,15 +586,18 @@ static int cm_get_battery_temperature(st
+ return -ENODEV;
+
+ #ifdef CONFIG_THERMAL
+- ret = thermal_zone_get_temp(cm->tzd_batt, (unsigned long *)temp);
+- if (!ret)
+- /* Calibrate temperature unit */
+- *temp /= 100;
+-#else
+- ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
+- POWER_SUPPLY_PROP_TEMP,
+- (union power_supply_propval *)temp);
++ if (cm->tzd_batt) {
++ ret = thermal_zone_get_temp(cm->tzd_batt, (unsigned long *)temp);
++ if (!ret)
++ /* Calibrate temperature unit */
++ *temp /= 100;
++ } else
+ #endif
++ {
++ /* if-else continued from CONFIG_THERMAL */
++ ret = cm_get_battery_temperature_by_psy(cm, temp);
++ }
++
+ return ret;
+ }
+
+@@ -827,6 +856,7 @@ static int charger_get_property(struct p
+ struct charger_manager *cm = container_of(psy,
+ struct charger_manager, charger_psy);
+ struct charger_desc *desc = cm->desc;
++ struct power_supply *fuel_gauge;
+ int ret = 0;
+ int uV;
+
+@@ -857,14 +887,20 @@ static int charger_get_property(struct p
+ ret = get_batt_uV(cm, &val->intval);
+ break;
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+- ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
++ fuel_gauge = power_supply_get_by_name(cm->desc->psy_fuel_gauge);
++ if (!fuel_gauge) {
++ ret = -ENODEV;
++ break;
++ }
++ ret = fuel_gauge->get_property(fuel_gauge,
+ POWER_SUPPLY_PROP_CURRENT_NOW, val);
+ break;
+ case POWER_SUPPLY_PROP_TEMP:
+ case POWER_SUPPLY_PROP_TEMP_AMBIENT:
+ return cm_get_battery_temperature(cm, &val->intval);
+ case POWER_SUPPLY_PROP_CAPACITY:
+- if (!cm->fuel_gauge) {
++ fuel_gauge = power_supply_get_by_name(cm->desc->psy_fuel_gauge);
++ if (!fuel_gauge) {
+ ret = -ENODEV;
+ break;
+ }
+@@ -875,7 +911,7 @@ static int charger_get_property(struct p
+ break;
+ }
+
+- ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
++ ret = fuel_gauge->get_property(fuel_gauge,
+ POWER_SUPPLY_PROP_CAPACITY, val);
+ if (ret)
+ break;
+@@ -924,7 +960,14 @@ static int charger_get_property(struct p
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ if (is_charging(cm)) {
+- ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
++ fuel_gauge = power_supply_get_by_name(
++ cm->desc->psy_fuel_gauge);
++ if (!fuel_gauge) {
++ ret = -ENODEV;
++ break;
++ }
++
++ ret = fuel_gauge->get_property(fuel_gauge,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+ val);
+ if (ret) {
+@@ -1485,14 +1528,15 @@ err:
+ return ret;
+ }
+
+-static int cm_init_thermal_data(struct charger_manager *cm)
++static int cm_init_thermal_data(struct charger_manager *cm,
++ struct power_supply *fuel_gauge)
+ {
+ struct charger_desc *desc = cm->desc;
+ union power_supply_propval val;
+ int ret;
+
+ /* Verify whether fuel gauge provides battery temperature */
+- ret = cm->fuel_gauge->get_property(cm->fuel_gauge,
++ ret = fuel_gauge->get_property(fuel_gauge,
+ POWER_SUPPLY_PROP_TEMP, &val);
+
+ if (!ret) {
+@@ -1502,8 +1546,6 @@ static int cm_init_thermal_data(struct c
+ cm->desc->measure_battery_temp = true;
+ }
+ #ifdef CONFIG_THERMAL
+- cm->tzd_batt = cm->fuel_gauge->tzd;
+-
+ if (ret && desc->thermal_zone) {
+ cm->tzd_batt =
+ thermal_zone_get_zone_by_name(desc->thermal_zone);
+@@ -1666,6 +1708,7 @@ static int charger_manager_probe(struct
+ int ret = 0, i = 0;
+ int j = 0;
+ union power_supply_propval val;
++ struct power_supply *fuel_gauge;
+
+ if (g_desc && !rtc_dev && g_desc->rtc_name) {
+ rtc_dev = rtc_class_open(g_desc->rtc_name);
+@@ -1744,8 +1787,8 @@ static int charger_manager_probe(struct
+ }
+ }
+
+- cm->fuel_gauge = power_supply_get_by_name(desc->psy_fuel_gauge);
+- if (!cm->fuel_gauge) {
++ fuel_gauge = power_supply_get_by_name(desc->psy_fuel_gauge);
++ if (!fuel_gauge) {
+ dev_err(&pdev->dev, "Cannot find power supply \"%s\"\n",
+ desc->psy_fuel_gauge);
+ return -ENODEV;
+@@ -1788,13 +1831,13 @@ static int charger_manager_probe(struct
+ cm->charger_psy.num_properties = psy_default.num_properties;
+
+ /* Find which optional psy-properties are available */
+- if (!cm->fuel_gauge->get_property(cm->fuel_gauge,
++ if (!fuel_gauge->get_property(fuel_gauge,
+ POWER_SUPPLY_PROP_CHARGE_NOW, &val)) {
+ cm->charger_psy.properties[cm->charger_psy.num_properties] =
+ POWER_SUPPLY_PROP_CHARGE_NOW;
+ cm->charger_psy.num_properties++;
+ }
+- if (!cm->fuel_gauge->get_property(cm->fuel_gauge,
++ if (!fuel_gauge->get_property(fuel_gauge,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ &val)) {
+ cm->charger_psy.properties[cm->charger_psy.num_properties] =
+@@ -1802,7 +1845,7 @@ static int charger_manager_probe(struct
+ cm->charger_psy.num_properties++;
+ }
+
+- ret = cm_init_thermal_data(cm);
++ ret = cm_init_thermal_data(cm, fuel_gauge);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to initialize thermal data\n");
+ cm->desc->measure_battery_temp = false;
+--- a/include/linux/power/charger-manager.h
++++ b/include/linux/power/charger-manager.h
+@@ -253,7 +253,6 @@ struct charger_manager {
+ struct device *dev;
+ struct charger_desc *desc;
+
+- struct power_supply *fuel_gauge;
+ struct power_supply **charger_stat;
+
+ #ifdef CONFIG_THERMAL
input-alps-ignore-potential-bare-packets-when-device-is-out-of-sync.patch
input-alps-allow-up-to-2-invalid-packets-without-resetting-device.patch
input-alps-ignore-bad-data-on-dell-latitudes-e6440-and-e7440.patch
+power-charger-manager-fix-accessing-invalidated-power-supply-after-fuel-gauge-unbind.patch
+power-charger-manager-fix-accessing-invalidated-power-supply-after-charger-unbind.patch
+power-bq2415x_charger-properly-handle-enodev-from-power_supply_get_by_phandle.patch
+power-bq2415x_charger-fix-memory-leak-on-dts-parsing-error.patch
+x86-microcode-amd-fix-early-ucode-loading-on-32-bit.patch
+x86-microcode-amd-fix-ucode-patch-stashing-on-32-bit.patch
+x86-kaslr-prevent-.bss-from-overlaping-initrd.patch
+md-always-set-recovery_needed-when-clearing-recovery_frozen.patch
+nfsv4-ensure-that-we-remove-nfsv4.0-delegations-when-state-has-expired.patch
+nfs-don-t-try-to-reclaim-delegation-open-state-if-recovery-failed.patch
+nfs-fix-use-of-uninitialized-variable-in-nfs_getattr.patch
+nfsv4-fix-races-between-nfs_remove_bad_delegation-and-delegation-return.patch
+nfsv4.1-nfs41_clear_delegation_stateid-shouldn-t-trust-nfs_delegated_state.patch
--- /dev/null
+From e6023367d779060fddc9a52d1f474085b2b36298 Mon Sep 17 00:00:00 2001
+From: Junjie Mao <eternal.n08@gmail.com>
+Date: Fri, 31 Oct 2014 21:40:38 +0800
+Subject: x86, kaslr: Prevent .bss from overlaping initrd
+
+From: Junjie Mao <eternal.n08@gmail.com>
+
+commit e6023367d779060fddc9a52d1f474085b2b36298 upstream.
+
+When choosing a random address, the current implementation does not take into
+account the reversed space for .bss and .brk sections. Thus the relocated kernel
+may overlap other components in memory. Here is an example of the overlap from a
+x86_64 kernel in qemu (the ranges of physical addresses are presented):
+
+ Physical Address
+
+ 0x0fe00000 --+--------------------+ <-- randomized base
+ / | relocated kernel |
+ vmlinux.bin | (from vmlinux.bin) |
+ 0x1336d000 (an ELF file) +--------------------+--
+ \ | | \
+ 0x1376d870 --+--------------------+ |
+ | relocs table | |
+ 0x13c1c2a8 +--------------------+ .bss and .brk
+ | | |
+ 0x13ce6000 +--------------------+ |
+ | | /
+ 0x13f77000 | initrd |--
+ | |
+ 0x13fef374 +--------------------+
+
+The initrd image will then be overwritten by the memset during early
+initialization:
+
+[ 1.655204] Unpacking initramfs...
+[ 1.662831] Initramfs unpacking failed: junk in compressed archive
+
+This patch prevents the above situation by requiring a larger space when looking
+for a random kernel base, so that existing logic can effectively avoids the
+overlap.
+
+[kees: switched to perl to avoid hex translation pain in mawk vs gawk]
+[kees: calculated overlap without relocs table]
+
+Fixes: 82fa9637a2 ("x86, kaslr: Select random position from e820 maps")
+Reported-by: Fengguang Wu <fengguang.wu@intel.com>
+Signed-off-by: Junjie Mao <eternal.n08@gmail.com>
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Cc: Josh Triplett <josh@joshtriplett.org>
+Cc: Matt Fleming <matt.fleming@intel.com>
+Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+Cc: Vivek Goyal <vgoyal@redhat.com>
+Cc: Andi Kleen <ak@linux.intel.com>
+Link: http://lkml.kernel.org/r/1414762838-13067-1-git-send-email-eternal.n08@gmail.com
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/boot/compressed/Makefile | 4 +++-
+ arch/x86/boot/compressed/head_32.S | 5 +++--
+ arch/x86/boot/compressed/head_64.S | 5 ++++-
+ arch/x86/boot/compressed/misc.c | 13 ++++++++++---
+ arch/x86/boot/compressed/mkpiggy.c | 9 +++++++--
+ arch/x86/tools/calc_run_size.pl | 30 ++++++++++++++++++++++++++++++
+ 6 files changed, 57 insertions(+), 9 deletions(-)
+
+--- a/arch/x86/boot/compressed/Makefile
++++ b/arch/x86/boot/compressed/Makefile
+@@ -75,8 +75,10 @@ suffix-$(CONFIG_KERNEL_XZ) := xz
+ suffix-$(CONFIG_KERNEL_LZO) := lzo
+ suffix-$(CONFIG_KERNEL_LZ4) := lz4
+
++RUN_SIZE = $(shell objdump -h vmlinux | \
++ perl $(srctree)/arch/x86/tools/calc_run_size.pl)
+ quiet_cmd_mkpiggy = MKPIGGY $@
+- cmd_mkpiggy = $(obj)/mkpiggy $< > $@ || ( rm -f $@ ; false )
++ cmd_mkpiggy = $(obj)/mkpiggy $< $(RUN_SIZE) > $@ || ( rm -f $@ ; false )
+
+ targets += piggy.S
+ $(obj)/piggy.S: $(obj)/vmlinux.bin.$(suffix-y) $(obj)/mkpiggy FORCE
+--- a/arch/x86/boot/compressed/head_32.S
++++ b/arch/x86/boot/compressed/head_32.S
+@@ -186,7 +186,8 @@ relocated:
+ * Do the decompression, and jump to the new kernel..
+ */
+ /* push arguments for decompress_kernel: */
+- pushl $z_output_len /* decompressed length */
++ pushl $z_run_size /* size of kernel with .bss and .brk */
++ pushl $z_output_len /* decompressed length, end of relocs */
+ leal z_extract_offset_negative(%ebx), %ebp
+ pushl %ebp /* output address */
+ pushl $z_input_len /* input_len */
+@@ -196,7 +197,7 @@ relocated:
+ pushl %eax /* heap area */
+ pushl %esi /* real mode pointer */
+ call decompress_kernel /* returns kernel location in %eax */
+- addl $24, %esp
++ addl $28, %esp
+
+ /*
+ * Jump to the decompressed kernel.
+--- a/arch/x86/boot/compressed/head_64.S
++++ b/arch/x86/boot/compressed/head_64.S
+@@ -334,13 +334,16 @@ relocated:
+ * Do the decompression, and jump to the new kernel..
+ */
+ pushq %rsi /* Save the real mode argument */
++ movq $z_run_size, %r9 /* size of kernel with .bss and .brk */
++ pushq %r9
+ movq %rsi, %rdi /* real mode address */
+ leaq boot_heap(%rip), %rsi /* malloc area for uncompression */
+ leaq input_data(%rip), %rdx /* input_data */
+ movl $z_input_len, %ecx /* input_len */
+ movq %rbp, %r8 /* output target address */
+- movq $z_output_len, %r9 /* decompressed length */
++ movq $z_output_len, %r9 /* decompressed length, end of relocs */
+ call decompress_kernel /* returns kernel location in %rax */
++ popq %r9
+ popq %rsi
+
+ /*
+--- a/arch/x86/boot/compressed/misc.c
++++ b/arch/x86/boot/compressed/misc.c
+@@ -393,7 +393,8 @@ asmlinkage void *decompress_kernel(void
+ unsigned char *input_data,
+ unsigned long input_len,
+ unsigned char *output,
+- unsigned long output_len)
++ unsigned long output_len,
++ unsigned long run_size)
+ {
+ real_mode = rmode;
+
+@@ -416,8 +417,14 @@ asmlinkage void *decompress_kernel(void
+ free_mem_ptr = heap; /* Heap */
+ free_mem_end_ptr = heap + BOOT_HEAP_SIZE;
+
+- output = choose_kernel_location(input_data, input_len,
+- output, output_len);
++ /*
++ * The memory hole needed for the kernel is the larger of either
++ * the entire decompressed kernel plus relocation table, or the
++ * entire decompressed kernel plus .bss and .brk sections.
++ */
++ output = choose_kernel_location(input_data, input_len, output,
++ output_len > run_size ? output_len
++ : run_size);
+
+ /* Validate memory location choices. */
+ if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1))
+--- a/arch/x86/boot/compressed/mkpiggy.c
++++ b/arch/x86/boot/compressed/mkpiggy.c
+@@ -36,11 +36,13 @@ int main(int argc, char *argv[])
+ uint32_t olen;
+ long ilen;
+ unsigned long offs;
++ unsigned long run_size;
+ FILE *f = NULL;
+ int retval = 1;
+
+- if (argc < 2) {
+- fprintf(stderr, "Usage: %s compressed_file\n", argv[0]);
++ if (argc < 3) {
++ fprintf(stderr, "Usage: %s compressed_file run_size\n",
++ argv[0]);
+ goto bail;
+ }
+
+@@ -74,6 +76,7 @@ int main(int argc, char *argv[])
+ offs += olen >> 12; /* Add 8 bytes for each 32K block */
+ offs += 64*1024 + 128; /* Add 64K + 128 bytes slack */
+ offs = (offs+4095) & ~4095; /* Round to a 4K boundary */
++ run_size = atoi(argv[2]);
+
+ printf(".section \".rodata..compressed\",\"a\",@progbits\n");
+ printf(".globl z_input_len\n");
+@@ -85,6 +88,8 @@ int main(int argc, char *argv[])
+ /* z_extract_offset_negative allows simplification of head_32.S */
+ printf(".globl z_extract_offset_negative\n");
+ printf("z_extract_offset_negative = -0x%lx\n", offs);
++ printf(".globl z_run_size\n");
++ printf("z_run_size = %lu\n", run_size);
+
+ printf(".globl input_data, input_data_end\n");
+ printf("input_data:\n");
+--- /dev/null
++++ b/arch/x86/tools/calc_run_size.pl
+@@ -0,0 +1,30 @@
++#!/usr/bin/perl
++#
++# Calculate the amount of space needed to run the kernel, including room for
++# the .bss and .brk sections.
++#
++# Usage:
++# objdump -h a.out | perl calc_run_size.pl
++use strict;
++
++my $mem_size = 0;
++my $file_offset = 0;
++
++my $sections=" *[0-9]+ \.(?:bss|brk) +";
++while (<>) {
++ if (/^$sections([0-9a-f]+) +(?:[0-9a-f]+ +){2}([0-9a-f]+)/) {
++ my $size = hex($1);
++ my $offset = hex($2);
++ $mem_size += $size;
++ if ($file_offset == 0) {
++ $file_offset = $offset;
++ } elsif ($file_offset != $offset) {
++ die ".bss and .brk lack common file offset\n";
++ }
++ }
++}
++
++if ($file_offset == 0) {
++ die "Never found .bss or .brk file offset\n";
++}
++printf("%d\n", $mem_size + $file_offset);
--- /dev/null
+From 4750a0d112cbfcc744929f1530ffe3193436766c Mon Sep 17 00:00:00 2001
+From: Borislav Petkov <bp@suse.de>
+Date: Fri, 31 Oct 2014 23:23:43 +0100
+Subject: x86, microcode, AMD: Fix early ucode loading on 32-bit
+
+From: Borislav Petkov <bp@suse.de>
+
+commit 4750a0d112cbfcc744929f1530ffe3193436766c upstream.
+
+Konrad triggered the following splat below in a 32-bit guest on an AMD
+box. As it turns out, in save_microcode_in_initrd_amd() we're using the
+*physical* address of the container *after* we have enabled paging and
+thus we #PF in load_microcode_amd() when trying to access the microcode
+container in the ramdisk range.
+
+Because the ramdisk is exactly there:
+
+[ 0.000000] RAMDISK: [mem 0x35e04000-0x36ef9fff]
+
+and we fault at 0x35e04304.
+
+And since this guest doesn't relocate the ramdisk, we don't do the
+computation which will give us the correct virtual address and we end up
+with the PA.
+
+So, we should actually be using virtual addresses on 32-bit too by the
+time we're freeing the initrd. Do that then!
+
+Unpacking initramfs...
+BUG: unable to handle kernel paging request at 35d4e304
+IP: [<c042e905>] load_microcode_amd+0x25/0x4a0
+*pde = 00000000
+Oops: 0000 [#1] SMP
+Modules linked in:
+CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.17.1-302.fc21.i686 #1
+Hardware name: Xen HVM domU, BIOS 4.4.1 10/01/2014
+task: f5098000 ti: f50d0000 task.ti: f50d0000
+EIP: 0060:[<c042e905>] EFLAGS: 00010246 CPU: 0
+EIP is at load_microcode_amd+0x25/0x4a0
+EAX: 00000000 EBX: f6e9ec4c ECX: 00001ec4 EDX: 00000000
+ESI: f5d4e000 EDI: 35d4e2fc EBP: f50d1ed0 ESP: f50d1e94
+ DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
+CR0: 8005003b CR2: 35d4e304 CR3: 00e33000 CR4: 000406d0
+Stack:
+ 00000000 00000000 f50d1ebc f50d1ec4 f5d4e000 c0d7735a f50d1ed0 15a3d17f
+ f50d1ec4 00600f20 00001ec4 bfb83203 f6e9ec4c f5d4e000 c0d7735a f50d1ed8
+ c0d80861 f50d1ee0 c0d80429 f50d1ef0 c0d889a9 f5d4e000 c0000000 f50d1f04
+Call Trace:
+? unpack_to_rootfs
+? unpack_to_rootfs
+save_microcode_in_initrd_amd
+save_microcode_in_initrd
+free_initrd_mem
+populate_rootfs
+? unpack_to_rootfs
+do_one_initcall
+? unpack_to_rootfs
+? repair_env_string
+? proc_mkdir
+kernel_init_freeable
+kernel_init
+ret_from_kernel_thread
+? rest_init
+
+Reported-and-tested-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+References: https://bugzilla.redhat.com/show_bug.cgi?id=1158204
+Fixes: 75a1ba5b2c52 ("x86, microcode, AMD: Unify valid container checks")
+Signed-off-by: Borislav Petkov <bp@suse.de>
+Link: http://lkml.kernel.org/r/20141101100100.GA4462@pd.tnic
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/kernel/cpu/microcode/amd_early.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+--- a/arch/x86/kernel/cpu/microcode/amd_early.c
++++ b/arch/x86/kernel/cpu/microcode/amd_early.c
+@@ -348,6 +348,7 @@ int __init save_microcode_in_initrd_amd(
+ {
+ unsigned long cont;
+ enum ucode_state ret;
++ u8 *cont_va;
+ u32 eax;
+
+ if (!container)
+@@ -355,13 +356,15 @@ int __init save_microcode_in_initrd_amd(
+
+ #ifdef CONFIG_X86_32
+ get_bsp_sig();
+- cont = (unsigned long)container;
++ cont = (unsigned long)container;
++ cont_va = __va(container);
+ #else
+ /*
+ * We need the physical address of the container for both bitness since
+ * boot_params.hdr.ramdisk_image is a physical address.
+ */
+- cont = __pa(container);
++ cont = __pa(container);
++ cont_va = container;
+ #endif
+
+ /*
+@@ -372,6 +375,8 @@ int __init save_microcode_in_initrd_amd(
+ if (relocated_ramdisk)
+ container = (u8 *)(__va(relocated_ramdisk) +
+ (cont - boot_params.hdr.ramdisk_image));
++ else
++ container = cont_va;
+
+ if (ucode_new_rev)
+ pr_info("microcode: updated early to new patch_level=0x%08x\n",
--- /dev/null
+From c0a717f23dccdb6e3b03471bc846fdc636f2b353 Mon Sep 17 00:00:00 2001
+From: Borislav Petkov <bp@suse.de>
+Date: Wed, 5 Nov 2014 17:42:42 +0100
+Subject: x86, microcode, AMD: Fix ucode patch stashing on 32-bit
+
+From: Borislav Petkov <bp@suse.de>
+
+commit c0a717f23dccdb6e3b03471bc846fdc636f2b353 upstream.
+
+Save the patch while we're running on the BSP instead of later, before
+the initrd has been jettisoned. More importantly, on 32-bit we need to
+access the physical address instead of the virtual.
+
+This way we actually do find it on the APs instead of having to go
+through the initrd each time.
+
+Tested-by: Richard Hendershot <rshendershot@mchsi.com>
+Fixes: 5335ba5cf475 ("x86, microcode, AMD: Fix early ucode loading")
+Signed-off-by: Borislav Petkov <bp@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/x86/kernel/cpu/microcode/amd_early.c | 24 ++++++++++++++----------
+ 1 file changed, 14 insertions(+), 10 deletions(-)
+
+--- a/arch/x86/kernel/cpu/microcode/amd_early.c
++++ b/arch/x86/kernel/cpu/microcode/amd_early.c
+@@ -108,12 +108,13 @@ static size_t compute_container_size(u8
+ * load_microcode_amd() to save equivalent cpu table and microcode patches in
+ * kernel heap memory.
+ */
+-static void apply_ucode_in_initrd(void *ucode, size_t size)
++static void apply_ucode_in_initrd(void *ucode, size_t size, bool save_patch)
+ {
+ struct equiv_cpu_entry *eq;
+ size_t *cont_sz;
+ u32 *header;
+ u8 *data, **cont;
++ u8 (*patch)[PATCH_MAX_SIZE];
+ u16 eq_id = 0;
+ int offset, left;
+ u32 rev, eax, ebx, ecx, edx;
+@@ -123,10 +124,12 @@ static void apply_ucode_in_initrd(void *
+ new_rev = (u32 *)__pa_nodebug(&ucode_new_rev);
+ cont_sz = (size_t *)__pa_nodebug(&container_size);
+ cont = (u8 **)__pa_nodebug(&container);
++ patch = (u8 (*)[PATCH_MAX_SIZE])__pa_nodebug(&amd_ucode_patch);
+ #else
+ new_rev = &ucode_new_rev;
+ cont_sz = &container_size;
+ cont = &container;
++ patch = &amd_ucode_patch;
+ #endif
+
+ data = ucode;
+@@ -213,9 +216,9 @@ static void apply_ucode_in_initrd(void *
+ rev = mc->hdr.patch_id;
+ *new_rev = rev;
+
+- /* save ucode patch */
+- memcpy(amd_ucode_patch, mc,
+- min_t(u32, header[1], PATCH_MAX_SIZE));
++ if (save_patch)
++ memcpy(patch, mc,
++ min_t(u32, header[1], PATCH_MAX_SIZE));
+ }
+ }
+
+@@ -246,7 +249,7 @@ void __init load_ucode_amd_bsp(void)
+ *data = cp.data;
+ *size = cp.size;
+
+- apply_ucode_in_initrd(cp.data, cp.size);
++ apply_ucode_in_initrd(cp.data, cp.size, true);
+ }
+
+ #ifdef CONFIG_X86_32
+@@ -263,7 +266,7 @@ void load_ucode_amd_ap(void)
+ size_t *usize;
+ void **ucode;
+
+- mc = (struct microcode_amd *)__pa(amd_ucode_patch);
++ mc = (struct microcode_amd *)__pa_nodebug(amd_ucode_patch);
+ if (mc->hdr.patch_id && mc->hdr.processor_rev_id) {
+ __apply_microcode_amd(mc);
+ return;
+@@ -275,7 +278,7 @@ void load_ucode_amd_ap(void)
+ if (!*ucode || !*usize)
+ return;
+
+- apply_ucode_in_initrd(*ucode, *usize);
++ apply_ucode_in_initrd(*ucode, *usize, false);
+ }
+
+ static void __init collect_cpu_sig_on_bsp(void *arg)
+@@ -339,7 +342,7 @@ void load_ucode_amd_ap(void)
+ * AP has a different equivalence ID than BSP, looks like
+ * mixed-steppings silicon so go through the ucode blob anew.
+ */
+- apply_ucode_in_initrd(ucode_cpio.data, ucode_cpio.size);
++ apply_ucode_in_initrd(ucode_cpio.data, ucode_cpio.size, false);
+ }
+ }
+ #endif
+@@ -347,6 +350,7 @@ void load_ucode_amd_ap(void)
+ int __init save_microcode_in_initrd_amd(void)
+ {
+ unsigned long cont;
++ int retval = 0;
+ enum ucode_state ret;
+ u8 *cont_va;
+ u32 eax;
+@@ -387,7 +391,7 @@ int __init save_microcode_in_initrd_amd(
+
+ ret = load_microcode_amd(eax, container, container_size);
+ if (ret != UCODE_OK)
+- return -EINVAL;
++ retval = -EINVAL;
+
+ /*
+ * This will be freed any msec now, stash patches for the current
+@@ -396,5 +400,5 @@ int __init save_microcode_in_initrd_amd(
+ container = NULL;
+ container_size = 0;
+
+- return 0;
++ return retval;
+ }