Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apple NVMe low-power self-refresh mode #133

Open
07151129 opened this issue Jan 20, 2020 · 3 comments
Open

Apple NVMe low-power self-refresh mode #133

07151129 opened this issue Jan 20, 2020 · 3 comments

Comments

@07151129
Copy link

07151129 commented Jan 20, 2020

Some Apple NVMe controllers support low-power self-refresh mode, LPSR. The following information describes the usage of LPSR by IONVMeFamily. Note that it is not derived from any Apple documentation and may be inaccurate. In addition to LPSR, there's also QoS with power budgets features, which is not considered here.

ACPI property "nvme-self-refresh" for the PCI controller indicates whether LPSR is supported for
that device. It appears that LPSR is not supported by S3ELab.

LPSR is entered when the controller has been idle for some time. The idleness period is determined
by the LPSR counter. Let lpsrCount denote the current LPSR counter value, lpsrTimeout the idle
timer period in seconds. Then, whenever the timer expires, the values are updated as follows:

if (lpsrCount >= 9500000) {
    lpsrTimeout = 0; // Disable timer
} else {
    if (RunningOnExternalPower)
        lpsrTimeout = 15;
    else if (lpsrCount <= 6999999)
        lpsrTimeout = 3;
    else if (lpsrCount <= 7999999)
        lpsrTimeout = 5;
    else
        lpsrTimeout = 8;
}

setIdleTimerPeriod(lpsrTimeout);

LPSR is prohibited in ACPI S3, S4 states if ACPI property for the controller
nvme-LPSR-during-S3-S4 != 1.

Value lpsrCount is initialised whenever the Identify command has been completed for the
controller. In order to fetch lpsrCount, the following command is used:

command.features.opcode = 0xc2; // DebugServiceRead
command.features.dword12 = 0;
command.features.dword13 = 848;

lpsrCount = IssueCommand(command) << 32;

command.features.dword13 = 849;
lpsrCount |= IssueCommand(command);

When the timer expires, LPSR entry is initiated:

  1. lpsrCount is incremented.
  2. Submission and completion queues are frozen, and the shutdown notification is sent by writing
    0b11 to CC.SHN controller register.
  3. CSTS is then polled to ensure completion of shutdown.
  4. ACPI device "_PS3" or "_PS0" object is evaluated, respectively when entering or exiting LPSR.

For S3X, command with opcode 0xcc is sent (PrepareForShutdown) before LPSR entry.

Note that for LPSR the reserved bit of CC.SHN is used. Otherwise, for a normal shutdown, CC.SHN
is set to 0b01.

IONVMeFamily hardcodes the response timeout for the above procedure to be 30 s for S3ELab, 60 s for S3X, and 5 s otherwise.

There is a public patent, describing parts of LPSR.

@leifliddy
Copy link

leifliddy commented Jan 21, 2020

There was some discussion regarding LPSR and how it was needed to put the NVMecontroller in sleep mode. However, no solution was ever found. It's believed that this is the reason that suspend/resume does not work on the macbook 12-inch models (8,1 + 9,1 and 10,1)

cb22/macbook12-spi-driver#2
cb22/macbook12-spi-driver#30

@07151129
Copy link
Author

07151129 commented Jan 21, 2020

@leifliddy you're right about command 0xcc being issued before shutdown, but it is only needed for S3X. I don't believe that LPSR is required for NVM shutdown in general, though.

@leifliddy
Copy link

leifliddy commented Feb 4, 2020

@07151129 I'm not a kernel developer and don't know enough about acpi or nvme to know to implement that. There is however, a lot of interest in getting resume/suspend working on the
Macbook 12 inch models: 8,1 + 9,1 + 10,1 and Macbook Pro models: 13,1 and 14,1
It sounds like this nvme LPSR problem is at the heart of the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants