diff options
Diffstat (limited to 'drivers/firmware/dmi_scan.c')
| -rw-r--r-- | drivers/firmware/dmi_scan.c | 78 | 
1 files changed, 61 insertions, 17 deletions
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index b298158cb92..fd3ae6290d7 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -16,6 +16,7 @@   */  static char dmi_empty_string[] = "        "; +static u16 __initdata dmi_ver;  /*   * Catch too early calls to dmi_check_system():   */ @@ -118,12 +119,12 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,  	return 0;  } -static int __init dmi_checksum(const u8 *buf) +static int __init dmi_checksum(const u8 *buf, u8 len)  {  	u8 sum = 0;  	int a; -	for (a = 0; a < 15; a++) +	for (a = 0; a < len; a++)  		sum += buf[a];  	return sum == 0; @@ -161,8 +162,10 @@ static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int inde  		return;  	for (i = 0; i < 16 && (is_ff || is_00); i++) { -		if(d[i] != 0x00) is_ff = 0; -		if(d[i] != 0xFF) is_00 = 0; +		if (d[i] != 0x00) +			is_00 = 0; +		if (d[i] != 0xFF) +			is_ff = 0;  	}  	if (is_ff || is_00) @@ -172,7 +175,15 @@ static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int inde  	if (!s)  		return; -	sprintf(s, "%pUB", d); +	/* +	 * As of version 2.6 of the SMBIOS specification, the first 3 fields of +	 * the UUID are supposed to be little-endian encoded.  The specification +	 * says that this is the defacto standard. +	 */ +	if (dmi_ver >= 0x0206) +		sprintf(s, "%pUL", d); +	else +		sprintf(s, "%pUB", d);          dmi_ident[slot] = s;  } @@ -404,29 +415,57 @@ static int __init dmi_present(const char __iomem *p)  	u8 buf[15];  	memcpy_fromio(buf, p, 15); -	if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) { +	if (dmi_checksum(buf, 15)) {  		dmi_num = (buf[13] << 8) | buf[12];  		dmi_len = (buf[7] << 8) | buf[6];  		dmi_base = (buf[11] << 24) | (buf[10] << 16) |  			(buf[9] << 8) | buf[8]; -		/* -		 * DMI version 0.0 means that the real version is taken from -		 * the SMBIOS version, which we don't know at this point. -		 */ -		if (buf[14] != 0) -			printk(KERN_INFO "DMI %d.%d present.\n", -			       buf[14] >> 4, buf[14] & 0xF); -		else -			printk(KERN_INFO "DMI present.\n");  		if (dmi_walk_early(dmi_decode) == 0) { +			if (dmi_ver) +				pr_info("SMBIOS %d.%d present.\n", +				       dmi_ver >> 8, dmi_ver & 0xFF); +			else { +				dmi_ver = (buf[14] & 0xF0) << 4 | +					   (buf[14] & 0x0F); +				pr_info("Legacy DMI %d.%d present.\n", +				       dmi_ver >> 8, dmi_ver & 0xFF); +			}  			dmi_dump_ids();  			return 0;  		}  	} +	dmi_ver = 0;  	return 1;  } +static int __init smbios_present(const char __iomem *p) +{ +	u8 buf[32]; +	int offset = 0; + +	memcpy_fromio(buf, p, 32); +	if ((buf[5] < 32) && dmi_checksum(buf, buf[5])) { +		dmi_ver = (buf[6] << 8) + buf[7]; + +		/* Some BIOS report weird SMBIOS version, fix that up */ +		switch (dmi_ver) { +		case 0x021F: +		case 0x0221: +			pr_debug("SMBIOS version fixup(2.%d->2.%d)\n", +			       dmi_ver & 0xFF, 3); +			dmi_ver = 0x0203; +			break; +		case 0x0233: +			pr_debug("SMBIOS version fixup(2.%d->2.%d)\n", 51, 6); +			dmi_ver = 0x0206; +			break; +		} +		offset = 16; +	} +	return dmi_present(buf + offset); +} +  void __init dmi_scan_machine(void)  {  	char __iomem *p, *q; @@ -444,7 +483,7 @@ void __init dmi_scan_machine(void)  		if (p == NULL)  			goto error; -		rc = dmi_present(p + 0x10); /* offset of _DMI_ string */ +		rc = smbios_present(p);  		dmi_iounmap(p, 32);  		if (!rc) {  			dmi_available = 1; @@ -462,7 +501,12 @@ void __init dmi_scan_machine(void)  			goto error;  		for (q = p; q < p + 0x10000; q += 16) { -			rc = dmi_present(q); +			if (memcmp(q, "_SM_", 4) == 0 && q - p <= 0xFFE0) +				rc = smbios_present(q); +			else if (memcmp(q, "_DMI_", 5) == 0) +				rc = dmi_present(q); +			else +				continue;  			if (!rc) {  				dmi_available = 1;  				dmi_iounmap(p, 0x10000);  |