Exemple #1
0
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);
}
Exemple #2
0
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;
}
Exemple #3
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;
}
Exemple #4
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);
	}
}
Exemple #6
0
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;
}
Exemple #7
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;
    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);
}
Exemple #8
0
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;
}
Exemple #9
0
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;
}
Exemple #10
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;
}
Exemple #11
0
void
nouveau_timer_alarm_cancel(void *obj, struct nouveau_alarm *alarm)
{
	struct nouveau_timer *ptimer = nouveau_timer(obj);
	ptimer->alarm_cancel(ptimer, alarm);
}
Exemple #12
0
void
nouveau_timer_alarm(void *obj, u32 nsec, struct nouveau_alarm *alarm)
{
	struct nouveau_timer *ptimer = nouveau_timer(obj);
	ptimer->alarm(ptimer, nsec, alarm);
}