aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware/dmi_scan.c
diff options
context:
space:
mode:
authorZhenzhong Duan <zhenzhong.duan@oracle.com>2012-12-20 18:05:14 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-20 20:40:19 -0500
commit9f9c9cbb60576a1518d0bf93fb8e499cffccf377 (patch)
tree217db9db9baf699c4392dedbc4a9ae4fce6f442a /drivers/firmware/dmi_scan.c
parentf1d8e614d74b09531b9a85e812485340f3df7b1c (diff)
drivers/firmware/dmi_scan.c: fetch dmi version from SMBIOS if it exists
The right dmi version is in SMBIOS if it's zero in DMI region This issue was originally found from an oracle bug. One customer noticed system UUID doesn't match between dmidecode & uek2. - HP ProLiant BL460c G6 : # cat /sys/devices/virtual/dmi/id/product_uuid 00000000-0000-4C48-3031-4D5030333531 # dmidecode | grep -i uuid UUID: 00000000-0000-484C-3031-4D5030333531 From SMBIOS 2.6 on, spec use little-endian encoding for UUID other than network byte order. So we need to get dmi version to distinguish. If version is 0.0, the real version is taken from the SMBIOS version. This is part of original kernel comment in code. [akpm@linux-foundation.org: checkpatch fixes] Signed-off-by: Zhenzhong Duan <zhenzhong.duan@oracle.com> Cc: Feng Jin <joe.jin@oracle.com> Cc: Jean Delvare <khali@linux-fr.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/firmware/dmi_scan.c')
-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);