xref: /openbmc/linux/drivers/acpi/blacklist.c (revision 1c2dd16a)
1 /*
2  *  blacklist.c
3  *
4  *  Check to see if the given machine has a known bad ACPI BIOS
5  *  or if the BIOS is too old.
6  *  Check given machine against acpi_rev_dmi_table[].
7  *
8  *  Copyright (C) 2004 Len Brown <len.brown@intel.com>
9  *  Copyright (C) 2002 Andy Grover <andrew.grover@intel.com>
10  *
11  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12  *
13  *  This program is free software; you can redistribute it and/or modify
14  *  it under the terms of the GNU General Public License as published by
15  *  the Free Software Foundation; either version 2 of the License, or (at
16  *  your option) any later version.
17  *
18  *  This program is distributed in the hope that it will be useful, but
19  *  WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  *  General Public License for more details.
22  *
23  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24  */
25 
26 #include <linux/kernel.h>
27 #include <linux/init.h>
28 #include <linux/acpi.h>
29 #include <linux/dmi.h>
30 
31 #include "internal.h"
32 
33 enum acpi_blacklist_predicates {
34 	all_versions,
35 	less_than_or_equal,
36 	equal,
37 	greater_than_or_equal,
38 };
39 
40 struct acpi_blacklist_item {
41 	char oem_id[7];
42 	char oem_table_id[9];
43 	u32 oem_revision;
44 	char *table;
45 	enum acpi_blacklist_predicates oem_revision_predicate;
46 	char *reason;
47 	u32 is_critical_error;
48 };
49 
50 static struct dmi_system_id acpi_rev_dmi_table[] __initdata;
51 
52 /*
53  * POLICY: If *anything* doesn't work, put it on the blacklist.
54  *	   If they are critical errors, mark it critical, and abort driver load.
55  */
56 static struct acpi_blacklist_item acpi_blacklist[] __initdata = {
57 	/* Compaq Presario 1700 */
58 	{"PTLTD ", "  DSDT  ", 0x06040000, ACPI_SIG_DSDT, less_than_or_equal,
59 	 "Multiple problems", 1},
60 	/* Sony FX120, FX140, FX150? */
61 	{"SONY  ", "U0      ", 0x20010313, ACPI_SIG_DSDT, less_than_or_equal,
62 	 "ACPI driver problem", 1},
63 	/* Compaq Presario 800, Insyde BIOS */
64 	{"INT440", "SYSFexxx", 0x00001001, ACPI_SIG_DSDT, less_than_or_equal,
65 	 "Does not use _REG to protect EC OpRegions", 1},
66 	/* IBM 600E - _ADR should return 7, but it returns 1 */
67 	{"IBM   ", "TP600E  ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal,
68 	 "Incorrect _ADR", 1},
69 
70 	{""}
71 };
72 
73 int __init acpi_blacklisted(void)
74 {
75 	int i = 0;
76 	int blacklisted = 0;
77 	struct acpi_table_header table_header;
78 
79 	while (acpi_blacklist[i].oem_id[0] != '\0') {
80 		if (acpi_get_table_header(acpi_blacklist[i].table, 0, &table_header)) {
81 			i++;
82 			continue;
83 		}
84 
85 		if (strncmp(acpi_blacklist[i].oem_id, table_header.oem_id, 6)) {
86 			i++;
87 			continue;
88 		}
89 
90 		if (strncmp
91 		    (acpi_blacklist[i].oem_table_id, table_header.oem_table_id,
92 		     8)) {
93 			i++;
94 			continue;
95 		}
96 
97 		if ((acpi_blacklist[i].oem_revision_predicate == all_versions)
98 		    || (acpi_blacklist[i].oem_revision_predicate ==
99 			less_than_or_equal
100 			&& table_header.oem_revision <=
101 			acpi_blacklist[i].oem_revision)
102 		    || (acpi_blacklist[i].oem_revision_predicate ==
103 			greater_than_or_equal
104 			&& table_header.oem_revision >=
105 			acpi_blacklist[i].oem_revision)
106 		    || (acpi_blacklist[i].oem_revision_predicate == equal
107 			&& table_header.oem_revision ==
108 			acpi_blacklist[i].oem_revision)) {
109 
110 			printk(KERN_ERR PREFIX
111 			       "Vendor \"%6.6s\" System \"%8.8s\" "
112 			       "Revision 0x%x has a known ACPI BIOS problem.\n",
113 			       acpi_blacklist[i].oem_id,
114 			       acpi_blacklist[i].oem_table_id,
115 			       acpi_blacklist[i].oem_revision);
116 
117 			printk(KERN_ERR PREFIX
118 			       "Reason: %s. This is a %s error\n",
119 			       acpi_blacklist[i].reason,
120 			       (acpi_blacklist[i].
121 				is_critical_error ? "non-recoverable" :
122 				"recoverable"));
123 
124 			blacklisted = acpi_blacklist[i].is_critical_error;
125 			break;
126 		} else {
127 			i++;
128 		}
129 	}
130 
131 	(void)early_acpi_osi_init();
132 	dmi_check_system(acpi_rev_dmi_table);
133 
134 	return blacklisted;
135 }
136 #ifdef CONFIG_DMI
137 #ifdef CONFIG_ACPI_REV_OVERRIDE_POSSIBLE
138 static int __init dmi_enable_rev_override(const struct dmi_system_id *d)
139 {
140 	printk(KERN_NOTICE PREFIX "DMI detected: %s (force ACPI _REV to 5)\n",
141 	       d->ident);
142 	acpi_rev_override_setup(NULL);
143 	return 0;
144 }
145 #endif
146 
147 static struct dmi_system_id acpi_rev_dmi_table[] __initdata = {
148 #ifdef CONFIG_ACPI_REV_OVERRIDE_POSSIBLE
149 	/*
150 	 * DELL XPS 13 (2015) switches sound between HDA and I2S
151 	 * depending on the ACPI _REV callback. If userspace supports
152 	 * I2S sufficiently (or if you do not care about sound), you
153 	 * can safely disable this quirk.
154 	 */
155 	{
156 	 .callback = dmi_enable_rev_override,
157 	 .ident = "DELL XPS 13 (2015)",
158 	 .matches = {
159 		      DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
160 		      DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9343"),
161 		},
162 	},
163 	{
164 	 .callback = dmi_enable_rev_override,
165 	 .ident = "DELL Precision 5520",
166 	 .matches = {
167 		      DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
168 		      DMI_MATCH(DMI_PRODUCT_NAME, "Precision 5520"),
169 		},
170 	},
171 	{
172 	 .callback = dmi_enable_rev_override,
173 	 .ident = "DELL Precision 3520",
174 	 .matches = {
175 		      DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
176 		      DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3520"),
177 		},
178 	},
179 	/*
180 	 * Resolves a quirk with the Dell Latitude 3350 that
181 	 * causes the ethernet adapter to not function.
182 	 */
183 	{
184 	 .callback = dmi_enable_rev_override,
185 	 .ident = "DELL Latitude 3350",
186 	 .matches = {
187 		      DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
188 		      DMI_MATCH(DMI_PRODUCT_NAME, "Latitude 3350"),
189 		},
190 	},
191 	{
192 	 .callback = dmi_enable_rev_override,
193 	 .ident = "DELL Inspiron 7537",
194 	 .matches = {
195 		      DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
196 		      DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7537"),
197 		},
198 	},
199 #endif
200 	{}
201 };
202 
203 #endif /* CONFIG_DMI */
204