diff options
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/dmi_scan.c | 62 |
1 files changed, 47 insertions, 15 deletions
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 3714e3c03df6..fd3ae6290d71 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c | |||
@@ -119,12 +119,12 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *, | |||
119 | return 0; | 119 | return 0; |
120 | } | 120 | } |
121 | 121 | ||
122 | static int __init dmi_checksum(const u8 *buf) | 122 | static int __init dmi_checksum(const u8 *buf, u8 len) |
123 | { | 123 | { |
124 | u8 sum = 0; | 124 | u8 sum = 0; |
125 | int a; | 125 | int a; |
126 | 126 | ||
127 | for (a = 0; a < 15; a++) | 127 | for (a = 0; a < len; a++) |
128 | sum += buf[a]; | 128 | sum += buf[a]; |
129 | 129 | ||
130 | return sum == 0; | 130 | return sum == 0; |
@@ -415,30 +415,57 @@ static int __init dmi_present(const char __iomem *p) | |||
415 | u8 buf[15]; | 415 | u8 buf[15]; |
416 | 416 | ||
417 | memcpy_fromio(buf, p, 15); | 417 | memcpy_fromio(buf, p, 15); |
418 | if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) { | 418 | if (dmi_checksum(buf, 15)) { |
419 | dmi_num = (buf[13] << 8) | buf[12]; | 419 | dmi_num = (buf[13] << 8) | buf[12]; |
420 | dmi_len = (buf[7] << 8) | buf[6]; | 420 | dmi_len = (buf[7] << 8) | buf[6]; |
421 | dmi_base = (buf[11] << 24) | (buf[10] << 16) | | 421 | dmi_base = (buf[11] << 24) | (buf[10] << 16) | |
422 | (buf[9] << 8) | buf[8]; | 422 | (buf[9] << 8) | buf[8]; |
423 | 423 | ||
424 | /* | ||
425 | * DMI version 0.0 means that the real version is taken from | ||
426 | * the SMBIOS version, which we don't know at this point. | ||
427 | */ | ||
428 | dmi_ver = (buf[14] & 0xf0) << 4 | (buf[14] & 0x0f); | ||
429 | if (buf[14] != 0) | ||
430 | printk(KERN_INFO "DMI %d.%d present.\n", | ||
431 | buf[14] >> 4, buf[14] & 0xF); | ||
432 | else | ||
433 | printk(KERN_INFO "DMI present.\n"); | ||
434 | if (dmi_walk_early(dmi_decode) == 0) { | 424 | if (dmi_walk_early(dmi_decode) == 0) { |
425 | if (dmi_ver) | ||
426 | pr_info("SMBIOS %d.%d present.\n", | ||
427 | dmi_ver >> 8, dmi_ver & 0xFF); | ||
428 | else { | ||
429 | dmi_ver = (buf[14] & 0xF0) << 4 | | ||
430 | (buf[14] & 0x0F); | ||
431 | pr_info("Legacy DMI %d.%d present.\n", | ||
432 | dmi_ver >> 8, dmi_ver & 0xFF); | ||
433 | } | ||
435 | dmi_dump_ids(); | 434 | dmi_dump_ids(); |
436 | return 0; | 435 | return 0; |
437 | } | 436 | } |
438 | } | 437 | } |
438 | dmi_ver = 0; | ||
439 | return 1; | 439 | return 1; |
440 | } | 440 | } |
441 | 441 | ||
442 | static int __init smbios_present(const char __iomem *p) | ||
443 | { | ||
444 | u8 buf[32]; | ||
445 | int offset = 0; | ||
446 | |||
447 | memcpy_fromio(buf, p, 32); | ||
448 | if ((buf[5] < 32) && dmi_checksum(buf, buf[5])) { | ||
449 | dmi_ver = (buf[6] << 8) + buf[7]; | ||
450 | |||
451 | /* Some BIOS report weird SMBIOS version, fix that up */ | ||
452 | switch (dmi_ver) { | ||
453 | case 0x021F: | ||
454 | case 0x0221: | ||
455 | pr_debug("SMBIOS version fixup(2.%d->2.%d)\n", | ||
456 | dmi_ver & 0xFF, 3); | ||
457 | dmi_ver = 0x0203; | ||
458 | break; | ||
459 | case 0x0233: | ||
460 | pr_debug("SMBIOS version fixup(2.%d->2.%d)\n", 51, 6); | ||
461 | dmi_ver = 0x0206; | ||
462 | break; | ||
463 | } | ||
464 | offset = 16; | ||
465 | } | ||
466 | return dmi_present(buf + offset); | ||
467 | } | ||
468 | |||
442 | void __init dmi_scan_machine(void) | 469 | void __init dmi_scan_machine(void) |
443 | { | 470 | { |
444 | char __iomem *p, *q; | 471 | char __iomem *p, *q; |
@@ -456,7 +483,7 @@ void __init dmi_scan_machine(void) | |||
456 | if (p == NULL) | 483 | if (p == NULL) |
457 | goto error; | 484 | goto error; |
458 | 485 | ||
459 | rc = dmi_present(p + 0x10); /* offset of _DMI_ string */ | 486 | rc = smbios_present(p); |
460 | dmi_iounmap(p, 32); | 487 | dmi_iounmap(p, 32); |
461 | if (!rc) { | 488 | if (!rc) { |
462 | dmi_available = 1; | 489 | dmi_available = 1; |
@@ -474,7 +501,12 @@ void __init dmi_scan_machine(void) | |||
474 | goto error; | 501 | goto error; |
475 | 502 | ||
476 | for (q = p; q < p + 0x10000; q += 16) { | 503 | for (q = p; q < p + 0x10000; q += 16) { |
477 | rc = dmi_present(q); | 504 | if (memcmp(q, "_SM_", 4) == 0 && q - p <= 0xFFE0) |
505 | rc = smbios_present(q); | ||
506 | else if (memcmp(q, "_DMI_", 5) == 0) | ||
507 | rc = dmi_present(q); | ||
508 | else | ||
509 | continue; | ||
478 | if (!rc) { | 510 | if (!rc) { |
479 | dmi_available = 1; | 511 | dmi_available = 1; |
480 | dmi_iounmap(p, 0x10000); | 512 | dmi_iounmap(p, 0x10000); |