]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From 2969c7df1c1808d2a38a9adfbb158de7632a0cfb Mon Sep 17 00:00:00 2001 |
2 | From: Rafael J. Wysocki <rjw@sisk.pl> | |
3 | Date: Mon, 3 Nov 2008 19:01:03 +0900 | |
4 | Subject: [PATCH] DMI: Introduce dmi_first_match to make the interface more flexible | |
5 | References: bnc#441721 | |
6 | ||
7 | Some notebooks from HP have the problem that their BIOSes attempt to | |
8 | spin down hard drives before entering ACPI system states S4 and S5. | |
9 | This leads to a yo-yo effect during system power-off shutdown and the | |
10 | last phase of hibernation when the disk is first spun down by the | |
11 | kernel and then almost immediately turned on and off by the BIOS. | |
12 | This, in turn, may result in shortening the disk's life times. | |
13 | ||
14 | To prevent this from happening we can blacklist the affected systems | |
15 | using DMI information. However, only the on-board controlles should | |
16 | be blacklisted and their PCI slot numbers can be used for this | |
17 | purpose. Unfortunately the existing interface for checking DMI | |
18 | information of the system is not very convenient for this purpose, | |
19 | because to use it, we would have to define special callback functions | |
20 | or create a separate struct dmi_system_id table for each blacklisted | |
21 | system. | |
22 | ||
23 | To overcome this difficulty introduce a new function | |
24 | dmi_first_match() returning a pointer to the first entry in an array | |
25 | of struct dmi_system_id elements that matches the system DMI | |
26 | information. Then, we can use this pointer to access the entry's | |
27 | .driver_data field containing the additional information, such as | |
28 | the PCI slot number, allowing us to do the desired blacklisting. | |
29 | ||
30 | Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> | |
31 | Signed-off-by: Tejun Heo <tj@kernel.org> | |
32 | Signed-off-by: Jeff Garzik <jgarzik@redhat.com> | |
33 | Signed-off-by: Tejun Heo <teheo@suse.de> | |
34 | --- | |
35 | drivers/firmware/dmi_scan.c | 68 +++++++++++++++++++++++++++++++++----------- | |
36 | include/linux/dmi.h | 3 + | |
37 | 2 files changed, 55 insertions(+), 16 deletions(-) | |
38 | ||
39 | --- a/drivers/firmware/dmi_scan.c | |
40 | +++ b/drivers/firmware/dmi_scan.c | |
41 | @@ -407,6 +407,27 @@ void __init dmi_scan_machine(void) | |
42 | } | |
43 | ||
44 | /** | |
45 | + * dmi_match - check if dmi_system_id structure matches system DMI data | |
46 | + * @dmi: pointer to the dmi_system_id structure to check | |
47 | + */ | |
48 | +static bool dmi_match(const struct dmi_system_id *dmi) | |
49 | +{ | |
50 | + int i; | |
51 | + | |
52 | + for (i = 0; i < ARRAY_SIZE(dmi->matches); i++) { | |
53 | + int s = dmi->matches[i].slot; | |
54 | + if (s == DMI_NONE) | |
55 | + continue; | |
56 | + if (dmi_ident[s] | |
57 | + && strstr(dmi_ident[s], dmi->matches[i].substr)) | |
58 | + continue; | |
59 | + /* No match */ | |
60 | + return false; | |
61 | + } | |
62 | + return true; | |
63 | +} | |
64 | + | |
65 | +/** | |
66 | * dmi_check_system - check system DMI data | |
67 | * @list: array of dmi_system_id structures to match against | |
68 | * All non-null elements of the list must match | |
69 | @@ -421,30 +442,45 @@ void __init dmi_scan_machine(void) | |
70 | */ | |
71 | int dmi_check_system(const struct dmi_system_id *list) | |
72 | { | |
73 | - int i, count = 0; | |
74 | - const struct dmi_system_id *d = list; | |
75 | + int count = 0; | |
76 | + const struct dmi_system_id *d; | |
77 | ||
78 | - while (d->ident) { | |
79 | - for (i = 0; i < ARRAY_SIZE(d->matches); i++) { | |
80 | - int s = d->matches[i].slot; | |
81 | - if (s == DMI_NONE) | |
82 | - continue; | |
83 | - if (dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr)) | |
84 | - continue; | |
85 | - /* No match */ | |
86 | - goto fail; | |
87 | + for (d = list; d->ident; d++) | |
88 | + if (dmi_match(d)) { | |
89 | + count++; | |
90 | + if (d->callback && d->callback(d)) | |
91 | + break; | |
92 | } | |
93 | - count++; | |
94 | - if (d->callback && d->callback(d)) | |
95 | - break; | |
96 | -fail: d++; | |
97 | - } | |
98 | ||
99 | return count; | |
100 | } | |
101 | EXPORT_SYMBOL(dmi_check_system); | |
102 | ||
103 | /** | |
104 | + * dmi_first_match - find dmi_system_id structure matching system DMI data | |
105 | + * @list: array of dmi_system_id structures to match against | |
106 | + * All non-null elements of the list must match | |
107 | + * their slot's (field index's) data (i.e., each | |
108 | + * list string must be a substring of the specified | |
109 | + * DMI slot's string data) to be considered a | |
110 | + * successful match. | |
111 | + * | |
112 | + * Walk the blacklist table until the first match is found. Return the | |
113 | + * pointer to the matching entry or NULL if there's no match. | |
114 | + */ | |
115 | +const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list) | |
116 | +{ | |
117 | + const struct dmi_system_id *d; | |
118 | + | |
119 | + for (d = list; d->ident; d++) | |
120 | + if (dmi_match(d)) | |
121 | + return d; | |
122 | + | |
123 | + return NULL; | |
124 | +} | |
125 | +EXPORT_SYMBOL(dmi_first_match); | |
126 | + | |
127 | +/** | |
128 | * dmi_get_system_info - return DMI data value | |
129 | * @field: data index (see enum dmi_field) | |
130 | * | |
131 | --- a/include/linux/dmi.h | |
132 | +++ b/include/linux/dmi.h | |
133 | @@ -75,6 +75,7 @@ struct dmi_device { | |
134 | #ifdef CONFIG_DMI | |
135 | ||
136 | extern int dmi_check_system(const struct dmi_system_id *list); | |
137 | +const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list); | |
138 | extern const char * dmi_get_system_info(int field); | |
139 | extern const struct dmi_device * dmi_find_device(int type, const char *name, | |
140 | const struct dmi_device *from); | |
141 | @@ -88,6 +89,8 @@ extern int dmi_walk(void (*decode)(const | |
142 | #else | |
143 | ||
144 | static inline int dmi_check_system(const struct dmi_system_id *list) { return 0; } | |
145 | +static inline const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list) | |
146 | + { return NULL; } | |
147 | static inline const char * dmi_get_system_info(int field) { return NULL; } | |
148 | static inline const struct dmi_device * dmi_find_device(int type, const char *name, | |
149 | const struct dmi_device *from) { return NULL; } |