aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/dmi_scan.c62
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
122static int __init dmi_checksum(const u8 *buf) 122static 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
442static 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
442void __init dmi_scan_machine(void) 469void __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);