]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 18 Nov 2014 20:24:31 +0000 (12:24 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 18 Nov 2014 20:24:31 +0000 (12:24 -0800)
added patches:
md-always-set-recovery_needed-when-clearing-recovery_frozen.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-ensure-that-we-remove-nfsv4.0-delegations-when-state-has-expired.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
power-bq2415x_charger-fix-memory-leak-on-dts-parsing-error.patch
power-bq2415x_charger-properly-handle-enodev-from-power_supply_get_by_phandle.patch
power-charger-manager-fix-accessing-invalidated-power-supply-after-charger-unbind.patch
power-charger-manager-fix-accessing-invalidated-power-supply-after-fuel-gauge-unbind.patch
x86-kaslr-prevent-.bss-from-overlaping-initrd.patch
x86-microcode-amd-fix-early-ucode-loading-on-32-bit.patch
x86-microcode-amd-fix-ucode-patch-stashing-on-32-bit.patch

14 files changed:
queue-3.14/md-always-set-recovery_needed-when-clearing-recovery_frozen.patch [new file with mode: 0644]
queue-3.14/nfs-don-t-try-to-reclaim-delegation-open-state-if-recovery-failed.patch [new file with mode: 0644]
queue-3.14/nfs-fix-use-of-uninitialized-variable-in-nfs_getattr.patch [new file with mode: 0644]
queue-3.14/nfsv4-ensure-that-we-remove-nfsv4.0-delegations-when-state-has-expired.patch [new file with mode: 0644]
queue-3.14/nfsv4-fix-races-between-nfs_remove_bad_delegation-and-delegation-return.patch [new file with mode: 0644]
queue-3.14/nfsv4.1-nfs41_clear_delegation_stateid-shouldn-t-trust-nfs_delegated_state.patch [new file with mode: 0644]
queue-3.14/power-bq2415x_charger-fix-memory-leak-on-dts-parsing-error.patch [new file with mode: 0644]
queue-3.14/power-bq2415x_charger-properly-handle-enodev-from-power_supply_get_by_phandle.patch [new file with mode: 0644]
queue-3.14/power-charger-manager-fix-accessing-invalidated-power-supply-after-charger-unbind.patch [new file with mode: 0644]
queue-3.14/power-charger-manager-fix-accessing-invalidated-power-supply-after-fuel-gauge-unbind.patch [new file with mode: 0644]
queue-3.14/series
queue-3.14/x86-kaslr-prevent-.bss-from-overlaping-initrd.patch [new file with mode: 0644]
queue-3.14/x86-microcode-amd-fix-early-ucode-loading-on-32-bit.patch [new file with mode: 0644]
queue-3.14/x86-microcode-amd-fix-ucode-patch-stashing-on-32-bit.patch [new file with mode: 0644]

diff --git a/queue-3.14/md-always-set-recovery_needed-when-clearing-recovery_frozen.patch b/queue-3.14/md-always-set-recovery_needed-when-clearing-recovery_frozen.patch
new file mode 100644 (file)
index 0000000..010d196
--- /dev/null
@@ -0,0 +1,56 @@
+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;
diff --git a/queue-3.14/nfs-don-t-try-to-reclaim-delegation-open-state-if-recovery-failed.patch b/queue-3.14/nfs-don-t-try-to-reclaim-delegation-open-state-if-recovery-failed.patch
new file mode 100644 (file)
index 0000000..7022ce8
--- /dev/null
@@ -0,0 +1,31 @@
+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);
diff --git a/queue-3.14/nfs-fix-use-of-uninitialized-variable-in-nfs_getattr.patch b/queue-3.14/nfs-fix-use-of-uninitialized-variable-in-nfs_getattr.patch
new file mode 100644 (file)
index 0000000..f7309ae
--- /dev/null
@@ -0,0 +1,32 @@
+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.  */
diff --git a/queue-3.14/nfsv4-ensure-that-we-remove-nfsv4.0-delegations-when-state-has-expired.patch b/queue-3.14/nfsv4-ensure-that-we-remove-nfsv4.0-delegations-when-state-has-expired.patch
new file mode 100644 (file)
index 0000000..c30f16c
--- /dev/null
@@ -0,0 +1,61 @@
+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,
+ };
diff --git a/queue-3.14/nfsv4-fix-races-between-nfs_remove_bad_delegation-and-delegation-return.patch b/queue-3.14/nfsv4-fix-races-between-nfs_remove_bad_delegation-and-delegation-return.patch
new file mode 100644 (file)
index 0000000..057e0c4
--- /dev/null
@@ -0,0 +1,105 @@
+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);
diff --git a/queue-3.14/nfsv4.1-nfs41_clear_delegation_stateid-shouldn-t-trust-nfs_delegated_state.patch b/queue-3.14/nfsv4.1-nfs41_clear_delegation_stateid-shouldn-t-trust-nfs_delegated_state.patch
new file mode 100644 (file)
index 0000000..e12805a
--- /dev/null
@@ -0,0 +1,102 @@
+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);
diff --git a/queue-3.14/power-bq2415x_charger-fix-memory-leak-on-dts-parsing-error.patch b/queue-3.14/power-bq2415x_charger-fix-memory-leak-on-dts-parsing-error.patch
new file mode 100644 (file)
index 0000000..42fb6b3
--- /dev/null
@@ -0,0 +1,63 @@
+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));
+       }
diff --git a/queue-3.14/power-bq2415x_charger-properly-handle-enodev-from-power_supply_get_by_phandle.patch b/queue-3.14/power-bq2415x_charger-properly-handle-enodev-from-power_supply_get_by_phandle.patch
new file mode 100644 (file)
index 0000000..7fe966b
--- /dev/null
@@ -0,0 +1,52 @@
+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);
diff --git a/queue-3.14/power-charger-manager-fix-accessing-invalidated-power-supply-after-charger-unbind.patch b/queue-3.14/power-charger-manager-fix-accessing-invalidated-power-supply-after-charger-unbind.patch
new file mode 100644 (file)
index 0000000..15aa8ed
--- /dev/null
@@ -0,0 +1,211 @@
+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
diff --git a/queue-3.14/power-charger-manager-fix-accessing-invalidated-power-supply-after-fuel-gauge-unbind.patch b/queue-3.14/power-charger-manager-fix-accessing-invalidated-power-supply-after-fuel-gauge-unbind.patch
new file mode 100644 (file)
index 0000000..0f9b4bf
--- /dev/null
@@ -0,0 +1,339 @@
+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
index 35ab7b36eeb4f1d4c24d1c6165d56b916a5fd2e7..e0529d3bc540e0b0db9569902ddc6445984f3427 100644 (file)
@@ -57,3 +57,16 @@ input-synaptics-add-min-max-quirk-for-lenovo-t440s.patch
 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
diff --git a/queue-3.14/x86-kaslr-prevent-.bss-from-overlaping-initrd.patch b/queue-3.14/x86-kaslr-prevent-.bss-from-overlaping-initrd.patch
new file mode 100644 (file)
index 0000000..3f7d447
--- /dev/null
@@ -0,0 +1,218 @@
+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);
diff --git a/queue-3.14/x86-microcode-amd-fix-early-ucode-loading-on-32-bit.patch b/queue-3.14/x86-microcode-amd-fix-early-ucode-loading-on-32-bit.patch
new file mode 100644 (file)
index 0000000..3cf11a1
--- /dev/null
@@ -0,0 +1,113 @@
+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",
diff --git a/queue-3.14/x86-microcode-amd-fix-ucode-patch-stashing-on-32-bit.patch b/queue-3.14/x86-microcode-amd-fix-ucode-patch-stashing-on-32-bit.patch
new file mode 100644 (file)
index 0000000..c4c6069
--- /dev/null
@@ -0,0 +1,128 @@
+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;
+ }