int nouveau_therm_fan_set_mode(struct nouveau_therm *therm, enum nouveau_therm_fan_mode mode) { struct nouveau_therm_priv *priv = (void *)therm; if (priv->fan.mode == mode) return 0; if (mode < FAN_CONTROL_NONE || mode >= FAN_CONTROL_NR) return -EINVAL; switch (mode) { case FAN_CONTROL_NONE: nv_info(therm, "switch fan to no-control mode\n"); break; case FAN_CONTROL_MANUAL: nv_info(therm, "switch fan to manual mode\n"); break; case FAN_CONTROL_NR: break; } priv->fan.mode = mode; return 0; }
void nouveau_therm_sensor_event(struct nouveau_therm *therm, enum nouveau_therm_thrs thrs, enum nouveau_therm_thrs_direction dir) { struct nouveau_therm_priv *priv = (void *)therm; bool active; const char *thresolds[] = { "fanboost", "downclock", "critical", "shutdown" }; int temperature = therm->temp_get(therm); if (thrs < 0 || thrs > 3) return; if (dir == NOUVEAU_THERM_THRS_FALLING) nv_info(therm, "temperature (%i C) went below the '%s' threshold\n", temperature, thresolds[thrs]); else nv_info(therm, "temperature (%i C) hit the '%s' threshold\n", temperature, thresolds[thrs]); active = (dir == NOUVEAU_THERM_THRS_RISING); switch (thrs) { case NOUVEAU_THERM_THRS_FANBOOST: if (active) { nouveau_therm_fan_set(therm, true, 100); nouveau_therm_fan_mode(therm, NOUVEAU_THERM_CTRL_AUTO); } break; case NOUVEAU_THERM_THRS_DOWNCLOCK: if (priv->emergency.downclock) priv->emergency.downclock(therm, active); break; case NOUVEAU_THERM_THRS_CRITICAL: if (priv->emergency.pause) priv->emergency.pause(therm, active); break; case NOUVEAU_THERM_THRS_SHUTDOWN: if (active) { struct work_struct *work; work = kmalloc(sizeof(*work), GFP_ATOMIC); if (work) { INIT_WORK(work, nv_poweroff_work); schedule_work(work); } } break; case NOUVEAU_THERM_THRS_NR: break; } }
void nv50_mpeg_intr(struct nvkm_subdev *subdev) { struct nv50_mpeg_priv *priv = (void *)subdev; u32 stat = nv_rd32(priv, 0x00b100); u32 type = nv_rd32(priv, 0x00b230); u32 mthd = nv_rd32(priv, 0x00b234); u32 data = nv_rd32(priv, 0x00b238); u32 show = stat; if (stat & 0x01000000) { /* happens on initial binding of the object */ if (type == 0x00000020 && mthd == 0x0000) { nv_wr32(priv, 0x00b308, 0x00000100); show &= ~0x01000000; } } if (show) { nv_info(priv, "0x%08x 0x%08x 0x%08x 0x%08x\n", stat, type, mthd, data); } nv_wr32(priv, 0x00b100, stat); nv_wr32(priv, 0x00b230, 0x00000001); }
int nouveau_fb_created(struct nouveau_fb *pfb) { static const char *name[] = { [NV_MEM_TYPE_UNKNOWN] = "unknown", [NV_MEM_TYPE_STOLEN ] = "stolen system memory", [NV_MEM_TYPE_SGRAM ] = "SGRAM", [NV_MEM_TYPE_SDRAM ] = "SDRAM", [NV_MEM_TYPE_DDR1 ] = "DDR1", [NV_MEM_TYPE_DDR2 ] = "DDR2", [NV_MEM_TYPE_DDR3 ] = "DDR3", [NV_MEM_TYPE_GDDR2 ] = "GDDR2", [NV_MEM_TYPE_GDDR3 ] = "GDDR3", [NV_MEM_TYPE_GDDR4 ] = "GDDR4", [NV_MEM_TYPE_GDDR5 ] = "GDDR5", }; if (pfb->ram.size == 0) { nv_fatal(pfb, "no vram detected!!\n"); return -ERANGE; } nv_info(pfb, "RAM type: %s\n", name[pfb->ram.type]); nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram.size >> 20)); return 0; }
static bool probe_monitoring_device(struct nouveau_i2c_port *i2c, struct i2c_board_info *info, void *data) { struct nouveau_therm_priv *priv = data; struct nvbios_therm_sensor *sensor = &priv->bios_sensor; struct i2c_client *client; request_module("%s%s", I2C_MODULE_PREFIX, info->type); client = i2c_new_device(&i2c->adapter, info); if (!client) return false; if (!client->dev.driver || to_i2c_driver(client->dev.driver)->detect(client, info)) { i2c_unregister_device(client); return false; } nv_info(priv, "Found an %s at address 0x%x (controlled by lm_sensors, " "temp offset %+i C)\n", info->type, info->addr, sensor->offset_constant); priv->ic = client; return true; }
int nouveau_therm_fan_mode(struct nouveau_therm *therm, int mode) { struct nouveau_therm_priv *priv = (void *)therm; struct nouveau_device *device = nv_device(therm); static const char *name[] = { "disabled", "manual", "automatic" }; /* The default PDAEMON ucode interferes with fan management */ if ((mode >= ARRAY_SIZE(name)) || (mode != NOUVEAU_THERM_CTRL_NONE && device->card_type >= NV_C0)) return -EINVAL; /* do not allow automatic fan management if the thermal sensor is * not available */ if (priv->mode == 2 && therm->temp_get(therm) < 0) return -EINVAL; if (priv->mode == mode) return 0; nv_info(therm, "fan management: %s\n", name[mode]); nouveau_therm_update(therm, mode); return 0; }
int nouveau_therm_fan_ctor(struct nouveau_therm *therm) { struct nouveau_therm_priv *priv = (void *)therm; struct nouveau_gpio *gpio = nouveau_gpio(therm); struct nouveau_bios *bios = nouveau_bios(therm); struct dcb_gpio_func func; int ret; /* attempt to locate a drivable fan, and determine control method */ ret = gpio->find(gpio, 0, DCB_GPIO_FAN, 0xff, &func); if (ret == 0) { /* FIXME: is this really the place to perform such checks ? */ if (func.line != 16 && func.log[0] & DCB_GPIO_LOG_DIR_IN) { nv_debug(therm, "GPIO_FAN is in input mode\n"); ret = -EINVAL; } else { ret = nouveau_fanpwm_create(therm, &func); if (ret != 0) ret = nouveau_fantog_create(therm, &func); } } /* no controllable fan found, create a dummy fan module */ if (ret != 0) { ret = nouveau_fannil_create(therm); if (ret) return ret; } nv_info(therm, "FAN control: %s\n", priv->fan->type); /* read the current speed, it is useful when resuming */ priv->fan->percent = nouveau_therm_fan_get(therm); /* attempt to detect a tachometer connection */ ret = gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &priv->fan->tach); if (ret) priv->fan->tach.func = DCB_GPIO_UNUSED; /* initialise fan bump/slow update handling */ priv->fan->parent = therm; nouveau_alarm_init(&priv->fan->alarm, nouveau_fan_alarm); spin_lock_init(&priv->fan->lock); /* other random init... */ nouveau_therm_fan_set_defaults(therm); nvbios_perf_fan_parse(bios, &priv->fan->perf); if (!nvbios_fan_parse(bios, &priv->fan->bios)) { nv_debug(therm, "parsing the fan table failed\n"); if (nvbios_therm_fan_parse(bios, &priv->fan->bios)) nv_error(therm, "parsing both fan tables failed\n"); } nouveau_therm_fan_safety_checks(therm); return 0; }
void nouveau_therm_sensor_preinit(struct nouveau_therm *therm) { const char *sensor_avail = "yes"; if (therm->temp_get(therm) < 0) sensor_avail = "no"; nv_info(therm, "internal sensor: %s\n", sensor_avail); }
static int nouveau_bios_score(struct nouveau_bios *bios, const bool writeable) { if (bios->size < 3 || !bios->data || bios->data[0] != 0x55 || bios->data[1] != 0xAA) { nv_info(bios, "... signature not found\n"); return 0; } if (nvbios_checksum(bios->data, min_t(u32, bios->data[2] * 512, bios->size))) { nv_info(bios, "... checksum invalid\n"); /* if a ro image is somewhat bad, it's probably all rubbish */ return writeable ? 2 : 1; } nv_info(bios, "... appears to be valid\n"); return 3; }
static void gm107_ltc_lts_isr(struct nvkm_ltc_priv *priv, int ltc, int lts) { u32 base = 0x140000 + (ltc * 0x2000) + (lts * 0x400); u32 stat = nv_rd32(priv, base + 0x00c); if (stat) { nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", ltc, lts, stat); nv_wr32(priv, base + 0x00c, stat); } }
static void nvc0_ltcg_subp_isr(struct nvc0_ltcg_priv *priv, int unit, int subp) { u32 subp_base = 0x141000 + (unit * 0x2000) + (subp * 0x400); u32 stat = nv_rd32(priv, subp_base + 0x020); if (stat) { nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", unit, subp, stat); nv_wr32(priv, subp_base + 0x020, stat); } }
static void gf100_ltcg_lts_isr(struct gf100_ltcg_priv *priv, int ltc, int lts) { u32 base = 0x141000 + (ltc * 0x2000) + (lts * 0x400); u32 stat = nv_rd32(priv, base + 0x020); if (stat) { nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", ltc, lts, stat); nv_wr32(priv, base + 0x020, stat); } }
static void nv50_vpe_intr(struct nvkm_subdev *subdev) { struct nv50_mpeg_priv *priv = (void *)subdev; if (nv_rd32(priv, 0x00b100)) nv50_mpeg_intr(subdev); if (nv_rd32(priv, 0x00b800)) { u32 stat = nv_rd32(priv, 0x00b800); nv_info(priv, "PMSRCH: 0x%08x\n", stat); nv_wr32(priv, 0xb800, stat); } }
static void gf100_ltc_lts_intr(struct nvkm_ltc_priv *priv, int ltc, int lts) { u32 base = 0x141000 + (ltc * 0x2000) + (lts * 0x400); u32 intr = nv_rd32(priv, base + 0x020); u32 stat = intr & 0x0000ffff; if (stat) { nv_info(priv, "LTC%d_LTS%d:", ltc, lts); nvkm_bitfield_print(gf100_ltc_lts_intr_name, stat); pr_cont("\n"); } nv_wr32(priv, base + 0x020, intr); }
static unsigned long get_agp_mode(struct nouveau_drm *drm, const struct drm_agp_info *info) { struct nouveau_device *device = nv_device(drm->device); struct nouveau_agpmode_quirk *quirk = nouveau_agpmode_quirk_list; int agpmode = nouveau_agpmode; unsigned long mode = info->mode; /* * FW seems to be broken on nv18, it makes the card lock up * randomly. */ if (device->chipset == 0x18) mode &= ~PCI_AGP_COMMAND_FW; /* * Go through the quirks list and adjust the agpmode accordingly. */ while (agpmode == -1 && quirk->hostbridge_vendor) { if (info->id_vendor == quirk->hostbridge_vendor && info->id_device == quirk->hostbridge_device && device->pdev->vendor == quirk->chip_vendor && device->pdev->device == quirk->chip_device) { agpmode = quirk->mode; nv_info(device, "Forcing agp mode to %dX. Use agpmode to override.\n", agpmode); break; } ++quirk; } /* * AGP mode set in the command line. */ if (agpmode > 0) { bool agpv3 = mode & 0x8; int rate = agpv3 ? agpmode / 4 : agpmode; mode = (mode & ~0x7) | (rate & 0x7); } return mode; }
int nv04_devinit_init(struct nouveau_object *object) { struct nv04_devinit_priv *priv = (void *)object; if (!priv->base.post) { u32 htotal = nv_rdvgac(priv, 0, 0x06); htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x01) << 8; htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x20) << 4; htotal |= (nv_rdvgac(priv, 0, 0x25) & 0x01) << 10; htotal |= (nv_rdvgac(priv, 0, 0x41) & 0x01) << 11; if (!htotal) { nv_info(priv, "adaptor not initialised\n"); priv->base.post = true; } } return nouveau_devinit_init(&priv->base); }
int _nouveau_volt_init(struct nouveau_object *object) { struct nouveau_volt *volt = (void *)object; int ret; ret = nouveau_subdev_init(&volt->base); if (ret) return ret; ret = volt->get(volt); if (ret < 0) { if (ret != -ENODEV) nv_debug(volt, "current voltage unknown\n"); return 0; } nv_info(volt, "GPU voltage: %duv\n", ret); return 0; }
static void nouveau_bios_shadow_of(struct nouveau_bios *bios) { struct pci_dev *pdev = nv_device(bios)->pdev; struct device_node *dn; const u32 *data; int size; dn = pci_device_to_OF_node(pdev); if (!dn) { nv_info(bios, "Unable to get the OF node\n"); return; } data = of_get_property(dn, "NVDA,BMP", &size); if (data && size) { bios->size = size; bios->data = kmalloc(bios->size, GFP_KERNEL); if (bios->data) memcpy(bios->data, data, size); } }
static int gk20a_volt_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { struct gk20a_volt_priv *priv; struct nvkm_volt *volt; struct nouveau_platform_device *plat; int i, ret, uv; ret = nvkm_volt_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; volt = &priv->base; plat = nv_device_to_platform(nv_device(parent)); uv = regulator_get_voltage(plat->gpu->vdd); nv_info(priv, "The default voltage is %duV\n", uv); priv->vdd = plat->gpu->vdd; priv->base.vid_get = gk20a_volt_vid_get; priv->base.vid_set = gk20a_volt_vid_set; priv->base.set_id = gk20a_volt_set_id; volt->vid_nr = ARRAY_SIZE(gk20a_cvb_coef); nv_debug(priv, "%s - vid_nr = %d\n", __func__, volt->vid_nr); for (i = 0; i < volt->vid_nr; i++) { volt->vid[i].vid = i; volt->vid[i].uv = gk20a_volt_calc_voltage(&gk20a_cvb_coef[i], plat->gpu_speedo); nv_debug(priv, "%2d: vid=%d, uv=%d\n", i, volt->vid[i].vid, volt->vid[i].uv); } return 0; }
bool GeforceSensors::start(IOService *provider) { HWSensorsDebugLog("Starting..."); if (!super::start(provider)) return false; struct nouveau_device *device = &card; // map device memory if ((device->pcidev = (IOPCIDevice*)provider)) { device->pcidev->setMemoryEnable(true); if ((device->mmio = device->pcidev->mapDeviceMemoryWithIndex(0))) { nv_debug(device, "memory mapped successfully\n"); } else { HWSensorsFatalLog("failed to map memory"); return false; } } else { HWSensorsFatalLog("failed to assign PCI device"); return false; } card.card_index = -1; if (OSData *multiboard_capable = OSDynamicCast(OSData, provider->getProperty("rm_multiboard_capable"))) { if (0x1 == *((UInt32*)multiboard_capable->getBytesNoCopy())) { if (OSData *board_number = OSDynamicCast(OSData, provider->getProperty("rm_board_number"))) { UInt8 index = *((UInt32*)board_number->getBytesNoCopy()); card.card_index = takeGPUIndex(index); } } } if (card.card_index < 0) card.card_index = takeVacantGPUIndex(); if (card.card_index < 0) { HWSensorsFatalLog("failed to take vacant GPU index"); return false; } // identify chipset if (!nouveau_identify(device)) { releaseGPUIndex(card.card_index); return false; } // shadow and parse bios //try to load bios from registry first from "vbios" property created by Chameleon boolloader if (OSData *vbios = OSDynamicCast(OSData, provider->getProperty("vbios"))) { device->bios.size = vbios->getLength(); device->bios.data = (u8*)IOMalloc(card.bios.size); memcpy(device->bios.data, vbios->getBytesNoCopy(), device->bios.size); } if (!device->bios.data || !device->bios.size || nouveau_bios_score(device, true) < 1) if (!nouveau_bios_shadow(device)) { if (device->bios.data && device->bios.size) { IOFree(card.bios.data, card.bios.size); device->bios.data = NULL; device->bios.size = 0; } nv_fatal(device, "unable to shadow VBIOS\n"); releaseGPUIndex(card.card_index); card.card_index = -1; return false; } nouveau_vbios_init(device); nouveau_bios_parse(device); // initialize funcs and variables if (!nouveau_init(device)) { nv_error(device, "unable to initialize monitoring driver\n"); releaseGPUIndex(card.card_index); card.card_index = -1; return false; } nv_info(device, "chipset: %s (NV%02X) bios: %02x.%02x.%02x.%02x\n", device->cname, device->chipset, device->bios.version.major, device->bios.version.chip, device->bios.version.minor, device->bios.version.micro); if (device->card_type < NV_C0) { // init i2c structures nouveau_i2c_create(device); // setup nouveau i2c sensors nouveau_i2c_probe(device); } // Register sensors char key[5]; if (card.core_temp_get || card.board_temp_get) { nv_debug(device, "registering i2c temperature sensors...\n"); if (card.core_temp_get && card.board_temp_get) { snprintf(key, 5, KEY_FORMAT_GPU_DIODE_TEMPERATURE, card.card_index); addSensor(key, TYPE_SP78, 2, kFakeSMCTemperatureSensor, nouveau_temp_core); snprintf(key, 5, KEY_FORMAT_GPU_HEATSINK_TEMPERATURE, card.card_index); addSensor(key, TYPE_SP78, 2, kFakeSMCTemperatureSensor, nouveau_temp_board); } else if (card.core_temp_get) { snprintf(key, 5, KEY_FORMAT_GPU_DIODE_TEMPERATURE, card.card_index); addSensor(key, TYPE_SP78, 2, kFakeSMCTemperatureSensor, nouveau_temp_core); } else if (card.board_temp_get) { snprintf(key, 5, KEY_FORMAT_GPU_HEATSINK_TEMPERATURE, card.card_index); addSensor(key, TYPE_SP78, 2, kFakeSMCTemperatureSensor, nouveau_temp_board); } } else if (card.temp_get) { nv_debug(device, "registering temperature sensors...\n"); snprintf(key, 5, KEY_FORMAT_GPU_DIODE_TEMPERATURE, card.card_index); addSensor(key, TYPE_SP78, 2, kFakeSMCTemperatureSensor, nouveau_temp_diode); } int arg_value = 1; if (card.clocks_get && !PE_parse_boot_argn("-gpusensors-no-clocks", &arg_value, sizeof(arg_value))) { nv_debug(device, "registering clocks sensors...\n"); if (card.clocks_get(&card, nouveau_clock_core) > 0) { snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_FREQUENCY, card.card_index); addSensor(key, TYPE_UI32, TYPE_UI32_SIZE, kFakeSMCFrequencySensor, nouveau_clock_core); } // if (card.clocks_get(&card, nouveau_clock_shader) > 0) { // snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_SHADER_FREQUENCY, card.card_index); // addSensor(key, TYPE_UI32, TYPE_UI32_SIZE, kFakeSMCFrequencySensor, nouveau_clock_shader); // } if (card.clocks_get(&card, nouveau_clock_rop) > 0) { snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_ROP_FREQUENCY, card.card_index); addSensor(key, TYPE_UI32, TYPE_UI32_SIZE, kFakeSMCFrequencySensor, nouveau_clock_rop); } if (card.clocks_get(&card, nouveau_clock_memory) > 0) { snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_MEMORY_FREQUENCY, card.card_index); addSensor(key, TYPE_UI32, TYPE_UI32_SIZE, kFakeSMCFrequencySensor, nouveau_clock_memory); } } if (card.fan_pwm_get || card.fan_rpm_get) { nv_debug(device, "registering PWM sensors...\n"); char title[DIAG_FUNCTION_STR_LEN]; snprintf (title, DIAG_FUNCTION_STR_LEN, "GPU %X", card.card_index + 1); if (card.fan_rpm_get && card.fan_rpm_get(device) >= 0) addTachometer(nouveau_fan_rpm, title, GPU_FAN_RPM, card.card_index); if (card.fan_pwm_get && card.fan_pwm_get(device) >= 0) addTachometer(nouveau_fan_pwm, title, GPU_FAN_PWM_CYCLE, card.card_index); } if (card.voltage_get && card.voltage.supported) { nv_debug(device, "registering voltage sensors...\n"); snprintf(key, 5, KEY_FORMAT_GPU_VOLTAGE, card.card_index); addSensor(key, TYPE_FP2E, TYPE_FPXX_SIZE, kFakeSMCVoltageSensor, 0); } registerService(); nv_info(device, "started\n"); return true; }
static int nouveau_bios_shadow(struct nouveau_bios *bios) { struct methods shadow_methods[] = { #if defined(__powerpc__) { "OpenFirmware", nouveau_bios_shadow_of, true, 0, 0, NULL }, #endif { "PRAMIN", nouveau_bios_shadow_pramin, true, 0, 0, NULL }, { "PROM", nouveau_bios_shadow_prom, false, 0, 0, NULL }, { "ACPI", nouveau_bios_shadow_acpi, true, 0, 0, NULL }, { "PCIROM", nouveau_bios_shadow_pci, true, 0, 0, NULL }, { "PLATFORM", nouveau_bios_shadow_platform, true, 0, 0, NULL }, {} }; struct methods *mthd, *best; const struct firmware *fw; const char *optarg; int optlen, ret; char *source; optarg = nouveau_stropt(nv_device(bios)->cfgopt, "NvBios", &optlen); source = optarg ? kstrndup(optarg, optlen, GFP_KERNEL) : NULL; if (source) { /* try to match one of the built-in methods */ mthd = shadow_methods; do { if (strcasecmp(source, mthd->desc)) continue; nv_info(bios, "source: %s\n", mthd->desc); mthd->shadow(bios); mthd->score = nouveau_bios_score(bios, mthd->rw); if (mthd->score) { kfree(source); return 0; } } while ((++mthd)->shadow); /* attempt to load firmware image */ ret = request_firmware(&fw, source, &nv_device(bios)->pdev->dev); if (ret == 0) { bios->size = fw->size; bios->data = kmemdup(fw->data, fw->size, GFP_KERNEL); release_firmware(fw); nv_info(bios, "image: %s\n", source); if (nouveau_bios_score(bios, 1)) { kfree(source); return 0; } kfree(bios->data); bios->data = NULL; } nv_error(bios, "source \'%s\' invalid\n", source); kfree(source); } mthd = shadow_methods; do { nv_info(bios, "checking %s for image...\n", mthd->desc); mthd->shadow(bios); mthd->score = nouveau_bios_score(bios, mthd->rw); mthd->size = bios->size; mthd->data = bios->data; bios->data = NULL; } while (mthd->score != 3 && (++mthd)->shadow); mthd = shadow_methods; best = mthd; do { if (mthd->score > best->score) { kfree(best->data); best = mthd; } } while ((++mthd)->shadow); if (best->score) { nv_info(bios, "using image from %s\n", best->desc); bios->size = best->size; bios->data = best->data; return 0; } nv_error(bios, "unable to locate usable image\n"); return -EINVAL; }
int nv50_devinit_init(struct nouveau_object *object) { struct nouveau_bios *bios = nouveau_bios(object); struct nv50_devinit_priv *priv = (void *)object; struct nvbios_outp info; struct dcb_output outp; u8 ver = 0xff, hdr, cnt, len; int ret, i = 0; if (!priv->base.post) { if (!nv_rdvgac(priv, 0, 0x00) && !nv_rdvgac(priv, 0, 0x1a)) { nv_info(priv, "adaptor not initialised\n"); priv->base.post = true; } } ret = nouveau_devinit_init(&priv->base); if (ret) return ret; /* if we ran the init tables, we have to execute the first script * pointer of each dcb entry's display encoder table in order * to properly initialise each encoder. */ while (priv->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) { if (nvbios_outp_match(bios, outp.hasht, outp.hashm, &ver, &hdr, &cnt, &len, &info)) { struct nvbios_init init = { .subdev = nv_subdev(priv), .bios = bios, .offset = info.script[0], .outp = &outp, .crtc = -1, .execute = 1, }; nvbios_exec(&init); } i++; } return 0; } static int nv50_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { struct nv50_devinit_priv *priv; int ret; ret = nouveau_devinit_create(parent, engine, oclass, &priv); *pobject = nv_object(priv); if (ret) return ret; priv->base.pll_set = nv50_devinit_pll_set; return 0; } struct nouveau_oclass nv50_devinit_oclass = { .handle = NV_SUBDEV(DEVINIT, 0x50), .ofuncs = &(struct nouveau_ofuncs) { .ctor = nv50_devinit_ctor, .dtor = _nouveau_devinit_dtor, .init = nv50_devinit_init, .fini = _nouveau_devinit_fini, }, };
int nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *bclass, int length, void **pobject) { const struct nouveau_mc_oclass *oclass = (void *)bclass; struct nouveau_device *device = nv_device(parent); struct nouveau_mc *pmc; int ret; ret = nouveau_subdev_create_(parent, engine, bclass, 0, "PMC", "master", length, pobject); pmc = *pobject; if (ret) return ret; if (nv_device_is_pci(device)) switch (device->pdev->device & 0x0ff0) { case 0x00f0: case 0x02e0: /* BR02? NFI how these would be handled yet exactly */ break; default: switch (device->chipset) { case 0xaa: /* reported broken, nv also disable it */ break; default: pmc->use_msi = true; break; } pmc->use_msi = nouveau_boolopt(device->cfgopt, "NvMSI", pmc->use_msi); if (pmc->use_msi && oclass->msi_rearm) { pmc->use_msi = pci_enable_msi(device->pdev) == 0; if (pmc->use_msi) { nv_info(pmc, "MSI interrupts enabled\n"); oclass->msi_rearm(pmc); } } else { pmc->use_msi = false; } } #if defined(__NetBSD__) if (nv_device_is_pci(device)) { const pci_chipset_tag_t pc = device->pdev->pd_pa.pa_pc; pci_intr_handle_t ih; if (pci_intr_map(&device->pdev->pd_pa, &ih)) return -EIO; pmc->irq_cookie = pci_intr_establish(pc, ih, IPL_VM, &nouveau_mc_intr, pmc); if (pmc->irq_cookie == NULL) return -EIO; #if defined (__arm__) } else { pmc->irq_cookie = intr_establish(TEGRA_INTR_GPU, IPL_VM, IST_LEVEL, nouveau_mc_intr, pmc); if (pmc->irq_cookie == NULL) return -EIO; #endif } #else ret = nv_device_get_irq(device, true); if (ret < 0) return ret; pmc->irq = ret; ret = request_irq(pmc->irq, nouveau_mc_intr, IRQF_SHARED, "nouveau", pmc); if (ret < 0) return ret; #endif return 0; }
bool nvclock_i2c_sensor_init(nouveau_device *device) { int num_busses = 0; I2CBusPtr busses[4]; struct nouveau_i2c_port *port = NULL; for (int i = 0; i <= 4; i++) { if ((port = nouveau_i2c_find(&device->i2c, NV_I2C_DEFAULT(i)))) { char name[16]; snprintf(name, 16, "NV_I2C_DEFAULT%X", i); busses[num_busses++] = nvclock_i2c_create_bus_ptr(device, STRDUP(name, sizeof(name)), port->drive); } } if (num_busses > 0) { device->nvclock_i2c_sensor = nvclock_i2c_probe_devices(device, busses, num_busses); /* When a sensor is available, enable the correct function pointers */ if(device->nvclock_i2c_sensor) { nv_info(device, "found %s monitoring chip\n", device->nvclock_i2c_sensor->chip_name); switch(device->nvclock_i2c_sensor->chip_id) { case LM99: case MAX6559: device->board_temp_get = lm99_get_board_temp; device->diode_temp_get = lm99_get_gpu_temp; break; case F75375: device->board_temp_get = f75375_get_board_temp; device->diode_temp_get = f75375_get_gpu_temp; device->rpm_fan_get = f75375_get_fanspeed_rpm; device->pwm_fan_get = f75375_get_fanspeed_pwm; break; case W83781D: device->board_temp_get = w83781d_get_board_temp; device->diode_temp_get = w83781d_get_gpu_temp; //nv_card->get_i2c_fanspeed_rpm = w83781d_get_fanspeed_rpm; //nv_card->get_i2c_fanspeed_pwm = w83781d_get_fanspeed_pwm; break; case W83L785R: device->board_temp_get = w83l785r_get_board_temp; device->diode_temp_get = w83l785r_get_gpu_temp; device->rpm_fan_get = w83l785r_get_fanspeed_rpm; device->pwm_fan_get = w83l785r_get_fanspeed_pwm; break; case ADT7473: device->board_temp_get = adt7473_get_board_temp; device->diode_temp_get = adt7473_get_gpu_temp; device->rpm_fan_get = adt7473_get_fanspeed_rpm; device->pwm_fan_get = adt7473_get_fanspeed_pwm; break; default: break; } } return true; } return false; }
bool GeforceSensors::managedStart(IOService *provider) { HWSensorsDebugLog("Starting..."); struct nouveau_device *device = &card; if (!device->bios.data || !device->bios.size) { if (!shadowBios()) { nv_fatal(device, "unable to shadow VBIOS\n"); releaseGPUIndex(card.card_index); card.card_index = -1; return false; } } nouveau_vbios_init(device); nouveau_bios_parse(device); // initialize funcs and variables if (!nouveau_init(device)) { nv_error(device, "unable to initialize monitoring driver\n"); releaseGPUIndex(card.card_index); card.card_index = -1; return false; } nv_info(device, "chipset: %s (NV%02X) bios: %02x.%02x.%02x.%02x\n", device->cname, device->chipset, device->bios.version.major, device->bios.version.chip, device->bios.version.minor, device->bios.version.micro); if (device->card_type < NV_C0) { // init i2c structures nouveau_i2c_create(device); // setup nouveau i2c sensors nouveau_i2c_probe(device); } // Register sensors char key[5]; if (card.core_temp_get || card.board_temp_get) { nv_debug(device, "registering i2c temperature sensors...\n"); if (card.core_temp_get) { snprintf(key, 5, KEY_FORMAT_GPU_DIODE_TEMPERATURE, card.card_index); addSensorForKey(key, TYPE_SP78, 2, kFakeSMCTemperatureSensor, nouveau_temp_core); } else if (card.board_temp_get) { snprintf(key, 5, KEY_FORMAT_GPU_HEATSINK_TEMPERATURE, card.card_index); addSensorForKey(key, TYPE_SP78, 2, kFakeSMCTemperatureSensor, nouveau_temp_board); } } else if (card.temp_get) { nv_debug(device, "registering temperature sensors...\n"); snprintf(key, 5, KEY_FORMAT_GPU_DIODE_TEMPERATURE, card.card_index); addSensorForKey(key, TYPE_SP78, 2, kFakeSMCTemperatureSensor, nouveau_temp_diode); } int arg_value = 1; if (card.clocks_get && !PE_parse_boot_argn("-gpusensors-no-clocks", &arg_value, sizeof(arg_value))) { nv_debug(device, "registering clocks sensors...\n"); if (card.clocks_get(&card, nouveau_clock_core) > 0) { snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_FREQUENCY, card.card_index); addSensorForKey(key, TYPE_UI32, TYPE_UI32_SIZE, kFakeSMCFrequencySensor, nouveau_clock_core); } // if (card.clocks_get(&card, nouveau_clock_shader) > 0) { // snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_SHADER_FREQUENCY, card.card_index); // addSensor(key, TYPE_UI32, TYPE_UI32_SIZE, kFakeSMCFrequencySensor, nouveau_clock_shader); // } if (card.clocks_get(&card, nouveau_clock_rop) > 0) { snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_ROP_FREQUENCY, card.card_index); addSensorForKey(key, TYPE_UI32, TYPE_UI32_SIZE, kFakeSMCFrequencySensor, nouveau_clock_rop); } if (card.clocks_get(&card, nouveau_clock_memory) > 0) { snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_MEMORY_FREQUENCY, card.card_index); addSensorForKey(key, TYPE_UI32, TYPE_UI32_SIZE, kFakeSMCFrequencySensor, nouveau_clock_memory); } } if (card.fan_pwm_get || card.fan_rpm_get) { nv_debug(device, "registering PWM sensors...\n"); char title[DIAG_FUNCTION_STR_LEN]; snprintf (title, DIAG_FUNCTION_STR_LEN, "GPU %X", card.card_index + 1); if (card.fan_rpm_get && card.fan_rpm_get(&card) >= 0) addTachometer(nouveau_fan_rpm, title, GPU_FAN_RPM, card.card_index); if (card.fan_pwm_get && card.fan_pwm_get(&card) >= 0) addTachometer(nouveau_fan_pwm, title, GPU_FAN_PWM_CYCLE, card.card_index); } if (card.volt.get && card.volt.get(&card) >= 0/*card.voltage_get && card.voltage.supported*/) { nv_debug(device, "registering voltage sensors...\n"); snprintf(key, 5, KEY_FORMAT_GPU_VOLTAGE, card.card_index); addSensorForKey(key, TYPE_FP2E, TYPE_FPXX_SIZE, kFakeSMCVoltageSensor, 0); } registerService(); nv_info(device, "started\n"); return true; }
bool GeforceSensors::start(IOService * provider) { DebugLog("Starting..."); if (!super::start(provider)) return false; if (!(fakeSMC = waitForService(serviceMatching(kFakeSMCDeviceService)))) { WarningLog("Can't locate fake SMC device, kext will not load"); return false; } struct nouveau_device *device = &card; //Find card number card.card_index = getVacantGPUIndex(); if (card.card_index < 0) { nv_error(device, "failed to obtain vacant GPU index\n"); return false; } // map device memory // device->pcidev = (IOPCIDevice*)provider; if (device->pcidev) { device->pcidev->setMemoryEnable(true); if ((device->mmio = device->pcidev->mapDeviceMemoryWithIndex(0))) { nv_debug(device, "memory mapped successfully\n"); } else { nv_error(device, "failed to map memory\n"); return false; } } else { nv_error(device, "failed to assign PCI device\n"); return false; } // identify chipset if (!nouveau_identify(device)) return false; // shadow and parse bios //try to load bios from registry first from "vbios" property created by Chameleon boolloader if (OSData *vbios = OSDynamicCast(OSData, provider->getProperty("vbios"))) { device->bios.size = vbios->getLength(); device->bios.data = (u8*)IOMalloc(card.bios.size); memcpy(device->bios.data, vbios->getBytesNoCopy(), device->bios.size); } if (!device->bios.data || !device->bios.size || nouveau_bios_score(device, true) < 1) if (!nouveau_bios_shadow(device)) { if (device->bios.data && device->bios.size) { IOFree(card.bios.data, card.bios.size); device->bios.data = NULL; device->bios.size = 0; } nv_error(device, "unable to shadow VBIOS\n"); return false; } nouveau_vbios_init(device); nouveau_bios_parse(device); // initialize funcs and variables if (!nouveau_init(device)) { nv_error(device, "unable to initialize monitoring driver\n"); return false; } nv_info(device, "chipset: %s (NV%02X) bios: %02x.%02x.%02x.%02x\n", device->cname, (unsigned int)device->chipset, device->bios.version.major, device->bios.version.chip, device->bios.version.minor, device->bios.version.micro); if (device->card_type < NV_C0) { // init i2c structures nouveau_i2c_create(device); // setup nouveau i2c sensors nouveau_i2c_probe(device); } // Register sensors char key[5]; if (card.core_temp_get || card.board_temp_get) { nv_debug(device, "registering i2c temperature sensors...\n"); if (card.core_temp_get && card.board_temp_get) { snprintf(key, 5, KEY_FORMAT_GPU_DIODE_TEMPERATURE, card.card_index); this->addSensor(key, TYPE_SP78, 2, 0); snprintf(key, 5, KEY_FORMAT_GPU_HEATSINK_TEMPERATURE, card.card_index); addSensor(key, TYPE_SP78, 2, 0); } else if (card.core_temp_get) { snprintf(key, 5, KEY_FORMAT_GPU_PROXIMITY_TEMPERATURE, card.card_index); addSensor(key, TYPE_SP78, 2, 0); } else if (card.board_temp_get) { snprintf(key, 5, KEY_FORMAT_GPU_PROXIMITY_TEMPERATURE, card.card_index); addSensor(key, TYPE_SP78, 2, 0); } } else if (card.temp_get) { nv_debug(device, "registering temperature sensors...\n"); snprintf(key, 5, KEY_FORMAT_GPU_PROXIMITY_TEMPERATURE, card.card_index); addSensor(key, TYPE_SP78, 2, 0); } if (card.clocks_get) { nv_debug(device, "registering clocks sensors...\n"); if (card.clocks_get(&card, nouveau_clock_core) > 0) { snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_FREQUENCY, card.card_index); addSensor(key, TYPE_UI32, TYPE_UI32_SIZE, nouveau_clock_core); } if (card.clocks_get(&card, nouveau_clock_shader) > 0) { snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_SHADER_FREQUENCY, card.card_index); addSensor(key, TYPE_UI32, TYPE_UI32_SIZE, nouveau_clock_shader); } if (card.clocks_get(&card, nouveau_clock_rop) > 0) { snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_ROP_FREQUENCY, card.card_index); addSensor(key, TYPE_UI32, TYPE_UI32_SIZE, nouveau_clock_rop); } if (card.clocks_get(&card, nouveau_clock_memory) > 0) { snprintf(key, 5, KEY_FAKESMC_FORMAT_GPU_MEMORY_FREQUENCY, card.card_index); addSensor(key, TYPE_UI32, TYPE_UI32_SIZE, nouveau_clock_memory); } } if (card.fan_pwm_get || card.fan_rpm_get) { nv_debug(device, "registering PWM sensors...\n"); if (card.fan_rpm_get && card.fan_rpm_get(device) > 0) { char title[6]; snprintf (title, 6, "GPU %X", card.card_index + 1); UInt8 fanIndex = 0; if (addTachometer( fanIndex)) { if (card.fan_pwm_get && card.fan_pwm_get(device) > 0) { snprintf(key, 5, KEY_FAKESMC_FORMAT_GPUPWM, fanIndex); addSensor(key, TYPE_UI8, TYPE_UI8_SIZE, 0); } } } } if (card.voltage_get && card.voltage.supported) { nv_debug(device, "registering voltage sensors...\n"); snprintf(key, 5, KEY_FORMAT_GPU_VOLTAGE, card.card_index); addSensor(key, TYPE_FP2E, TYPE_FPXX_SIZE, 0); } nv_info(device, "started\n"); return true; }