brintos

brintos / linux-shallow public Read only

0
0
Text · 12.1 KiB · df9328c Raw
490 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  osi.c - _OSI implementation4 *5 *  Copyright (C) 2016 Intel Corporation6 *    Author: Lv Zheng <lv.zheng@intel.com>7 */8 9/* Uncomment next line to get verbose printout */10/* #define DEBUG */11#define pr_fmt(fmt) "ACPI: " fmt12 13#include <linux/module.h>14#include <linux/kernel.h>15#include <linux/acpi.h>16#include <linux/dmi.h>17#include <linux/platform_data/x86/apple.h>18 19#include "internal.h"20 21 22#define OSI_STRING_LENGTH_MAX	6423#define OSI_STRING_ENTRIES_MAX	1624 25struct acpi_osi_entry {26	char string[OSI_STRING_LENGTH_MAX];27	bool enable;28};29 30static struct acpi_osi_config {31	u8		default_disabling;32	unsigned int	linux_enable:1;33	unsigned int	linux_dmi:1;34	unsigned int	linux_cmdline:1;35	unsigned int	darwin_enable:1;36	unsigned int	darwin_dmi:1;37	unsigned int	darwin_cmdline:1;38} osi_config;39 40static struct acpi_osi_config osi_config;41static struct acpi_osi_entry42osi_setup_entries[OSI_STRING_ENTRIES_MAX] __initdata = {43	{"Module Device", true},44	{"Processor Device", true},45	{"3.0 _SCP Extensions", true},46	{"Processor Aggregator Device", true},47};48 49static u32 acpi_osi_handler(acpi_string interface, u32 supported)50{51	if (!strcmp("Linux", interface)) {52		pr_notice_once(FW_BUG53			"BIOS _OSI(Linux) query %s%s\n",54			osi_config.linux_enable ? "honored" : "ignored",55			osi_config.linux_cmdline ? " via cmdline" :56			osi_config.linux_dmi ? " via DMI" : "");57	}58	if (!strcmp("Darwin", interface)) {59		pr_notice_once(60			"BIOS _OSI(Darwin) query %s%s\n",61			osi_config.darwin_enable ? "honored" : "ignored",62			osi_config.darwin_cmdline ? " via cmdline" :63			osi_config.darwin_dmi ? " via DMI" : "");64	}65 66	return supported;67}68 69void __init acpi_osi_setup(char *str)70{71	struct acpi_osi_entry *osi;72	bool enable = true;73	int i;74 75	if (!acpi_gbl_create_osi_method)76		return;77 78	if (str == NULL || *str == '\0') {79		pr_info("_OSI method disabled\n");80		acpi_gbl_create_osi_method = FALSE;81		return;82	}83 84	if (*str == '!') {85		str++;86		if (*str == '\0') {87			/* Do not override acpi_osi=!* */88			if (!osi_config.default_disabling)89				osi_config.default_disabling =90					ACPI_DISABLE_ALL_VENDOR_STRINGS;91			return;92		} else if (*str == '*') {93			osi_config.default_disabling = ACPI_DISABLE_ALL_STRINGS;94			for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {95				osi = &osi_setup_entries[i];96				osi->enable = false;97			}98			return;99		} else if (*str == '!') {100			osi_config.default_disabling = 0;101			return;102		}103		enable = false;104	}105 106	for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {107		osi = &osi_setup_entries[i];108		if (!strcmp(osi->string, str)) {109			osi->enable = enable;110			break;111		} else if (osi->string[0] == '\0') {112			osi->enable = enable;113			strscpy(osi->string, str, OSI_STRING_LENGTH_MAX);114			break;115		}116	}117}118 119static void __init __acpi_osi_setup_darwin(bool enable)120{121	osi_config.darwin_enable = !!enable;122	if (enable) {123		acpi_osi_setup("!");124		acpi_osi_setup("Darwin");125	} else {126		acpi_osi_setup("!!");127		acpi_osi_setup("!Darwin");128	}129}130 131static void __init acpi_osi_setup_darwin(bool enable)132{133	/* Override acpi_osi_dmi_blacklisted() */134	osi_config.darwin_dmi = 0;135	osi_config.darwin_cmdline = 1;136	__acpi_osi_setup_darwin(enable);137}138 139/*140 * The story of _OSI(Linux)141 *142 * From pre-history through Linux-2.6.22, Linux responded TRUE upon a BIOS143 * OSI(Linux) query.144 *145 * Unfortunately, reference BIOS writers got wind of this and put146 * OSI(Linux) in their example code, quickly exposing this string as147 * ill-conceived and opening the door to an un-bounded number of BIOS148 * incompatibilities.149 *150 * For example, OSI(Linux) was used on resume to re-POST a video card on151 * one system, because Linux at that time could not do a speedy restore in152 * its native driver. But then upon gaining quick native restore153 * capability, Linux has no way to tell the BIOS to skip the time-consuming154 * POST -- putting Linux at a permanent performance disadvantage. On155 * another system, the BIOS writer used OSI(Linux) to infer native OS156 * support for IPMI!  On other systems, OSI(Linux) simply got in the way of157 * Linux claiming to be compatible with other operating systems, exposing158 * BIOS issues such as skipped device initialization.159 *160 * So "Linux" turned out to be a really poor chose of OSI string, and from161 * Linux-2.6.23 onward we respond FALSE.162 *163 * BIOS writers should NOT query _OSI(Linux) on future systems. Linux will164 * complain on the console when it sees it, and return FALSE. To get Linux165 * to return TRUE for your system  will require a kernel source update to166 * add a DMI entry, or boot with "acpi_osi=Linux"167 */168static void __init __acpi_osi_setup_linux(bool enable)169{170	osi_config.linux_enable = !!enable;171	if (enable)172		acpi_osi_setup("Linux");173	else174		acpi_osi_setup("!Linux");175}176 177static void __init acpi_osi_setup_linux(bool enable)178{179	/* Override acpi_osi_dmi_blacklisted() */180	osi_config.linux_dmi = 0;181	osi_config.linux_cmdline = 1;182	__acpi_osi_setup_linux(enable);183}184 185/*186 * Modify the list of "OS Interfaces" reported to BIOS via _OSI187 *188 * empty string disables _OSI189 * string starting with '!' disables that string190 * otherwise string is added to list, augmenting built-in strings191 */192static void __init acpi_osi_setup_late(void)193{194	struct acpi_osi_entry *osi;195	char *str;196	int i;197	acpi_status status;198 199	if (osi_config.default_disabling) {200		status = acpi_update_interfaces(osi_config.default_disabling);201		if (ACPI_SUCCESS(status))202			pr_info("Disabled all _OSI OS vendors%s\n",203				osi_config.default_disabling ==204				ACPI_DISABLE_ALL_STRINGS ?205				" and feature groups" : "");206	}207 208	for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) {209		osi = &osi_setup_entries[i];210		str = osi->string;211		if (*str == '\0')212			break;213		if (osi->enable) {214			status = acpi_install_interface(str);215			if (ACPI_SUCCESS(status))216				pr_info("Added _OSI(%s)\n", str);217		} else {218			status = acpi_remove_interface(str);219			if (ACPI_SUCCESS(status))220				pr_info("Deleted _OSI(%s)\n", str);221		}222	}223}224 225static int __init osi_setup(char *str)226{227	if (str && !strcmp("Linux", str))228		acpi_osi_setup_linux(true);229	else if (str && !strcmp("!Linux", str))230		acpi_osi_setup_linux(false);231	else if (str && !strcmp("Darwin", str))232		acpi_osi_setup_darwin(true);233	else if (str && !strcmp("!Darwin", str))234		acpi_osi_setup_darwin(false);235	else236		acpi_osi_setup(str);237 238	return 1;239}240__setup("acpi_osi=", osi_setup);241 242bool acpi_osi_is_win8(void)243{244	return acpi_gbl_osi_data >= ACPI_OSI_WIN_8;245}246EXPORT_SYMBOL(acpi_osi_is_win8);247 248static void __init acpi_osi_dmi_darwin(void)249{250	pr_notice("DMI detected to setup _OSI(\"Darwin\"): Apple hardware\n");251	osi_config.darwin_dmi = 1;252	__acpi_osi_setup_darwin(true);253}254 255static void __init acpi_osi_dmi_linux(bool enable,256				      const struct dmi_system_id *d)257{258	pr_notice("DMI detected to setup _OSI(\"Linux\"): %s\n", d->ident);259	osi_config.linux_dmi = 1;260	__acpi_osi_setup_linux(enable);261}262 263static int __init dmi_enable_osi_linux(const struct dmi_system_id *d)264{265	acpi_osi_dmi_linux(true, d);266 267	return 0;268}269 270static int __init dmi_disable_osi_vista(const struct dmi_system_id *d)271{272	pr_notice("DMI detected: %s\n", d->ident);273	acpi_osi_setup("!Windows 2006");274	acpi_osi_setup("!Windows 2006 SP1");275	acpi_osi_setup("!Windows 2006 SP2");276 277	return 0;278}279 280static int __init dmi_disable_osi_win7(const struct dmi_system_id *d)281{282	pr_notice("DMI detected: %s\n", d->ident);283	acpi_osi_setup("!Windows 2009");284 285	return 0;286}287 288static int __init dmi_disable_osi_win8(const struct dmi_system_id *d)289{290	pr_notice("DMI detected: %s\n", d->ident);291	acpi_osi_setup("!Windows 2012");292 293	return 0;294}295 296/*297 * Linux default _OSI response behavior is determined by this DMI table.298 *299 * Note that _OSI("Linux")/_OSI("Darwin") determined here can be overridden300 * by acpi_osi=!Linux/acpi_osi=!Darwin command line options.301 */302static const struct dmi_system_id acpi_osi_dmi_table[] __initconst = {303	{304	.callback = dmi_disable_osi_vista,305	.ident = "Fujitsu Siemens",306	.matches = {307		     DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),308		     DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"),309		},310	},311	{312	/*313	 * There have a NVIF method in MSI GX723 DSDT need call by Nvidia314	 * driver (e.g. nouveau) when user press brightness hotkey.315	 * Currently, nouveau driver didn't do the job and it causes there316	 * have a infinite while loop in DSDT when user press hotkey.317	 * We add MSI GX723's dmi information to this table for workaround318	 * this issue.319	 * Will remove MSI GX723 from the table after nouveau grows support.320	 */321	.callback = dmi_disable_osi_vista,322	.ident = "MSI GX723",323	.matches = {324		     DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),325		     DMI_MATCH(DMI_PRODUCT_NAME, "GX723"),326		},327	},328	{329	.callback = dmi_disable_osi_vista,330	.ident = "Sony VGN-NS10J_S",331	.matches = {332		     DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),333		     DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NS10J_S"),334		},335	},336	{337	.callback = dmi_disable_osi_vista,338	.ident = "Sony VGN-SR290J",339	.matches = {340		     DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),341		     DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR290J"),342		},343	},344	{345	.callback = dmi_disable_osi_vista,346	.ident = "VGN-NS50B_L",347	.matches = {348		     DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),349		     DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NS50B_L"),350		},351	},352	{353	.callback = dmi_disable_osi_vista,354	.ident = "VGN-SR19XN",355	.matches = {356		     DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),357		     DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR19XN"),358		},359	},360	{361	.callback = dmi_disable_osi_vista,362	.ident = "Toshiba Satellite L355",363	.matches = {364		     DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),365		     DMI_MATCH(DMI_PRODUCT_VERSION, "Satellite L355"),366		},367	},368	{369	.callback = dmi_disable_osi_win7,370	.ident = "ASUS K50IJ",371	.matches = {372		     DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),373		     DMI_MATCH(DMI_PRODUCT_NAME, "K50IJ"),374		},375	},376	{377	.callback = dmi_disable_osi_vista,378	.ident = "Toshiba P305D",379	.matches = {380		     DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),381		     DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P305D"),382		},383	},384	{385	.callback = dmi_disable_osi_vista,386	.ident = "Toshiba NB100",387	.matches = {388		     DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),389		     DMI_MATCH(DMI_PRODUCT_NAME, "NB100"),390		},391	},392 393	/*394	 * The wireless hotkey does not work on those machines when395	 * returning true for _OSI("Windows 2012")396	 */397	{398	.callback = dmi_disable_osi_win8,399	.ident = "Dell Inspiron 7737",400	.matches = {401		    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),402		    DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7737"),403		},404	},405	{406	.callback = dmi_disable_osi_win8,407	.ident = "Dell Inspiron 7537",408	.matches = {409		    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),410		    DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7537"),411		},412	},413	{414	.callback = dmi_disable_osi_win8,415	.ident = "Dell Inspiron 5437",416	.matches = {417		    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),418		    DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5437"),419		},420	},421	{422	.callback = dmi_disable_osi_win8,423	.ident = "Dell Inspiron 3437",424	.matches = {425		    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),426		    DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 3437"),427		},428	},429	{430	.callback = dmi_disable_osi_win8,431	.ident = "Dell Vostro 3446",432	.matches = {433		    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),434		    DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3446"),435		},436	},437	{438	.callback = dmi_disable_osi_win8,439	.ident = "Dell Vostro 3546",440	.matches = {441		    DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),442		    DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3546"),443		},444	},445 446	/*447	 * BIOS invocation of _OSI(Linux) is almost always a BIOS bug.448	 * Linux ignores it, except for the machines enumerated below.449	 */450 451	/*452	 * Without this EEEpc exports a non working WMI interface, with453	 * this it exports a working "good old" eeepc_laptop interface,454	 * fixing both brightness control, and rfkill not working.455	 */456	{457	.callback = dmi_enable_osi_linux,458	.ident = "Asus EEE PC 1015PX",459	.matches = {460		     DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),461		     DMI_MATCH(DMI_PRODUCT_NAME, "1015PX"),462		},463	},464	{}465};466 467static __init void acpi_osi_dmi_blacklisted(void)468{469	dmi_check_system(acpi_osi_dmi_table);470 471	/* Enable _OSI("Darwin") for Apple platforms. */472	if (x86_apple_machine)473		acpi_osi_dmi_darwin();474}475 476int __init early_acpi_osi_init(void)477{478	acpi_osi_dmi_blacklisted();479 480	return 0;481}482 483int __init acpi_osi_init(void)484{485	acpi_install_interface_handler(acpi_osi_handler);486	acpi_osi_setup_late();487 488	return 0;489}490