aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2018-04-10 07:49:32 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2018-04-24 23:24:13 -0400
commit682e6b4da5cbe8e9a53f979a58c2a9d7dc997175 (patch)
tree25b4eb837ae2f09cfd0ba5a54dc975fa0cfcaa92 /drivers
parent75ecfb49516c53da00c57b9efe48fa3f5504a791 (diff)
rtc: opal: Fix OPAL RTC driver OPAL_BUSY loops
The OPAL RTC driver does not sleep in case it gets OPAL_BUSY or OPAL_BUSY_EVENT from firmware, which causes large scheduling latencies, up to 50 seconds have been observed here when RTC stops responding (BMC reboot can do it). Fix this by converting it to the standard form OPAL_BUSY loop that sleeps. Fixes: 628daa8d5abf ("powerpc/powernv: Add RTC and NVRAM support plus RTAS fallbacks") Cc: stable@vger.kernel.org # v3.2+ Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Acked-by: Alexandre Belloni <alexandre.belloni@bootlin.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/rtc/rtc-opal.c37
1 files changed, 23 insertions, 14 deletions
diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c
index 304e891e35fc..60f2250fd96b 100644
--- a/drivers/rtc/rtc-opal.c
+++ b/drivers/rtc/rtc-opal.c
@@ -57,7 +57,7 @@ static void tm_to_opal(struct rtc_time *tm, u32 *y_m_d, u64 *h_m_s_ms)
57 57
58static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm) 58static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm)
59{ 59{
60 long rc = OPAL_BUSY; 60 s64 rc = OPAL_BUSY;
61 int retries = 10; 61 int retries = 10;
62 u32 y_m_d; 62 u32 y_m_d;
63 u64 h_m_s_ms; 63 u64 h_m_s_ms;
@@ -66,13 +66,17 @@ static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm)
66 66
67 while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { 67 while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
68 rc = opal_rtc_read(&__y_m_d, &__h_m_s_ms); 68 rc = opal_rtc_read(&__y_m_d, &__h_m_s_ms);
69 if (rc == OPAL_BUSY_EVENT) 69 if (rc == OPAL_BUSY_EVENT) {
70 msleep(OPAL_BUSY_DELAY_MS);
70 opal_poll_events(NULL); 71 opal_poll_events(NULL);
71 else if (retries-- && (rc == OPAL_HARDWARE 72 } else if (rc == OPAL_BUSY) {
72 || rc == OPAL_INTERNAL_ERROR)) 73 msleep(OPAL_BUSY_DELAY_MS);
73 msleep(10); 74 } else if (rc == OPAL_HARDWARE || rc == OPAL_INTERNAL_ERROR) {
74 else if (rc != OPAL_BUSY && rc != OPAL_BUSY_EVENT) 75 if (retries--) {
75 break; 76 msleep(10); /* Wait 10ms before retry */
77 rc = OPAL_BUSY; /* go around again */
78 }
79 }
76 } 80 }
77 81
78 if (rc != OPAL_SUCCESS) 82 if (rc != OPAL_SUCCESS)
@@ -87,21 +91,26 @@ static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm)
87 91
88static int opal_set_rtc_time(struct device *dev, struct rtc_time *tm) 92static int opal_set_rtc_time(struct device *dev, struct rtc_time *tm)
89{ 93{
90 long rc = OPAL_BUSY; 94 s64 rc = OPAL_BUSY;
91 int retries = 10; 95 int retries = 10;
92 u32 y_m_d = 0; 96 u32 y_m_d = 0;
93 u64 h_m_s_ms = 0; 97 u64 h_m_s_ms = 0;
94 98
95 tm_to_opal(tm, &y_m_d, &h_m_s_ms); 99 tm_to_opal(tm, &y_m_d, &h_m_s_ms);
100
96 while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { 101 while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
97 rc = opal_rtc_write(y_m_d, h_m_s_ms); 102 rc = opal_rtc_write(y_m_d, h_m_s_ms);
98 if (rc == OPAL_BUSY_EVENT) 103 if (rc == OPAL_BUSY_EVENT) {
104 msleep(OPAL_BUSY_DELAY_MS);
99 opal_poll_events(NULL); 105 opal_poll_events(NULL);
100 else if (retries-- && (rc == OPAL_HARDWARE 106 } else if (rc == OPAL_BUSY) {
101 || rc == OPAL_INTERNAL_ERROR)) 107 msleep(OPAL_BUSY_DELAY_MS);
102 msleep(10); 108 } else if (rc == OPAL_HARDWARE || rc == OPAL_INTERNAL_ERROR) {
103 else if (rc != OPAL_BUSY && rc != OPAL_BUSY_EVENT) 109 if (retries--) {
104 break; 110 msleep(10); /* Wait 10ms before retry */
111 rc = OPAL_BUSY; /* go around again */
112 }
113 }
105 } 114 }
106 115
107 return rc == OPAL_SUCCESS ? 0 : -EIO; 116 return rc == OPAL_SUCCESS ? 0 : -EIO;