Compare commits
11 Commits
add-rtx509
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 9cab5fb0c3 | |||
|
|
b5e11b1d75 | ||
|
|
8ae6f2199f | ||
|
|
147f79f871 | ||
|
|
0912afa296 | ||
|
|
d83355b2cc | ||
|
|
2c179c395b | ||
|
|
7ef74c5997 | ||
|
|
caf23c2212 | ||
|
|
0ace205dfd | ||
|
|
8dfc9a5e29 |
29
PKGBUILD
Normal file
29
PKGBUILD
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
pkgname=gddr6-git
|
||||||
|
pkgver=r105.b5e11b1
|
||||||
|
pkgrel=1
|
||||||
|
pkgdesc="Linux based GDDR6/GDDR6X VRAM temperature reader for NVIDIA RTX 3000/4000 series GPUs"
|
||||||
|
arch=('x86_64')
|
||||||
|
url="https://github.com/olealgoritme/gddr6"
|
||||||
|
license=('GPL3')
|
||||||
|
depends=('pciutils')
|
||||||
|
makedepends=('git' 'gcc' 'cmake' 'make')
|
||||||
|
provides=('gddr6')
|
||||||
|
conflicts=('gddr6')
|
||||||
|
source=('gddr6-git::git+https://github.com/olealgoritme/gddr6')
|
||||||
|
md5sums=('SKIP')
|
||||||
|
|
||||||
|
pkgver() {
|
||||||
|
cd "$srcdir/gddr6-git"
|
||||||
|
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||||
|
}
|
||||||
|
|
||||||
|
build() {
|
||||||
|
cd "$srcdir/gddr6-git"
|
||||||
|
cmake -B build -DCMAKE_INSTALL_PREFIX=/usr
|
||||||
|
cmake --build build
|
||||||
|
}
|
||||||
|
|
||||||
|
package() {
|
||||||
|
cd "$srcdir/gddr6-git"
|
||||||
|
DESTDIR="$pkgdir" cmake --install build
|
||||||
|
}
|
||||||
@@ -16,6 +16,9 @@ sudo gddr6 --per-module # each of the 8 GDDR7 modules separately
|
|||||||
This is reverse-engineered and unofficial (NVIDIA does not expose memory temperature via nvidia-smi/NVML
|
This is reverse-engineered and unofficial (NVIDIA does not expose memory temperature via nvidia-smi/NVML
|
||||||
on this card) — treat the readings as approximate.
|
on this card) — treat the readings as approximate.
|
||||||
|
|
||||||
|
For a dedicated Blackwell app with a TUI (plus ASCII/JSON output) and a reusable C library, see
|
||||||
|
[**gpuwatch**](https://github.com/olealgoritme/gpuwatch).
|
||||||
|
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
@@ -67,6 +70,7 @@ sudo gddr6
|
|||||||
- RTX 4070 Ti (AD104)
|
- RTX 4070 Ti (AD104)
|
||||||
- RTX 4070 Super (AD104)
|
- RTX 4070 Super (AD104)
|
||||||
- RTX 4070 (AD104)
|
- RTX 4070 (AD104)
|
||||||
|
- RTX 4060 Max-Q / Mobile (AD107)
|
||||||
- RTX 3090 Ti (GA102)
|
- RTX 3090 Ti (GA102)
|
||||||
- RTX 3090 (GA102)
|
- RTX 3090 (GA102)
|
||||||
- RTX 3080 Ti (GA102)
|
- RTX 3080 Ti (GA102)
|
||||||
@@ -75,9 +79,10 @@ sudo gddr6
|
|||||||
- RTX 3070 (GA104)
|
- RTX 3070 (GA104)
|
||||||
- RTX 3070 LHR (GA104)
|
- RTX 3070 LHR (GA104)
|
||||||
- RTX A2000 (GA106)
|
- RTX A2000 (GA106)
|
||||||
|
- RTX A4000 (GA104)
|
||||||
- RTX A4500 (GA102)
|
- RTX A4500 (GA102)
|
||||||
- RTX A5000 (GA102)
|
- RTX A5000 (GA102)
|
||||||
- RTX A6000 (AD102)
|
- RTX 6000 Ada Generation (AD102)
|
||||||
- L4 (AD104)
|
- L4 (AD104)
|
||||||
- L40S (AD102)
|
- L40S (AD102)
|
||||||
- A10 (GA102)
|
- A10 (GA102)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ enum temp_decode {
|
|||||||
|
|
||||||
struct device
|
struct device
|
||||||
{
|
{
|
||||||
uint32_t bar0;
|
uint64_t bar0;
|
||||||
uint8_t bus, dev, func;
|
uint8_t bus, dev, func;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
enum temp_decode decode; // how to turn the raw reg into Celsius
|
enum temp_decode decode; // how to turn the raw reg into Celsius
|
||||||
@@ -22,8 +22,8 @@ struct device
|
|||||||
const char *arch;
|
const char *arch;
|
||||||
const char *name;
|
const char *name;
|
||||||
void *mapped_addr;
|
void *mapped_addr;
|
||||||
uint32_t phys_addr;
|
uint64_t phys_addr;
|
||||||
uint32_t base_offset;
|
uint64_t base_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct gddr6_ctx {
|
struct gddr6_ctx {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// gddr6.c
|
// gddr6.c
|
||||||
|
#define _FILE_OFFSET_BITS 64
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
#include "gddr6.h"
|
#include "gddr6.h"
|
||||||
@@ -34,6 +35,7 @@ struct device dev_table[] =
|
|||||||
{ .offset = 0x0000E2A8, .dev_id = 0x2783, .vram = "GDDR6X", .arch = "AD104", .name = "RTX 4070 Super" },
|
{ .offset = 0x0000E2A8, .dev_id = 0x2783, .vram = "GDDR6X", .arch = "AD104", .name = "RTX 4070 Super" },
|
||||||
{ .offset = 0x0000E2A8, .dev_id = 0x2786, .vram = "GDDR6X", .arch = "AD104", .name = "RTX 4070" },
|
{ .offset = 0x0000E2A8, .dev_id = 0x2786, .vram = "GDDR6X", .arch = "AD104", .name = "RTX 4070" },
|
||||||
{ .offset = 0x0000E2A8, .dev_id = 0x2860, .vram = "GDDR6", .arch = "AD106", .name = "RTX 4070 Max-Q / Mobile" },
|
{ .offset = 0x0000E2A8, .dev_id = 0x2860, .vram = "GDDR6", .arch = "AD106", .name = "RTX 4070 Max-Q / Mobile" },
|
||||||
|
{ .offset = 0x0000E2A8, .dev_id = 0x28e0, .vram = "GDDR6", .arch = "AD107", .name = "RTX 4060 Max-Q / Mobile" },
|
||||||
{ .offset = 0x0000E2A8, .dev_id = 0x2203, .vram = "GDDR6X", .arch = "GA102", .name = "RTX 3090 Ti" },
|
{ .offset = 0x0000E2A8, .dev_id = 0x2203, .vram = "GDDR6X", .arch = "GA102", .name = "RTX 3090 Ti" },
|
||||||
{ .offset = 0x0000E2A8, .dev_id = 0x2204, .vram = "GDDR6X", .arch = "GA102", .name = "RTX 3090" },
|
{ .offset = 0x0000E2A8, .dev_id = 0x2204, .vram = "GDDR6X", .arch = "GA102", .name = "RTX 3090" },
|
||||||
{ .offset = 0x0000E2A8, .dev_id = 0x2208, .vram = "GDDR6X", .arch = "GA102", .name = "RTX 3080 Ti" },
|
{ .offset = 0x0000E2A8, .dev_id = 0x2208, .vram = "GDDR6X", .arch = "GA102", .name = "RTX 3080 Ti" },
|
||||||
@@ -43,9 +45,10 @@ struct device dev_table[] =
|
|||||||
{ .offset = 0x0000EE50, .dev_id = 0x2488, .vram = "GDDR6", .arch = "GA104", .name = "RTX 3070 LHR" },
|
{ .offset = 0x0000EE50, .dev_id = 0x2488, .vram = "GDDR6", .arch = "GA104", .name = "RTX 3070 LHR" },
|
||||||
{ .offset = 0x0000E2A8, .dev_id = 0x2531, .vram = "GDDR6", .arch = "GA106", .name = "RTX A2000" },
|
{ .offset = 0x0000E2A8, .dev_id = 0x2531, .vram = "GDDR6", .arch = "GA106", .name = "RTX A2000" },
|
||||||
{ .offset = 0x0000E2A8, .dev_id = 0x2571, .vram = "GDDR6", .arch = "GA106", .name = "RTX A2000" },
|
{ .offset = 0x0000E2A8, .dev_id = 0x2571, .vram = "GDDR6", .arch = "GA106", .name = "RTX A2000" },
|
||||||
|
{ .offset = 0x0000E2A8, .dev_id = 0x24b0, .vram = "GDDR6", .arch = "GA104", .name = "RTX A4000" },
|
||||||
{ .offset = 0x0000E2A8, .dev_id = 0x2232, .vram = "GDDR6", .arch = "GA102", .name = "RTX A4500" },
|
{ .offset = 0x0000E2A8, .dev_id = 0x2232, .vram = "GDDR6", .arch = "GA102", .name = "RTX A4500" },
|
||||||
{ .offset = 0x0000E2A8, .dev_id = 0x2231, .vram = "GDDR6", .arch = "GA102", .name = "RTX A5000" },
|
{ .offset = 0x0000E2A8, .dev_id = 0x2231, .vram = "GDDR6", .arch = "GA102", .name = "RTX A5000" },
|
||||||
{ .offset = 0x0000E2A8, .dev_id = 0x26B1, .vram = "GDDR6", .arch = "AD102", .name = "RTX A6000" },
|
{ .offset = 0x0000E2A8, .dev_id = 0x26B1, .vram = "GDDR6", .arch = "AD102", .name = "RTX 6000 Ada Generation" },
|
||||||
{ .offset = 0x0000E2A8, .dev_id = 0x27b8, .vram = "GDDR6", .arch = "AD104", .name = "L4" },
|
{ .offset = 0x0000E2A8, .dev_id = 0x27b8, .vram = "GDDR6", .arch = "AD104", .name = "L4" },
|
||||||
{ .offset = 0x0000E2A8, .dev_id = 0x26b9, .vram = "GDDR6", .arch = "AD102", .name = "L40S" },
|
{ .offset = 0x0000E2A8, .dev_id = 0x26b9, .vram = "GDDR6", .arch = "AD102", .name = "L40S" },
|
||||||
{ .offset = 0x0000E2A8, .dev_id = 0x2236, .vram = "GDDR6", .arch = "GA102", .name = "A10" },
|
{ .offset = 0x0000E2A8, .dev_id = 0x2236, .vram = "GDDR6", .arch = "GA102", .name = "A10" },
|
||||||
@@ -99,7 +102,8 @@ int gddr6_detect_compatible_gpus(void)
|
|||||||
ctx.devices = new_devices;
|
ctx.devices = new_devices;
|
||||||
|
|
||||||
ctx.devices[ctx.num_devices] = dev_table[i];
|
ctx.devices[ctx.num_devices] = dev_table[i];
|
||||||
ctx.devices[ctx.num_devices].bar0 = (pci_dev->base_addr[0] & 0xffffffff);
|
ctx.devices[ctx.num_devices].bar0 =
|
||||||
|
(uint64_t)(pci_dev->base_addr[0] & PCI_ADDR_MEM_MASK);
|
||||||
ctx.devices[ctx.num_devices].bus = pci_dev->bus;
|
ctx.devices[ctx.num_devices].bus = pci_dev->bus;
|
||||||
ctx.devices[ctx.num_devices].dev = pci_dev->dev;
|
ctx.devices[ctx.num_devices].dev = pci_dev->dev;
|
||||||
ctx.devices[ctx.num_devices].func = pci_dev->func;
|
ctx.devices[ctx.num_devices].func = pci_dev->func;
|
||||||
@@ -117,9 +121,11 @@ void gddr6_memory_map(void)
|
|||||||
for (uint32_t i = 0; i < ctx.num_devices; i++)
|
for (uint32_t i = 0; i < ctx.num_devices; i++)
|
||||||
{
|
{
|
||||||
ctx.devices[i].phys_addr = (ctx.devices[i].bar0 + ctx.devices[i].offset);
|
ctx.devices[i].phys_addr = (ctx.devices[i].bar0 + ctx.devices[i].offset);
|
||||||
ctx.devices[i].base_offset = ctx.devices[i].phys_addr & ~(PG_SZ - 1);
|
ctx.devices[i].base_offset =
|
||||||
|
ctx.devices[i].phys_addr & ~((uint64_t)PG_SZ - 1);
|
||||||
|
|
||||||
ctx.devices[i].mapped_addr = mmap(0, PG_SZ, PROT_READ, MAP_SHARED, ctx.fd, ctx.devices[i].base_offset);
|
ctx.devices[i].mapped_addr = mmap(0, PG_SZ, PROT_READ, MAP_SHARED,
|
||||||
|
ctx.fd, (off_t)ctx.devices[i].base_offset);
|
||||||
if (ctx.devices[i].mapped_addr == MAP_FAILED)
|
if (ctx.devices[i].mapped_addr == MAP_FAILED)
|
||||||
{
|
{
|
||||||
ctx.devices[i].mapped_addr = NULL;
|
ctx.devices[i].mapped_addr = NULL;
|
||||||
@@ -163,12 +169,12 @@ static int decode_temp(enum temp_decode decode, uint32_t raw)
|
|||||||
|
|
||||||
// Read one 32-bit MMIO register at BAR0+off via a fresh read-only page mmap.
|
// Read one 32-bit MMIO register at BAR0+off via a fresh read-only page mmap.
|
||||||
// Returns 0 on success. Used only for the on-demand per-module GDDR7 reads.
|
// Returns 0 on success. Used only for the on-demand per-module GDDR7 reads.
|
||||||
static int read_bar0_reg(uint32_t bar0, uint32_t off, uint32_t *out)
|
static int read_bar0_reg(uint64_t bar0, uint32_t off, uint32_t *out)
|
||||||
{
|
{
|
||||||
long pg = PG_SZ;
|
long pg = PG_SZ;
|
||||||
uint64_t phys = (uint64_t)bar0 + off;
|
uint64_t phys = (uint64_t)bar0 + off;
|
||||||
uint64_t base = phys & ~((uint64_t)pg - 1);
|
uint64_t base = phys & ~((uint64_t)pg - 1);
|
||||||
volatile void *map = mmap(0, pg, PROT_READ, MAP_SHARED, ctx.fd, base);
|
volatile void *map = mmap(0, pg, PROT_READ, MAP_SHARED, ctx.fd, (off_t)base);
|
||||||
if (map == MAP_FAILED) return -1;
|
if (map == MAP_FAILED) return -1;
|
||||||
*out = *(volatile uint32_t *)((const uint8_t *)map + (phys - base));
|
*out = *(volatile uint32_t *)((const uint8_t *)map + (phys - base));
|
||||||
munmap((void *)map, pg);
|
munmap((void *)map, pg);
|
||||||
@@ -179,7 +185,7 @@ static int read_bar0_reg(uint32_t bar0, uint32_t off, uint32_t *out)
|
|||||||
// to DQR_MAX_MODULES, returns the module count found and the hottest temp in
|
// to DQR_MAX_MODULES, returns the module count found and the hottest temp in
|
||||||
// *hottest. A module counts as present only if all 4 DQR valid bits are set and
|
// *hottest. A module counts as present only if all 4 DQR valid bits are set and
|
||||||
// the data word is not the 0xBADF.... poison sentinel.
|
// the data word is not the 0xBADF.... poison sentinel.
|
||||||
static int gddr7_read_modules(uint32_t bar0, int temps[], int *hottest)
|
static int gddr7_read_modules(uint64_t bar0, int temps[], int *hottest)
|
||||||
{
|
{
|
||||||
int count = 0, hot = -128;
|
int count = 0, hot = -128;
|
||||||
for (int p = 0; p < DQR_MAX_MODULES; p++)
|
for (int p = 0; p < DQR_MAX_MODULES; p++)
|
||||||
|
|||||||
Reference in New Issue
Block a user