diff --git a/amdgpu.c b/amdgpu.c index 135b4e5f..c2c9c594 100644 --- a/amdgpu.c +++ b/amdgpu.c @@ -69,6 +69,37 @@ void init_amdgpu(int fd) { if (amdgpu_device_initialize(fd, &drm_major, &drm_minor, &amdgpu_dev)) return; + // Query the GC (Graphics & Compute) block number from amdgpu + // for family detection fallback. The GC number is the + // authoritative chip identifier on modern hardware, more + // reliable than the PCI device ID (which is reused across APU + // SKUs). + { + 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 pack (minor << 8 | rev) into the + * minor field. GC 11.x onward only exists on + * these kernels, and for GC 10.x a value >= 256 + * is unambiguously the new packing. + */ + 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..9fa6577e 100644 --- a/detect.c +++ b/detect.c @@ -23,10 +23,13 @@ #include struct bits_t bits; +unsigned int gfx_version; uint64_t vramsize; uint64_t gttsize; unsigned int sclk_max = 0; // kilohertz unsigned int mclk_max = 0; // kilohertz +unsigned int is_apu = 0; // 1 if APU (unified memory), 0 if discrete GPU +unsigned int has_power_sensor = 0; // 1 if power sensor available, 0 if unavailable const void *area; static const void *srbm_area; @@ -38,6 +41,8 @@ int (*getvram)(uint64_t *out); int (*getgtt)(uint64_t *out); int (*getsclk)(uint32_t *out); int (*getmclk)(uint32_t *out); +int (*gettemp)(uint32_t *out); +int (*getpower)(uint32_t *out); static int find_pci(short bus, struct pci_device *pci_dev) { int ret = pci_system_init(); @@ -265,7 +270,7 @@ static int getuint64_null(uint64_t *out) { UNUSED(out); return -1; } void init_pci(const char *path, short *bus, unsigned int *device_id, const unsigned char forcemem) { short device_bus = -1; int err = 1; - getgrbm = getsclk = getmclk = getuint32_null; + getgrbm = getsclk = getmclk = gettemp = getpower = getuint32_null; getsrbm = getsrbm2 = getuint32_null; getvram = getgtt = getuint64_null; @@ -341,6 +346,61 @@ int getfamily(unsigned int id) { return 0; } +/* + * Map the GC (Graphics & Compute) block number to chip family. + * The number is encoded as major * 100 + minor * 10 + rev, with + * major/minor/rev coming from amdgpu_query_hw_ip_info(GFX). + * + * Note: for GC 10.x the rev matches the GFX shader target name + * (GC 10.3.0 == gfx1030). For GC 11.0.x they diverge: GC 11.0.1 + * is Phoenix (gfx1103), GC 11.0.3 is Navi 32 (gfx1101). + */ +int getfamily_gfx(unsigned int gc_ver) { + + switch(gc_ver) { + // RDNA 1 (GC 10.1.x) + case 1010: return NAVI10; + case 1011: return NAVI12; + case 1012: return NAVI14; + // RDNA 2 (GC 10.3.x) + 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; + case 1037: return MENDOCINO; + // RDNA 3 (GC 11.0.x) - GC rev != GFX shader target + case 1100: return NAVI31; // GC 11.0.0 = gfx1100 + case 1101: return RADEON_780M; // GC 11.0.1 = gfx1103 (Phoenix1) + case 1102: return NAVI33; // GC 11.0.2 = gfx1102 + case 1103: return NAVI32; // GC 11.0.3 = gfx1101 (Navi 32) + case 1104: return RADEON_780M; // GC 11.0.4 = gfx1103 (Phoenix2) + // RDNA 3.5 (GC 11.5.x) + case 1150: return STRIX_POINT; + case 1151: return RADEON_880M; + case 1152: return KRACKAN_POINT; + // RDNA 4m (GC 11.7.x) + case 1170: return MEDUSA_POINT; + case 1171: return MEDUSA_POINT_2; + case 1172: return MEDUSA_POINT_3; + // RDNA 4 (GC 12.0.x) + case 1200: return RADEON_9000; + case 1201: return GFX1201; + // RDNA 5 (GC 13.x) + case 1300: return GFX1300; + case 1310: return GFX1310; + } + + // No major.minor catch-all: revisions within a GC family report + // genuinely different SKUs (GC 11.0.0 = NAVI31 vs GC 11.0.1 = + // Phoenix iGPU), so rounding by major.minor mislabels cards. + // Unknown GC numbers return 0 and radeontop.c prints + // "GFX#### (unknown)" instead. + return 0; +} + void initbits(int fam) { // The majority of these is the same from R600 to Southern Islands. @@ -377,4 +437,12 @@ void initbits(int fam) { bits.vce0 = (1U << 7); } } + + // RDNA (GFX10+): VGT replaced by Geometry Engine at bit 21, + // Event Engine and Sequencer Instruction Cache bits undefined. + if (fam >= NAVI10) { + bits.ee = 0; + bits.vgt = (1U << 21); + bits.sh = 0; + } } diff --git a/family_str.c b/family_str.c index 666b78f0..843e8bcd 100644 --- a/family_str.c +++ b/family_str.c @@ -81,4 +81,39 @@ const char * const family_str[] = { str(ALDEBARAN), str(CYAN_SKILLFISH), str(BEIGE_GOBY), + // RDNA 2 (gfx10.x) + "Radeon RX 6800/6900 XT (gfx1030)", + "Radeon RX 6700/6750/6800M/6850M (gfx1031)", + "Radeon RX 6600 (gfx1032)", + "Radeon RX 6500/W6300 (gfx1034)", + // RDNA 3 APUs (gfx1103-1151) + "Radeon 660M/680M (gfx1035)", + "Radeon Graphics 128SP (gfx1036)", + "Steam Deck GPU (gfx1033)", + "Radeon 740M/760M/780M (gfx1103)", + "Radeon 890M (Strix Point)", + "Radeon 880M (Strix Halo)", + // RDNA 4 APUs (gfx115x - Kraken) + "Radeon 820M/840M/860M (Krackan Point)", + // RDNA 4 APUs (gfx117x - Medusa Point variants) + "Medusa Point (gfx1170)", + "Medusa Point (gfx1171)", + "Medusa Point (gfx1172)", + // RDNA 4 dGPU (gfx12xx) + "Radeon 9000 (gfx1200)", + "Radeon 9000 XT (gfx1201)", + // RDNA 5 (gfx13xx) + "Radeon (gfx1300)", + "Radeon (gfx1310)", + // Instinct MI (gfx90x) + "Instinct MI8/MI6 (gfx803)", + "Instinct MI25 (gfx900)", + "Instinct MI50/MI60 (gfx906)", + "Instinct MI100 (gfx908)", + "Instinct MI210/MI250/MI250X (gfx90a)", + "Instinct MI300/MI300X/MI325X (gfx940)", + // RDNA 3 dGPU (gfx110x) + "Radeon RX 7900 (gfx1100)", + "Radeon RX 7800/7700 (gfx1101)", + "Radeon RX 7600/7500 (gfx1102)", }; diff --git a/include/r600_pci_ids.h b/include/r600_pci_ids.h index 550a2bf5..cc5f0222 100644 --- a/include/r600_pci_ids.h +++ b/include/r600_pci_ids.h @@ -642,3 +642,29 @@ CHIPSET(0x7422, 0x7422, BEIGE_GOBY) CHIPSET(0x7423, 0x7423, BEIGE_GOBY) CHIPSET(0x7424, 0x7424, BEIGE_GOBY) CHIPSET(0x743F, 0x743F, BEIGE_GOBY) +CHIPSET(0x7446, 0x7446, NAVI31) +CHIPSET(0x7448, 0x7448, NAVI31) +CHIPSET(0x744A, 0x744A, NAVI31) +CHIPSET(0x744B, 0x744B, NAVI31) +CHIPSET(0x744C, 0x744C, NAVI31) +CHIPSET(0x745E, 0x745E, NAVI31) +CHIPSET(0x7460, 0x7460, NAVI32) +CHIPSET(0x7461, 0x7461, NAVI32) +CHIPSET(0x7470, 0x7470, NAVI32) +CHIPSET(0x747E, 0x747E, NAVI32) +CHIPSET(0x73F0, 0x73F0, NAVI33) +CHIPSET(0x7480, 0x7480, NAVI33) +CHIPSET(0x7481, 0x7481, NAVI33) +CHIPSET(0x7483, 0x7483, NAVI33) +CHIPSET(0x7487, 0x7487, NAVI33) +CHIPSET(0x7489, 0x7489, NAVI33) +CHIPSET(0x748B, 0x748B, NAVI33) +CHIPSET(0x7499, 0x7499, NAVI33) +CHIPSET(0x749F, 0x749F, NAVI33) +// APU PCI device IDs are ambiguous (same ID across SKUs / pci.ids +// versions). Identification is done via the GC (Graphics & +// Compute) block number in getfamily_gfx() when amdgpu reports it. +// See PR #180 discussion. +CHIPSET(0x7550, 0x7550, GFX1201) +CHIPSET(0x7551, 0x7551, GFX1201) +CHIPSET(0x7590, 0x7590, RADEON_9000) diff --git a/include/radeontop.h b/include/radeontop.h index b1a13226..4316b01c 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,40 @@ enum radeon_family { ALDEBARAN, CYAN_SKILLFISH, BEIGE_GOBY, + // RDNA 2 (gfx10.x) + GFX1030, // gfx1030, RX 6800/6900 XT, Pro W6800/V620 + GFX1031, // gfx1031, RX 6700/6750/6800M/6850M + GFX1032, // gfx1032, RX 6600 series, Pro W6600 + GFX1034, // gfx1034, RX 6300/6400/6500 XT, Pro W6300/W6400 + // RDNA 3 APUs (gfx1103-1151) + GFX1035, // gfx1035, Radeon 660M/680M + MENDOCINO, // gfx1036, Radeon Graphics 128SP + GFX1033, // gfx1033, Steam Deck GPU + RADEON_780M, // gfx1103, Radeon 740M/760M/780M/ROG Ally + STRIX_POINT, // gfx1150, Radeon 890M (Strix Point) + RADEON_880M, // gfx1151, Radeon 880M (Strix Halo) + // RDNA 4 APUs (gfx115x - Krackan) + KRACKAN_POINT, // gfx1152, Radeon 820M/840M/860M (Krackan Point) + // RDNA 4 APUs (gfx117x - Medusa) + MEDUSA_POINT, // gfx1170, Medusa Point + MEDUSA_POINT_2, // gfx1171, Medusa Point (variant mapping TBD) + MEDUSA_POINT_3, // gfx1172, Medusa Point (variant mapping TBD) + // RDNA 4 dGPU (gfx12xx) + RADEON_9000, // gfx1200, Radeon 9000 series + GFX1201, // gfx1201 + // RDNA 5 (gfx13xx) + GFX1300, // gfx1300, RDNA 5 + GFX1310, // gfx1310, RDNA 5 + // Instinct MI (gfx90x) + MI8, // gfx803, Instinct MI8/MI6 + MI25, // gfx900, Instinct MI25 + MI50, // gfx906, Instinct MI50/MI60 + MI100, // gfx908, Instinct MI100 + MI210, // gfx90a, Instinct MI210/MI250/MI250X + MI300, // gfx940, Instinct MI300/MI300X/MI325X + NAVI31, // gfx1100, RX 7900 series + NAVI32, // gfx1101, RX 7800/7700 series + NAVI33, // gfx1102, RX 7600/7500 series }; extern const char * const family_str[]; @@ -178,5 +213,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..4cb6e2ea 100644 --- a/radeontop.c +++ b/radeontop.c @@ -139,11 +139,41 @@ int main(int argc, char **argv) { setuid(getuid()); - const int family = getfamily(device_id); + // The GC (Graphics & Compute) block number is the authoritative + // chip identifier on modern hardware (libdrm_amdgpu queries it + // directly via amdgpu_query_hw_ip_info), so try it first. PCI + // ID lookup is the fallback for legacy cards that don't expose + // a GC number, and for amdgpu init failures. + int family = 0; + if (gfx_version) + family = getfamily_gfx(gfx_version); if (!family) - fprintf(stderr, _("Unknown Radeon card. <= R500 won't work, new cards might.\n")); - - const char * const cardname = family_str[family]; + family = getfamily(device_id); + + const char *cardname; + static char gfx_fallback[40]; + + if (!family) { + if (gfx_version) { + // When the family is unknown but a GC number is + // available, show the GC number (certain - queried + // straight from the chip) together with the putative + // GFX shader target. The two coincide for GC 10.x but + // diverge for GC 11.0.x APUs, hence the '?' on GFX. + 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]; + fprintf(stderr, _("Unknown Radeon card. <= R500 won't work, new cards might.\n")); + } + } else { + cardname = family_str[family]; + } initbits(family);