]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 6 Apr 2017 07:45:36 +0000 (09:45 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 6 Apr 2017 07:45:36 +0000 (09:45 +0200)
added patches:
blk-ensure-users-for-current-bio_list-can-see-the-full-list.patch
blk-improve-order-of-bio-handling-in-generic_make_request.patch
kvm-kvm_io_bus_unregister_dev-should-never-fail.patch
mips-lantiq-fix-cascaded-irq-setup.patch
power-reset-at91-poweroff-timely-shutdown-lpddr-memories.patch
rtc-s35390a-fix-reading-out-alarm.patch
rtc-s35390a-implement-reset-routine-as-suggested-by-the-reference.patch
rtc-s35390a-improve-irq-handling.patch
rtc-s35390a-make-sure-all-members-in-the-output-are-set.patch

queue-4.4/blk-ensure-users-for-current-bio_list-can-see-the-full-list.patch [new file with mode: 0644]
queue-4.4/blk-improve-order-of-bio-handling-in-generic_make_request.patch [new file with mode: 0644]
queue-4.4/kvm-kvm_io_bus_unregister_dev-should-never-fail.patch [new file with mode: 0644]
queue-4.4/mips-lantiq-fix-cascaded-irq-setup.patch [new file with mode: 0644]
queue-4.4/power-reset-at91-poweroff-timely-shutdown-lpddr-memories.patch [new file with mode: 0644]
queue-4.4/rtc-s35390a-fix-reading-out-alarm.patch [new file with mode: 0644]
queue-4.4/rtc-s35390a-implement-reset-routine-as-suggested-by-the-reference.patch [new file with mode: 0644]
queue-4.4/rtc-s35390a-improve-irq-handling.patch [new file with mode: 0644]
queue-4.4/rtc-s35390a-make-sure-all-members-in-the-output-are-set.patch [new file with mode: 0644]
queue-4.4/series

diff --git a/queue-4.4/blk-ensure-users-for-current-bio_list-can-see-the-full-list.patch b/queue-4.4/blk-ensure-users-for-current-bio_list-can-see-the-full-list.patch
new file mode 100644 (file)
index 0000000..520ab47
--- /dev/null
@@ -0,0 +1,164 @@
+From f5fe1b51905df7cfe4fdfd85c5fb7bc5b71a094f Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.com>
+Date: Fri, 10 Mar 2017 17:00:47 +1100
+Subject: blk: Ensure users for current->bio_list can see the full list.
+
+From: NeilBrown <neilb@suse.com>
+
+commit f5fe1b51905df7cfe4fdfd85c5fb7bc5b71a094f upstream.
+
+Commit 79bd99596b73 ("blk: improve order of bio handling in generic_make_request()")
+changed current->bio_list so that it did not contain *all* of the
+queued bios, but only those submitted by the currently running
+make_request_fn.
+
+There are two places which walk the list and requeue selected bios,
+and others that check if the list is empty.  These are no longer
+correct.
+
+So redefine current->bio_list to point to an array of two lists, which
+contain all queued bios, and adjust various code to test or walk both
+lists.
+
+Signed-off-by: NeilBrown <neilb@suse.com>
+Fixes: 79bd99596b73 ("blk: improve order of bio handling in generic_make_request()")
+Signed-off-by: Jens Axboe <axboe@fb.com>
+[jwang: backport to 4.4]
+Signed-off-by: Jack Wang <jinpu.wang@profitbricks.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ block/bio.c         |   12 +++++++++---
+ block/blk-core.c    |   31 +++++++++++++++++++------------
+ drivers/md/raid1.c  |    3 ++-
+ drivers/md/raid10.c |    3 ++-
+ 4 files changed, 32 insertions(+), 17 deletions(-)
+
+--- a/block/bio.c
++++ b/block/bio.c
+@@ -373,10 +373,14 @@ static void punt_bios_to_rescuer(struct
+       bio_list_init(&punt);
+       bio_list_init(&nopunt);
+-      while ((bio = bio_list_pop(current->bio_list)))
++      while ((bio = bio_list_pop(&current->bio_list[0])))
+               bio_list_add(bio->bi_pool == bs ? &punt : &nopunt, bio);
++      current->bio_list[0] = nopunt;
+-      *current->bio_list = nopunt;
++      bio_list_init(&nopunt);
++      while ((bio = bio_list_pop(&current->bio_list[1])))
++              bio_list_add(bio->bi_pool == bs ? &punt : &nopunt, bio);
++      current->bio_list[1] = nopunt;
+       spin_lock(&bs->rescue_lock);
+       bio_list_merge(&bs->rescue_list, &punt);
+@@ -464,7 +468,9 @@ struct bio *bio_alloc_bioset(gfp_t gfp_m
+                * we retry with the original gfp_flags.
+                */
+-              if (current->bio_list && !bio_list_empty(current->bio_list))
++              if (current->bio_list &&
++                  (!bio_list_empty(&current->bio_list[0]) ||
++                   !bio_list_empty(&current->bio_list[1])))
+                       gfp_mask &= ~__GFP_DIRECT_RECLAIM;
+               p = mempool_alloc(bs->bio_pool, gfp_mask);
+--- a/block/blk-core.c
++++ b/block/blk-core.c
+@@ -2021,7 +2021,14 @@ end_io:
+  */
+ blk_qc_t generic_make_request(struct bio *bio)
+ {
+-      struct bio_list bio_list_on_stack;
++      /*
++       * bio_list_on_stack[0] contains bios submitted by the current
++       * make_request_fn.
++       * bio_list_on_stack[1] contains bios that were submitted before
++       * the current make_request_fn, but that haven't been processed
++       * yet.
++       */
++      struct bio_list bio_list_on_stack[2];
+       blk_qc_t ret = BLK_QC_T_NONE;
+       if (!generic_make_request_checks(bio))
+@@ -2038,7 +2045,7 @@ blk_qc_t generic_make_request(struct bio
+        * should be added at the tail
+        */
+       if (current->bio_list) {
+-              bio_list_add(current->bio_list, bio);
++              bio_list_add(&current->bio_list[0], bio);
+               goto out;
+       }
+@@ -2057,17 +2064,17 @@ blk_qc_t generic_make_request(struct bio
+        * bio_list, and call into ->make_request() again.
+        */
+       BUG_ON(bio->bi_next);
+-      bio_list_init(&bio_list_on_stack);
+-      current->bio_list = &bio_list_on_stack;
++      bio_list_init(&bio_list_on_stack[0]);
++      current->bio_list = bio_list_on_stack;
+       do {
+               struct request_queue *q = bdev_get_queue(bio->bi_bdev);
+               if (likely(blk_queue_enter(q, __GFP_DIRECT_RECLAIM) == 0)) {
+-                      struct bio_list lower, same, hold;
++                      struct bio_list lower, same;
+                       /* Create a fresh bio_list for all subordinate requests */
+-                      hold = bio_list_on_stack;
+-                      bio_list_init(&bio_list_on_stack);
++                      bio_list_on_stack[1] = bio_list_on_stack[0];
++                      bio_list_init(&bio_list_on_stack[0]);
+                       ret = q->make_request_fn(q, bio);
+@@ -2077,19 +2084,19 @@ blk_qc_t generic_make_request(struct bio
+                        */
+                       bio_list_init(&lower);
+                       bio_list_init(&same);
+-                      while ((bio = bio_list_pop(&bio_list_on_stack)) != NULL)
++                      while ((bio = bio_list_pop(&bio_list_on_stack[0])) != NULL)
+                               if (q == bdev_get_queue(bio->bi_bdev))
+                                       bio_list_add(&same, bio);
+                               else
+                                       bio_list_add(&lower, bio);
+                       /* now assemble so we handle the lowest level first */
+-                      bio_list_merge(&bio_list_on_stack, &lower);
+-                      bio_list_merge(&bio_list_on_stack, &same);
+-                      bio_list_merge(&bio_list_on_stack, &hold);
++                      bio_list_merge(&bio_list_on_stack[0], &lower);
++                      bio_list_merge(&bio_list_on_stack[0], &same);
++                      bio_list_merge(&bio_list_on_stack[0], &bio_list_on_stack[1]);
+               } else {
+                       bio_io_error(bio);
+               }
+-              bio = bio_list_pop(current->bio_list);
++              bio = bio_list_pop(&bio_list_on_stack[0]);
+       } while (bio);
+       current->bio_list = NULL; /* deactivate */
+--- a/drivers/md/raid1.c
++++ b/drivers/md/raid1.c
+@@ -877,7 +877,8 @@ static sector_t wait_barrier(struct r1co
+                                    ((conf->start_next_window <
+                                      conf->next_resync + RESYNC_SECTORS) &&
+                                     current->bio_list &&
+-                                    !bio_list_empty(current->bio_list))),
++                                   (!bio_list_empty(&current->bio_list[0]) ||
++                                    !bio_list_empty(&current->bio_list[1])))),
+                                   conf->resync_lock);
+               conf->nr_waiting--;
+       }
+--- a/drivers/md/raid10.c
++++ b/drivers/md/raid10.c
+@@ -946,7 +946,8 @@ static void wait_barrier(struct r10conf
+                                   !conf->barrier ||
+                                   (conf->nr_pending &&
+                                    current->bio_list &&
+-                                   !bio_list_empty(current->bio_list)),
++                                   (!bio_list_empty(&current->bio_list[0]) ||
++                                    !bio_list_empty(&current->bio_list[1]))),
+                                   conf->resync_lock);
+               conf->nr_waiting--;
+       }
diff --git a/queue-4.4/blk-improve-order-of-bio-handling-in-generic_make_request.patch b/queue-4.4/blk-improve-order-of-bio-handling-in-generic_make_request.patch
new file mode 100644 (file)
index 0000000..30745c2
--- /dev/null
@@ -0,0 +1,118 @@
+From 79bd99596b7305ab08109a8bf44a6a4511dbf1cd Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.com>
+Date: Wed, 8 Mar 2017 07:38:05 +1100
+Subject: blk: improve order of bio handling in generic_make_request()
+
+From: NeilBrown <neilb@suse.com>
+
+commit 79bd99596b7305ab08109a8bf44a6a4511dbf1cd upstream.
+
+To avoid recursion on the kernel stack when stacked block devices
+are in use, generic_make_request() will, when called recursively,
+queue new requests for later handling.  They will be handled when the
+make_request_fn for the current bio completes.
+
+If any bios are submitted by a make_request_fn, these will ultimately
+be handled seqeuntially.  If the handling of one of those generates
+further requests, they will be added to the end of the queue.
+
+This strict first-in-first-out behaviour can lead to deadlocks in
+various ways, normally because a request might need to wait for a
+previous request to the same device to complete.  This can happen when
+they share a mempool, and can happen due to interdependencies
+particular to the device.  Both md and dm have examples where this happens.
+
+These deadlocks can be erradicated by more selective ordering of bios.
+Specifically by handling them in depth-first order.  That is: when the
+handling of one bio generates one or more further bios, they are
+handled immediately after the parent, before any siblings of the
+parent.  That way, when generic_make_request() calls make_request_fn
+for some particular device, we can be certain that all previously
+submited requests for that device have been completely handled and are
+not waiting for anything in the queue of requests maintained in
+generic_make_request().
+
+An easy way to achieve this would be to use a last-in-first-out stack
+instead of a queue.  However this will change the order of consecutive
+bios submitted by a make_request_fn, which could have unexpected consequences.
+Instead we take a slightly more complex approach.
+A fresh queue is created for each call to a make_request_fn.  After it completes,
+any bios for a different device are placed on the front of the main queue, followed
+by any bios for the same device, followed by all bios that were already on
+the queue before the make_request_fn was called.
+This provides the depth-first approach without reordering bios on the same level.
+
+This, by itself, it not enough to remove all deadlocks.  It just makes
+it possible for drivers to take the extra step required themselves.
+
+To avoid deadlocks, drivers must never risk waiting for a request
+after submitting one to generic_make_request.  This includes never
+allocing from a mempool twice in the one call to a make_request_fn.
+
+A common pattern in drivers is to call bio_split() in a loop, handling
+the first part and then looping around to possibly split the next part.
+Instead, a driver that finds it needs to split a bio should queue
+(with generic_make_request) the second part, handle the first part,
+and then return.  The new code in generic_make_request will ensure the
+requests to underlying bios are processed first, then the second bio
+that was split off.  If it splits again, the same process happens.  In
+each case one bio will be completely handled before the next one is attempted.
+
+With this is place, it should be possible to disable the
+punt_bios_to_recover() recovery thread for many block devices, and
+eventually it may be possible to remove it completely.
+
+Ref: http://www.spinics.net/lists/raid/msg54680.html
+Tested-by: Jinpu Wang <jinpu.wang@profitbricks.com>
+Inspired-by: Lars Ellenberg <lars.ellenberg@linbit.com>
+Signed-off-by: NeilBrown <neilb@suse.com>
+Signed-off-by: Jens Axboe <axboe@fb.com>
+[jwang: backport to 4.4]
+Signed-off-by: Jack Wang <jinpu.wang@profitbricks.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ block/blk-core.c |   25 ++++++++++++++++++++-----
+ 1 file changed, 20 insertions(+), 5 deletions(-)
+
+--- a/block/blk-core.c
++++ b/block/blk-core.c
+@@ -2063,18 +2063,33 @@ blk_qc_t generic_make_request(struct bio
+               struct request_queue *q = bdev_get_queue(bio->bi_bdev);
+               if (likely(blk_queue_enter(q, __GFP_DIRECT_RECLAIM) == 0)) {
++                      struct bio_list lower, same, hold;
++
++                      /* Create a fresh bio_list for all subordinate requests */
++                      hold = bio_list_on_stack;
++                      bio_list_init(&bio_list_on_stack);
+                       ret = q->make_request_fn(q, bio);
+                       blk_queue_exit(q);
+-
+-                      bio = bio_list_pop(current->bio_list);
++                      /* sort new bios into those for a lower level
++                       * and those for the same level
++                       */
++                      bio_list_init(&lower);
++                      bio_list_init(&same);
++                      while ((bio = bio_list_pop(&bio_list_on_stack)) != NULL)
++                              if (q == bdev_get_queue(bio->bi_bdev))
++                                      bio_list_add(&same, bio);
++                              else
++                                      bio_list_add(&lower, bio);
++                      /* now assemble so we handle the lowest level first */
++                      bio_list_merge(&bio_list_on_stack, &lower);
++                      bio_list_merge(&bio_list_on_stack, &same);
++                      bio_list_merge(&bio_list_on_stack, &hold);
+               } else {
+-                      struct bio *bio_next = bio_list_pop(current->bio_list);
+-
+                       bio_io_error(bio);
+-                      bio = bio_next;
+               }
++              bio = bio_list_pop(current->bio_list);
+       } while (bio);
+       current->bio_list = NULL; /* deactivate */
diff --git a/queue-4.4/kvm-kvm_io_bus_unregister_dev-should-never-fail.patch b/queue-4.4/kvm-kvm_io_bus_unregister_dev-should-never-fail.patch
new file mode 100644 (file)
index 0000000..6f13b36
--- /dev/null
@@ -0,0 +1,167 @@
+From 90db10434b163e46da413d34db8d0e77404cc645 Mon Sep 17 00:00:00 2001
+From: David Hildenbrand <david@redhat.com>
+Date: Thu, 23 Mar 2017 18:24:19 +0100
+Subject: KVM: kvm_io_bus_unregister_dev() should never fail
+
+From: David Hildenbrand <david@redhat.com>
+
+commit 90db10434b163e46da413d34db8d0e77404cc645 upstream.
+
+No caller currently checks the return value of
+kvm_io_bus_unregister_dev(). This is evil, as all callers silently go on
+freeing their device. A stale reference will remain in the io_bus,
+getting at least used again, when the iobus gets teared down on
+kvm_destroy_vm() - leading to use after free errors.
+
+There is nothing the callers could do, except retrying over and over
+again.
+
+So let's simply remove the bus altogether, print an error and make
+sure no one can access this broken bus again (returning -ENOMEM on any
+attempt to access it).
+
+Fixes: e93f8a0f821e ("KVM: convert io_bus to SRCU")
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
+Signed-off-by: David Hildenbrand <david@redhat.com>
+Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ include/linux/kvm_host.h |    4 ++--
+ virt/kvm/eventfd.c       |    3 ++-
+ virt/kvm/kvm_main.c      |   40 +++++++++++++++++++++++-----------------
+ 3 files changed, 27 insertions(+), 20 deletions(-)
+
+--- a/include/linux/kvm_host.h
++++ b/include/linux/kvm_host.h
+@@ -182,8 +182,8 @@ int kvm_io_bus_read(struct kvm_vcpu *vcp
+                   int len, void *val);
+ int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,
+                           int len, struct kvm_io_device *dev);
+-int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
+-                            struct kvm_io_device *dev);
++void kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
++                             struct kvm_io_device *dev);
+ #ifdef CONFIG_KVM_ASYNC_PF
+ struct kvm_async_pf {
+--- a/virt/kvm/eventfd.c
++++ b/virt/kvm/eventfd.c
+@@ -868,7 +868,8 @@ kvm_deassign_ioeventfd_idx(struct kvm *k
+                       continue;
+               kvm_io_bus_unregister_dev(kvm, bus_idx, &p->dev);
+-              kvm->buses[bus_idx]->ioeventfd_count--;
++              if (kvm->buses[bus_idx])
++                      kvm->buses[bus_idx]->ioeventfd_count--;
+               ioeventfd_release(p);
+               ret = 0;
+               break;
+--- a/virt/kvm/kvm_main.c
++++ b/virt/kvm/kvm_main.c
+@@ -655,7 +655,8 @@ static void kvm_destroy_vm(struct kvm *k
+       spin_unlock(&kvm_lock);
+       kvm_free_irq_routing(kvm);
+       for (i = 0; i < KVM_NR_BUSES; i++) {
+-              kvm_io_bus_destroy(kvm->buses[i]);
++              if (kvm->buses[i])
++                      kvm_io_bus_destroy(kvm->buses[i]);
+               kvm->buses[i] = NULL;
+       }
+       kvm_coalesced_mmio_free(kvm);
+@@ -3273,6 +3274,8 @@ int kvm_io_bus_write(struct kvm_vcpu *vc
+       };
+       bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu);
++      if (!bus)
++              return -ENOMEM;
+       r = __kvm_io_bus_write(vcpu, bus, &range, val);
+       return r < 0 ? r : 0;
+ }
+@@ -3290,6 +3293,8 @@ int kvm_io_bus_write_cookie(struct kvm_v
+       };
+       bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu);
++      if (!bus)
++              return -ENOMEM;
+       /* First try the device referenced by cookie. */
+       if ((cookie >= 0) && (cookie < bus->dev_count) &&
+@@ -3340,6 +3345,8 @@ int kvm_io_bus_read(struct kvm_vcpu *vcp
+       };
+       bus = srcu_dereference(vcpu->kvm->buses[bus_idx], &vcpu->kvm->srcu);
++      if (!bus)
++              return -ENOMEM;
+       r = __kvm_io_bus_read(vcpu, bus, &range, val);
+       return r < 0 ? r : 0;
+ }
+@@ -3352,6 +3359,9 @@ int kvm_io_bus_register_dev(struct kvm *
+       struct kvm_io_bus *new_bus, *bus;
+       bus = kvm->buses[bus_idx];
++      if (!bus)
++              return -ENOMEM;
++
+       /* exclude ioeventfd which is limited by maximum fd */
+       if (bus->dev_count - bus->ioeventfd_count > NR_IOBUS_DEVS - 1)
+               return -ENOSPC;
+@@ -3371,45 +3381,41 @@ int kvm_io_bus_register_dev(struct kvm *
+ }
+ /* Caller must hold slots_lock. */
+-int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
+-                            struct kvm_io_device *dev)
++void kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
++                             struct kvm_io_device *dev)
+ {
+-      int i, r;
++      int i;
+       struct kvm_io_bus *new_bus, *bus;
+       bus = kvm->buses[bus_idx];
+-
+-      /*
+-       * It's possible the bus being released before hand. If so,
+-       * we're done here.
+-       */
+       if (!bus)
+-              return 0;
++              return;
+-      r = -ENOENT;
+       for (i = 0; i < bus->dev_count; i++)
+               if (bus->range[i].dev == dev) {
+-                      r = 0;
+                       break;
+               }
+-      if (r)
+-              return r;
++      if (i == bus->dev_count)
++              return;
+       new_bus = kmalloc(sizeof(*bus) + ((bus->dev_count - 1) *
+                         sizeof(struct kvm_io_range)), GFP_KERNEL);
+-      if (!new_bus)
+-              return -ENOMEM;
++      if (!new_bus)  {
++              pr_err("kvm: failed to shrink bus, removing it completely\n");
++              goto broken;
++      }
+       memcpy(new_bus, bus, sizeof(*bus) + i * sizeof(struct kvm_io_range));
+       new_bus->dev_count--;
+       memcpy(new_bus->range + i, bus->range + i + 1,
+              (new_bus->dev_count - i) * sizeof(struct kvm_io_range));
++broken:
+       rcu_assign_pointer(kvm->buses[bus_idx], new_bus);
+       synchronize_srcu_expedited(&kvm->srcu);
+       kfree(bus);
+-      return r;
++      return;
+ }
+ static struct notifier_block kvm_cpu_notifier = {
diff --git a/queue-4.4/mips-lantiq-fix-cascaded-irq-setup.patch b/queue-4.4/mips-lantiq-fix-cascaded-irq-setup.patch
new file mode 100644 (file)
index 0000000..424efb3
--- /dev/null
@@ -0,0 +1,104 @@
+From 6c356eda225e3ee134ed4176b9ae3a76f793f4dd Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 19 Jan 2017 12:28:22 +0100
+Subject: MIPS: Lantiq: Fix cascaded IRQ setup
+
+From: Felix Fietkau <nbd@nbd.name>
+
+commit 6c356eda225e3ee134ed4176b9ae3a76f793f4dd upstream.
+
+With the IRQ stack changes integrated, the XRX200 devices started
+emitting a constant stream of kernel messages like this:
+
+[  565.415310] Spurious IRQ: CAUSE=0x1100c300
+
+This is caused by IP0 getting handled by plat_irq_dispatch() rather than
+its vectored interrupt handler, which is fixed by commit de856416e714
+("MIPS: IRQ Stack: Fix erroneous jal to plat_irq_dispatch").
+
+Fix plat_irq_dispatch() to handle non-vectored IPI interrupts correctly
+by setting up IP2-6 as proper chained IRQ handlers and calling do_IRQ
+for all MIPS CPU interrupts.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Acked-by: John Crispin <john@phrozen.org>
+Cc: linux-mips@linux-mips.org
+Patchwork: https://patchwork.linux-mips.org/patch/15077/
+[james.hogan@imgtec.com: tweaked commit message]
+Signed-off-by: James Hogan <james.hogan@imgtec.com>
+Signed-off-by: Amit Pundir <amit.pundir@linaro.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ arch/mips/lantiq/irq.c |   36 ++++++++++++++++--------------------
+ 1 file changed, 16 insertions(+), 20 deletions(-)
+
+--- a/arch/mips/lantiq/irq.c
++++ b/arch/mips/lantiq/irq.c
+@@ -269,6 +269,11 @@ static void ltq_hw5_irqdispatch(void)
+ DEFINE_HWx_IRQDISPATCH(5)
+ #endif
++static void ltq_hw_irq_handler(struct irq_desc *desc)
++{
++      ltq_hw_irqdispatch(irq_desc_get_irq(desc) - 2);
++}
++
+ #ifdef CONFIG_MIPS_MT_SMP
+ void __init arch_init_ipiirq(int irq, struct irqaction *action)
+ {
+@@ -313,23 +318,19 @@ static struct irqaction irq_call = {
+ asmlinkage void plat_irq_dispatch(void)
+ {
+       unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
+-      unsigned int i;
++      int irq;
+-      if ((MIPS_CPU_TIMER_IRQ == 7) && (pending & CAUSEF_IP7)) {
+-              do_IRQ(MIPS_CPU_TIMER_IRQ);
+-              goto out;
+-      } else {
+-              for (i = 0; i < MAX_IM; i++) {
+-                      if (pending & (CAUSEF_IP2 << i)) {
+-                              ltq_hw_irqdispatch(i);
+-                              goto out;
+-                      }
+-              }
++      if (!pending) {
++              spurious_interrupt();
++              return;
+       }
+-      pr_alert("Spurious IRQ: CAUSE=0x%08x\n", read_c0_status());
+-out:
+-      return;
++      pending >>= CAUSEB_IP;
++      while (pending) {
++              irq = fls(pending) - 1;
++              do_IRQ(MIPS_CPU_IRQ_BASE + irq);
++              pending &= ~BIT(irq);
++      }
+ }
+ static int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
+@@ -354,11 +355,6 @@ static const struct irq_domain_ops irq_d
+       .map = icu_map,
+ };
+-static struct irqaction cascade = {
+-      .handler = no_action,
+-      .name = "cascade",
+-};
+-
+ int __init icu_of_init(struct device_node *node, struct device_node *parent)
+ {
+       struct device_node *eiu_node;
+@@ -390,7 +386,7 @@ int __init icu_of_init(struct device_nod
+       mips_cpu_irq_init();
+       for (i = 0; i < MAX_IM; i++)
+-              setup_irq(i + 2, &cascade);
++              irq_set_chained_handler(i + 2, ltq_hw_irq_handler);
+       if (cpu_has_vint) {
+               pr_info("Setting up vectored interrupts\n");
diff --git a/queue-4.4/power-reset-at91-poweroff-timely-shutdown-lpddr-memories.patch b/queue-4.4/power-reset-at91-poweroff-timely-shutdown-lpddr-memories.patch
new file mode 100644 (file)
index 0000000..f3f683f
--- /dev/null
@@ -0,0 +1,126 @@
+From 0b0408745e7ff24757cbfd571d69026c0ddb803c Mon Sep 17 00:00:00 2001
+From: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+Date: Tue, 25 Oct 2016 11:37:59 +0200
+Subject: power: reset: at91-poweroff: timely shutdown LPDDR memories
+
+From: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+
+commit 0b0408745e7ff24757cbfd571d69026c0ddb803c upstream.
+
+LPDDR memories can only handle up to 400 uncontrolled power off. Ensure the
+proper power off sequence is used before shutting down the platform.
+
+Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+Signed-off-by: Sebastian Reichel <sre@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/power/reset/at91-poweroff.c |   54 +++++++++++++++++++++++++++++++++++-
+ 1 file changed, 53 insertions(+), 1 deletion(-)
+
+--- a/drivers/power/reset/at91-poweroff.c
++++ b/drivers/power/reset/at91-poweroff.c
+@@ -14,9 +14,12 @@
+ #include <linux/io.h>
+ #include <linux/module.h>
+ #include <linux/of.h>
++#include <linux/of_address.h>
+ #include <linux/platform_device.h>
+ #include <linux/printk.h>
++#include <soc/at91/at91sam9_ddrsdr.h>
++
+ #define AT91_SHDW_CR  0x00            /* Shut Down Control Register */
+ #define AT91_SHDW_SHDW                BIT(0)                  /* Shut Down command */
+ #define AT91_SHDW_KEY         (0xa5 << 24)            /* KEY Password */
+@@ -50,6 +53,7 @@ static const char *shdwc_wakeup_modes[]
+ static void __iomem *at91_shdwc_base;
+ static struct clk *sclk;
++static void __iomem *mpddrc_base;
+ static void __init at91_wakeup_status(void)
+ {
+@@ -73,6 +77,29 @@ static void at91_poweroff(void)
+       writel(AT91_SHDW_KEY | AT91_SHDW_SHDW, at91_shdwc_base + AT91_SHDW_CR);
+ }
++static void at91_lpddr_poweroff(void)
++{
++      asm volatile(
++              /* Align to cache lines */
++              ".balign 32\n\t"
++
++              /* Ensure AT91_SHDW_CR is in the TLB by reading it */
++              "       ldr     r6, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
++
++              /* Power down SDRAM0 */
++              "       str     %1, [%0, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t"
++              /* Shutdown CPU */
++              "       str     %3, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
++
++              "       b       .\n\t"
++              :
++              : "r" (mpddrc_base),
++                "r" cpu_to_le32(AT91_DDRSDRC_LPDDR2_PWOFF),
++                "r" (at91_shdwc_base),
++                "r" cpu_to_le32(AT91_SHDW_KEY | AT91_SHDW_SHDW)
++              : "r0");
++}
++
+ static int at91_poweroff_get_wakeup_mode(struct device_node *np)
+ {
+       const char *pm;
+@@ -124,6 +151,8 @@ static void at91_poweroff_dt_set_wakeup_
+ static int __init at91_poweroff_probe(struct platform_device *pdev)
+ {
+       struct resource *res;
++      struct device_node *np;
++      u32 ddr_type;
+       int ret;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+@@ -150,12 +179,30 @@ static int __init at91_poweroff_probe(st
+       pm_power_off = at91_poweroff;
++      np = of_find_compatible_node(NULL, NULL, "atmel,sama5d3-ddramc");
++      if (!np)
++              return 0;
++
++      mpddrc_base = of_iomap(np, 0);
++      of_node_put(np);
++
++      if (!mpddrc_base)
++              return 0;
++
++      ddr_type = readl(mpddrc_base + AT91_DDRSDRC_MDR) & AT91_DDRSDRC_MD;
++      if ((ddr_type == AT91_DDRSDRC_MD_LPDDR2) ||
++          (ddr_type == AT91_DDRSDRC_MD_LPDDR3))
++              pm_power_off = at91_lpddr_poweroff;
++      else
++              iounmap(mpddrc_base);
++
+       return 0;
+ }
+ static int __exit at91_poweroff_remove(struct platform_device *pdev)
+ {
+-      if (pm_power_off == at91_poweroff)
++      if (pm_power_off == at91_poweroff ||
++          pm_power_off == at91_lpddr_poweroff)
+               pm_power_off = NULL;
+       clk_disable_unprepare(sclk);
+@@ -163,6 +210,11 @@ static int __exit at91_poweroff_remove(s
+       return 0;
+ }
++static const struct of_device_id at91_ramc_of_match[] = {
++      { .compatible = "atmel,sama5d3-ddramc", },
++      { /* sentinel */ }
++};
++
+ static const struct of_device_id at91_poweroff_of_match[] = {
+       { .compatible = "atmel,at91sam9260-shdwc", },
+       { .compatible = "atmel,at91sam9rl-shdwc", },
diff --git a/queue-4.4/rtc-s35390a-fix-reading-out-alarm.patch b/queue-4.4/rtc-s35390a-fix-reading-out-alarm.patch
new file mode 100644 (file)
index 0000000..dfb76a5
--- /dev/null
@@ -0,0 +1,98 @@
+From f87e904ddd8f0ef120e46045b0addeb1cc88354e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <uwe@kleine-koenig.org>
+Date: Sat, 2 Jul 2016 17:28:08 +0200
+Subject: rtc: s35390a: fix reading out alarm
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <uwe@kleine-koenig.org>
+
+commit f87e904ddd8f0ef120e46045b0addeb1cc88354e upstream.
+
+There are several issues fixed in this patch:
+
+ - When alarm isn't enabled, set .enabled to zero instead of returning
+   -EINVAL.
+ - Ignore how IRQ1 is configured when determining if IRQ2 is on.
+ - The three alarm registers have an enable flag which must be
+   evaluated.
+ - The chip always triggers when the seconds register gets 0.
+
+Note that the rtc framework however doesn't handle the result correctly
+because it doesn't check wday being initialized and so interprets an
+alarm being set for 10:00 AM in three days as 10:00 AM tomorrow (or
+today if that's not over yet).
+
+Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
+Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/rtc/rtc-s35390a.c |   40 +++++++++++++++++++++++++++++++---------
+ 1 file changed, 31 insertions(+), 9 deletions(-)
+
+--- a/drivers/rtc/rtc-s35390a.c
++++ b/drivers/rtc/rtc-s35390a.c
+@@ -242,6 +242,8 @@ static int s35390a_set_alarm(struct i2c_
+       if (alm->time.tm_wday != -1)
+               buf[S35390A_ALRM_BYTE_WDAY] = bin2bcd(alm->time.tm_wday) | 0x80;
++      else
++              buf[S35390A_ALRM_BYTE_WDAY] = 0;
+       buf[S35390A_ALRM_BYTE_HOURS] = s35390a_hr2reg(s35390a,
+                       alm->time.tm_hour) | 0x80;
+@@ -269,23 +271,43 @@ static int s35390a_read_alarm(struct i2c
+       if (err < 0)
+               return err;
+-      if (bitrev8(sts) != S35390A_INT2_MODE_ALARM)
+-              return -EINVAL;
++      if ((bitrev8(sts) & S35390A_INT2_MODE_MASK) != S35390A_INT2_MODE_ALARM) {
++              /*
++               * When the alarm isn't enabled, the register to configure
++               * the alarm time isn't accessible.
++               */
++              alm->enabled = 0;
++              return 0;
++      } else {
++              alm->enabled = 1;
++      }
+       err = s35390a_get_reg(s35390a, S35390A_CMD_INT2_REG1, buf, sizeof(buf));
+       if (err < 0)
+               return err;
+       /* This chip returns the bits of each byte in reverse order */
+-      for (i = 0; i < 3; ++i) {
++      for (i = 0; i < 3; ++i)
+               buf[i] = bitrev8(buf[i]);
+-              buf[i] &= ~0x80;
+-      }
+-      alm->time.tm_wday = bcd2bin(buf[S35390A_ALRM_BYTE_WDAY]);
+-      alm->time.tm_hour = s35390a_reg2hr(s35390a,
+-                                              buf[S35390A_ALRM_BYTE_HOURS]);
+-      alm->time.tm_min = bcd2bin(buf[S35390A_ALRM_BYTE_MINS]);
++      /*
++       * B0 of the three matching registers is an enable flag. Iff it is set
++       * the configured value is used for matching.
++       */
++      if (buf[S35390A_ALRM_BYTE_WDAY] & 0x80)
++              alm->time.tm_wday =
++                      bcd2bin(buf[S35390A_ALRM_BYTE_WDAY] & ~0x80);
++
++      if (buf[S35390A_ALRM_BYTE_HOURS] & 0x80)
++              alm->time.tm_hour =
++                      s35390a_reg2hr(s35390a,
++                                     buf[S35390A_ALRM_BYTE_HOURS] & ~0x80);
++
++      if (buf[S35390A_ALRM_BYTE_MINS] & 0x80)
++              alm->time.tm_min = bcd2bin(buf[S35390A_ALRM_BYTE_MINS] & ~0x80);
++
++      /* alarm triggers always at s=0 */
++      alm->time.tm_sec = 0;
+       dev_dbg(&client->dev, "%s: alm is mins=%d, hours=%d, wday=%d\n",
+                       __func__, alm->time.tm_min, alm->time.tm_hour,
diff --git a/queue-4.4/rtc-s35390a-implement-reset-routine-as-suggested-by-the-reference.patch b/queue-4.4/rtc-s35390a-implement-reset-routine-as-suggested-by-the-reference.patch
new file mode 100644 (file)
index 0000000..c2822f1
--- /dev/null
@@ -0,0 +1,133 @@
+From 8e6583f1b5d1f5f129b873f1428b7e414263d847 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <uwe@kleine-koenig.org>
+Date: Sat, 2 Jul 2016 17:28:09 +0200
+Subject: rtc: s35390a: implement reset routine as suggested by the reference
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <uwe@kleine-koenig.org>
+
+commit 8e6583f1b5d1f5f129b873f1428b7e414263d847 upstream.
+
+There were two deviations from the reference manual: you have to wait
+half a second when POC is active and you might have to repeat
+initialization when POC or BLD are still set after the sequence.
+
+Note however that as POC and BLD are cleared by read the driver might
+not be able to detect that a reset is necessary. I don't have a good
+idea how to fix this.
+
+Additionally report the value read from STATUS1 to the caller. This
+prepares the next patch.
+
+Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
+Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/rtc/rtc-s35390a.c |   69 ++++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 57 insertions(+), 12 deletions(-)
+
+--- a/drivers/rtc/rtc-s35390a.c
++++ b/drivers/rtc/rtc-s35390a.c
+@@ -15,6 +15,7 @@
+ #include <linux/bitrev.h>
+ #include <linux/bcd.h>
+ #include <linux/slab.h>
++#include <linux/delay.h>
+ #define S35390A_CMD_STATUS1   0
+ #define S35390A_CMD_STATUS2   1
+@@ -94,19 +95,63 @@ static int s35390a_get_reg(struct s35390
+       return 0;
+ }
+-static int s35390a_reset(struct s35390a *s35390a)
+-{
+-      char buf[1];
+-
+-      if (s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf)) < 0)
+-              return -EIO;
++/*
++ * Returns <0 on error, 0 if rtc is setup fine and 1 if the chip was reset.
++ * To keep the information if an irq is pending, pass the value read from
++ * STATUS1 to the caller.
++ */
++static int s35390a_reset(struct s35390a *s35390a, char *status1)
++{
++      char buf;
++      int ret;
++      unsigned initcount = 0;
++
++      ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, status1, 1);
++      if (ret < 0)
++              return ret;
+-      if (!(buf[0] & (S35390A_FLAG_POC | S35390A_FLAG_BLD)))
++      if (*status1 & S35390A_FLAG_POC)
++              /*
++               * Do not communicate for 0.5 seconds since the power-on
++               * detection circuit is in operation.
++               */
++              msleep(500);
++      else if (!(*status1 & S35390A_FLAG_BLD))
++              /*
++               * If both POC and BLD are unset everything is fine.
++               */
+               return 0;
+-      buf[0] |= (S35390A_FLAG_RESET | S35390A_FLAG_24H);
+-      buf[0] &= 0xf0;
+-      return s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf));
++      /*
++       * At least one of POC and BLD are set, so reinitialise chip. Keeping
++       * this information in the hardware to know later that the time isn't
++       * valid is unfortunately not possible because POC and BLD are cleared
++       * on read. So the reset is best done now.
++       *
++       * The 24H bit is kept over reset, so set it already here.
++       */
++initialize:
++      *status1 = S35390A_FLAG_24H;
++      buf = S35390A_FLAG_RESET | S35390A_FLAG_24H;
++      ret = s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
++
++      if (ret < 0)
++              return ret;
++
++      ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
++      if (ret < 0)
++              return ret;
++
++      if (buf & (S35390A_FLAG_POC | S35390A_FLAG_BLD)) {
++              /* Try up to five times to reset the chip */
++              if (initcount < 5) {
++                      ++initcount;
++                      goto initialize;
++              } else
++                      return -EIO;
++      }
++
++      return 1;
+ }
+ static int s35390a_disable_test_mode(struct s35390a *s35390a)
+@@ -367,7 +412,7 @@ static int s35390a_probe(struct i2c_clie
+       unsigned int i;
+       struct s35390a *s35390a;
+       struct rtc_time tm;
+-      char buf[1];
++      char buf[1], status1;
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               err = -ENODEV;
+@@ -396,7 +441,7 @@ static int s35390a_probe(struct i2c_clie
+               }
+       }
+-      err = s35390a_reset(s35390a);
++      err = s35390a_reset(s35390a, &status1);
+       if (err < 0) {
+               dev_err(&client->dev, "error resetting chip\n");
+               goto exit_dummy;
diff --git a/queue-4.4/rtc-s35390a-improve-irq-handling.patch b/queue-4.4/rtc-s35390a-improve-irq-handling.patch
new file mode 100644 (file)
index 0000000..feb479a
--- /dev/null
@@ -0,0 +1,127 @@
+From 3bd32722c827d00eafe8e6d5b83e9f3148ea7c7e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= <uwe@kleine-koenig.org>
+Date: Sat, 2 Jul 2016 17:28:10 +0200
+Subject: rtc: s35390a: improve irq handling
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Uwe Kleine-König <uwe@kleine-koenig.org>
+
+commit 3bd32722c827d00eafe8e6d5b83e9f3148ea7c7e upstream.
+
+On some QNAP NAS devices the rtc can wake the machine. Several people
+noticed that once the machine was woken this way it fails to shut down.
+That's because the driver fails to acknowledge the interrupt and so it
+keeps active and restarts the machine immediatly after shutdown. See
+https://bugs.debian.org/794266 for a bug report.
+
+Doing this correctly requires to interpret the INT2 flag of the first read
+of the STATUS1 register because this bit is cleared by read.
+
+Note this is not maximally robust though because a pending irq isn't
+detected when the STATUS1 register was already read (and so INT2 is not
+set) but the irq was not disabled. But that is a hardware imposed problem
+that cannot easily be fixed by software.
+
+Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
+Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/rtc/rtc-s35390a.c |   48 +++++++++++++++++++++++++++++-----------------
+ 1 file changed, 31 insertions(+), 17 deletions(-)
+
+--- a/drivers/rtc/rtc-s35390a.c
++++ b/drivers/rtc/rtc-s35390a.c
+@@ -35,10 +35,14 @@
+ #define S35390A_ALRM_BYTE_HOURS       1
+ #define S35390A_ALRM_BYTE_MINS        2
++/* flags for STATUS1 */
+ #define S35390A_FLAG_POC      0x01
+ #define S35390A_FLAG_BLD      0x02
++#define S35390A_FLAG_INT2     0x04
+ #define S35390A_FLAG_24H      0x40
+ #define S35390A_FLAG_RESET    0x80
++
++/* flag for STATUS2 */
+ #define S35390A_FLAG_TEST     0x01
+ #define S35390A_INT2_MODE_MASK                0xF0
+@@ -408,11 +412,11 @@ static struct i2c_driver s35390a_driver;
+ static int s35390a_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+ {
+-      int err;
++      int err, err_reset;
+       unsigned int i;
+       struct s35390a *s35390a;
+       struct rtc_time tm;
+-      char buf[1], status1;
++      char buf, status1;
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               err = -ENODEV;
+@@ -441,29 +445,35 @@ static int s35390a_probe(struct i2c_clie
+               }
+       }
+-      err = s35390a_reset(s35390a, &status1);
+-      if (err < 0) {
++      err_reset = s35390a_reset(s35390a, &status1);
++      if (err_reset < 0) {
++              err = err_reset;
+               dev_err(&client->dev, "error resetting chip\n");
+               goto exit_dummy;
+       }
+-      err = s35390a_disable_test_mode(s35390a);
+-      if (err < 0) {
+-              dev_err(&client->dev, "error disabling test mode\n");
+-              goto exit_dummy;
+-      }
+-
+-      err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf));
+-      if (err < 0) {
+-              dev_err(&client->dev, "error checking 12/24 hour mode\n");
+-              goto exit_dummy;
+-      }
+-      if (buf[0] & S35390A_FLAG_24H)
++      if (status1 & S35390A_FLAG_24H)
+               s35390a->twentyfourhour = 1;
+       else
+               s35390a->twentyfourhour = 0;
+-      if (s35390a_get_datetime(client, &tm) < 0)
++      if (status1 & S35390A_FLAG_INT2) {
++              /* disable alarm (and maybe test mode) */
++              buf = 0;
++              err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &buf, 1);
++              if (err < 0) {
++                      dev_err(&client->dev, "error disabling alarm");
++                      goto exit_dummy;
++              }
++      } else {
++              err = s35390a_disable_test_mode(s35390a);
++              if (err < 0) {
++                      dev_err(&client->dev, "error disabling test mode\n");
++                      goto exit_dummy;
++              }
++      }
++
++      if (err_reset > 0 || s35390a_get_datetime(client, &tm) < 0)
+               dev_warn(&client->dev, "clock needs to be set\n");
+       device_set_wakeup_capable(&client->dev, 1);
+@@ -476,6 +486,10 @@ static int s35390a_probe(struct i2c_clie
+               err = PTR_ERR(s35390a->rtc);
+               goto exit_dummy;
+       }
++
++      if (status1 & S35390A_FLAG_INT2)
++              rtc_update_irq(s35390a->rtc, 1, RTC_AF);
++
+       return 0;
+ exit_dummy:
diff --git a/queue-4.4/rtc-s35390a-make-sure-all-members-in-the-output-are-set.patch b/queue-4.4/rtc-s35390a-make-sure-all-members-in-the-output-are-set.patch
new file mode 100644 (file)
index 0000000..9f73ef1
--- /dev/null
@@ -0,0 +1,51 @@
+From uwe@kleine-koenig.org  Thu Apr  6 09:35:55 2017
+From: Uwe Kleine-König <uwe@kleine-koenig.org>
+Date: Mon,  3 Apr 2017 23:32:38 +0200
+Subject: rtc: s35390a: make sure all members in the output are set
+To: stable@vger.kernel.org
+Cc: Martin Michlmayr <tbm@cyrius.com>, peter <ptrbucr3075@gmail.com>, Alexandre Belloni <alexandre.belloni@free-electrons.com>, debian-kernel@lists.debian.org
+Message-ID: <20170403213240.3856-3-uwe@kleine-koenig.org>
+
+From: Uwe Kleine-König <uwe@kleine-koenig.org>
+
+The rtc core calls the .read_alarm with all fields initialized to 0. As
+the s35390a driver doesn't touch some fields the returned date is
+interpreted as a date in January 1900. So make sure all fields are set
+to -1; some of them are then overwritten with the right data depending
+on the hardware state.
+
+In mainline this is done by commit d68778b80dd7 ("rtc: initialize output
+parameter for read alarm to "uninitialized"") in the core. This is
+considered to dangerous for stable as it might have side effects for
+other rtc drivers that might for example rely on alarm->time.tm_sec
+being initialized to 0.
+
+Signed-off-by: Uwe Kleine-König <uwe@kleine-koenig.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/rtc/rtc-s35390a.c |   14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/drivers/rtc/rtc-s35390a.c
++++ b/drivers/rtc/rtc-s35390a.c
+@@ -267,6 +267,20 @@ static int s35390a_read_alarm(struct i2c
+       char buf[3], sts;
+       int i, err;
++      /*
++       * initialize all members to -1 to signal the core that they are not
++       * defined by the hardware.
++       */
++      alm->time.tm_sec = -1;
++      alm->time.tm_min = -1;
++      alm->time.tm_hour = -1;
++      alm->time.tm_mday = -1;
++      alm->time.tm_mon = -1;
++      alm->time.tm_year = -1;
++      alm->time.tm_wday = -1;
++      alm->time.tm_yday = -1;
++      alm->time.tm_isdst = -1;
++
+       err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
+       if (err < 0)
+               return err;
index dbe3d4f5d779ae9f6383dfda586ee98a624b9fee..5b041565e9e8032344ca8104ce98adbfd63d5030 100644 (file)
@@ -14,3 +14,12 @@ usb-fix-linked-list-corruption-in-rh_call_control.patch
 kvm-x86-clear-bus-pointer-when-destroyed.patch
 drm-radeon-override-fpfn-for-all-vram-placements-in-radeon_evict_flags.patch
 mm-hugetlb-use-pte_present-instead-of-pmd_present-in-follow_huge_pmd.patch
+mips-lantiq-fix-cascaded-irq-setup.patch
+rtc-s35390a-fix-reading-out-alarm.patch
+rtc-s35390a-make-sure-all-members-in-the-output-are-set.patch
+rtc-s35390a-implement-reset-routine-as-suggested-by-the-reference.patch
+rtc-s35390a-improve-irq-handling.patch
+kvm-kvm_io_bus_unregister_dev-should-never-fail.patch
+power-reset-at91-poweroff-timely-shutdown-lpddr-memories.patch
+blk-improve-order-of-bio-handling-in-generic_make_request.patch
+blk-ensure-users-for-current-bio_list-can-see-the-full-list.patch