Example #1
0
void
k7_powernow_setperf(int level)
{
	unsigned int i;
	int cvid, cfid, vid = 0, fid = 0;
	uint64_t status, ctl;
	struct k7pnow_cpu_state * cstate;

	cstate = k7pnow_current_state;

	i = ((level * cstate->n_states) + 1) / 101;
	if (i >= cstate->n_states)
		i = cstate->n_states - 1;
	fid = cstate->state_table[i].fid;
	vid = cstate->state_table[i].vid;

	if (fid == 0 || vid == 0)
		return;

	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
	cfid = PN7_STA_CFID(status);
	cvid = PN7_STA_CVID(status);

	/*
	 * We're already at the requested level.
	 */
	if (fid == cfid && vid == cvid)
		return;

	ctl = rdmsr(MSR_AMDK7_FIDVID_CTL) & PN7_CTR_FIDCHRATIO;

	ctl |= PN7_CTR_FID(fid);
	ctl |= PN7_CTR_VID(vid);
	ctl |= PN7_CTR_SGTC(cstate->sgtc);

	if (cstate->flags & PN7_FLAG_ERRATA_A0)
		disable_intr();

	if (k7pnow_fid_to_mult[fid] < k7pnow_fid_to_mult[cfid]) {
		wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC);
		if (vid != cvid)
			wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC);
	} else {
		wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_VIDC);
		if (fid != cfid)
			wrmsr(MSR_AMDK7_FIDVID_CTL, ctl | PN7_CTR_FIDC);
	}

	if (cstate->flags & PN7_FLAG_ERRATA_A0)
		enable_intr();

	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
	cfid = PN7_STA_CFID(status);
	cvid = PN7_STA_CVID(status);
	if (cfid == fid || cvid == vid)
		cpuspeed = cstate->state_table[i].freq;
}
Example #2
0
static int
pn_probe(device_t dev)
{
	struct pn_softc *sc;
	uint64_t status;
	uint64_t rate;
	struct pcpu *pc;
	u_int sfid, mfid, cfid;

	sc = device_get_softc(dev);
	sc->errata = 0;
	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);

	pc = cpu_get_pcpu(dev);
	if (pc == NULL)
		return (ENODEV);

	cpu_est_clockrate(pc->pc_cpuid, &rate);

	switch (cpu_id & 0xf00) {
	case 0x600:
		sfid = PN7_STA_SFID(status);
		mfid = PN7_STA_MFID(status);
		cfid = PN7_STA_CFID(status);
		sc->pn_type = PN7_TYPE;
		sc->fsb = rate / 100000 / pn7_fid_to_mult[cfid];

		/*
		 * If start FID is different to max FID, then it is a
		 * mobile processor.  If not, it is a low powered desktop
		 * processor.
		 */
		if (PN7_STA_SFID(status) != PN7_STA_MFID(status)) {
			sc->vid_to_volts = pn7_mobile_vid_to_volts;
			device_set_desc(dev, "PowerNow! K7");
		} else {
			sc->vid_to_volts = pn7_desktop_vid_to_volts;
			device_set_desc(dev, "Cool`n'Quiet K7");
		}
		break;

	case 0xf00:
		sfid = PN8_STA_SFID(status);
		mfid = PN8_STA_MFID(status);
		cfid = PN8_STA_CFID(status);
		sc->pn_type = PN8_TYPE;
		sc->vid_to_volts = pn8_vid_to_volts;
		sc->fsb = rate / 100000 / pn8_fid_to_mult[cfid];

		if (PN8_STA_SFID(status) != PN8_STA_MFID(status))
			device_set_desc(dev, "PowerNow! K8");
		else
			device_set_desc(dev, "Cool`n'Quiet K8");
		break;
	default:
		return (ENODEV);
	}

	return (0);
}
Example #3
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 #4
0
void
k7_powernow_init(void)
{
	u_int regs[4];
	uint64_t status;
	u_int maxfid, startvid, currentfid;
	struct k7pnow_cpu_state *cstate;
	struct k7pnow_state *state;
	struct cpu_info *ci;
	char *techname = NULL;
	int i;

	if (setperf_prio > 1)
		return;

	ci = curcpu();

	cpuid(0x80000000, regs);
	if (regs[0] < 0x80000007)
		return;

	cpuid(0x80000007, regs);
	if (!(regs[3] & AMD_PN_FID_VID))
		return;

	/* Extended CPUID signature value */
	cpuid(0x80000001, regs);

	cstate = malloc(sizeof(struct k7pnow_cpu_state), M_DEVBUF, M_NOWAIT);
	if (!cstate)
		return;

	cstate->flags = cstate->n_states = 0;
	if (ci->ci_signature == AMD_ERRATA_A0_CPUSIG)
		cstate->flags |= PN7_FLAG_ERRATA_A0;

	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
	maxfid = PN7_STA_MFID(status);
	startvid = PN7_STA_SVID(status);
	currentfid = PN7_STA_CFID(status);

	cstate->fsb = cpuspeed / (k7pnow_fid_to_mult[currentfid]/10);

	if (!k7pnow_states(cstate, ci->ci_signature, maxfid, startvid))
		if (!k7pnow_states(cstate, regs[0], maxfid, startvid)) {
#if NACPICPU > 0
			/* If we have it try ACPI */
			k7pnow_acpi_init(cstate, status);
#endif
	}

	if (cstate->n_states) {
		if (cstate->flags & PN7_FLAG_DESKTOP_VRM)
			techname = "Cool'n'Quiet K7";
		else
			techname = "PowerNow! K7";
		printf("%s: %s %d MHz: speeds:",
		    ci->ci_dev.dv_xname, techname, cpuspeed);
		for (i = cstate->n_states; i > 0; i--) {
			state = &cstate->state_table[i-1];
			printf(" %d", state->freq);
		}
		printf(" MHz\n");

		k7pnow_current_state = cstate;
		cpu_setperf = k7_powernow_setperf;
		setperf_prio = 1;
		return;
	}
	free(cstate, M_DEVBUF, sizeof(*cstate));
}