aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2009-01-19 14:55:50 -0500
committerJeff Garzik <jgarzik@redhat.com>2009-01-27 02:15:47 -0500
commitd7b1956fed33d30c4815e848fd7a143722916868 (patch)
tree611ed604c363b7e8b98c49126f11aa2e24cf857b
parentabfe2d7b915c872f3a1fd203267cedebf90daa45 (diff)
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>
-rw-r--r--drivers/firmware/dmi_scan.c74
-rw-r--r--include/linux/dmi.h1
2 files changed, 56 insertions, 19 deletions
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index d76adfea5df7..8f0f7c449305 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -415,6 +415,29 @@ void __init dmi_scan_machine(void)
415} 415}
416 416
417/** 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 */
421static 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/**
418 * dmi_check_system - check system DMI data 441 * dmi_check_system - check system DMI data
419 * @list: array of dmi_system_id structures to match against 442 * @list: array of dmi_system_id structures to match against
420 * All non-null elements of the list must match 443 * All non-null elements of the list must match
@@ -429,32 +452,45 @@ void __init dmi_scan_machine(void)
429 */ 452 */
430int dmi_check_system(const struct dmi_system_id *list) 453int dmi_check_system(const struct dmi_system_id *list)
431{ 454{
432 int i, count = 0; 455 int count = 0;
433 const struct dmi_system_id *d = list; 456 const struct dmi_system_id *d;
434 457
435 WARN(!dmi_initialized, KERN_ERR "dmi check: not initialized yet.\n"); 458 for (d = list; d->ident; d++)
436 459 if (dmi_matches(d)) {
437 while (d->ident) { 460 count++;
438 for (i = 0; i < ARRAY_SIZE(d->matches); i++) { 461 if (d->callback && d->callback(d))
439 int s = d->matches[i].slot; 462 break;
440 if (s == DMI_NONE)
441 continue;
442 if (dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr))
443 continue;
444 /* No match */
445 goto fail;
446 } 463 }
447 count++;
448 if (d->callback && d->callback(d))
449 break;
450fail: d++;
451 }
452 464
453 return count; 465 return count;
454} 466}
455EXPORT_SYMBOL(dmi_check_system); 467EXPORT_SYMBOL(dmi_check_system);
456 468
457/** 469/**
470 * dmi_first_match - find dmi_system_id structure matching system DMI data
471 * @list: array of dmi_system_id structures to match against
472 * All non-null elements of the list must match
473 * their slot's (field index's) data (i.e., each
474 * list string must be a substring of the specified
475 * DMI slot's string data) to be considered a
476 * successful match.
477 *
478 * Walk the blacklist table until the first match is found. Return the
479 * pointer to the matching entry or NULL if there's no match.
480 */
481const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list)
482{
483 const struct dmi_system_id *d;
484
485 for (d = list; d->ident; d++)
486 if (dmi_matches(d))
487 return d;
488
489 return NULL;
490}
491EXPORT_SYMBOL(dmi_first_match);
492
493/**
458 * dmi_get_system_info - return DMI data value 494 * dmi_get_system_info - return DMI data value
459 * @field: data index (see enum dmi_field) 495 * @field: data index (see enum dmi_field)
460 * 496 *
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index 34161907b2f8..aea23105d3ed 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -38,6 +38,7 @@ struct dmi_device {
38#ifdef CONFIG_DMI 38#ifdef CONFIG_DMI
39 39
40extern int dmi_check_system(const struct dmi_system_id *list); 40extern int dmi_check_system(const struct dmi_system_id *list);
41const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list);
41extern const char * dmi_get_system_info(int field); 42extern const char * dmi_get_system_info(int field);
42extern const struct dmi_device * dmi_find_device(int type, const char *name, 43extern const struct dmi_device * dmi_find_device(int type, const char *name,
43 const struct dmi_device *from); 44 const struct dmi_device *from);