Download raw body.
[PATCH] ahci(4) Do not write to read-only registers
Hi,
This patch removes the code that likely never worked as intended. I came
across this while trying to understand how the AHCI driver works.
The commit that introduced the code says "Save BIOS configured
parameters over reset. Always enable staggered spin-up.", but the code
obviously has a bug that clears all but one bit in the capabilities
register. If that had ever worked, it would have broken things.
So I checked the AHCI spec [1], and it says all capabilities bits are
read-only (section 3.1.1), but some are "loaded by the BIOS prior to OS
initialization". Just in case, I checked that it has always been the
case since the spec version 0.95 that was contemporary to the commit.
The same applies to the "ports implemented" register (section 3.1.4).
I have three different controllers to play with: Intel ADL-N AHCI,
JMicron JMB585 and ASMedia ASM1166.
It is not relevant to this patch, but just for visibility, I have a
timeout problem with the latter two that I am trying to investigate, but
the problem occurs at a later stage (and does not occur in Linux and
FreeBSD). I believe this is the same problem as [2].
So I tested the controllers, and they all follow the spec, that is, I
can change register values in the BIOS settings, but after the system
boots up and the registers are loaded by the BIOS, it is not possible to
change them programmatically.
I used the following code to test them:
---
printf("!!! caps to write: 0x%x\n", cap);
ahci_write(sc, AHCI_REG_CAP, cap);
delay(1000000);
cap = ahci_read(sc, AHCI_REG_CAP);
printf("!!! caps after restore: 0x%x\n", cap);
pi = 1;
printf("!!! ports implemented to write: 0x%x\n", pi);
ahci_write(sc, AHCI_REG_PI, pi);
delay(1000000);
pi = ahci_read(sc, AHCI_REG_PI);
printf("!!! ports implemented after restore: 0x%x\n", pi);
---
The results are below:
Intel ADL-N AHCI
!!! caps to write: 0x8000000
!!! caps after restore: 0xe534ff00
!!! ports implemented to write: 0x1
!!! ports implemented after restore: 0x0 (prior, I disabled the single
port in the BIOS settings)
JMicron JMB585
!!! caps to write: 0x8000000
!!! caps after restore: 0xef33ff84
!!! ports implemented to write: 0x1
!!! ports implemented after restore: 0x1f
ASMedia ASM1166
!!! caps to write: 0x8000000
!!! caps after restore: 0xee349f3f
!!! ports implemented to write: 0x1
!!! ports implemented after restore: 0xffffff3f
As can be seen, the read-only registers never store the written values.
[1] https://www.intel.com/content/www/us/en/io/serial-ata/serial-ata-ahci-spec-rev1-3-1.html
[2] https://marc.info/?l=openbsd-misc&m=172207535832024&w=2
Regards,
Pavel Knoblokh
Index: sys/dev/ic/ahci.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/ahci.c,v
diff -u -p -u -p -r1.41 ahci.c
--- sys/dev/ic/ahci.c 28 May 2024 01:37:53 -0000 1.41
+++ sys/dev/ic/ahci.c 2 Aug 2024 13:29:04 -0000
@@ -397,18 +397,12 @@ ahci_activate(struct device *self, int a
int
ahci_init(struct ahci_softc *sc)
{
- u_int32_t reg, cap, pi;
+ u_int32_t reg;
const char *revision;
DPRINTF(AHCI_D_VERBOSE, " GHC 0x%b", ahci_read(sc, AHCI_REG_GHC),
AHCI_FMT_GHC);
- /* save BIOS initialised parameters, enable staggered spin up */
- cap = ahci_read(sc, AHCI_REG_CAP);
- cap &= AHCI_REG_CAP_SMPS;
- cap |= AHCI_REG_CAP_SSS;
- pi = ahci_read(sc, AHCI_REG_PI);
-
if (ISSET(AHCI_REG_GHC_AE, ahci_read(sc, AHCI_REG_GHC))) {
/* reset the controller */
ahci_write(sc, AHCI_REG_GHC, AHCI_REG_GHC_HR);
@@ -421,10 +415,6 @@ ahci_init(struct ahci_softc *sc)
/* enable ahci (global interrupts disabled) */
ahci_write(sc, AHCI_REG_GHC, AHCI_REG_GHC_AE);
-
- /* restore parameters */
- ahci_write(sc, AHCI_REG_CAP, cap);
- ahci_write(sc, AHCI_REG_PI, pi);
/* check the revision */
reg = ahci_read(sc, AHCI_REG_VS);
[PATCH] ahci(4) Do not write to read-only registers