[linux] 01/01: Cherry pick and backport patches for rtc-s35390a from next

debian-kernel at lists.debian.org debian-kernel at lists.debian.org
Tue Jul 12 20:35:49 UTC 2016


This is an automated email from the git hooks/post-receive script.

ukleinek pushed a commit to branch ukleinek/jessie
in repository linux.

commit 1d69dac66c315a290fb61c5f400e056e8d01fe50
Author: Uwe Kleine-König <ukleinek at debian.org>
Date:   Tue Jul 12 22:30:36 2016 +0200

    Cherry pick and backport patches for rtc-s35390a from next
    
    This fixes shutting down some QNAP NAS devices after being waked up by
    the rtc.
---
 debian/changelog                                   |   6 +
 .../all/rtc-s35390a-fix-reading-out-alarm.patch    |  94 ++++++++++++++++
 ...-implement-reset-routine-as-suggested-by-.patch | 125 +++++++++++++++++++++
 .../all/rtc-s35390a-improve-irq-handling.patch     | 118 +++++++++++++++++++
 .../all/rtc-s35390a-initialize-all-fields.patch    |  40 +++++++
 debian/patches/series                              |   4 +
 6 files changed, 387 insertions(+)

diff --git a/debian/changelog b/debian/changelog
index cdcdc7b..c4c6aa7 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+linux (3.16.36-2) UNRELEASED; urgency=medium
+
+  * backport patches to rtc-s35390a to fix alarm handling (Closes: #794266)
+
+ -- Uwe Kleine-König <ukleinek at debian.org>  Tue, 12 Jul 2016 22:15:44 +0200
+
 linux (3.16.36-1) jessie; urgency=medium
 
   * New upstream stable update:
diff --git a/debian/patches/bugfix/all/rtc-s35390a-fix-reading-out-alarm.patch b/debian/patches/bugfix/all/rtc-s35390a-fix-reading-out-alarm.patch
new file mode 100644
index 0000000..29f1dfa
--- /dev/null
+++ b/debian/patches/bugfix/all/rtc-s35390a-fix-reading-out-alarm.patch
@@ -0,0 +1,94 @@
+From: Uwe Kleine-König <uwe at kleine-koenig.org>
+Date: Sat, 2 Jul 2016 17:28:08 +0200
+Subject: [PATCH] rtc: s35390a: fix reading out alarm
+Origin: https://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/commit/?id=ee82c046c1031af95e8c24dda072e04c565d4247
+
+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 at kleine-koenig.org>
+Signed-off-by: Alexandre Belloni <alexandre.belloni at free-electrons.com>
+---
+ drivers/rtc/rtc-s35390a.c | 40 +++++++++++++++++++++++++++++++---------
+ 1 file changed, 31 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c
+index f40afdd0e5f5..6507a01cf9ad 100644
+--- a/drivers/rtc/rtc-s35390a.c
++++ b/drivers/rtc/rtc-s35390a.c
+@@ -242,6 +242,8 @@ static int s35390a_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alm)
+ 
+ 	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_client *client, struct rtc_wkalrm *alm)
+ 	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,
+-- 
+2.8.1
+
diff --git a/debian/patches/bugfix/all/rtc-s35390a-implement-reset-routine-as-suggested-by-.patch b/debian/patches/bugfix/all/rtc-s35390a-implement-reset-routine-as-suggested-by-.patch
new file mode 100644
index 0000000..2b8439d
--- /dev/null
+++ b/debian/patches/bugfix/all/rtc-s35390a-implement-reset-routine-as-suggested-by-.patch
@@ -0,0 +1,125 @@
+From: Uwe Kleine-König <uwe at kleine-koenig.org>
+Date: Sat, 2 Jul 2016 17:28:09 +0200
+Subject: [PATCH] rtc: s35390a: implement reset routine as suggested by the
+ reference
+Origin: https://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/commit/?id=0af8a35b6ab4ba000d8f18748bb621c8ed5e7827
+
+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 at kleine-koenig.org>
+Signed-off-by: Alexandre Belloni <alexandre.belloni at free-electrons.com>
+---
+ drivers/rtc/rtc-s35390a.c | 65 +++++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 55 insertions(+), 10 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 @@
+ 	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 @@
+ 	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 @@
+ 		}
+ 	}
+ 
+-	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/debian/patches/bugfix/all/rtc-s35390a-improve-irq-handling.patch b/debian/patches/bugfix/all/rtc-s35390a-improve-irq-handling.patch
new file mode 100644
index 0000000..6badf83
--- /dev/null
+++ b/debian/patches/bugfix/all/rtc-s35390a-improve-irq-handling.patch
@@ -0,0 +1,118 @@
+From: Uwe Kleine-König <uwe at kleine-koenig.org>
+Date: Sat, 2 Jul 2016 17:28:10 +0200
+Subject: [PATCH] rtc: s35390a: improve irq handling
+Origin: https://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/commit/?id=998dd84e542720cf02cbe9ea002de3850df32996
+
+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 at kleine-koenig.org>
+Signed-off-by: Alexandre Belloni <alexandre.belloni at free-electrons.com>
+---
+ 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 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 @@
+ 		}
+ 	}
+ 
+-	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 @@
+ 		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/debian/patches/bugfix/all/rtc-s35390a-initialize-all-fields.patch b/debian/patches/bugfix/all/rtc-s35390a-initialize-all-fields.patch
new file mode 100644
index 0000000..70f8061
--- /dev/null
+++ b/debian/patches/bugfix/all/rtc-s35390a-initialize-all-fields.patch
@@ -0,0 +1,40 @@
+From: Uwe Kleine-König <uwe at kleine-koenig.org>
+Subject: [PATCH] rtc: s35390a: make sure all members in the output are set
+Forwarded: not-needed
+
+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 at kleine-koenig.org>
+---
+--- a/drivers/rtc/rtc-s35390a.c
++++ b/drivers/rtc/rtc-s35390a.c
+@@ -267,6 +267,20 @@
+ 	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;
diff --git a/debian/patches/series b/debian/patches/series
index 2341f9c..1b4788c 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -236,6 +236,10 @@ bugfix/all/ip_vti-ip6_vti-do-not-touch-skb-mark-on-xmit.patch
 bugfix/all/xfrm-override-skb-mark-with-tunnel-parm.i_key-in-xfr.patch
 bugfix/all/ip_vti-ip6_vti-preserve-skb-mark-after-rcv_cb-call.patch
 bugfix/all/revert-usb-hub-do-not-clear-bos-field-during-reset-d.patch
+bugfix/all/rtc-s35390a-fix-reading-out-alarm.patch
+bugfix/all/rtc-s35390a-initialize-all-fields.patch
+bugfix/all/rtc-s35390a-implement-reset-routine-as-suggested-by-.patch
+bugfix/all/rtc-s35390a-improve-irq-handling.patch
 
 # memfd_create() & kdbus backport
 features/all/kdbus/mm-allow-drivers-to-prevent-new-writable-mappings.patch

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/kernel/linux.git



More information about the Kernel-svn-changes mailing list