Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amdgpu: Add vbios info ioctl interface

Add AMDGPU_INFO_VBIOS_INFO subquery id for detailed vbios info.

Provides a way for the user application to get the VBIOS
information without having to parse the binary.
It is useful for the user to be able to display in a simple way the VBIOS
version in their system if they happen to encounter an issue.

V2:
Use numeric serial.
Parse and expose vbios version string.

V3:
Remove redundant data in drm_amdgpu_info_vbios struct.

V4:
64 bit alignment in drm_amdgpu_info_vbios.

v5: squash together all the reverts, etc. (Alex)

Signed-off-by: Jiawei Gu <Jiawei.Gu@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Jiawei Gu and committed by
Alex Deucher
29b4c589 915821a7

+219 -6
+15
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
··· 867 867 min((size_t)size, (size_t)(bios_size - bios_offset))) 868 868 ? -EFAULT : 0; 869 869 } 870 + case AMDGPU_INFO_VBIOS_INFO: { 871 + struct drm_amdgpu_info_vbios vbios_info = {}; 872 + struct atom_context *atom_context; 873 + 874 + atom_context = adev->mode_info.atom_context; 875 + memcpy(vbios_info.name, atom_context->name, sizeof(atom_context->name)); 876 + memcpy(vbios_info.vbios_pn, atom_context->vbios_pn, sizeof(atom_context->vbios_pn)); 877 + vbios_info.version = atom_context->version; 878 + memcpy(vbios_info.vbios_ver_str, atom_context->vbios_ver_str, 879 + sizeof(atom_context->vbios_ver_str)); 880 + memcpy(vbios_info.date, atom_context->date, sizeof(atom_context->date)); 881 + 882 + return copy_to_user(out, &vbios_info, 883 + min((size_t)size, sizeof(vbios_info))) ? -EFAULT : 0; 884 + } 870 885 default: 871 886 DRM_DEBUG_KMS("Invalid request %d\n", 872 887 info->vbios_info.type);
+172
drivers/gpu/drm/amd/amdgpu/atom.c
··· 31 31 32 32 #define ATOM_DEBUG 33 33 34 + #include "atomfirmware.h" 34 35 #include "atom.h" 35 36 #include "atom-names.h" 36 37 #include "atom-bits.h" ··· 1300 1299 } 1301 1300 } 1302 1301 1302 + static void atom_get_vbios_name(struct atom_context *ctx) 1303 + { 1304 + unsigned char *p_rom; 1305 + unsigned char str_num; 1306 + unsigned short off_to_vbios_str; 1307 + unsigned char *c_ptr; 1308 + int name_size; 1309 + int i; 1310 + 1311 + const char *na = "--N/A--"; 1312 + char *back; 1313 + 1314 + p_rom = ctx->bios; 1315 + 1316 + str_num = *(p_rom + OFFSET_TO_GET_ATOMBIOS_NUMBER_OF_STRINGS); 1317 + if (str_num != 0) { 1318 + off_to_vbios_str = 1319 + *(unsigned short *)(p_rom + OFFSET_TO_GET_ATOMBIOS_STRING_START); 1320 + 1321 + c_ptr = (unsigned char *)(p_rom + off_to_vbios_str); 1322 + } else { 1323 + /* do not know where to find name */ 1324 + memcpy(ctx->name, na, 7); 1325 + ctx->name[7] = 0; 1326 + return; 1327 + } 1328 + 1329 + /* 1330 + * skip the atombios strings, usually 4 1331 + * 1st is P/N, 2nd is ASIC, 3rd is PCI type, 4th is Memory type 1332 + */ 1333 + for (i = 0; i < str_num; i++) { 1334 + while (*c_ptr != 0) 1335 + c_ptr++; 1336 + c_ptr++; 1337 + } 1338 + 1339 + /* skip the following 2 chars: 0x0D 0x0A */ 1340 + c_ptr += 2; 1341 + 1342 + name_size = strnlen(c_ptr, STRLEN_LONG - 1); 1343 + memcpy(ctx->name, c_ptr, name_size); 1344 + back = ctx->name + name_size; 1345 + while ((*--back) == ' ') 1346 + ; 1347 + *(back + 1) = '\0'; 1348 + } 1349 + 1350 + static void atom_get_vbios_date(struct atom_context *ctx) 1351 + { 1352 + unsigned char *p_rom; 1353 + unsigned char *date_in_rom; 1354 + 1355 + p_rom = ctx->bios; 1356 + 1357 + date_in_rom = p_rom + OFFSET_TO_VBIOS_DATE; 1358 + 1359 + ctx->date[0] = '2'; 1360 + ctx->date[1] = '0'; 1361 + ctx->date[2] = date_in_rom[6]; 1362 + ctx->date[3] = date_in_rom[7]; 1363 + ctx->date[4] = '/'; 1364 + ctx->date[5] = date_in_rom[0]; 1365 + ctx->date[6] = date_in_rom[1]; 1366 + ctx->date[7] = '/'; 1367 + ctx->date[8] = date_in_rom[3]; 1368 + ctx->date[9] = date_in_rom[4]; 1369 + ctx->date[10] = ' '; 1370 + ctx->date[11] = date_in_rom[9]; 1371 + ctx->date[12] = date_in_rom[10]; 1372 + ctx->date[13] = date_in_rom[11]; 1373 + ctx->date[14] = date_in_rom[12]; 1374 + ctx->date[15] = date_in_rom[13]; 1375 + ctx->date[16] = '\0'; 1376 + } 1377 + 1378 + static unsigned char *atom_find_str_in_rom(struct atom_context *ctx, char *str, int start, 1379 + int end, int maxlen) 1380 + { 1381 + unsigned long str_off; 1382 + unsigned char *p_rom; 1383 + unsigned short str_len; 1384 + 1385 + str_off = 0; 1386 + str_len = strnlen(str, maxlen); 1387 + p_rom = ctx->bios; 1388 + 1389 + for (; start <= end; ++start) { 1390 + for (str_off = 0; str_off < str_len; ++str_off) { 1391 + if (str[str_off] != *(p_rom + start + str_off)) 1392 + break; 1393 + } 1394 + 1395 + if (str_off == str_len || str[str_off] == 0) 1396 + return p_rom + start; 1397 + } 1398 + return NULL; 1399 + } 1400 + 1401 + static void atom_get_vbios_pn(struct atom_context *ctx) 1402 + { 1403 + unsigned char *p_rom; 1404 + unsigned short off_to_vbios_str; 1405 + unsigned char *vbios_str; 1406 + int count; 1407 + 1408 + off_to_vbios_str = 0; 1409 + p_rom = ctx->bios; 1410 + 1411 + if (*(p_rom + OFFSET_TO_GET_ATOMBIOS_NUMBER_OF_STRINGS) != 0) { 1412 + off_to_vbios_str = 1413 + *(unsigned short *)(p_rom + OFFSET_TO_GET_ATOMBIOS_STRING_START); 1414 + 1415 + vbios_str = (unsigned char *)(p_rom + off_to_vbios_str); 1416 + } else { 1417 + vbios_str = p_rom + OFFSET_TO_VBIOS_PART_NUMBER; 1418 + } 1419 + 1420 + if (*vbios_str == 0) { 1421 + vbios_str = atom_find_str_in_rom(ctx, BIOS_ATOM_PREFIX, 3, 1024, 64); 1422 + if (vbios_str == NULL) 1423 + vbios_str += sizeof(BIOS_ATOM_PREFIX) - 1; 1424 + } 1425 + if (vbios_str != NULL && *vbios_str == 0) 1426 + vbios_str++; 1427 + 1428 + if (vbios_str != NULL) { 1429 + count = 0; 1430 + while ((count < BIOS_STRING_LENGTH) && vbios_str[count] >= ' ' && 1431 + vbios_str[count] <= 'z') { 1432 + ctx->vbios_pn[count] = vbios_str[count]; 1433 + count++; 1434 + } 1435 + 1436 + ctx->vbios_pn[count] = 0; 1437 + } 1438 + } 1439 + 1440 + static void atom_get_vbios_version(struct atom_context *ctx) 1441 + { 1442 + unsigned char *vbios_ver; 1443 + 1444 + /* find anchor ATOMBIOSBK-AMD */ 1445 + vbios_ver = atom_find_str_in_rom(ctx, BIOS_VERSION_PREFIX, 3, 1024, 64); 1446 + if (vbios_ver != NULL) { 1447 + /* skip ATOMBIOSBK-AMD VER */ 1448 + vbios_ver += 18; 1449 + memcpy(ctx->vbios_ver_str, vbios_ver, STRLEN_NORMAL); 1450 + } else { 1451 + ctx->vbios_ver_str[0] = '\0'; 1452 + } 1453 + } 1454 + 1303 1455 struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios) 1304 1456 { 1305 1457 int base; 1306 1458 struct atom_context *ctx = 1307 1459 kzalloc(sizeof(struct atom_context), GFP_KERNEL); 1308 1460 char *str; 1461 + struct _ATOM_ROM_HEADER *atom_rom_header; 1462 + struct _ATOM_MASTER_DATA_TABLE *master_table; 1463 + struct _ATOM_FIRMWARE_INFO *atom_fw_info; 1309 1464 u16 idx; 1310 1465 1311 1466 if (!ctx) ··· 1510 1353 strlcpy(ctx->vbios_version, str, sizeof(ctx->vbios_version)); 1511 1354 } 1512 1355 1356 + atom_rom_header = (struct _ATOM_ROM_HEADER *)CSTR(base); 1357 + if (atom_rom_header->usMasterDataTableOffset != 0) { 1358 + master_table = (struct _ATOM_MASTER_DATA_TABLE *) 1359 + CSTR(atom_rom_header->usMasterDataTableOffset); 1360 + if (master_table->ListOfDataTables.FirmwareInfo != 0) { 1361 + atom_fw_info = (struct _ATOM_FIRMWARE_INFO *) 1362 + CSTR(master_table->ListOfDataTables.FirmwareInfo); 1363 + ctx->version = atom_fw_info->ulFirmwareRevision; 1364 + } 1365 + } 1366 + 1367 + atom_get_vbios_name(ctx); 1368 + atom_get_vbios_pn(ctx); 1369 + atom_get_vbios_date(ctx); 1370 + atom_get_vbios_version(ctx); 1513 1371 1514 1372 return ctx; 1515 1373 }
+10
drivers/gpu/drm/amd/amdgpu/atom.h
··· 112 112 #define ATOM_IO_SYSIO 2 113 113 #define ATOM_IO_IIO 0x80 114 114 115 + #define STRLEN_NORMAL 32 116 + #define STRLEN_LONG 64 117 + #define STRLEN_VERYLONG 254 118 + 115 119 struct card_info { 116 120 struct drm_device *dev; 117 121 void (* reg_write)(struct card_info *, uint32_t, uint32_t); /* filled by driver */ ··· 144 140 uint32_t *scratch; 145 141 int scratch_size_bytes; 146 142 char vbios_version[20]; 143 + 144 + uint8_t name[STRLEN_LONG]; 145 + uint8_t vbios_pn[STRLEN_LONG]; 146 + uint32_t version; 147 + uint8_t vbios_ver_str[STRLEN_NORMAL]; 148 + uint8_t date[STRLEN_NORMAL]; 147 149 }; 148 150 149 151 extern int amdgpu_atom_debug;
+11 -6
drivers/gpu/drm/amd/include/atomfirmware.h
··· 197 197 DP_VS_LEVEL0_PREEMPH_LEVEL3 = 0x18, 198 198 }; 199 199 200 + #define BIOS_ATOM_PREFIX "ATOMBIOS" 201 + #define BIOS_VERSION_PREFIX "ATOMBIOSBK-AMD" 202 + #define BIOS_STRING_LENGTH 43 200 203 201 204 /* 202 205 enum atom_string_def{ ··· 212 209 #pragma pack(1) /* BIOS data must use byte aligment*/ 213 210 214 211 enum atombios_image_offset{ 215 - OFFSET_TO_ATOM_ROM_HEADER_POINTER =0x00000048, 216 - OFFSET_TO_ATOM_ROM_IMAGE_SIZE =0x00000002, 217 - OFFSET_TO_ATOMBIOS_ASIC_BUS_MEM_TYPE =0x94, 218 - MAXSIZE_OF_ATOMBIOS_ASIC_BUS_MEM_TYPE =20, /*including the terminator 0x0!*/ 219 - OFFSET_TO_GET_ATOMBIOS_NUMBER_OF_STRINGS =0x2f, 220 - OFFSET_TO_GET_ATOMBIOS_STRING_START =0x6e, 212 + OFFSET_TO_ATOM_ROM_HEADER_POINTER = 0x00000048, 213 + OFFSET_TO_ATOM_ROM_IMAGE_SIZE = 0x00000002, 214 + OFFSET_TO_ATOMBIOS_ASIC_BUS_MEM_TYPE = 0x94, 215 + MAXSIZE_OF_ATOMBIOS_ASIC_BUS_MEM_TYPE = 20, /*including the terminator 0x0!*/ 216 + OFFSET_TO_GET_ATOMBIOS_NUMBER_OF_STRINGS = 0x2f, 217 + OFFSET_TO_GET_ATOMBIOS_STRING_START = 0x6e, 218 + OFFSET_TO_VBIOS_PART_NUMBER = 0x80, 219 + OFFSET_TO_VBIOS_DATE = 0x50, 221 220 }; 222 221 223 222 /****************************************************************************
+11
include/uapi/drm/amdgpu_drm.h
··· 757 757 #define AMDGPU_INFO_VBIOS_SIZE 0x1 758 758 /* Subquery id: Query vbios image */ 759 759 #define AMDGPU_INFO_VBIOS_IMAGE 0x2 760 + /* Subquery id: Query vbios info */ 761 + #define AMDGPU_INFO_VBIOS_INFO 0x3 760 762 /* Query UVD handles */ 761 763 #define AMDGPU_INFO_NUM_HANDLES 0x1C 762 764 /* Query sensor related information */ ··· 950 948 struct drm_amdgpu_info_firmware { 951 949 __u32 ver; 952 950 __u32 feature; 951 + }; 952 + 953 + struct drm_amdgpu_info_vbios { 954 + __u8 name[64]; 955 + __u8 vbios_pn[64]; 956 + __u32 version; 957 + __u32 pad; 958 + __u8 vbios_ver_str[32]; 959 + __u8 date[32]; 953 960 }; 954 961 955 962 #define AMDGPU_VRAM_TYPE_UNKNOWN 0