static void alarm_timer_callback(struct nouveau_alarm *alarm) { struct nouveau_therm_priv *priv = container_of(alarm, struct nouveau_therm_priv, sensor.therm_poll_alarm); struct nvbios_therm_sensor *sensor = &priv->bios_sensor; struct nouveau_timer *ptimer = nouveau_timer(priv); struct nouveau_therm *therm = &priv->base; unsigned long flags; spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags); nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_fan_boost, NOUVEAU_THERM_THRS_FANBOOST); nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_down_clock, NOUVEAU_THERM_THRS_DOWNCLOCK); nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_critical, NOUVEAU_THERM_THRS_CRITICAL); nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_shutdown, NOUVEAU_THERM_THRS_SHUTDOWN); /* schedule the next poll in one second */ if (therm->temp_get(therm) >= 0 && list_empty(&alarm->head)) ptimer->alarm(ptimer, 1000 * 1000 * 1000, alarm); spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags); }
int nv04_pm_clocks_set(struct drm_device *dev, void *pre_state) { struct nouveau_device *device = nouveau_dev(dev); struct nouveau_timer *ptimer = nouveau_timer(device); struct nv04_pm_state *state = pre_state; prog_pll(dev, &state->core); if (state->memory.pll.reg) { prog_pll(dev, &state->memory); if (device->card_type < NV_30) { if (device->card_type == NV_20) nv_mask(device, 0x1002c4, 0, 1 << 20); /* Reset the DLLs */ nv_mask(device, 0x1002c0, 0, 1 << 8); } } nv_ofuncs(ptimer)->init(nv_object(ptimer)); kfree(state); return 0; }
static int nv84_graph_tlb_flush(struct nouveau_engine *engine) { struct nouveau_timer *ptimer = nouveau_timer(engine); struct nv50_graph_priv *priv = (void *)engine; bool idle, timeout = false; unsigned long flags; u64 start; u32 tmp; spin_lock_irqsave(&priv->lock, flags); nv_mask(priv, 0x400500, 0x00000001, 0x00000000); start = ptimer->read(ptimer); do { idle = true; for (tmp = nv_rd32(priv, 0x400380); tmp && idle; tmp >>= 3) { if ((tmp & 7) == 1) idle = false; } for (tmp = nv_rd32(priv, 0x400384); tmp && idle; tmp >>= 3) { if ((tmp & 7) == 1) idle = false; } for (tmp = nv_rd32(priv, 0x400388); tmp && idle; tmp >>= 3) { if ((tmp & 7) == 1) idle = false; } } while (!idle && !(timeout = ptimer->read(ptimer) - start > 2000000000)); if (timeout) { nv_error(priv, "PGRAPH TLB flush idle timeout fail\n"); tmp = nv_rd32(priv, 0x400700); nv_error(priv, "PGRAPH_STATUS : 0x%08x", tmp); nouveau_bitfield_print(nv50_pgraph_status, tmp); pr_cont("\n"); nouveau_pgraph_vstatus_print(priv, 0, nv50_pgraph_vstatus_0, nv_rd32(priv, 0x400380)); nouveau_pgraph_vstatus_print(priv, 1, nv50_pgraph_vstatus_1, nv_rd32(priv, 0x400384)); nouveau_pgraph_vstatus_print(priv, 2, nv50_pgraph_vstatus_2, nv_rd32(priv, 0x400388)); } nv_wr32(priv, 0x100c80, 0x00000001); if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000)) nv_error(priv, "vm flush timeout\n"); nv_mask(priv, 0x400500, 0x00000001, 0x00000001); spin_unlock_irqrestore(&priv->lock, flags); return timeout ? -EBUSY : 0; }
int nouveau_therm_fan_fini(struct nouveau_therm *therm, bool suspend) { struct nouveau_therm_priv *priv = (void *)therm; struct nouveau_timer *ptimer = nouveau_timer(therm); if (suspend) ptimer->alarm_cancel(ptimer, &priv->fan->alarm); 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); } }
bool nouveau_timer_wait_cb(void *obj, u64 nsec, bool (*func)(void *), void *data) { struct nouveau_timer *ptimer = nouveau_timer(obj); u64 time0; time0 = ptimer->read(ptimer); do { if (func(data) == true) return true; } while (ptimer->read(ptimer) - time0 < nsec); return false; }
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); }
bool nouveau_timer_wait_ne(void *obj, u64 nsec, u32 addr, u32 mask, u32 data) { struct nouveau_timer *ptimer = nouveau_timer(obj); u64 time0; time0 = ptimer->read(ptimer); do { if (nv_iclass(obj, NV_SUBDEV_CLASS)) { if ((nv_rd32(obj, addr) & mask) != data) return true; } else { if ((nv_ro32(obj, addr) & mask) != data) return true; } } while (ptimer->read(ptimer) - time0 < nsec); return false; }
int nouveau_therm_fan_sense(struct nouveau_therm *therm) { struct nouveau_therm_priv *priv = (void *)therm; struct nouveau_timer *ptimer = nouveau_timer(therm); struct nouveau_gpio *gpio = nouveau_gpio(therm); u32 cycles, cur, prev; u64 start, end, tach; if (priv->fan->tach.func == DCB_GPIO_UNUSED) return -ENODEV; /* Time a complete rotation and extrapolate to RPM: * When the fan spins, it changes the value of GPIO FAN_SENSE. * We get 4 changes (0 -> 1 -> 0 -> 1) per complete rotation. */ start = ptimer->read(ptimer); prev = gpio->get(gpio, 0, priv->fan->tach.func, priv->fan->tach.line); cycles = 0; do { usleep_range(500, 1000); /* supports 0 < rpm < 7500 */ cur = gpio->get(gpio, 0, priv->fan->tach.func, priv->fan->tach.line); if (prev != cur) { if (!start) start = ptimer->read(ptimer); cycles++; prev = cur; } } while (cycles < 5 && ptimer->read(ptimer) - start < 250000000); end = ptimer->read(ptimer); if (cycles == 5) { tach = (u64)60000000000ULL; do_div(tach, (end - start)); return tach; } else return 0; }
static int nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target) { struct nouveau_therm *therm = fan->parent; struct nouveau_therm_priv *priv = (void *)therm; struct nouveau_timer *ptimer = nouveau_timer(priv); unsigned long flags; int ret = 0; int duty; /* update target fan speed, restricting to allowed range */ spin_lock_irqsave(&fan->lock, flags); if (target < 0) target = fan->percent; target = max_t(u8, target, fan->bios.min_duty); target = min_t(u8, target, fan->bios.max_duty); if (fan->percent != target) { nv_debug(therm, "FAN target: %d\n", target); fan->percent = target; } /* check that we're not already at the target duty cycle */ duty = fan->get(therm); if (duty == target) { spin_unlock_irqrestore(&fan->lock, flags); return 0; } /* smooth out the fanspeed increase/decrease */ if (!immediate && duty >= 0) { /* the constant "3" is a rough approximation taken from * nvidia's behaviour. * it is meant to bump the fan speed more incrementally */ if (duty < target) duty = min(duty + 3, target); else if (duty > target) duty = max(duty - 3, target); } else { duty = target; } nv_debug(therm, "FAN update: %d\n", duty); ret = fan->set(therm, duty); if (ret) { spin_unlock_irqrestore(&fan->lock, flags); return ret; } /* fan speed updated, drop the fan lock before grabbing the * alarm-scheduling lock and risking a deadlock */ spin_unlock_irqrestore(&fan->lock, flags); /* schedule next fan update, if not at target speed already */ if (list_empty(&fan->alarm.head) && target != duty) { u16 bump_period = fan->bios.bump_period; u16 slow_down_period = fan->bios.slow_down_period; u64 delay; if (duty > target) delay = slow_down_period; else if (duty == target) delay = min(bump_period, slow_down_period) ; else delay = bump_period; ptimer->alarm(ptimer, delay * 1000 * 1000, &fan->alarm); } return ret; }
void nouveau_timer_alarm_cancel(void *obj, struct nouveau_alarm *alarm) { struct nouveau_timer *ptimer = nouveau_timer(obj); ptimer->alarm_cancel(ptimer, alarm); }
void nouveau_timer_alarm(void *obj, u32 nsec, struct nouveau_alarm *alarm) { struct nouveau_timer *ptimer = nouveau_timer(obj); ptimer->alarm(ptimer, nsec, alarm); }