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; }
static void nouveau_therm_update(struct nouveau_therm *therm, int mode) { struct nouveau_timer *ptimer = nouveau_timer(therm); struct nouveau_therm_priv *priv = (void *)therm; unsigned long flags; bool immd = true; bool poll = true; int duty = -1; spin_lock_irqsave(&priv->lock, flags); if (mode < 0) mode = priv->mode; priv->mode = mode; switch (mode) { case NOUVEAU_THERM_CTRL_MANUAL: ptimer->alarm_cancel(ptimer, &priv->alarm); duty = nouveau_therm_fan_get(therm); if (duty < 0) duty = 100; poll = false; break; case NOUVEAU_THERM_CTRL_AUTO: switch(priv->fan->bios.fan_mode) { case NVBIOS_THERM_FAN_TRIP: duty = nouveau_therm_update_trip(therm); break; case NVBIOS_THERM_FAN_LINEAR: duty = nouveau_therm_update_linear(therm); break; case NVBIOS_THERM_FAN_OTHER: if (priv->cstate) duty = priv->cstate; poll = false; break; } immd = false; break; case NOUVEAU_THERM_CTRL_NONE: default: ptimer->alarm_cancel(ptimer, &priv->alarm); poll = false; } if (list_empty(&priv->alarm.head) && poll) ptimer->alarm(ptimer, 1000000000ULL, &priv->alarm); spin_unlock_irqrestore(&priv->lock, flags); if (duty >= 0) { nv_debug(therm, "FAN target request: %d%%\n", duty); nouveau_therm_fan_set(therm, immd, duty); } }
static void nouveau_therm_update(struct nouveau_therm *therm, int mode) { struct nouveau_timer *ptimer = nouveau_timer(therm); struct nouveau_therm_priv *priv = (void *)therm; unsigned long flags; int duty; spin_lock_irqsave(&priv->lock, flags); nv_debug(therm, "FAN speed check\n"); if (mode < 0) mode = priv->mode; priv->mode = mode; switch (mode) { case NOUVEAU_THERM_CTRL_MANUAL: ptimer->alarm_cancel(ptimer, &priv->alarm); duty = nouveau_therm_fan_get(therm); if (duty < 0) duty = 100; break; case NOUVEAU_THERM_CTRL_AUTO: if (priv->fan->bios.nr_fan_trip) duty = nouveau_therm_update_trip(therm); else duty = nouveau_therm_update_linear(therm); break; case NOUVEAU_THERM_CTRL_NONE: default: ptimer->alarm_cancel(ptimer, &priv->alarm); goto done; } nv_debug(therm, "FAN target request: %d%%\n", duty); nouveau_therm_fan_set(therm, (mode != NOUVEAU_THERM_CTRL_AUTO), duty); done: if (list_empty(&priv->alarm.head) && (mode == NOUVEAU_THERM_CTRL_AUTO)) ptimer->alarm(ptimer, 1000000000ULL, &priv->alarm); else if (!list_empty(&priv->alarm.head)) nv_debug(therm, "therm fan alarm list is not empty\n"); spin_unlock_irqrestore(&priv->lock, flags); }
int nouveau_therm_fan_user_get(struct nouveau_therm *therm) { return nouveau_therm_fan_get(therm); }