summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSolomon Peachy <pizza@shaftnet.org>2021-03-12 09:37:36 -0500
committerSolomon Peachy <pizza@shaftnet.org>2021-03-12 10:04:52 -0500
commit2743bde09b970e44af1c55a0750790146697e28a (patch)
treeb6335031d965d1971c118fb39e8c7f10172dc0f9
parent04c29984cecd4e971f7d60226b96b83872488849 (diff)
downloadrockbox-2743bde09b970e44af1c55a0750790146697e28a.tar.gz
rockbox-2743bde09b970e44af1c55a0750790146697e28a.zip
ATA: Increase delay to power-off when device doesn't support ATA SLEEP
The storage subsystem aggressively issues SLEEPNOW events when idle and power off happened a fixed 2s later. This turns out to not be enough time for FC1307A (eg iFlash) adapters to flush outstanding writes. So, when we detect a lack of PM support, increase the poweroff delay to 5 seconds to compensate for not being able to issue the ATA SLEEP command. Hopefully this is enough time. If not, we will have to re-disable PM entirely when we detect these popular adapters. Thankfully that is now just an #ifdef away. Change-Id: I4112b9acb965973d81f70483bd9d595461c7301c
-rw-r--r--firmware/drivers/ata.c46
1 files changed, 42 insertions, 4 deletions
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c
index d2e1ad4a22..3514511270 100644
--- a/firmware/drivers/ata.c
+++ b/firmware/drivers/ata.c
@@ -18,6 +18,9 @@
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21
22//#define LOGF_ENABLE
23
21#include <stdbool.h> 24#include <stdbool.h>
22#include <inttypes.h> 25#include <inttypes.h>
23#include "led.h" 26#include "led.h"
@@ -31,6 +34,15 @@
31#include "ata-defines.h" 34#include "ata-defines.h"
32#include "fs_defines.h" 35#include "fs_defines.h"
33#include "storage.h" 36#include "storage.h"
37#include "logf.h"
38
39/* The FC1307A ATA->SD chipset (used by the common iFlash adapters)
40 doesn't support mandatory ATA power management commands. Unfortunately
41 simply gating off the SLEEP command isn't sufficient; we need to
42 disable advanced powersaving entirely because otherwise we might
43 kill power before the device has finished flusing writes.
44*/
45//#define FC1307A_WORKAROUND
34 46
35#define SELECT_DEVICE1 0x10 47#define SELECT_DEVICE1 0x10
36#define SELECT_LBA 0x40 48#define SELECT_LBA 0x40
@@ -63,6 +75,7 @@
63 75
64#ifdef HAVE_ATA_POWER_OFF 76#ifdef HAVE_ATA_POWER_OFF
65#define ATA_POWER_OFF_TIMEOUT 2*HZ 77#define ATA_POWER_OFF_TIMEOUT 2*HZ
78#define ATA_POWER_OFF_TIMEOUT_NOPM 5*HZ
66#endif 79#endif
67 80
68#if defined(HAVE_USBSTACK) 81#if defined(HAVE_USBSTACK)
@@ -147,7 +160,12 @@ static inline bool ata_sleep_timed_out(void)
147static inline void schedule_ata_power_off(void) 160static inline void schedule_ata_power_off(void)
148{ 161{
149#ifdef HAVE_ATA_POWER_OFF 162#ifdef HAVE_ATA_POWER_OFF
150 power_off_tick = current_tick + ATA_POWER_OFF_TIMEOUT; 163 power_off_tick = current_tick;
164 /* If our device doesn't support SLEEP give a bit more time to flush */
165 if (!(identify_info[82] & (1 << 3)))
166 power_off_tick += ATA_POWER_OFF_TIMEOUT_NOPM;
167 else
168 power_off_tick += ATA_POWER_OFF_TIMEOUT;
151#endif 169#endif
152} 170}
153 171
@@ -202,6 +220,7 @@ static ICODE_ATTR int wait_for_rdy(void)
202 220
203static int ata_perform_wakeup(int state) 221static int ata_perform_wakeup(int state)
204{ 222{
223 logf("ata WAKE %ld", current_tick);
205 if (state > ATA_OFF) { 224 if (state > ATA_OFF) {
206 if (perform_soft_reset()) { 225 if (perform_soft_reset()) {
207 return -1; 226 return -1;
@@ -222,13 +241,12 @@ static int ata_perform_sleep(void)
222{ 241{
223 /* Don't issue the sleep command if the device 242 /* Don't issue the sleep command if the device
224 doesn't support (mandatory!) ATA power management commands! 243 doesn't support (mandatory!) ATA power management commands!
225
226 The FC1307A ATA->SD chipset (used by the common iFlash adapters)
227 is the only known offender, and will eat your data if told to sleep.
228 */ 244 */
229 if (!(identify_info[82] & (1 << 3))) 245 if (!(identify_info[82] & (1 << 3)))
230 return 0; 246 return 0;
231 247
248 logf("ata SLEEP %ld", current_tick);
249
232 ATA_OUT8(ATA_SELECT, ata_device); 250 ATA_OUT8(ATA_SELECT, ata_device);
233 251
234 if(!wait_for_rdy()) { 252 if(!wait_for_rdy()) {
@@ -818,12 +836,26 @@ void ata_spindown(int seconds)
818 836
819bool ata_disk_is_active(void) 837bool ata_disk_is_active(void)
820{ 838{
839#ifdef FC1307A_WORKAROUND
840 /* "active" == "spinning" in this context.
841 without power management this becomes moot */
842 if (!(identify_info[82] & (1 << 3)))
843 return false;
844#endif
845
821 return ata_state >= ATA_SPINUP; 846 return ata_state >= ATA_SPINUP;
822} 847}
823 848
824void ata_sleepnow(void) 849void ata_sleepnow(void)
825{ 850{
851#ifdef FC1307A_WORKAROUND
852 /* Completely disable all power management */
853 if (!(identify_info[82] & (1 << 3)))
854 return;
855#endif
856
826 if (ata_state >= ATA_SPINUP) { 857 if (ata_state >= ATA_SPINUP) {
858 logf("ata SLEEPNOW %ld", current_tick);
827 mutex_lock(&ata_mtx); 859 mutex_lock(&ata_mtx);
828 if (ata_state == ATA_ON) { 860 if (ata_state == ATA_ON) {
829 if (!ata_perform_sleep()) { 861 if (!ata_perform_sleep()) {
@@ -904,6 +936,8 @@ static int perform_soft_reset(void)
904 int ret; 936 int ret;
905 int retry_count; 937 int retry_count;
906 938
939 logf("ata SOFT RESET %ld", current_tick);
940
907 ATA_OUT8(ATA_SELECT, SELECT_LBA | ata_device ); 941 ATA_OUT8(ATA_SELECT, SELECT_LBA | ata_device );
908 ATA_OUT8(ATA_CONTROL, CONTROL_nIEN|CONTROL_SRST ); 942 ATA_OUT8(ATA_CONTROL, CONTROL_nIEN|CONTROL_SRST );
909 sleep(1); /* >= 5us */ 943 sleep(1); /* >= 5us */
@@ -960,6 +994,8 @@ static int ata_power_on(void)
960{ 994{
961 int rc; 995 int rc;
962 996
997 logf("ata ON %ld", current_tick);
998
963 ide_power_enable(true); 999 ide_power_enable(true);
964 sleep(HZ/4); /* allow voltage to build up */ 1000 sleep(HZ/4); /* allow voltage to build up */
965 1001
@@ -1381,6 +1417,7 @@ int ata_event(long id, intptr_t data)
1381 if (state == ATA_SLEEPING && ata_power_off_timed_out()) { 1417 if (state == ATA_SLEEPING && ata_power_off_timed_out()) {
1382 mutex_lock(&ata_mtx); 1418 mutex_lock(&ata_mtx);
1383 if (ata_state == ATA_SLEEPING) { 1419 if (ata_state == ATA_SLEEPING) {
1420 logf("ata OFF %ld", current_tick);
1384 ide_power_enable(false); 1421 ide_power_enable(false);
1385 ata_state = ATA_OFF; 1422 ata_state = ATA_OFF;
1386 } 1423 }
@@ -1397,6 +1434,7 @@ int ata_event(long id, intptr_t data)
1397 } 1434 }
1398#ifndef USB_NONE 1435#ifndef USB_NONE
1399 else if (id == SYS_USB_CONNECTED) { 1436 else if (id == SYS_USB_CONNECTED) {
1437 logf("deq USB %ld", current_tick);
1400 if (ATA_ACTIVE_IN_USB) { 1438 if (ATA_ACTIVE_IN_USB) {
1401 /* There is no need to force ATA power on */ 1439 /* There is no need to force ATA power on */
1402 STG_EVENT_ASSERT_ACTIVE(STORAGE_ATA); 1440 STG_EVENT_ASSERT_ACTIVE(STORAGE_ATA);