DMI: Introduce dmi_first_match to make the interface more flexible

Some notebooks from HP have the problem that their BIOSes attempt to
spin down hard drives before entering ACPI system states S4 and S5.
This leads to a yo-yo effect during system power-off shutdown and the
last phase of hibernation when the disk is first spun down by the
kernel and then almost immediately turned on and off by the BIOS.
This, in turn, may result in shortening the disk's life times.

To prevent this from happening we can blacklist the affected systems
using DMI information. However, only the on-board controlles should
be blacklisted and their PCI slot numbers can be used for this
purpose. Unfortunately the existing interface for checking DMI
information of the system is not very convenient for this purpose,
because to use it, we would have to define special callback functions
or create a separate struct dmi_system_id table for each blacklisted
system.

To overcome this difficulty introduce a new function
dmi_first_match() returning a pointer to the first entry in an array
of struct dmi_system_id elements that matches the system DMI
information. Then, we can use this pointer to access the entry's
.driver_data field containing the additional information, such as
the PCI slot number, allowing us to do the desired blacklisting.

Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>

authored by Rafael J. Wysocki and committed by Jeff Garzik d7b1956f abfe2d7b

+55 -18
+54 -18
drivers/firmware/dmi_scan.c
··· 415 } 416 417 /** 418 * dmi_check_system - check system DMI data 419 * @list: array of dmi_system_id structures to match against 420 * All non-null elements of the list must match ··· 452 */ 453 int dmi_check_system(const struct dmi_system_id *list) 454 { 455 - int i, count = 0; 456 - const struct dmi_system_id *d = list; 457 458 - WARN(!dmi_initialized, KERN_ERR "dmi check: not initialized yet.\n"); 459 - 460 - while (d->ident) { 461 - for (i = 0; i < ARRAY_SIZE(d->matches); i++) { 462 - int s = d->matches[i].slot; 463 - if (s == DMI_NONE) 464 - continue; 465 - if (dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr)) 466 - continue; 467 - /* No match */ 468 - goto fail; 469 } 470 - count++; 471 - if (d->callback && d->callback(d)) 472 - break; 473 - fail: d++; 474 - } 475 476 return count; 477 } 478 EXPORT_SYMBOL(dmi_check_system); 479 480 /** 481 * dmi_get_system_info - return DMI data value
··· 415 } 416 417 /** 418 + * dmi_matches - check if dmi_system_id structure matches system DMI data 419 + * @dmi: pointer to the dmi_system_id structure to check 420 + */ 421 + static bool dmi_matches(const struct dmi_system_id *dmi) 422 + { 423 + int i; 424 + 425 + WARN(!dmi_initialized, KERN_ERR "dmi check: not initialized yet.\n"); 426 + 427 + for (i = 0; i < ARRAY_SIZE(dmi->matches); i++) { 428 + int s = dmi->matches[i].slot; 429 + if (s == DMI_NONE) 430 + continue; 431 + if (dmi_ident[s] 432 + && strstr(dmi_ident[s], dmi->matches[i].substr)) 433 + continue; 434 + /* No match */ 435 + return false; 436 + } 437 + return true; 438 + } 439 + 440 + /** 441 * dmi_check_system - check system DMI data 442 * @list: array of dmi_system_id structures to match against 443 * All non-null elements of the list must match ··· 429 */ 430 int dmi_check_system(const struct dmi_system_id *list) 431 { 432 + int count = 0; 433 + const struct dmi_system_id *d; 434 435 + for (d = list; d->ident; d++) 436 + if (dmi_matches(d)) { 437 + count++; 438 + if (d->callback && d->callback(d)) 439 + break; 440 } 441 442 return count; 443 } 444 EXPORT_SYMBOL(dmi_check_system); 445 + 446 + /** 447 + * dmi_first_match - find dmi_system_id structure matching system DMI data 448 + * @list: array of dmi_system_id structures to match against 449 + * All non-null elements of the list must match 450 + * their slot's (field index's) data (i.e., each 451 + * list string must be a substring of the specified 452 + * DMI slot's string data) to be considered a 453 + * successful match. 454 + * 455 + * Walk the blacklist table until the first match is found. Return the 456 + * pointer to the matching entry or NULL if there's no match. 457 + */ 458 + const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list) 459 + { 460 + const struct dmi_system_id *d; 461 + 462 + for (d = list; d->ident; d++) 463 + if (dmi_matches(d)) 464 + return d; 465 + 466 + return NULL; 467 + } 468 + EXPORT_SYMBOL(dmi_first_match); 469 470 /** 471 * dmi_get_system_info - return DMI data value
+1
include/linux/dmi.h
··· 38 #ifdef CONFIG_DMI 39 40 extern int dmi_check_system(const struct dmi_system_id *list); 41 extern const char * dmi_get_system_info(int field); 42 extern const struct dmi_device * dmi_find_device(int type, const char *name, 43 const struct dmi_device *from);
··· 38 #ifdef CONFIG_DMI 39 40 extern int dmi_check_system(const struct dmi_system_id *list); 41 + const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list); 42 extern const char * dmi_get_system_info(int field); 43 extern const struct dmi_device * dmi_find_device(int type, const char *name, 44 const struct dmi_device *from);