int
k8pnow_acpi_states(struct k8pnow_cpu_state * cstate, struct acpicpu_pss * pss,
    int nstates, uint64_t status)
{
	struct k8pnow_state state;
	int j, k, n;
	uint32_t ctrl;

	k = -1;

	for (n = 0; n < cstate->n_states; n++) {
		if ((PN8_STA_CFID(status) == PN8_PSS_CFID(pss[n].pss_status)) &&
		    (PN8_STA_CVID(status) == PN8_PSS_CVID(pss[n].pss_status)))
			k = n;
		ctrl = pss[n].pss_ctrl;
		state.fid = PN8_ACPI_CTRL_TO_FID(ctrl);
		state.vid = PN8_ACPI_CTRL_TO_VID(ctrl);

		state.freq = pss[n].pss_core_freq;
		j = n;
		while (j > 0 && cstate->state_table[j - 1].freq > state.freq) {
			memcpy(&cstate->state_table[j],
			    &cstate->state_table[j - 1],
			    sizeof(struct k8pnow_state));
			--j;
		}
		memcpy(&cstate->state_table[j], &state,
		    sizeof(struct k8pnow_state));
	}

	return k;
}
Example #2
0
static int
pn_get(device_t dev, struct cf_setting *cf)
{
	struct pn_softc *sc;
	u_int cfid = 0, cvid = 0;
	int i;
	uint64_t status;

	if (cf == NULL)
		return (EINVAL);
	sc = device_get_softc(dev);
	if (sc->errata & PENDING_STUCK)
		return (ENXIO);

	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);

	switch (sc->pn_type) {
	case PN7_TYPE:
		cfid = PN7_STA_CFID(status);
		cvid = PN7_STA_CVID(status);
		break;
	case PN8_TYPE:
		cfid = PN8_STA_CFID(status);
		cvid = PN8_STA_CVID(status);
		break;
	}
	for (i = 0; i < sc->powernow_max_states; ++i)
		if (cfid == sc->powernow_states[i].fid &&
		    cvid == sc->powernow_states[i].vid)
			break;

	if (i < sc->powernow_max_states) {
		cf->freq = sc->powernow_states[i].freq / 1000;
		cf->power = sc->powernow_states[i].power;
		cf->lat = 200;
		cf->volts = sc->vid_to_volts[cvid];
		cf->dev = dev;
	} else {
		memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf));
		cf->dev = NULL;
	}

	return (0);
}
Example #3
0
static int
k8_get_curfreq(void)
{
	unsigned int	i;
	uint64_t	status;
	int		cfid      , cvid, fid = 0, vid = 0;
	struct k8pnow_cpu_state *cstate;
	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
	if (PN8_STA_PENDING(status))
		return 1;
	cfid = PN8_STA_CFID(status);
	cvid = PN8_STA_CVID(status);
	cstate = k8pnow_current_state;
	for (i = 0; i < cstate->n_states; i++) {
		if (cstate->state_table[i].fid == cfid &&
		    cstate->state_table[i].vid == cvid) {
			fid = cstate->state_table[i].fid;
			vid = cstate->state_table[i].vid;
			return (cstate->state_table[i].freq);
		}
	}
	/* Not reached */
	return -1;
}
void
k8pnow_transition(struct k8pnow_cpu_state *cstate, int level)
{
	uint64_t status;
	int cfid, cvid, fid = 0, vid = 0;
	int rvo;
	u_int val;

	/*
	 * We dont do a k8pnow_read_pending_wait here, need to ensure that the
	 * change pending bit isn't stuck,
	 */
	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
	if (PN8_STA_PENDING(status))
		return;
	cfid = PN8_STA_CFID(status);
	cvid = PN8_STA_CVID(status);

	fid = cstate->state_table[level].fid;
	vid = cstate->state_table[level].vid;

	if (fid == cfid && vid == cvid)
		return;

	/*
	 * Phase 1: Raise core voltage to requested VID if frequency is
	 * going up.
	 */
	while (cvid > vid) {
		val = cvid - (1 << cstate->mvs);
		WRITE_FIDVID(cfid, (val > 0) ? val : 0, 1ULL);
		if (k8pnow_read_pending_wait(&status))
			return;
		cvid = PN8_STA_CVID(status);
		COUNT_OFF_VST(cstate->vst);
	}

	/* ... then raise to voltage + RVO (if required) */
	for (rvo = cstate->rvo; rvo > 0 && cvid > 0; --rvo) {
		/* XXX It's not clear from spec if we have to do that
		 * in 0.25 step or in MVS.  Therefore do it as it's done
		 * under Linux */
		WRITE_FIDVID(cfid, cvid - 1, 1ULL);
		if (k8pnow_read_pending_wait(&status))
			return;
		cvid = PN8_STA_CVID(status);
		COUNT_OFF_VST(cstate->vst);
	}

	/* Phase 2: change to requested core frequency */
	if (cfid != fid) {
		u_int vco_fid, vco_cfid;

		vco_fid = FID_TO_VCO_FID(fid);
		vco_cfid = FID_TO_VCO_FID(cfid);

		while (abs(vco_fid - vco_cfid) > 2) {
			if (fid > cfid) {
				if (cfid > 6)
					val = cfid + 2;
				else
					val = FID_TO_VCO_FID(cfid) + 2;
			} else
				val = cfid - 2;
			WRITE_FIDVID(val, cvid, (uint64_t)cstate->pll * 1000 / 5);

			if (k8pnow_read_pending_wait(&status))
				return;
			cfid = PN8_STA_CFID(status);
			COUNT_OFF_IRT(cstate->irt);

			vco_cfid = FID_TO_VCO_FID(cfid);
		}

		WRITE_FIDVID(fid, cvid, (uint64_t) cstate->pll * 1000 / 5);
		if (k8pnow_read_pending_wait(&status))
			return;
		cfid = PN8_STA_CFID(status);
		COUNT_OFF_IRT(cstate->irt);
	}

	/* Phase 3: change to requested voltage */
	if (cvid != vid) {
		WRITE_FIDVID(cfid, vid, 1ULL);
		if (k8pnow_read_pending_wait(&status))
			return;
		cvid = PN8_STA_CVID(status);
		COUNT_OFF_VST(cstate->vst);
	}

	if (cfid == fid || cvid == vid)
		cpuspeed = cstate->state_table[level].freq;
}
Example #5
0
static int
pn8_setfidvid(struct pn_softc *sc, int fid, int vid)
{
	uint64_t status;
	int cfid, cvid;
	int rvo;
	int rv;
	u_int val;

	rv = pn8_read_pending_wait(&status);
	if (rv)
		return (rv);

	cfid = PN8_STA_CFID(status);
	cvid = PN8_STA_CVID(status);

	if (fid == cfid && vid == cvid)
		return (0);

	/*
	 * Phase 1: Raise core voltage to requested VID if frequency is
	 * going up.
	 */
	while (cvid > vid) {
		val = cvid - (1 << sc->mvs);
		rv = pn8_write_fidvid(cfid, (val > 0) ? val : 0, 1ULL, &status);
		if (rv) {
			sc->errata |= PENDING_STUCK;
			return (rv);
		}
		cvid = PN8_STA_CVID(status);
		COUNT_OFF_VST(sc->vst);
	}

	/* ... then raise to voltage + RVO (if required) */
	for (rvo = sc->rvo; rvo > 0 && cvid > 0; --rvo) {
		/* XXX It's not clear from spec if we have to do that
		 * in 0.25 step or in MVS.  Therefore do it as it's done
		 * under Linux */
		rv = pn8_write_fidvid(cfid, cvid - 1, 1ULL, &status);
		if (rv) {
			sc->errata |= PENDING_STUCK;
			return (rv);
		}
		cvid = PN8_STA_CVID(status);
		COUNT_OFF_VST(sc->vst);
	}

	/* Phase 2: change to requested core frequency */
	if (cfid != fid) {
		u_int vco_fid, vco_cfid, fid_delta;

		vco_fid = FID_TO_VCO_FID(fid);
		vco_cfid = FID_TO_VCO_FID(cfid);

		while (abs(vco_fid - vco_cfid) > 2) {
			fid_delta = (vco_cfid & 1) ? 1 : 2;
			if (fid > cfid) {
				if (cfid > 7)
					val = cfid + fid_delta;
				else
					val = FID_TO_VCO_FID(cfid) + fid_delta;
			} else
				val = cfid - fid_delta;
			rv = pn8_write_fidvid(val, cvid,
			    sc->pll * (uint64_t) sc->fsb,
			    &status);
			if (rv) {
				sc->errata |= PENDING_STUCK;
				return (rv);
			}
			cfid = PN8_STA_CFID(status);
			COUNT_OFF_IRT(sc->irt);

			vco_cfid = FID_TO_VCO_FID(cfid);
		}

		rv = pn8_write_fidvid(fid, cvid,
		    sc->pll * (uint64_t) sc->fsb,
		    &status);
		if (rv) {
			sc->errata |= PENDING_STUCK;
			return (rv);
		}
		cfid = PN8_STA_CFID(status);
		COUNT_OFF_IRT(sc->irt);
	}

	/* Phase 3: change to requested voltage */
	if (cvid != vid) {
		rv = pn8_write_fidvid(cfid, vid, 1ULL, &status);
		cvid = PN8_STA_CVID(status);
		COUNT_OFF_VST(sc->vst);
	}

	/* Check if transition failed. */
	if (cfid != fid || cvid != vid)
		rv = ENXIO;

	return (rv);
}
Example #6
0
static int
k8_powernow_setperf(unsigned int freq)
{
	unsigned int	i;
	uint64_t	status;
	uint32_t	val;
	int		cfid      , cvid, fid = 0, vid = 0;
	int		rvo;
	struct k8pnow_cpu_state *cstate;
	/*
	 * We dont do a k8pnow_read_pending_wait here, need to ensure that
	 * the change pending bit isn't stuck,
	 */
	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
	if (PN8_STA_PENDING(status))
		return 1;
	cfid = PN8_STA_CFID(status);
	cvid = PN8_STA_CVID(status);
	cstate = k8pnow_current_state;
	for (i = 0; i < cstate->n_states; i++) {
		if (cstate->state_table[i].freq >= freq) {
			fid = cstate->state_table[i].fid;
			vid = cstate->state_table[i].vid;
			break;
		}
	}
	if (fid == cfid && vid == cvid) {
		cpuspeed = freq;
		return 0;
	}
	/*
	 * Phase 1: Raise core voltage to requested VID if frequency is going
	 * up.
	 */
	while (cvid > vid) {
		val = cvid - (1 << cstate->mvs);
		WRITE_FIDVID(cfid, (val > 0) ? val : 0, 1ULL);
		READ_PENDING_WAIT(status);
		cvid = PN8_STA_CVID(status);
		COUNT_OFF_VST(cstate->vst);
	}

	/* ... then raise to voltage + RVO (if required) */
	for (rvo = cstate->rvo; rvo > 0 && cvid > 0; --rvo) {
		/*
		 * XXX It's not clear from spec if we have to do that in 0.25
		 * step or in MVS.  Therefore do it as it's done under Linux
		 */
		WRITE_FIDVID(cfid, cvid - 1, 1ULL);
		READ_PENDING_WAIT(status);
		cvid = PN8_STA_CVID(status);
		COUNT_OFF_VST(cstate->vst);
	}
	/* Phase 2: change to requested core frequency */
	if (cfid != fid) {
		uint32_t	vco_fid, vco_cfid;
		vco_fid = FID_TO_VCO_FID(fid);
		vco_cfid = FID_TO_VCO_FID(cfid);
		while (abs(vco_fid - vco_cfid) > 2) {
			if (fid > cfid) {
				if (cfid > 6)
					val = cfid + 2;
				else
					val = FID_TO_VCO_FID(cfid) + 2;
			} else
				val = cfid - 2;
			WRITE_FIDVID(val, cvid, (uint64_t) cstate->pll * 1000 / 5);
			READ_PENDING_WAIT(status);
			cfid = PN8_STA_CFID(status);
			COUNT_OFF_IRT(cstate->irt);
			vco_cfid = FID_TO_VCO_FID(cfid);
		}
		WRITE_FIDVID(fid, cvid, (uint64_t) cstate->pll * 1000 / 5);
		READ_PENDING_WAIT(status);
		cfid = PN8_STA_CFID(status);
		COUNT_OFF_IRT(cstate->irt);
	}
	/* Phase 3: change to requested voltage */
	if (cvid != vid) {
		WRITE_FIDVID(cfid, vid, 1ULL);
		READ_PENDING_WAIT(status);
		cvid = PN8_STA_CVID(status);
		COUNT_OFF_VST(cstate->vst);
	}
	if (cfid == fid || cvid == vid)
		cpuspeed = cstate->state_table[i].freq;
	return 0;
}