mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 18:41:58 +09:00
arm64: efi: Use SMBIOS processor version to key off Ampere quirk
commiteb684408f3upstream. Instead of using the SMBIOS type 1 record 'family' field, which is often modified by OEMs, use the type 4 'processor ID' and 'processor version' fields, which are set to a small set of probe-able values on all known Ampere EFI systems in the field. Fixes:550b33cfd4("arm64: efi: Force the use of ...") Tested-by: Andrea Righi <andrea.righi@canonical.com> Signed-off-by: Ard Biesheuvel <ardb@kernel.org> Signed-off-by: Jeremi Piotrowski <jpiotrowski@linux.microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
b026755cc9
commit
e8631d84c0
@@ -17,20 +17,43 @@
|
|||||||
|
|
||||||
static bool system_needs_vamap(void)
|
static bool system_needs_vamap(void)
|
||||||
{
|
{
|
||||||
const u8 *type1_family = efi_get_smbios_string(1, family);
|
const struct efi_smbios_type4_record *record;
|
||||||
|
const u32 __aligned(1) *socid;
|
||||||
|
const u8 *version;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ampere eMAG, Altra, and Altra Max machines crash in SetTime() if
|
* Ampere eMAG, Altra, and Altra Max machines crash in SetTime() if
|
||||||
* SetVirtualAddressMap() has not been called prior.
|
* SetVirtualAddressMap() has not been called prior. Most Altra systems
|
||||||
|
* can be identified by the SMCCC soc ID, which is conveniently exposed
|
||||||
|
* via the type 4 SMBIOS records. Otherwise, test the processor version
|
||||||
|
* field. eMAG systems all appear to have the processor version field
|
||||||
|
* set to "eMAG".
|
||||||
*/
|
*/
|
||||||
if (!type1_family || (
|
record = (struct efi_smbios_type4_record *)efi_get_smbios_record(4);
|
||||||
strcmp(type1_family, "eMAG") &&
|
if (!record)
|
||||||
strcmp(type1_family, "Altra") &&
|
|
||||||
strcmp(type1_family, "Altra Max")))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
efi_warn("Working around broken SetVirtualAddressMap()\n");
|
socid = (u32 *)record->processor_id;
|
||||||
return true;
|
switch (*socid & 0xffff000f) {
|
||||||
|
static char const altra[] = "Ampere(TM) Altra(TM) Processor";
|
||||||
|
static char const emag[] = "eMAG";
|
||||||
|
|
||||||
|
default:
|
||||||
|
version = efi_get_smbios_string(&record->header, 4,
|
||||||
|
processor_version);
|
||||||
|
if (!version || (strncmp(version, altra, sizeof(altra) - 1) &&
|
||||||
|
strncmp(version, emag, sizeof(emag) - 1)))
|
||||||
|
break;
|
||||||
|
|
||||||
|
fallthrough;
|
||||||
|
|
||||||
|
case 0x0a160001: // Altra
|
||||||
|
case 0x0a160002: // Altra Max
|
||||||
|
efi_warn("Working around broken SetVirtualAddressMap()\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
efi_status_t check_platform_features(void)
|
efi_status_t check_platform_features(void)
|
||||||
|
|||||||
@@ -983,6 +983,8 @@ struct efi_smbios_record {
|
|||||||
u16 handle;
|
u16 handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const struct efi_smbios_record *efi_get_smbios_record(u8 type);
|
||||||
|
|
||||||
struct efi_smbios_type1_record {
|
struct efi_smbios_type1_record {
|
||||||
struct efi_smbios_record header;
|
struct efi_smbios_record header;
|
||||||
|
|
||||||
@@ -996,13 +998,46 @@ struct efi_smbios_type1_record {
|
|||||||
u8 family;
|
u8 family;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define efi_get_smbios_string(__type, __name) ({ \
|
struct efi_smbios_type4_record {
|
||||||
|
struct efi_smbios_record header;
|
||||||
|
|
||||||
|
u8 socket;
|
||||||
|
u8 processor_type;
|
||||||
|
u8 processor_family;
|
||||||
|
u8 processor_manufacturer;
|
||||||
|
u8 processor_id[8];
|
||||||
|
u8 processor_version;
|
||||||
|
u8 voltage;
|
||||||
|
u16 external_clock;
|
||||||
|
u16 max_speed;
|
||||||
|
u16 current_speed;
|
||||||
|
u8 status;
|
||||||
|
u8 processor_upgrade;
|
||||||
|
u16 l1_cache_handle;
|
||||||
|
u16 l2_cache_handle;
|
||||||
|
u16 l3_cache_handle;
|
||||||
|
u8 serial_number;
|
||||||
|
u8 asset_tag;
|
||||||
|
u8 part_number;
|
||||||
|
u8 core_count;
|
||||||
|
u8 enabled_core_count;
|
||||||
|
u8 thread_count;
|
||||||
|
u16 processor_characteristics;
|
||||||
|
u16 processor_family2;
|
||||||
|
u16 core_count2;
|
||||||
|
u16 enabled_core_count2;
|
||||||
|
u16 thread_count2;
|
||||||
|
u16 thread_enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define efi_get_smbios_string(__record, __type, __name) ({ \
|
||||||
int size = sizeof(struct efi_smbios_type ## __type ## _record); \
|
int size = sizeof(struct efi_smbios_type ## __type ## _record); \
|
||||||
int off = offsetof(struct efi_smbios_type ## __type ## _record, \
|
int off = offsetof(struct efi_smbios_type ## __type ## _record, \
|
||||||
__name); \
|
__name); \
|
||||||
__efi_get_smbios_string(__type, off, size); \
|
__efi_get_smbios_string((__record), __type, off, size); \
|
||||||
})
|
})
|
||||||
|
|
||||||
const u8 *__efi_get_smbios_string(u8 type, int offset, int recsize);
|
const u8 *__efi_get_smbios_string(const struct efi_smbios_record *record,
|
||||||
|
u8 type, int offset, int recsize);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -22,19 +22,28 @@ struct efi_smbios_protocol {
|
|||||||
u8 minor_version;
|
u8 minor_version;
|
||||||
};
|
};
|
||||||
|
|
||||||
const u8 *__efi_get_smbios_string(u8 type, int offset, int recsize)
|
const struct efi_smbios_record *efi_get_smbios_record(u8 type)
|
||||||
{
|
{
|
||||||
struct efi_smbios_record *record;
|
struct efi_smbios_record *record;
|
||||||
efi_smbios_protocol_t *smbios;
|
efi_smbios_protocol_t *smbios;
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
u16 handle = 0xfffe;
|
u16 handle = 0xfffe;
|
||||||
const u8 *strtable;
|
|
||||||
|
|
||||||
status = efi_bs_call(locate_protocol, &EFI_SMBIOS_PROTOCOL_GUID, NULL,
|
status = efi_bs_call(locate_protocol, &EFI_SMBIOS_PROTOCOL_GUID, NULL,
|
||||||
(void **)&smbios) ?:
|
(void **)&smbios) ?:
|
||||||
efi_call_proto(smbios, get_next, &handle, &type, &record, NULL);
|
efi_call_proto(smbios, get_next, &handle, &type, &record, NULL);
|
||||||
if (status != EFI_SUCCESS)
|
if (status != EFI_SUCCESS)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u8 *__efi_get_smbios_string(const struct efi_smbios_record *record,
|
||||||
|
u8 type, int offset, int recsize)
|
||||||
|
{
|
||||||
|
const u8 *strtable;
|
||||||
|
|
||||||
|
if (!record)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
strtable = (u8 *)record + record->length;
|
strtable = (u8 *)record + record->length;
|
||||||
for (int i = 1; i < ((u8 *)record)[offset]; i++) {
|
for (int i = 1; i < ((u8 *)record)[offset]; i++) {
|
||||||
|
|||||||
Reference in New Issue
Block a user