From d3976cf38d946757ea0e50e344918a0c0c580d07 Mon Sep 17 00:00:00 2001 From: Tanguy Pruvot Date: Wed, 29 Jun 2016 10:37:14 +0200 Subject: [PATCH] nvapi: sample i2c rvb led color (gigabyte) you can now use --led=0xFF00FF to change the color/level (windows only) for non-rvb standard nvidia devices, you can use a level value (0 to 100) ps: i really need to find how to turn them off on linux, not found yet... --- ccminer.cpp | 19 ++++++++- compat/nvapi/nvapi_ccminer.h | 24 ++++++++++- nvapi.cpp | 22 ++++++++++ nvml.cpp | 82 ++++++++++++++++++++++++++++-------- 4 files changed, 127 insertions(+), 20 deletions(-) diff --git a/ccminer.cpp b/ccminer.cpp index 476bc80..620b90e 100644 --- a/ccminer.cpp +++ b/ccminer.cpp @@ -130,6 +130,7 @@ uint32_t device_mem_clocks[MAX_GPUS] = { 0 }; uint32_t device_plimit[MAX_GPUS] = { 0 }; uint8_t device_tlimit[MAX_GPUS] = { 0 }; int8_t device_pstate[MAX_GPUS] = { -1, -1 }; +int32_t device_led[MAX_GPUS] = { -1, -1 }; int opt_cudaschedule = -1; static bool opt_keep_clocks = false; @@ -307,7 +308,8 @@ Options:\n\ --mem-clock=3505 Set the gpu memory boost clock\n\ --gpu-clock=1150 Set the gpu engine boost clock\n\ --plimit=100 Set the gpu power limit in percentage\n\ - --tlimit=80 Set the gpu thermal limit in degrees\n" + --tlimit=80 Set the gpu thermal limit in degrees\n\ + --led=100 Set the logo led level (0=disable, 0xFF00FF for RVB)\n" #endif #ifdef HAVE_SYSLOG_H "\ @@ -385,6 +387,7 @@ struct option options[] = { { "plimit", 1, NULL, 1073 }, { "keep-clocks", 0, NULL, 1074 }, { "tlimit", 1, NULL, 1075 }, + { "led", 1, NULL, 1080 }, #ifdef HAVE_SYSLOG_H { "syslog", 0, NULL, 'S' }, { "syslog-prefix", 1, NULL, 1018 }, @@ -2693,6 +2696,7 @@ void parse_arg(int key, char *arg) hnvml = nvml_create(); #ifdef WIN32 nvapi_init(); + cuda_devicenames(); // req for leds nvapi_init_settings(); #endif #endif @@ -2948,6 +2952,18 @@ void parse_arg(int key, char *arg) } } break; + case 1080: /* --led */ + { + char *pch = strtok(arg,","); + int n = 0; + while (pch != NULL && n < MAX_GPUS) { + int dev_id = device_map[n++]; + char * p = strstr(pch, "0x"); + device_led[dev_id] = p ? (int32_t) strtoul(p, NULL, 16) : atoi(arg); + pch = strtok(NULL, ","); + } + } + break; case 1005: opt_benchmark = true; want_longpoll = false; @@ -3320,6 +3336,7 @@ int main(int argc, char *argv[]) device_texturecache[i] = -1; device_singlememory[i] = -1; device_pstate[i] = -1; + device_led[i] = -1; } cuda_devicenames(); diff --git a/compat/nvapi/nvapi_ccminer.h b/compat/nvapi/nvapi_ccminer.h index 4d40e2a..45cc8b0 100644 --- a/compat/nvapi/nvapi_ccminer.h +++ b/compat/nvapi/nvapi_ccminer.h @@ -224,7 +224,6 @@ typedef struct { NVAPI_GPU_PERF_STATUS; // 1360 bytes (1-0550) #define NVAPI_GPU_PERF_STATUS_VER MAKE_NVAPI_VERSION(NVAPI_GPU_PERF_STATUS, 1) - NvAPI_Status NvAPI_DLL_GetInterfaceVersionString(NvAPI_ShortString string); NvAPI_Status NvAPI_DLL_PerfPoliciesGetInfo(NvPhysicalGpuHandle, NVAPI_GPU_PERF_INFO*); // 409D9841 1-004c @@ -260,7 +259,6 @@ NvAPI_Status NvAPI_DLL_GetSerialNumber(NvPhysicalGpuHandle handle, NvAPI_ShortSt NvAPI_Status NvAPI_DLL_SetPstates20v1(NvPhysicalGpuHandle handle, NV_GPU_PERF_PSTATES20_INFO_V1 *pSet); NvAPI_Status NvAPI_DLL_SetPstates20v2(NvPhysicalGpuHandle handle, NV_GPU_PERF_PSTATES20_INFO_V2 *pSet); - NvAPI_Status NvAPI_DLL_Unload(); #define NV_ASSERT(x) { NvAPI_Status ret = x; if(ret != NVAPI_OK) return ret; } @@ -277,3 +275,25 @@ NvAPI_Status NvAPI_DLL_Unload(); var = (TYPE*) calloc(1, TYPE##_VER & 0xFFFF); \ if (var) var->version = TYPE##_VER; \ } + +//! Used in NvAPI_I2CReadEx() +typedef struct +{ + NvU32 version; + NvU32 displayMask; // Display Mask of the concerned display. + NvU8 bIsDDCPort; // indicates either the DDC port (TRUE) or the communication port (FALSE) of the concerned display. + NvU8 i2cDevAddress; // address of the I2C slave. The address should be shifted left by one. 0x50 -> 0xA0. + NvU8* pbI2cRegAddress; // I2C target register address. May be NULL, which indicates no register address should be sent. + NvU32 regAddrSize; // size in bytes of target register address. If pbI2cRegAddress is NULL, this field must be 0. + NvU8* pbData; // buffer of data which is to be read or written (depending on the command). + NvU32 cbRead; // bytes to read ??? seems required on write too + NvU32 cbSize; // full size of the data buffer, pbData, to be read or written. + NV_I2C_SPEED i2cSpeedKhz; // target speed of the transaction in (kHz) (Chosen from the enum NV_I2C_SPEED). + NvU8 portId; // portid on which device is connected (remember to set bIsPortIdSet if this value is set) + NvU32 bIsPortIdSet; // set this flag on if and only if portid value is set + +} NV_I2C_INFO_EX; +#define NV_I2C_INFO_EX_VER MAKE_NVAPI_VERSION(NV_I2C_INFO_EX,3) + +NvAPI_Status NvAPI_DLL_I2CReadEx(NvPhysicalGpuHandle, NV_I2C_INFO_EX*, NvU32*); +NvAPI_Status NvAPI_DLL_I2CWriteEx(NvPhysicalGpuHandle, NV_I2C_INFO_EX*, NvU32*); diff --git a/nvapi.cpp b/nvapi.cpp index 5a347d5..a0da24d 100644 --- a/nvapi.cpp +++ b/nvapi.cpp @@ -347,6 +347,28 @@ NvAPI_Status NvAPI_DLL_GetVoltages(NvPhysicalGpuHandle handle, NVAPI_VOLTAGES_TA return (*pointer)(handle, pInfo); } +#define NVAPI_ID_I2CREADEX 0x4D7B0709 // 3-002c +NvAPI_Status NvAPI_DLL_I2CReadEx(NvPhysicalGpuHandle handle, NV_I2C_INFO_EX *i2c, NvU32 *exData) { + static NvAPI_Status (*pointer)(NvPhysicalGpuHandle, NV_I2C_INFO_EX*, NvU32*) = NULL; + if(!nvapi_dll_loaded) return NVAPI_API_NOT_INITIALIZED; + if(!pointer) { + pointer = (NvAPI_Status (*)(NvPhysicalGpuHandle, NV_I2C_INFO_EX*, NvU32*))nvidia_handle->query(NVAPI_ID_I2CREADEX); + } + if(!pointer) return NVAPI_NO_IMPLEMENTATION; + return (*pointer)(handle, i2c, exData); +} + +#define NVAPI_ID_I2CWRITEEX 0x283AC65A +NvAPI_Status NvAPI_DLL_I2CWriteEx(NvPhysicalGpuHandle handle, NV_I2C_INFO_EX *i2c, NvU32 *exData) { + static NvAPI_Status (*pointer)(NvPhysicalGpuHandle, NV_I2C_INFO_EX*, NvU32 *exData) = NULL; + if(!nvapi_dll_loaded) return NVAPI_API_NOT_INITIALIZED; + if(!pointer) { + pointer = (NvAPI_Status (*)(NvPhysicalGpuHandle, NV_I2C_INFO_EX*, NvU32 *exData))nvidia_handle->query(NVAPI_ID_I2CWRITEEX); + } + if(!pointer) return NVAPI_NO_IMPLEMENTATION; + return (*pointer)(handle, i2c, exData); +} + #define NVAPI_ID_UNLOAD 0xD22BDD7E NvAPI_Status NvAPI_DLL_Unload() { static NvAPI_Status (*pointer)() = NULL; diff --git a/nvml.cpp b/nvml.cpp index 71e3715..3bc7eba 100644 --- a/nvml.cpp +++ b/nvml.cpp @@ -37,6 +37,7 @@ extern uint32_t device_mem_clocks[MAX_GPUS]; extern uint32_t device_plimit[MAX_GPUS]; extern uint8_t device_tlimit[MAX_GPUS]; extern int8_t device_pstate[MAX_GPUS]; +extern int32_t device_led[MAX_GPUS]; uint32_t clock_prev[MAX_GPUS] = { 0 }; uint32_t clock_prev_mem[MAX_GPUS] = { 0 }; @@ -954,6 +955,63 @@ int nvapi_getbios(unsigned int devNum, char *desc, unsigned int maxlen) return 0; } +static int SetGigabyteRVBLogo(unsigned int devNum, uint32_t RVB) +{ + NvAPI_Status ret; + NV_I2C_INFO_EX* i2cInfo; + NV_INIT_STRUCT_ALLOC(NV_I2C_INFO_EX, i2cInfo); + if (i2cInfo == NULL) + return -ENOMEM; + + NvU32 readBuf[25] = { 0 }; + NvU32 data[5] = { 0 }; + data[0] = 1; // block count or i2c send ? + data[2] = swab32(RVB & 0xfcfcfcU) | 0x40; + + i2cInfo->i2cDevAddress = 0x90; + i2cInfo->pbI2cRegAddress = (NvU8*) (&data[2]); + i2cInfo->regAddrSize = 4; // NVAPI_MAX_SIZEOF_I2C_REG_ADDRESS + i2cInfo->pbData = (NvU8*) readBuf; + i2cInfo->cbRead = 2; + i2cInfo->cbSize = sizeof(readBuf); + i2cInfo->portId = 1; + i2cInfo->bIsPortIdSet = 1; + + //ret = NvAPI_DLL_I2CWriteEx(phys[devNum], i2cInfo, data); + ret = NvAPI_DLL_I2CReadEx(phys[devNum], i2cInfo, data); + free(i2cInfo); + return (int) ret; +} + +int nvapi_set_led(unsigned int devNum, int32_t RVB, char *device_name) +{ + uint16_t vid = 0, pid = 0; + NvAPI_Status ret; + if (strstr(device_name, "Gigabyte GTX 10")) { + return SetGigabyteRVBLogo(devNum, (uint32_t) RVB); + } else { + NV_GPU_QUERY_ILLUMINATION_SUPPORT_PARM* illu; + NV_INIT_STRUCT_ALLOC(NV_GPU_QUERY_ILLUMINATION_SUPPORT_PARM, illu); + illu->hPhysicalGpu = phys[devNum]; + illu->Attribute = NV_GPU_IA_LOGO_BRIGHTNESS; + ret = NvAPI_GPU_QueryIlluminationSupport(illu); + if (!ret && illu->bSupported) { + NV_GPU_GET_ILLUMINATION_PARM *led; + NV_INIT_STRUCT_ALLOC(NV_GPU_GET_ILLUMINATION_PARM, led); + led->hPhysicalGpu = phys[devNum]; + led->Attribute = NV_GPU_IA_LOGO_BRIGHTNESS; + NvAPI_GPU_GetIllumination(led); + if (opt_debug) + applog(LOG_DEBUG, " Led level was %u, set to %06x", RVB); + led->Value = (uint32_t) RVB; + ret = NvAPI_GPU_SetIllumination((NV_GPU_SET_ILLUMINATION_PARM*) led); + free(led); + } + free(illu); + return ret; + } +} + int nvapi_pstateinfo(unsigned int devNum) { uint32_t n; @@ -1193,23 +1251,6 @@ int nvapi_pstateinfo(unsigned int devNum) ret = NvAPI_DLL_PerfPoliciesGetStatus(phys[devNum], &ps); applog(LOG_BLUE, "%llx %lld. %lld. %llx %llx %llx", ps.timeRef, ps.val1, ps.val2, ps.values[0], ps.values[1], ps.values[2]); #endif - // led test - NV_GPU_QUERY_ILLUMINATION_SUPPORT_PARM* illu; - NV_INIT_STRUCT_ON(NV_GPU_QUERY_ILLUMINATION_SUPPORT_PARM, illu, mem); - illu->hPhysicalGpu = phys[devNum]; - illu->Attribute = NV_GPU_IA_LOGO_BRIGHTNESS; - ret = NvAPI_GPU_QueryIlluminationSupport(illu); - if (!ret && illu->bSupported) { - NV_GPU_GET_ILLUMINATION_PARM led = { 0 }; - led.version = NV_GPU_GET_ILLUMINATION_PARM_VER; - led.hPhysicalGpu = phys[devNum]; - led.Attribute = NV_GPU_IA_LOGO_BRIGHTNESS; - NvAPI_GPU_GetIllumination(&led); - applog(LOG_RAW, " Led level is %u", led.Value); - //applog(LOG_RAW, " Led level was %u, power off", led.Value); - //led.Value = 0; - //ret = NvAPI_GPU_SetIllumination((NV_GPU_SET_ILLUMINATION_PARM*) &led); - } #endif free(mem); @@ -1484,6 +1525,10 @@ int nvapi_init_settings() if (ret != NVAPI_OK) return ret; + if (!opt_n_threads) { + opt_n_threads = active_gpus; + } + for (int n=0; n < opt_n_threads; n++) { int dev_id = device_map[n % MAX_GPUS]; if (device_plimit[dev_id]) { @@ -1514,6 +1559,9 @@ int nvapi_init_settings() if (device_pstate[dev_id]) { // dunno how via nvapi or/and pascal } + if (device_led[dev_id] != -1) { + nvapi_set_led(nvapi_dev_map[dev_id], device_led[dev_id], device_name[dev_id]); + } } return ret;