Let's take acpi_osi=! acpi_osi=!Darwin for example.
Initially,
static struct osi_setup_entry
osi_setup_entries[OSI_STRING_ENTRIES_MAX] __initdata = {
{"Module Device", true},
{"Processor Device", true},
{"3.0 _SCP Extensions", true},
{"Processor Aggregator Device", true},
};
since it is a '!', we disable all the vendor strings,
if (*str == '!') {
str++;
if (*str == '\0') {
osi_linux.default_disabling = 1;
return;
}
}
and later in acpi_osi_setup_late,
if (osi_linux.default_disabling) {
status = acpi_update_interfaces(ACPI_DISABLE_ALL_VENDOR_STRINGS);
will disable all the vendor string in acpica, such as Windows 2009, Windows 2012, etc:
static struct acpi_interface_info acpi_default_supported_interfaces[] = {
/* Operating System Vendor Strings */
{"Windows 2000", NULL, 0, ACPI_OSI_WIN_2000}, /* Windows 2000 */
{"Windows 2001", NULL, 0, ACPI_OSI_WIN_XP}, /* Windows XP */
{"Windows 2001 SP1", NULL, 0, ACPI_OSI_WIN_XP_SP1}, /* Windows XP SP1 */
{"Windows 2001.1", NULL, 0, ACPI_OSI_WINSRV_2003}, /* Windows Server 2003 */
{"Windows 2001 SP2", NULL, 0, ACPI_OSI_WIN_XP_SP2}, /* Windows XP SP2 */
{"Windows 2001.1 SP1", NULL, 0, ACPI_OSI_WINSRV_2003_SP1}, /* Windows Server 2003 SP1 - Added 03/2006 */
{"Windows 2006", NULL, 0, ACPI_OSI_WIN_VISTA}, /* Windows vista - Added 03/2006 */
{"Windows 2006.1", NULL, 0, ACPI_OSI_WINSRV_2008}, /* Windows Server 2008 - Added 09/2009 */
{"Windows 2006 SP1", NULL, 0, ACPI_OSI_WIN_VISTA_SP1}, /* Windows Vista SP1 - Added 09/2009 */
{"Windows 2006 SP2", NULL, 0, ACPI_OSI_WIN_VISTA_SP2}, /* Windows Vista SP2 - Added 09/2010 */
{"Windows 2009", NULL, 0, ACPI_OSI_WIN_7}, /* Windows 7 and Server 2008 R2 - Added 09/2009 */
{"Windows 2012", NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8 and Server 2012 - Added 08/2012 */
{"Windows 2013", NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8.1 and Server 2012 R2 - Added 01/2014 */
{"Windows 2015", NULL, 0, ACPI_OSI_WIN_10}, /* Windows 10 - Added 03/2015 */
/* Feature Group Strings */
{"Extended Address Space Descriptor", NULL, ACPI_OSI_FEATURE, 0},
/*
* All "optional" feature group strings (features that are implemented
* by the host) should be dynamically modified to VALID by the host via
* acpi_install_interface or acpi_update_interfaces. Such optional feature
* group strings are set as INVALID by default here.
*/
{"Module Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
{"Processor Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
{"3.0 Thermal Model", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
{"3.0 _SCP Extensions", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
{"Processor Aggregator Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}
};
It is also deal in:
void __init acpi_osi_setup(char *str)
{
for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
osi = &osi_setup_entries[i];
if (!strcmp(osi->string, str)) {
osi->enable = enable;
break;
} else if (osi->string[0] == '\0') {
osi->enable = enable;
strncpy(osi->string, str, OSI_STRING_LENGTH_MAX);
break;
}
}
}
So it looks if there is Darwin entry in the osi_setup_entries,
we set the flag for it; other wise find an empty entry to copy
the Darwin name to it and update its flag. In our case we fall
into the second case and set Darwin entry with disabled.
So come to acpi_osi_setup_late again:
for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {
osi = &osi_setup_entries[i];
str = osi->string;
if (*str == '\0')
break;
if (osi->enable) {
status = acpi_install_interface(str);
if (ACPI_SUCCESS(status))
printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
} else {
status = acpi_remove_interface(str);
if (ACPI_SUCCESS(status))
printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
}
}
there is no match entry, so we failed in acpi_remove_interface(Darwin).
So it remind us that, if you want to disable Darwin by acpi_osi command,
you should firstly add Darwin support in the acpi_default_supported_interfaces
array, otherwise we don't get acpi_osi=!Darwin working.
So why don't we add Darwin in the array? This is because,
the Apply product would query many OS version, such as:
If (_OSI ("Darwin"))
{
OSYS = 0x2710
}
If (\_OSI ("Linux"))
{
OSYS = 0x03E8
}
If (\_OSI ("Windows 2009"))
{
OSYS = 0x07D9
}
If (\_OSI ("Windows 2012"))
{
OSYS = 0x07DC
}
This is ridiculous because even we support Darwin in the entry,and Linux
return _OSI(Darwin) with true, we could possibly also get
_OSI(Windows 2009) of true, then the Apple product might regard
this platform as a non-apple platform, then close the Thunderbolt interface.
So here comes the first solution:
author Matthew Garrett
Sat, 20 Sep 2014 19:19:47 +0800 (13:19 +0200)
committer Rafael J. Wysocki
Thu, 25 Sep 2014 05:31:12 +0800 (23:31 +0200)
commit 7bc5a2bad0b8d9d1ac9f7b8b33150e4ddf197334
tree a0dd3037aa6494c53edf89abb5e790f37a938d11 tree | snapshot
parent 9faf6136ff4647452580b019f4b16f8c5082e589 commit | diff
ACPI: Support _OSI("Darwin") correctly
Apple hardware queries _OSI("Darwin") in order to determine whether the
system is running OS X, and changes firmware behaviour based on the
answer. The most obvious difference in behaviour is that Thunderbolt
hardware is forcibly powered down unless the system is running OS X. The
obvious solution would be to simply add Darwin to the list of supported
_OSI strings, but this causes problems.
Recent Apple hardware includes two separate methods for checking _OSI
strings. The first will check whether Darwin is supported, and if so
will exit. The second will check whether Darwin is supported, but will
then continue to check for further operating systems. If a further
operating system is found then later firmware code will assume that the
OS is not OS X. This results in the unfortunate situation where the
Thunderbolt controller is available at boot time but remains powered
down after suspend.
The easiest way to handle this is to special-case it in the
Linux-specific OSI handling code. If we see Darwin, we should answer
true and then disable all other _OSI vendor strings.
so what we do is to introduce a DMI method that, when an Apple produce is detected,
we enable the Darwin by default, thus first disable all the default Vendor string by
acpi_update_interfaces(ACPI_DISABLE_ALL_VENDOR_STRINGS);
and then enable Darwin string by acpi_install_interface(str); so that any
_OSI(Windows) would return false, however _OSI(Darwin) returns true.
And for acpi_osi=!Darwin, we firstly should re-enable default vendor string such
as Windows 2009 Windows 2012, etc, which are disabled in dmi match, and then
we should disable Darwin by acpi_remove_interface(Darwin); to achieve this goal.
And this patch is sent at:
https://patchwork.kernel.org/patch/8953891/