diff options
author | Solomon Peachy <pizza@shaftnet.org> | 2024-04-11 11:54:02 -0400 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2024-04-22 15:46:30 -0400 |
commit | 886060475e25d04b9eb1753dbbaea0db8b78a0d4 (patch) | |
tree | 472b29d2dbb994cbfa1addac945f9043796614c6 /firmware/export/ata.h | |
parent | 6cbcde13b9eb10b50724f956ba5696fc82ed7cf4 (diff) | |
download | rockbox-886060475e25d04b9eb1753dbbaea0db8b78a0d4.tar.gz rockbox-886060475e25d04b9eb1753dbbaea0db8b78a0d4.zip |
ata: Heavily rework sleep and poweroff logic
* Use of ata_disk_can_poweroff() was inverted, resulting in SATA SSDs
getting powered off but leaving _everything_ else on, including spinning
rust!
* Replace the can_poweroff() heuristic with a test for the mandatory
ATA power mgmt feature flag. Notably, the CF->SD adapters don't claim
to support this!
* Eliminate duplicated tests in sleep code
* Wrap all poweroff-related code with HAVE_ATA_POWER_OFF
* Don't ever use SLEEP command, only STANDBY_IMMEDIATE
* Gate call to STANDBY_IMMEDIATE behind a can_poweroff() test
* Prefer FLUSH_CACHE_EXT to FLUSH_CACHE where available.
* Improve SSD detection heuristics to any of these:
* Explicltly identifies as SSD (covers newer CF and SATA)
* TRIM support
* CFA compliant AND (CF level 0 OR high speed support)
* Report SSD detection in debug menu
Change-Id: I7fcb83b6d6eabddc11c64326a573b08ab85412b5
Diffstat (limited to 'firmware/export/ata.h')
-rw-r--r-- | firmware/export/ata.h | 52 |
1 files changed, 50 insertions, 2 deletions
diff --git a/firmware/export/ata.h b/firmware/export/ata.h index 7c7c60e898..62c9467643 100644 --- a/firmware/export/ata.h +++ b/firmware/export/ata.h | |||
@@ -166,10 +166,58 @@ long ata_last_disk_activity(void); | |||
166 | int ata_spinup_time(void); /* ticks */ | 166 | int ata_spinup_time(void); /* ticks */ |
167 | 167 | ||
168 | /* Returns 1 if drive is solid-state */ | 168 | /* Returns 1 if drive is solid-state */ |
169 | int ata_disk_isssd(void); | 169 | static inline int ata_disk_isssd(void) |
170 | { | ||
171 | unsigned short *identify_info = ata_get_identify(); | ||
172 | /* | ||
173 | Offset 217 is "Nominal Rotation rate" | ||
174 | 0x0000 == Not reported | ||
175 | 0x0001 == Solid State | ||
176 | 0x0401 -> 0xffe == RPM | ||
177 | All others reserved | ||
178 | |||
179 | Some CF cards return 0x0100 (ie byteswapped 0x0001) so accept either. | ||
180 | However, this is a relatively recent change, and we can't rely on it, | ||
181 | especially for the FC1307A CF->SD adapters! | ||
182 | |||
183 | Offset 168 is "Nominal Form Factor" | ||
184 | all values >= 0x06 are guaranteed to be Solid State (mSATA, m.2, etc) | ||
185 | |||
186 | Offset 169 b0 is set to show device implements TRIM. | ||
187 | |||
188 | Unreliable mechanisms: | ||
189 | |||
190 | Offset 83 b2 shows device implements CFA commands. | ||
191 | However microdrives pose a problem as they support CFA but are not | ||
192 | SSD. | ||
193 | |||
194 | Offset 160 b15 indicates support for CF+ power level 1, if not set | ||
195 | then device is standard flash CF. However this is not foolproof | ||
196 | as newer CF cards may support it for extra performance. | ||
197 | |||
198 | Offset 163 shows CF Advanced timing modes; microdrive seems to | ||
199 | report 0, but all others (including iFlash) report higher! | ||
200 | |||
201 | So if device support CFA _AND_ reports higher speeds modes, it is SSD. | ||
202 | |||
203 | */ | ||
204 | return ( (identify_info[217] == 0x0001 || identify_info[217] == 0x0100) /* "Solid state" rotational rate */ | ||
205 | || ((identify_info[168] & 0x0f) >= 0x06) /* Explicit SSD form factors */ | ||
206 | || (identify_info[169] & (1<<0)) /* TRIM supported */ | ||
207 | || ((identify_info[83] & (1<<2)) && /* CFA compliant */ | ||
208 | (((identify_info[160] & (1<<15)) == 0) || /* CF level 0 */ | ||
209 | (identify_info[163] > 0))) /* Advanced timing modes */ | ||
210 | ); | ||
211 | } | ||
170 | 212 | ||
171 | /* Returns 1 if the drive can be powered off safely */ | 213 | /* Returns 1 if the drive can be powered off safely */ |
172 | int ata_disk_can_poweroff(void); | 214 | static inline int ata_disk_can_poweroff(void) |
215 | { | ||
216 | unsigned short *identify_info = ata_get_identify(); | ||
217 | /* Only devices that claim to support PM can be safely powered off. | ||
218 | This notably excludes the various SD adapters! */ | ||
219 | return (identify_info[82] & (1<<3) && identify_info[85] & (1<<3)); | ||
220 | } | ||
173 | 221 | ||
174 | #ifdef HAVE_ATA_DMA | 222 | #ifdef HAVE_ATA_DMA |
175 | /* Returns current DMA mode */ | 223 | /* Returns current DMA mode */ |