diff --git a/amdgpu.c b/amdgpu.c index 135b4e5f..09a9437e 100644 --- a/amdgpu.c +++ b/amdgpu.c @@ -69,6 +69,33 @@ void init_amdgpu(int fd) { if (amdgpu_device_initialize(fd, &drm_major, &drm_minor, &amdgpu_dev)) return; + // Query GFX IP version for family detection fallback + { + struct drm_amdgpu_info_hw_ip gfx_ip = {}; + if (!amdgpu_query_hw_ip_info(amdgpu_dev, AMDGPU_HW_IP_GFX, + 0, &gfx_ip)) { + unsigned int major = gfx_ip.hw_ip_version_major; + unsigned int minor_raw = gfx_ip.hw_ip_version_minor; + unsigned int minor, rev; + + /* + * Newer kernels encode (minor << 8 | rev) in + * hw_ip_version_minor. GFX11+ only exists on + * these kernels, and for GFX10 a value >= 256 + * is unambiguously the new encoding. + */ + if (major >= 11 || minor_raw >= 256) { + minor = (minor_raw >> 8) & 0xff; + rev = minor_raw & 0xff; + } else { + minor = minor_raw; + rev = 0; + } + + gfx_version = major * 100 + minor * 10 + rev; + } + } + if (!(ret = getgrbm_amdgpu(&out32))) { getgrbm = getgrbm_amdgpu; getsrbm = getsrbm_amdgpu; diff --git a/detect.c b/detect.c index f9a1e843..aa85a2d5 100644 --- a/detect.c +++ b/detect.c @@ -23,6 +23,7 @@ #include struct bits_t bits; +unsigned int gfx_version; uint64_t vramsize; uint64_t gttsize; unsigned int sclk_max = 0; // kilohertz @@ -341,6 +342,57 @@ int getfamily(unsigned int id) { return 0; } +int getfamily_gfx(unsigned int gfx_ver) { + + switch(gfx_ver) { + // RDNA 1 (GFX10.1) + case 1010: return NAVI10; + case 1011: return NAVI12; + case 1012: return NAVI14; + // RDNA 2 (GFX10.3) + case 1030: return SIENNA_CICHLID; + case 1031: return NAVY_FLOUNDER; + case 1032: return DIMGREY_CAVEFISH; + case 1033: return GFX1033; + case 1034: return GFX1034; + case 1035: return YELLOW_CARP; + case 1036: return MENDOCINO; + // RDNA 3 (GFX11.0) + case 1100: return NAVI31; + case 1101: return NAVI32; + case 1102: return NAVI33; + case 1103: return GFX1103; + // RDNA 3.5 (GFX11.5) + case 1150: return GFX1150; + case 1151: return GFX1151; + // RDNA 4m (GFX11.7) + case 1170: return GFX1170; + case 1171: return GFX1171; + case 1172: return GFX1172; + // RDNA 4 (GFX12.0) + case 1200: return GFX1200; + case 1201: return GFX1201; + // RDNA 5 (GFX13) + case 1300: return GFX1300; + case 1310: return GFX1310; + } + + // Fallback: recognize family by major.minor + unsigned int major_minor = (gfx_ver / 10) * 10; + switch(major_minor) { + case 1010: return NAVI10; + case 1030: return SIENNA_CICHLID; + case 1100: return NAVI31; + case 1150: return GFX1150; + case 1170: return GFX1170; + case 1200: return GFX1200; + case 1300: return GFX1300; + case 1310: return GFX1310; + } + + return 0; +} + void initbits(int fam) { // The majority of these is the same from R600 to Southern Islands. diff --git a/family_str.c b/family_str.c index 666b78f0..59fb1080 100644 --- a/family_str.c +++ b/family_str.c @@ -81,4 +81,20 @@ const char * const family_str[] = { str(ALDEBARAN), str(CYAN_SKILLFISH), str(BEIGE_GOBY), + str(MENDOCINO), + str(GFX1033), + str(GFX1034), + str(NAVI31), + str(NAVI32), + str(NAVI33), + str(GFX1103), + str(GFX1150), + str(GFX1151), + str(GFX1170), + str(GFX1171), + str(GFX1172), + str(GFX1200), + str(GFX1201), + str(GFX1300), + str(GFX1310), }; diff --git a/include/radeontop.h b/include/radeontop.h index b1a13226..1cc52350 100644 --- a/include/radeontop.h +++ b/include/radeontop.h @@ -52,6 +52,7 @@ void die(const char *why); // detect.c void init_pci(const char *path, short *bus, unsigned int *device_id, const unsigned char forcemem); int getfamily(unsigned int id); +int getfamily_gfx(unsigned int gfx_ver); void initbits(int fam); void cleanup(); @@ -138,6 +139,22 @@ enum radeon_family { ALDEBARAN, CYAN_SKILLFISH, BEIGE_GOBY, + MENDOCINO, // gfx1036 + GFX1033, // Steam Deck (Van Gogh custom) + GFX1034, // Navi 24 + NAVI31, // gfx1100 + NAVI32, // gfx1101 + NAVI33, // gfx1102 + GFX1103, // Radeon 780M iGPU + GFX1150, // Strix + GFX1151, // Strix Halo + GFX1170, // RDNA 4m + GFX1171, + GFX1172, + GFX1200, // RDNA 4 + GFX1201, + GFX1300, // RDNA 5 + GFX1310, }; extern const char * const family_str[]; @@ -178,5 +195,6 @@ void init_radeon(int fd, int drm_major, int drm_minor); // amdgpu.c void init_amdgpu(int fd); void cleanup_amdgpu(); +extern unsigned int gfx_version; #endif diff --git a/radeontop.c b/radeontop.c index 707b8e96..d0a9cd1e 100644 --- a/radeontop.c +++ b/radeontop.c @@ -139,11 +139,38 @@ int main(int argc, char **argv) { setuid(getuid()); - const int family = getfamily(device_id); + // The GC (Graphics & Compute) block number queried from + // amdgpu_query_hw_ip_info() identifies the chip unambiguously, + // while PCI device IDs are reused by AMD across APU SKUs (e.g. + // 0x150E is shared by Strix Point gfx1150 and Krackan Point + // gfx1152). When both are available, the GC number wins. PCI + // lookup is the fallback for legacy cards that don't expose a + // GC number (radeon driver, or amdgpu without IP query support). + int family = 0; + if (gfx_version) + family = getfamily_gfx(gfx_version); + if (!family) + family = getfamily(device_id); if (!family) fprintf(stderr, _("Unknown Radeon card. <= R500 won't work, new cards might.\n")); - const char * const cardname = family_str[family]; + // When the family is unknown but a GC number is available, show + // the GC number (which we know for certain) together with the + // best-guess GFX shader target (gfxNNNN?). The two coincide for + // GC 10.x but diverge for GC 11.0.x APUs, hence the '?' on GFX. + static char gfx_fallback[40]; + const char *cardname; + if (!family && gfx_version) { + snprintf(gfx_fallback, sizeof(gfx_fallback), + "gfx%u? (GC %u.%u.%u unknown)", + gfx_version, + gfx_version / 100, + (gfx_version / 10) % 10, + gfx_version % 10); + cardname = gfx_fallback; + } else { + cardname = family_str[family]; + } initbits(family);