diff options
Diffstat (limited to 'drivers/firmware/dmi_scan.c')
| -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 3714e3c03df..fd3ae6290d7 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 *,  	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; @@ -415,30 +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. -		 */ -		dmi_ver = (buf[14] & 0xf0) << 4 | (buf[14] & 0x0f); -		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; @@ -456,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; @@ -474,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);  |