[personal profile] mjg59
I wrote about Thunderbolt on Apple hardware a while ago. Since then Andreas Noever has somehow managed to write a working Thunderbolt stack, which awesome! But there was still the problem I mentioned of the device not appearing unless you passed acpi_osi="Darwin" on the kernel command line, and a further problem that if you suspended and then resumed it vanished again.

The ACPI _OSI interface is a mechanism for the firmware to determine the OS that the system is running. It turns out that this works fine for operating systems that export fairly static interfaces (Windows, which adds a new _OSI per release) and poorly for operating systems that don't even guarantee any kind of interface stability in security releases (Linux, which claimed to be "Linux" regardless of version until we turned that off). OS X claims to be Darwin and nothing else. As I mentioned before, claiming to be Darwin in addition to Windows was enough to get the Thunderbolt hardware to stay alive after boot, but it wasn't enough to get it powered up again after suspend.

It turns out that there's two sections of ACPI code where this Mac checks _OSI. The first is something like:

if (_OSI("Darwin")) Store 0x2710 OSYS; else if(_OSI("Windows 2009") Store 0x7D9 OSYS; else…

ie, if the OS claims to be Darwin, all other strings are ignored. This is called from \_SB._INI(), which is the first ACPI method the kernel executes. The check for whether to power down the Thunderbolt controller occurs after this and then works correctly.

The second version is less helpful. It's more like:

if (_OSI("Darwin")) Store 0x2710 OSYS; if (_OSI("Windows 2009")) Store 0x7D9 OSYS; if…

ie, if the OS claims to be both Darwin and Windows 2009 (which Linux will if you pass acpi_osi="Darwin"), the OSYS variable gets set to the Windows 2009 value. This version gets called during PCI initialisation, and once it's run all the other Thunderbolt ACPI calls stop doing anything and the controller gets powered down after suspend/resume. That can be fixed easily enough by special casing Darwin. If the platform requests Darwin before anything else, we'll just stop claiming to be Windows.

Phew. Working Thunderbolt! (Well, almost - _OSC fails and so we disable PCIe hotplug, but that's easy to work around). But boo, no working battery. Apple do something very strange with their ACPI battery interface. If you're running anything that doesn't claim to be Darwin, Apple expose an ACPI Control Method battery. Control Method interfaces abstract the complexity away into either ACPI bytecode or system management traps - the OS simply calls an ACPI method, magic happens and it gets an answer back. If you claim to be Darwin, Apple remove that interface and instead expose the raw ACPI Smart Battery System interface. This provides an i2c bus over which the OS must then speak the Smart Battery System protocol, allowing it to directly communicate with the battery.

Linux has support for this, but it seems that this wasn't working so well and hadn't been for years. Loading the driver resulted in modprobe hanging until a timeout occurred, and most accesses to the battery would (a) take forever and (b) probably fail. It also had the nasty habit of breaking suspend and resume, which was unfortunate since getting Thunderbolt working over suspend and resume was the whole point of this exercise.

So. I modified the sbs driver to dump every command it sent over the i2c bus and every response it got. Pretty quickly I found that the failing operation was a write - specifically, a write used to select which battery should be connected to the bus. Interestingly, Apple implemented their Control Method interface by just using ACPI bytecode to speak the SBS protocol. Looking at the code in question showed that they never issued any writes, and the battery worked fine anyway. So why were we writing? SBS provides a command to tell you the current state of the battery subsystem, including which battery (out of a maximum of 4) is currently selected. Unsurprisingly, calling this showed that the battery we wanted to talk to was already selected. We then asked the SBS manager to select it anyway, and the manager promptly fell off the bus and stopped talking to us. In keeping with the maxim of "If hardware complains when we do something, and if we don't really need to do that, don't do that", this makes it work.

Working Thunderbolt and working battery. We're even getting close to getting switchable GPU support working reasonably, which is probably just going to involve rewriting the entirety of fbcon or something similarly amusing.

Date: 2014-03-12 11:48 pm (UTC)
From: [personal profile] glyf
I feel a bit bad that it is *completely* beyond my capabilities to do anything but sit back and cheer for this, but cheering I am. It sounds like it might actually be a reasonable choice to boot Linux on an rMBP in a year or two!


Date: 2014-03-13 10:53 am (UTC)
From: (Anonymous)
Helly MJ, I'll help you getting the doc you need, I am going to send an email to Steve Jobs I am sure he will be of help

Interesting read

Date: 2014-03-13 01:33 pm (UTC)
From: (Anonymous)
ACPI can seem like a complicated subject for mere morals like me whose interaction with it is usually little more than passing an acpi_osi= line on problematic notebooks but found this this a very approachable and well explained article.

Appreciate you taking the time to document your experiences and particularly for your tireless efforts at reverse engineering the hardware.

Although i was led here from hackernews I've just recently bought a s/h MBPr so these advances are of particular interest and would like to echo the thoughts of the other commenters here.

Thank you

Date: 2014-03-13 01:45 pm (UTC)
From: (Anonymous)
They support FOUR batteries? That's interesting, the last Apple laptop to support more than one battery was the Powerbook G3 (Pismo) introduced in 2000 and discontinued in 2001. The SystemUIServer supported displaying the battery status in the menu bar up to and including MacOS X 10.4.11. Support for this was pulled from SystemUIServer starting with 10.5 (released in 2007) since this was the first OS version to no longer officially support the Pismo.

ARM SBSA, _OSI and Linux

Date: 2014-03-13 10:28 pm (UTC)
From: [identity profile] yuhong.wordpress.com
I hope that Linux on ARM SBSA will set _OSI(Windows) to false.

Date: 2014-03-14 12:23 am (UTC)
shortcipher: (LAN party)
From: [personal profile] shortcipher
"a write used to select which battery should be connected to the bus" - I have a bunch of zeros coming out of EC for battery information (LP#1289748) and this makes me wonder if I'm lacking such a select operation somewhere. DSDT doesn't mention any ACPI000x devices except AC, so nothing for the SBS driver to talk to? Although there is an SBUS device... I'm a bit lost here, tbh.

Working hotplug?

Date: 2014-03-16 02:13 pm (UTC)
From: (Anonymous)
Do yo have thunderbolt hotplug working? If so, can you post the exact list of patches needed to get it working?

Time frame

Date: 2014-04-03 08:46 pm (UTC)
From: (Anonymous)
Any expectations on which kernel release gets these patches (thunderbolt with battery working)?

thanks and applause

Date: 2014-07-03 08:29 pm (UTC)
From: (Anonymous)
I'm using a macbook pro 15" with debian linux. Thanks for all your hard work I appreciate it.

Wonder if anyone will write a driver for the PCI-e webcam too. That's the last piece missing from my jigsaw.


Matthew Garrett

About Matthew

Power management, mobile and firmware developer on Linux. Security developer at Google. Ex-biologist. @mjg59 on Twitter. Content here should not be interpreted as the opinion of my employer.

Page Summary

Expand Cut Tags

No cut tags