/* NVClock 0.8 - Linux overclocker for NVIDIA cards * * Copyright(C) 2001-2006 Roderick Colenbrander * * site: http://NVClock.sourceforge.net * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #include #include #include "config.h" #include #ifdef HAVE_NVCONTROL #include #endif static struct option long_options[] = { {"memclk", 1, 0, 'm'}, {"nvclk", 1, 0, 'n'}, {"card", 1, 0, 'c'}, {"backend", 1, 0, 'b'}, {"fanspeed", 1, 0, 'F'}, {"punit", 1, 0, 'P'}, {"devicid", 1, 0, 'Q'}, {"smartdimmer", 1, 0, 'S'}, {"vunit", 1, 0, 'V'}, {"force", 0, 0, 'f'}, {"assign", 1, 0, 'a'}, {"query", 1, 0, 'q'}, {"list", 0, 0, 'l'}, {"xdisplay", 1, 0, 'x'}, {"info", 0, 0, 'i'}, {"temperature", 0, 0, 'T'}, {"reset", 0, 0, 'r'}, {"speeds", 0, 0, 's'}, {"debug", 0, 0, 'd'}, {"Debug", 0, 0, 'D'}, {"help", 0, 0, 'h'}, {"version", 0, 0, 'v'}, {0, 0, 0, 0} }; int usage() { printf("NVClock v0.8 (Beta2)\n\n"); printf("Using NVClock you can overclock your Nvidia videocard under Linux and FreeBSD.\nUse this program at your own risk, because it can damage your system!\n\n"); printf("Usage: ./nvclock [options]\n\n"); printf("Overclock options:\n"); printf(" -b --backend backend\tBackend to use: coolbits/coolbits2d/coolbits3d/lowlevel (NV3X/NV4X only)\n"); printf(" -m --memclk speed\t\tMemory clock in MHz\n"); printf(" -n --nvclk speed\t\tGPU clock in MHz\n"); printf(" -r --reset\t\t\tRestore the original speeds\n"); printf(" -s --speeds\t\t\tPrint current speeds in MHz\n"); printf(" -d --debug\t\t\tEnable/Disable clock related debug info\n"); printf("Hardware options:\n"); printf(" -c --card number\t\tNumber of the card to use\n"); printf(" -D --Debug\t\t\tPrint detailed debug information\n"); printf(" -f --force\t\t\tForce support for disbled hardware\n"); printf(" -F --fanspeed speed\t\tAdjust the fanspeed; speed is a value between 10 and 100, a delta +10/-10 or 'auto'\n"); printf(" -P --punit mask\t\tActivate extra pixel pipelines. (NV4X only)\n"); printf(" -Q --deviceid digit\t\tAdjust the last digit of the pci id.\n"); printf(" -S --smartdimmer level\tAdjust brightness of the backlight; level is a value between 15 and 100 or a delta like +10/-10. (NV4X laptops only for now)\n"); printf(" -T --temperature\t\tShow the GPU temperatures.\n"); printf(" -V --vunit mask\t\tActivate extra vertex pipelines. (NV4X only)\n"); printf(" -i --info\t\t\tShow detailed card info.\n"); #ifdef HAVE_NVCONTROL printf("NVControl options:\n"); printf(" -a --assign\t\t\tSet an option to a value: -a fsaa=4 or -a vibrance[crt-0]\n"); printf(" -q --query\t\t\tGet the value for an option: -q fsaa or -q vibrance[crt-0]=63\n"); printf(" -l --list\t\t\tShow all available options\n"); printf(" -x --xdisplay\t\tChoose another X display\n"); #endif printf("Other options:\n"); printf(" -h --help\t\t\tShow this help info\n"); return 0; } #ifdef HAVE_NVCONTROL enum { QUERY_VALUE = 0, ASSIGN_VALUE }; /* Structure in which we'll temporarily store the requested opengl options */ typedef struct { int option; int value; int mask; } GLTmp; GLTmp *query_list = NULL; int query_size = 0; GLTmp *assign_list = NULL; int assign_size = 0; char *mask_to_device(int mask) { char *res; int i=0; if(mask & NV_CRT) { res = calloc(6, sizeof(char)); while((mask & (1<name != NULL; lst++) { if(strncmp(option, lst->name, lst->size) == 0) { int mask=0; short offset = lst->size; if(option[offset] == '[') { char *buf = &option[offset+1]; if(strncmp("crt", buf, 3) == 0) { if((buf[3] == '-') && isdigit(buf[4])) mask = CRT_0 << (buf[4] - 48); else mask = CRT_0; } else if(strncmp("dfp", buf, 3) == 0) { if((buf[3] == '-') && isdigit(buf[4])) mask = DFP_0 << (buf[4] - 48); else mask = DFP_0; } else if(strncmp("tv", buf, 2) == 0) { if((buf[2] == '-') && isdigit(buf[3])) mask = TV_0 << (buf[3] - 48); else mask = TV_0; } while(option[offset] != '=') offset++; } if(task == QUERY_VALUE) { if(query_list == NULL) { query_list = calloc(1, sizeof(GLTmp)); } else { query_list = realloc(query_list, sizeof(GLTmp)*(query_size+1)); } query_list[query_size].mask = mask; query_list[query_size].option = lst->option; query_size++; } else { if(option[offset] != '=') { printf("Incorrect option: '%s'\n", option); } else { int value; option[offset] = '\0'; option += offset + 1; value = atoi(option); if(assign_list == NULL) { assign_list = calloc(1, sizeof(GLTmp)); } else { assign_list = realloc(assign_list, (assign_size + 1)*sizeof(GLTmp)); } assign_list[assign_size].mask = mask; assign_list[assign_size].option = lst->option; assign_list[assign_size].value = value; assign_size++; } } return; } } printf("Unknown option '%s'\n", option); } void ShowGlAttributes(Display *dpy) { int val = 0; int mask; int i=0; NVOptionList *lst = option_list; printf("Available OpenGL options:\n"); for(; lst->name != NULL; lst++) { /* For now use NVGetAttribute to see if an option is supported as / NVGetValidAttributeValues is broken in current nvidia drivers. / For some unsupported options it returns supported. / Note that by keeping the disp_mask 0 we don't get screen-specific options. */ if(!NVGetAttribute(dpy, 0, 0, lst->option, &val)) { /* Option isn't supported on this card */ continue; } printf(" %s", lst->name); } printf("\n"); /* Get a mask of enabled displays to check what devices we have and what options they support */ NVGetAttribute(dpy, 0, 0, NV_ENABLED_DISPLAYS, &mask); /* Get first screen from the mask */ while(!((mask>>i) & 0x1)) i++; while(mask>>i && i < 32) { printf("Display options for %s:\n", mask_to_device((mask & (1<name != NULL; lst++) { int val; if(!NVGetAttribute(dpy, 0, mask & (1<option, &val)) { /* Option isn't supported on this card */ continue; } if((mask & (1<flags) printf(" %s", lst->name); } printf("\n"); i++; /* Get the next screen */ while(((mask>>i) & 0x1)==0) { i++; } } } void GetAttribute(Display *dpy, int screen, int disp_mask, int option) { NVOptionList *opt = nvcontrol_lookup_option(option); validated *res; int val=0; /* When flags is set then we are dealing with a display specific option. / Because of this we need to check if the given mask is valid. */ if(opt->flags) { int mask; NVGetAttribute(dpy, 0, 0, NV_ENABLED_DISPLAYS, &mask); if(disp_mask == 0) { printf("Error: Option '%s' needs a display.\n", opt->description); return; } if((disp_mask & mask) == 0) { printf("Error: Invalid display: %s.\n", mask_to_device(disp_mask)); return; } } if(!NVGetAttribute(dpy, 0, disp_mask, option, &val)) { printf("Error: Option '%s' isn't supported on this card.\n", opt->description); return; } else printf("Current value for option '%s': %d\n", opt->description, val); NVGetValidAttributeValues(dpy, screen, disp_mask, option, &res); /* boolean */ if(res->type == 3) { printf("Supported values for this option are: 0 and 1\n"); } /* range */ else if(res->type == 4) { printf("Supported values lie in the range from %d to %d\n", res->data1, res->data2); } /* bitmask */ else if(res->type == 5) { int i; printf("Supported values are:"); for(i=0; i <= 10; i++) { if((res->data1 >> i) & 0x1) { printf(" %d", i); } } printf("\n"); } } void SetAttribute(Display *dpy, int screen, int disp_mask, int option, int value) { int val=0; NVOptionList *opt = nvcontrol_lookup_option(option); validated *res; /* When flags is set then we are dealing with a display specific option. / Because of this we need to check if the given mask is valid. */ if(opt->flags) { int mask; NVGetAttribute(dpy, 0, 0, NV_ENABLED_DISPLAYS, &mask); if(disp_mask == 0) { printf("Error: Option '%s' needs a display.\n", opt->name); return; } if((disp_mask & mask) == 0) { printf("Error: Invalid display: %s.\n", mask_to_device(disp_mask)); return; } if(!NVGetAttribute(dpy, screen, disp_mask, option, &val)) { printf("Option '%s' isn't supported on display '%s'\n", opt->name, mask_to_device(disp_mask)); return; } } /* First use NVGetAttribute to see if the option is supported because NVGetValidAttributeValues is broken. */ if(!NVGetAttribute(dpy, screen, disp_mask, option, &val)) { printf("Option '%s' isn't supported on this card\n", opt->name); return; } NVGetValidAttributeValues(dpy, screen, disp_mask, option, &res); /* integer */ if(res->type == 1) { /* No value check is needed as there's no limit yet */ NVSetAttribute(dpy, screen, disp_mask, option, value); } /* bitmask */ else if(res->type == 2) { /* Do nothing as I don't have an option of this type yet */ } /* boolean */ else if(res->type == 3) { if(value > 1 || value < 0) { printf("Error: unsupported value %d for '%s'\n", value, opt->name); printf("Supported values for this option are: 0 and 1\n"); return; } else NVSetAttribute(dpy, screen, disp_mask, option, value); } /* range */ else if(res->type == 4) { int app_controlled=0; /* In case of FSAA and Aniso the application can decide what it likes to use. / As most applications don't support FSAA/Aniso there's a setting which allows / the user to choose settings himself. To allow user modifications application / control needs to be disabled else the changes don't do anything. / / The code below checks if application control is enabled for FSAA/Aniso and if / it is in case we want to adjust FSAA/Aniso it disables application control. */ if(option == NV_LOG_ANISO) { if(NVGetAttribute(dpy, screen, disp_mask, NV_ANISO_APP_CONTROLLED, &app_controlled)) { if(app_controlled) { NVSetAttribute(dpy, screen, disp_mask, NV_ANISO_APP_CONTROLLED, 0); } } } if(value < res->data1 || value > res->data2) { printf("Error: unsupported value %d for '%s'; ", value, opt->name); printf("Supported values lie in the range from %d to %d\n", res->data1, res->data2); return; } else NVSetAttribute(dpy, screen, disp_mask, option, value); } /* bitmask */ else if(res->type == 5) { int app_controlled=0; /* In case of FSAA/Aniso the application or user can decide which settings to use. / For modifactions done by the user application control needs to be disabled. For / more info read the comment located near the NV_ANISO check above. */ if(option == NV_FSAA) { if(NVGetAttribute(dpy, screen, disp_mask, NV_FSAA_APP_CONTROLLED, &app_controlled)) { if(app_controlled) { NVSetAttribute(dpy, screen, disp_mask, NV_FSAA_APP_CONTROLLED, 0); } } } if ((value > 31) || (value < 0) || ((res->data1 & (1<name); printf("Supported values are:"); for(i=0; i <= 10; i++) { if((res->data1 >> i) & 0x1) { printf(" %d", i); } } printf("\n"); return; } else NVSetAttribute(dpy, screen, disp_mask, option, value); } NVGetAttribute(dpy, screen, disp_mask, option, &val); printf("Option '%s' set to %d\n", opt->name, val); free(res); } #endif /* On various NV4x cards it is possible to enable additional / pixel and vertex units. On the commandline the user enters / a mask in binary/hexadecimal containing the pipelines to use. / This function convert the hex or binary value to a mask of several / bits that can be passed to the modding functions. */ unsigned char nv40_parse_units_mask(char *mask) { int i, check, value=0; /* Check if binary */ for(i=0, check=1; mask[i] && check; i++) check = ((mask[i] == '0') || (mask[i] == '1')) ? 1 : 0; if(check) value = strtol(mask, (char**)NULL, 2); /* Check if hex in case the value wasn't binary */ for(i=0, check=1; mask[i] && check && !value; i++) { check = isxdigit((unsigned char)mask[i]); /* strtoll supports both ff and 0xff */ if(!check && i==1) check = (mask[i] == 'x') ? 1 : 0; } /* Only convert if the value is hex; 10 / 11 are considered binary */ if(check && !value) value = strtol(mask, (char**)NULL, 16); if((value > 0) && (value < 256)) return (unsigned char)value; return 0; } /* Print various GPU registers for debugging purposes */ void print_debug_info() { printf("--- %s GPU registers ---\n", nv_card->card_name); printf("NV_PMC_BOOT_0 (0x0): %08x\n", nv_card->PMC[0]); printf("NV_PBUS_DEBUG_0 (0x1080): %08x\n", nv_card->PMC[0x1080/4]); printf("NV_PBUS_DEBUG_1 (0x1084): %08x\n", nv_card->PMC[0x1084/4]); printf("NV_PBUS_DEBUG_2 (0x1088): %08x\n", nv_card->PMC[0x1088/4]); printf("NV_PBUS_DEBUG_3 (0x108c): %08x\n", nv_card->PMC[0x108c/4]); printf("NV_10F0 (0x10f0): %08x\n", nv_card->PMC[0x10f0/4]); printf("NV_1540 (0x1540): %08x\n", nv_card->PMC[0x1540/4]); printf("NV_15B0 (0x15b0): %08x\n", nv_card->PMC[0x15b0/4]); printf("NV_15B4 (0x15b4): %08x\n", nv_card->PMC[0x15b4/4]); printf("NV_15B8 (0x15b8): %08x\n", nv_card->PMC[0x15b8/4]); printf("NV_15F0 (0x15f0): %08x\n", nv_card->PMC[0x15f0/4]); printf("NV_15F4 (0x15f4): %08x\n", nv_card->PMC[0x15f4/4]); printf("NV_15F8 (0x15f8): %08x\n", nv_card->PMC[0x15f8/4]); printf("NV_PBUS_PCI_0 (0x1800): %08x\n", nv_card->PMC[0x1800/4]); if(nv_card->arch & NV4X) { printf("NV_C010 (0xc010): %08x\n", nv_card->PMC[0xc010/4]); printf("NV_C014 (0xc014): %08x\n", nv_card->PMC[0xc014/4]); printf("NV_C018 (0xc018): %08x\n", nv_card->PMC[0xc018/4]); printf("NV_C01C (0xc01c): %08x\n", nv_card->PMC[0xc01c/4]); printf("NV_C020 (0xc020): %08x\n", nv_card->PMC[0xc020/4]); printf("NV_C024 (0xc024): %08x\n", nv_card->PMC[0xc024/4]); printf("NV_C028 (0xc028): %08x\n", nv_card->PMC[0xc028/4]); printf("NV_C02C (0xc02c): %08x\n", nv_card->PMC[0xc02c/4]); printf("NV_C040 (0xc040): %08x\n", nv_card->PMC[0xc040/4]); printf("NV40_NVPLL_A (0x4000): %08x\n", nv_card->PMC[0x4000/4]); printf("NV40_NVPLL_B (0x4004): %08x\n", nv_card->PMC[0x4004/4]); printf("NV_4008 (0x4008): %08x\n", nv_card->PMC[0x4008/4]); printf("NV_400C (0x400c): %08x\n", nv_card->PMC[0x400c/4]); printf("NV_4010 (0x4010): %08x\n", nv_card->PMC[0x4010/4]); printf("NV_4014 (0x4014): %08x\n", nv_card->PMC[0x4014/4]); printf("NV_4018 (0x4018): %08x\n", nv_card->PMC[0x4018/4]); printf("NV_401C (0x401c): %08x\n", nv_card->PMC[0x401c/4]); printf("NV40_MPLL_A (0x4020): %08x\n", nv_card->PMC[0x4020/4]); printf("NV40_MPLL_B (0x4024): %08x\n", nv_card->PMC[0x4024/4]); printf("NV_4028 (0x4028): %08x\n", nv_card->PMC[0x4028/4]); printf("NV_402C (0x402c): %08x\n", nv_card->PMC[0x402c/4]); printf("NV_4030 (0x4030): %08x\n", nv_card->PMC[0x4030/4]); printf("NV_4034 (0x4034): %08x\n", nv_card->PMC[0x4034/4]); printf("NV_4038 (0x4038): %08x\n", nv_card->PMC[0x4038/4]); printf("NV_403C (0x403c): %08x\n", nv_card->PMC[0x403c/4]); printf("NV_4040 (0x4040): %08x\n", nv_card->PMC[0x4040/4]); printf("NV_4044 (0x4044): %08x\n", nv_card->PMC[0x4044/4]); printf("NV_4048 (0x4048): %08x\n", nv_card->PMC[0x4048/4]); printf("NV_404C (0x404c): %08x\n", nv_card->PMC[0x404c/4]); printf("NV_4050 (0x4050): %08x\n", nv_card->PMC[0x4050/4]); printf("NV_4054 (0x4054): %08x\n", nv_card->PMC[0x4054/4]); printf("NV_4058 (0x4058): %08x\n", nv_card->PMC[0x4058/4]); printf("NV_405C (0x405c): %08x\n", nv_card->PMC[0x405c/4]); printf("NV_4060 (0x4060): %08x\n", nv_card->PMC[0x4060/4]); } printf("NV_PFB_CFG0 (0x100200): %08x\n", nv_card->PFB[0x200/4]); printf("NV_PFB_TIMING0 (0x100220): %08x\n", nv_card->PFB[0x220/4]); printf("NV_PFB_TIMING1 (0x100224): %08x\n", nv_card->PFB[0x224/4]); printf("NV_PFB_TIMING2 (0x100228): %08x\n", nv_card->PFB[0x228/4]); printf("NV_PEXTDEV_BOOT_0 (0x101000): %08x\n", nv_card->PEXTDEV[0x0/4]); printf("NV_NVPLL_COEFF_A (0x680500): %08x\n", nv_card->PRAMDAC[0x500/4]); printf("NV_MPLL_COEFF_A (0x680504): %08x\n", nv_card->PRAMDAC[0x504/4]); printf("NV_VPLL_COEFF (0x680508): %08x\n", nv_card->PRAMDAC[0x508/4]); printf("NV_PLL_COEFF_SELECT (0x68050c): %08x\n", nv_card->PRAMDAC[0x50c/4]); printf("NV_NVPLL_COEFF_B (0x680570: %08x\n", nv_card->PRAMDAC[0x570/4]); printf("NV_MPLL_COEFF_B (0x680574: %08x\n", nv_card->PRAMDAC[0x574/4]); } void unload_nvclock() { #ifdef HAVE_NVCONTROL /* Close the X display */ if(nvclock.dpy) XCloseDisplay(nvclock.dpy); #endif /* Free the config file structure */ if(nvclock.cfg) destroy(&nvclock.cfg); } int main(int argc, char *argv[]) { int backend, card_number, deviceid, opt; float memclk, nvclk; short backend_opt, card_opt, debug_opt, fanspeed_opt, force_opt, deviceid_opt, reset_opt, smartdimmer_opt, speeds_opt, temp_opt; short assign_opt, info_opt, list_opt, query_opt; short punit_opt, vunit_opt; char *fanspeed = NULL; char *screen = NULL; char *smartdimmer = NULL; unsigned char punit, vunit; #ifdef HAVE_NVCONTROL Display *dpy = NULL; #endif assign_opt = 0; backend_opt = 0; card_opt = 0; debug_opt = 0; deviceid_opt = 0; fanspeed_opt = 0; force_opt = 0; info_opt = 0; list_opt = 0; query_opt = 0; punit_opt = 0; reset_opt = 0; speeds_opt = 0; smartdimmer_opt = 0; temp_opt = 0; vunit_opt = 0; backend = 0; card_number = 0; deviceid = 0; memclk = 0; nvclk = 0; punit = 0; vunit = 0; nvclock.dpy = NULL; /* If no options are given. */ if (argc == 1) { usage(); return 0; } if(!init_nvclock()) { char buf[80]; fprintf(stderr, "Error: %s\n", get_error(buf, 80)); return 0; } /* We don't advertise the OpenGL options if we are building without X */ #ifndef HAVE_NVCONTROL while ( ( opt = getopt_long (argc, argv, "m:n:b:c:F:P:Q:S:V:fidDrsTh", long_options, NULL)) != -1 ) #else while ( ( opt = getopt_long (argc, argv, "m:n:b:a:q:c:F:P:Q:S:V:x:lfidDrsTh", long_options, NULL)) != -1 ) #endif { switch (opt) { case 'b': backend_opt = 1; if(!strcasecmp(optarg, "lowlevel")) backend = STATE_LOWLEVEL; else if(!strcasecmp(optarg, "coolbits2d")) backend = STATE_2D; else if(!strcasecmp(optarg, "coolbits3d")) backend = STATE_3D; else if(!strcasecmp(optarg, "coolbits")) backend = STATE_BOTH; else { fprintf(stderr, "Invalid backend '%s' use coolbits/coolbits2d/coolbits3d or lowlevel\n", optarg); return 0; } break; case 'c': card_number = strtol(optarg, (char **)NULL, 10)-1; /* If the user only the card number. */ if(argc == 3) { fprintf(stderr, "Error: You only used the -c option\n"); return 0; } /* Check if the card number is valid; Note that internally card_number is 1 smaller than the entered value. */ if((card_number < 0) || (card_number >= nvclock.num_cards)) { fprintf(stderr, "Error: You entered an invalid card number!\nUse the -s option to show all card numbers\n\n"); return 0; } card_opt = 1; break; case 'd': /* If the user only entered the -d option */ if(argc == 2) { fprintf(stderr, "Error: You only used the -d option\n"); return 0; } nv_card->debug = 1; break; case 'D': debug_opt = 1; break; case 'F': fanspeed = (char*)strdup(optarg); fanspeed_opt = 1; break; case 'f': /* If the user only entered the -f option */ if(argc == 2) { fprintf(stderr, "Error: You only used the -f option\n"); return 0; } force_opt = 1; break; case 'i': info_opt = 1; break; case 'm': memclk = strtol(optarg, (char **)NULL, 10); if(memclk < 0) { fprintf(stderr, "Wrong value for memclk: %f\n", memclk); return 1; } break; case 'n': nvclk = strtol(optarg, (char **)NULL, 10); if(nvclk < 0) { fprintf(stderr, "Wrong value of nvclk: %f\n", nvclk); return 1; } break; case 'P': punit = nv40_parse_units_mask(optarg); if(!punit) { fprintf(stderr, "Wrong value '%s' for pixel unit mask, the value needs to be a binary/hexadecimal number between 0 and 255 (decimal).\n", optarg); return 1; } punit_opt=1; break; case 'Q': deviceid = strtol(optarg, (char **)NULL, 10); deviceid_opt = 1; break; case 'S': smartdimmer = (char*)strdup(optarg); smartdimmer_opt = 1; break; case 'T': temp_opt = 1; break; case 'V': vunit = nv40_parse_units_mask(optarg); if(!vunit) { fprintf(stderr, "Wrong value '%s' for vertex unit mask, the value needs to be a binary/hexadecimal number between 0 and 255 (decimal).\n", optarg); return 1; } vunit_opt=1; break; case 'r': reset_opt = 1; break; case 's': speeds_opt = 1; break; /* NVControl options */ #ifdef HAVE_NVCONTROL case 'a': /* If the user only entered the -q option */ if(argc == 2) { fprintf(stderr, "Error: You only used the -a option\n"); return 0; } parse_gl_cmdline_option(optarg, ASSIGN_VALUE); assign_opt = 1; break; case 'l': list_opt = 1; break; case 'q': parse_gl_cmdline_option(optarg, QUERY_VALUE); query_opt = 1; break; case 'x': /* If the user only entered the -x option */ if(argc == 2) { fprintf(stderr, "Error: You only used the -x option\n"); return 0; } screen = (char*)strdup(optarg); break; #endif case 'h': usage(); break; default: return 0; } } atexit(unload_nvclock); #ifdef HAVE_NVCONTROL if(assign_opt || list_opt || query_opt) { dpy = XOpenDisplay(screen); if(dpy == NULL) { fprintf(stderr, "Can't open screen: %s\n", screen); return 0; } if(!init_nvcontrol(dpy)) { printf("Can't initialize the NV-CONTROL extension which is needed for changing OpenGL settings\n"); return 0; } nvclock.dpy = dpy; } if(list_opt) { ShowGlAttributes(dpy); } if(query_opt) { int i; for(i=0; icard_name); printf("Card number: \t%d\n", i+1); if(nv_card->caps & COOLBITS_OVERCLOCKING) { printf("Mode\t\tGPU Clock\tMemory Clock\n"); nv_card->set_state(STATE_2D); printf("Coolbits 2D: \t%0.3f MHz\t%0.3f MHz\n", nv_card->get_gpu_speed(), nv_card->get_memory_speed()); nv_card->set_state(STATE_3D); printf("Coolbits 3D: \t%0.3f MHz\t%0.3f MHz\n", nv_card->get_gpu_speed(), nv_card->get_memory_speed()); nv_card->set_state(STATE_LOWLEVEL); printf("Current: \t%0.3f MHz\t%0.3f MHz\n\n", nv_card->get_gpu_speed(), nv_card->get_memory_speed()); } else { printf("Memory clock: \t%0.3f MHz\n", nv_card->get_memory_speed()); printf("GPU clock: \t%0.3f MHz\n\n", nv_card->get_gpu_speed()); } /* Detect only the requested card */ if(card_opt) break; } return 0; } /* set the card object to the requested card */ if(!set_card(card_number)) { char buf[80]; fprintf(stderr, "Error: %s\n", get_error(buf, 80)); return 0; } if(backend_opt) { if(backend == STATE_LOWLEVEL) nv_card->set_state(STATE_LOWLEVEL); else if((nv_card->caps & COOLBITS_OVERCLOCKING) && nvclock.dpy) nv_card->set_state(backend); else if(!nvclock.dpy) /* If not lowlevel then we want to use Coolbits */ { fprintf(stderr, "Error:\n"); fprintf(stderr, "Can't switch to the Coolbits backend because X isn't loaded\n"); return 0; } else if(!(nv_card->arch & (NV3X | NV4X))) { fprintf(stderr, "Error:\n"); fprintf(stderr, "Can't switch to the Coolbits backend because it requires a GeforceFX/6/7 card.\n"); return 0; } else if(nv_card->gpu == MOBILE) { fprintf(stderr, "Error:\n"); fprintf(stderr, "Can't switch to the Coolbits backend because it doesn't work on Mobile GPUs.\n"); return 0; } else { fprintf(stderr, "Error:\n"); fprintf(stderr, "Can't switch to the Coolbits backend because the NV-CONTROL extension wans't found.\nThis can happen when you aren't using Nvidia driver 1.0-7676 or newer or when the option isn't enabled in the X config file.\n"); return 0; } } /* Make NVClock work on unsupported cards and access higher speeds as requested by the user */ if(force_opt && nv_card->gpu == UNKNOWN) { nvclock.card[card_number].gpu = DESKTOP; nv_card->number = -1; /* Force a re-init of the function pointers */ set_card(card_number); } /* Check if the card is supported, if not print a message. */ if((nvclock.card[card_number].gpu == UNKNOWN) && (force_opt == 0)) { fprintf(stderr, "It seems your card isn't officialy supported in NVClock yet.\n"); fprintf(stderr, "The reason can be that your card is too new.\n"); fprintf(stderr, "If you want to try it anyhow [DANGEROUS], use the option -f to force the setting(s).\n"); fprintf(stderr, "NVClock will then assume your card is a 'normal', it might be dangerous on other cards.\n"); fprintf(stderr, "Also please email the author the pci_id of the card for further investigation.\n[Get that value using the -i option].\n\n"); return 0; } /* Print debug info for debugging purposes; This is different from the -d switch / which only adds debugging to low-level clock functions. */ if(debug_opt) { print_debug_info(); return 0; } if(deviceid_opt) { if(!(nv_card->caps & GPU_ID_MODDING)) { fprintf(stderr, "Error: Your card doesn't support device id adjustments!\nThis can either be because your GPU is a Riva TNT/TNT2 or if your card is using a AGP->PCI-Express / PCI-Express->AGP bridge chip.\n"); return 0; } /* We support both specifying the digit and a full device id */ if((deviceid > 16) && ((deviceid & 0xfffffff0) != (nv_card->device_id & 0xfff0))) { fprintf(stderr, "Error: Invalid value! Specify either a correct digit (<16) or a full device id in decimal.\n"); return 0; } if(!nv_card->set_gpu_pci_id(deviceid & 0xf)) fprintf(stderr, "Error: Something went wrong during pci id adjustment. Most likely you are using a Geforce1/2 card in which case the specified 'digit' needs to be smaller than 4.\n"); printf("Adjusted the pci id to 0x%x (%s)\n", nv_card->device_id, nv_card->card_name); } if(fanspeed_opt && force_opt) { float dutycycle; if(!(nv_card->caps & (GPU_FANSPEED_MONITORING | I2C_FANSPEED_MONITORING))) { fprintf(stderr, "Error: Your card doesn't support fanspeed adjustments!\n"); return 0; } if(fanspeed[0] == '+' || fanspeed[0] == '-') { if(nv_card->caps & I2C_FANSPEED_MONITORING) dutycycle = nv_card->get_i2c_fanspeed_pwm(nv_card->sensor); else dutycycle = nv_card->get_fanspeed(); dutycycle += (float)strtol(fanspeed, (char**)NULL, 10); if((dutycycle < 10) || (dutycycle > 100)) { fprintf(stderr, "Error: The proposed fanspeed change would result in a fanspeed lower than 10%% or higher than 100%%.\n"); return 0; } } else if(strcmp(fanspeed, "auto") == 0) { if(!(nv_card->caps & I2C_AUTOMATIC_FANSPEED_CONTROL)) { fprintf(stderr, "Error: This card doesn't support automatic fanspeed adjustments.\n"); return 0; } nv_card->set_i2c_fanspeed_mode(nv_card->sensor, 0); /* Put the sensor back in auto mode */ printf("New fanspeed mode: %s\n", nv_card->get_i2c_fanspeed_mode(nv_card->sensor) ? "manual" : "auto"); } else { dutycycle = (float)strtol(fanspeed, (char**)NULL, 10); if((dutycycle < 10) || (dutycycle > 100)) { fprintf(stderr, "Error: Incorrect fanspeed '%.1f', you need to choose a value between 10%% and 100%%.\n", dutycycle); return 0; } } /* First process cards with 'advanced' sensor chips */ if(nv_card->caps & I2C_FANSPEED_MONITORING) { printf("Current fanspeed: %d RPM\n", nv_card->get_i2c_fanspeed_rpm(nv_card->sensor)); printf("PWM duty cycle: %.1f%%\n", nv_card->get_i2c_fanspeed_pwm(nv_card->sensor)); printf("Changing duty cycle from %.1f to %.1f\n", nv_card->get_i2c_fanspeed_pwm(nv_card->sensor), dutycycle); /* speed is a value between 10% and 100% */ nv_card->set_i2c_fanspeed_pwm(nv_card->sensor, dutycycle); /* It takes a short time for the fanspeed to change */ usleep(100); printf("Fanspeed: %d RPM\n", nv_card->get_i2c_fanspeed_rpm(nv_card->sensor)); printf("New PWM duty cycle: %.1f\n", nv_card->get_i2c_fanspeed_pwm(nv_card->sensor)); } /* Various standard GeforceFX/6 also have some fanspeed monitoring support */ else if(nv_card->caps & GPU_FANSPEED_MONITORING) { printf("Current fanspeed: %.1f%%\n", nv_card->get_fanspeed()); printf("Changing fanspeed from %.1f%% to %.1f%%\n", nv_card->get_fanspeed(), dutycycle); nv_card->set_fanspeed(dutycycle); printf("New fanspeed: %.1f%%\n", nv_card->get_fanspeed()); } free(fanspeed); } else if(fanspeed_opt) { if(nv_card->caps & (GPU_FANSPEED_MONITORING | I2C_FANSPEED_MONITORING)) { fprintf(stderr, "Error!\n"); fprintf(stderr, "While NVClock can adjust the fanspeed of your videocard this features is disabled by default because of safety reasons.!\n"); fprintf(stderr, "If you really know what you are doing you can enable it by adding the -f switch to the nvclock command.\n"); } else fprintf(stderr, "Error: Your adjustment of the fanspeed isn't supported on your type of videocard!\n"); return 0; } if(smartdimmer_opt) { int brightness; if(!(nv_card->caps & SMARTDIMMER)) { fprintf(stderr, "Error!\n"); fprintf(stderr, "Smartdimmer is only supported on laptops using a Geforce 6200Go. If you want support on your laptop contact the author.\n"); return 0; } if(smartdimmer[0] == '+' || smartdimmer[0] == '-') { brightness = nv_card->mobile_get_smartdimmer() + strtol(smartdimmer, (char**)NULL, 10); if((brightness < 15) || (brightness > 100)) { fprintf(stderr, "Error: The proposed Smartdimmer change would result in a brightness level lower than 15%% or higher than 100%%.\n"); return 0; } } else { brightness = strtol(smartdimmer, (char**)NULL, 10); if((brightness < 15) || (brightness > 100)) { fprintf(stderr, "Error: Incorrect Smartdimmer level '%d%%', you need to choose a value between 15%% and 100%%\n", brightness); return 0; } } printf("Changing Smartdimmer level from %d%% to %d%%\n", nv_card->mobile_get_smartdimmer(), brightness); nv_card->mobile_set_smartdimmer(brightness); printf("New Smartdimmer level: %d%%\n", nv_card->mobile_get_smartdimmer()); free(smartdimmer); } if(punit_opt && (nv_card->caps & PIPELINE_MODDING) && force_opt) { char pmask[8], vmask[8]; unsigned char hw_default = 0; int punits, total; if(nv_card->get_sw_masked_units(pmask, vmask, 1)) { hw_default = ~pmask[0] & nv_card->get_default_mask() & 0xff; } else if(nv_card->get_hw_masked_units(pmask, vmask, 1)) { hw_default = ~pmask[0] & nv_card->get_default_mask() & 0xff; } else /* No locked units, so nothing left to enable */ { fprintf(stderr, "Error: Your card doesn't contain any extra pixel units to enable.\n"); return 0; } /* We can't enable more pixel units then available */ if(punit > (nv_card->get_default_mask() & 0xff)) { fprintf(stderr, "Error: Illegal mask '%x', can't enable more pixel units than your card contains ('%x')!\n", punit, hw_default); return 0; } punits = nv_card->get_pixel_pipelines(pmask, 0, &total); printf("Current pixel unit configuration: %dx%d (%sb)\n", total, punits, pmask); nv_card->set_pixel_pipelines(punit); punits = nv_card->get_pixel_pipelines(pmask, 0, &total); printf("New pixel unit configuration: %dx%d (%sb)\n", total, punits, pmask); } else if(punit_opt) { if(nv_card->caps & PIPELINE_MODDING) { fprintf(stderr, "Error!\n"); fprintf(stderr, "While pipeline modding is supported on your card it is disabled by default because of safety reasons.\n"); fprintf(stderr, "Pipeline modding can't be used while the Nvidia driver is active (exit X and unload the kernel module).\n"); fprintf(stderr, "If you don't follow these instructions there's a big chance that your computer will freeze.\n"); fprintf(stderr, "When you are ready and know what you are doing enable this option using the -f switch.\n"); } else fprintf(stderr, "Error: your card doesn't support pipeline modding\n"); return 0; } if(vunit_opt && (nv_card->caps & PIPELINE_MODDING) && force_opt) { char pmask[8], vmask[8]; unsigned char hw_default = 0; int vunits; if(nv_card->get_sw_masked_units(pmask, vmask, 1)) { hw_default = ~vmask[0] & (nv_card->get_default_mask() >> 8); } else if(nv_card->get_hw_masked_units(pmask, vmask, 1)) { hw_default = ~vmask[0] & (nv_card->get_default_mask() >> 8); } else /* No locked units, so nothing left to enable */ { fprintf(stderr, "Error: Your card doesn't contain any extra vertex units to enable.\n"); return 0; } /* We can't enable more vertex units then available */ if(vunit > (nv_card->get_default_mask()>>8)) { fprintf(stderr, "Error: Illegal mask '%x', can't enable more vertex units than your card contains ('%x')!\n", punit, hw_default); return 0; } vunits = nv_card->get_vertex_pipelines(vmask, 0); printf("Current pixel unit configuration: %dx1 (%sb)\n", vunits, vmask); nv_card->set_vertex_pipelines(vunit); vunits = nv_card->get_vertex_pipelines(vmask, 0); printf("New vertex unit configuration: %dx1 (%sb)\n", vunits, vmask); } else if(vunit_opt) { if(nv_card->caps & PIPELINE_MODDING) { fprintf(stderr, "Error!\n"); fprintf(stderr, "While pipeline modding is supported on your card it is disabled by default because of safety reasons.\n"); fprintf(stderr, "Pipeline modding can't be used while the Nvidia driver is active (exit X and unload the kernel module).\n"); fprintf(stderr, "If you don't follow these instructions there's a big chance that your computer will freeze.\n"); fprintf(stderr, "When you are ready and know what you are doing enable this option using the -f switch.\n"); } else fprintf(stderr, "Error: your card doesn't support pipeline modding.\n"); return 0; } if(temp_opt) { if(nv_card->caps & (GPU_TEMP_MONITORING)) { printf("%s\n", nv_card->card_name); printf("=> GPU temperature: %dC\n", nv_card->get_gpu_temp(nv_card->sensor)); if(nv_card->caps & (BOARD_TEMP_MONITORING)) printf("=> Board temperature: %dC\n", nv_card->get_board_temp(nv_card->sensor)); } else fprintf(stderr, "Error: temperature monitoring isn't supported on your videocard.\n"); return 0; } /* Get the card information for the currently selected card */ if(info_opt) { /* In case of NV3x/NV4x boards make sure we use the low-level path */ if((nv_card->caps & COOLBITS_OVERCLOCKING) && (nv_card->state != STATE_LOWLEVEL)) nv_card->set_state(STATE_LOWLEVEL); printf("-- General info --\n"); printf("Card: \t\t%s\n", nv_card->card_name); printf("Architecture: \tNV%X %X\n", nv_card->get_gpu_architecture(), nv_card->get_gpu_revision()); printf("PCI id: \t0x%x\n", nv_card->device_id); printf("GPU clock: \t%0.3f MHz\n", nv_card->get_gpu_speed()); printf("Bustype: \t%s\n\n", nv_card->get_bus_type()); /* Pipeline info is supported on NV4X cards */ if(nv_card->arch & NV4X) { char pmask[8], vmask[8]; int pixel_pipes, vertex_pipes, total; printf("-- Pipeline info --\n"); pixel_pipes = nv_card->get_pixel_pipelines(pmask, 0, &total); printf("Pixel units: %dx%d (%sb)\n", pixel_pipes, total, pmask); vertex_pipes = nv_card->get_vertex_pipelines(vmask, 0); printf("Vertex units: %dx1 (%sb)\n", vertex_pipes, vmask); if(nv_card->get_hw_masked_units(pmask, vmask, 0)) printf("HW masked units: pixel %sb vertex %sb\n", pmask, vmask); else printf("HW masked units: None\n"); if(nv_card->get_sw_masked_units(pmask, vmask, 0)) printf("SW masked units: pixel %sb\t vertex %sb\n\n", pmask, vmask); else printf("SW masked units: None\n\n"); } printf("-- Memory info --\n"); printf("Amount: \t%d MB\n", nv_card->get_memory_size()); printf("Type: \t\t%d bit %s\n", nv_card->get_memory_width(), nv_card->get_memory_type()); printf("Clock: \t\t%0.3f MHz\n\n", nv_card->get_memory_speed()); if(strcmp(nv_card->get_bus_type(), "AGP") == 0) { printf("-- AGP info --\n"); printf("Status: \t%s\n", nv_card->get_agp_status()); printf("Rate: \t\t%dX\n", nv_card->get_bus_rate()); printf("AGP rates: \t%s\n", nv_card->get_agp_supported_rates()); printf("Fast Writes: \t%s\n", nv_card->get_agp_fw_status()); printf("SBA: \t\t%s\n\n", nv_card->get_agp_sba_status()); } if(strcmp(nv_card->get_bus_type(), "PCI-Express") == 0) { printf("-- PCI-Express info --\n"); printf("Current Rate: \t%dX\n", nv_card->get_bus_rate()); printf("Maximum rate: \t%dX\n\n", nv_card->get_pcie_max_bus_rate()); } if(nv_card->caps & SMARTDIMMER) { printf("-- Smartdimmer info --\n"); printf("Backlight level: %d%%\n\n", nv_card->mobile_get_smartdimmer()); } /* On some Geforce 6600(GT) cards, we can adjust the fans while we can't access the sensor yet */ if(nv_card->caps & (BOARD_TEMP_MONITORING | GPU_TEMP_MONITORING | GPU_FANSPEED_MONITORING)) { printf("-- Sensor info --\n"); printf("Sensor: %s\n", nv_card->sensor_name); if(nv_card->caps & BOARD_TEMP_MONITORING) printf("Board temperature: %dC\n", nv_card->get_board_temp(nv_card->sensor)); if(nv_card->caps & GPU_TEMP_MONITORING) printf("GPU temperature: %dC\n", nv_card->get_gpu_temp(nv_card->sensor)); /* Cards equipped with sensors like the Fintek F75375 use this chip for fanspeed stuff */ if(nv_card->caps & I2C_FANSPEED_MONITORING) { printf("Fanspeed: %d RPM\n", nv_card->get_i2c_fanspeed_rpm(nv_card->sensor)); if(nv_card->caps & I2C_AUTOMATIC_FANSPEED_CONTROL) printf("Fanspeed mode: %s\n", nv_card->get_i2c_fanspeed_mode(nv_card->sensor) ? "manual" : "auto"); printf("PWM duty cycle: %.1f%%\n", nv_card->get_i2c_fanspeed_pwm(nv_card->sensor)); } /* Nvidia reference boards allow fanspeed adjustments/monitoring using a special register */ else if(nv_card->caps & GPU_FANSPEED_MONITORING) printf("Fanspeed: %.1f%%\n", nv_card->get_fanspeed()); printf("\n"); } if(nv_card->bios) { int i; printf("-- VideoBios information --\n"); printf("Version: %s\n", nv_card->bios->version); printf("Signon message: %s\n", nv_card->bios->signon_msg); for(i=0; i< nv_card->bios->perf_entries; i++) { printf("Performance level %d: gpu %d", i, nv_card->bios->perf_lst[i].nvclk); if(nv_card->bios->perf_lst[i].delta) printf("(+%d)", nv_card->bios->perf_lst[i].delta); printf("MHz/memory %dMHz", nv_card->bios->perf_lst[i].memclk); if(nv_card->bios->volt_entries) printf("/%.2fV", nv_card->bios->perf_lst[i].voltage); if(nv_card->bios->perf_lst[i].fanspeed) printf("/%d%%", nv_card->bios->perf_lst[i].fanspeed); printf("\n"); } if(nv_card->bios->volt_entries) printf("VID mask: %x\n", nv_card->bios->volt_mask); for(i=0; i< nv_card->bios->volt_entries; i++) { /* For now assume the first memory entry is the right one; should be fixed as some bioses contain various different entries */ /* Note that voltage entries in general don't correspond to performance levels!! */ printf("Voltage level %d: %.2fV, VID: %x\n", i, nv_card->bios->volt_lst[i].voltage, nv_card->bios->volt_lst[i].VID); } printf("\n"); } return 0; } if(reset_opt) { if(nv_card->gpu == MOBILE && !force_opt) { fprintf(stderr, "Error: By default overclocking is disabled on laptops. If you know what you are doing enable it using the -f option.\n"); return 0; } nv_card->reset_gpu_speed(); nv_card->reset_memory_speed(); printf("Your %s has been restored to its original clocks\n", nv_card->card_name); printf("Memory clock: \t%0.3f MHz\n", nv_card->get_memory_speed()); printf("GPU clock: \t%0.3f MHz\n\n", nv_card->get_gpu_speed()); return 0; } /* Check if the gpu speed is higher than NVClock's max speed (+25%), if not print a message. */ if( (nvclk >= nv_card->nvclk_max) && force_opt == 0) { fprintf(stderr, "Warning!\n"); fprintf(stderr, "You entered a core speed of %.3f MHz and NVClock believes %d.000 MHz is the maximum!\n", nvclk, nv_card->nvclk_max); fprintf(stderr, "This error appears when the entered speed is 25%% higher than the default speed.\n"); fprintf(stderr, "If you really want to use this speed, use the option -f to force it.\n\n"); return 0; } /* Check if the memory speed is higher than NVClock's max speed (+25%), if not print a message. */ if( (memclk >= nv_card->memclk_max) && force_opt == 0) { fprintf(stderr, "Warning!\n"); fprintf(stderr, "You entered a memory speed of %.3f MHz and NVClock believes %d.000 MHz is the maximum!\n", memclk, nv_card->memclk_max); fprintf(stderr, "This error appears when the entered speed is 25%% higher than the default speed.\n"); fprintf(stderr, "If you really want to use this speed, use the option -f to force it.\n\n"); return 0; } if(memclk != 0) { /* Check if memory overclocking is supported; this isn't the case for the nforce where there's no real video memory */ if((nv_card->caps & MEM_OVERCLOCKING) || (nv_card->gpu == MOBILE && force_opt)) { printf("Requested memory clock: \t%0.3f MHz\n", memclk); nv_card->set_memory_speed(memclk); } else if(nv_card->gpu == MOBILE) { fprintf(stderr, "Error: Memory overclocking is disabled on laptops. If you know what you are doing enable it using the -f option.\n"); return 0; } else if(nv_card->gpu == NFORCE) { fprintf(stderr, "Error: Memory overclocking isn't supported on NForce cards because system memory is used for Video.\n"); return 0; } else { fprintf(stderr, "Error: Memory overclocking isn't supported on your videocard (yet).\n"); return 0; } } if(nvclk != 0) { if((nv_card->caps & GPU_OVERCLOCKING) || (nv_card->gpu == MOBILE && force_opt)) { printf("Requested core clock: \t\t%0.3f MHz\n", nvclk); nv_card->set_gpu_speed(nvclk); } else if(nv_card->gpu == MOBILE) { fprintf(stderr, "Error: GPU overclocking is disabled on laptops. If you know what you are doing enable it using the -f option.\n"); return 0; } else { fprintf(stderr, "Error: GPU overclocking isn't supported on your videocard (yet).\n"); return 0; } } /* Only show the speeds when the user is overclocking */ if(memclk || nvclk) { if((nv_card->caps & COOLBITS_OVERCLOCKING) && (nv_card->state != STATE_LOWLEVEL)) { if(nv_card->state == STATE_2D) printf("\nAdjusted Coolbits 2D clocks on a %s\n", nv_card->card_name); else if(nv_card->state == STATE_3D) printf("\nAdjusted Coolbits 3D clocks on a %s\n", nv_card->card_name); else printf("\nAdjusted Coolbits 2D/3D clocks on a %s\n", nv_card->card_name); } else printf("\nAdjusted low-level clocks on a %s\n", nv_card->card_name); printf("Memory clock: \t%0.3f MHz\n", nv_card->get_memory_speed()); printf("GPU clock: \t%0.3f MHz\n\n", nv_card->get_gpu_speed()); } return 0; }