示例#1
0
文件: powernow-k8.c 项目: bluhm/sys
void
k8_powernow_init(struct cpu_info *ci)
{
	uint64_t status;
	u_int maxfid, maxvid, i;
	u_int32_t extcpuid, dummy;
	struct k8pnow_cpu_state *cstate;
	struct k8pnow_state *state;
	char * techname = NULL;

	if (setperf_prio > 1)
		return;

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

	cstate->n_states = 0;
	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
	maxfid = PN8_STA_MFID(status);
	maxvid = PN8_STA_MVID(status);

	/*
	* If start FID is different to max FID, then it is a
	* mobile processor.  If not, it is a low powered desktop
	* processor.
	*/
	if (PN8_STA_SFID(status) != PN8_STA_MFID(status))
		techname = "PowerNow! K8";
	else
		techname = "Cool'n'Quiet K8";

#if NACPICPU > 0
	/* If we have acpi check acpi first */
	if (!k8pnow_acpi_init(cstate, status))
#endif
	{
		if (!k8pnow_states(cstate, ci->ci_signature, maxfid, maxvid)) {
			/* Extended CPUID signature value */
			CPUID(0x80000001, extcpuid, dummy, dummy, dummy);
			k8pnow_states(cstate, extcpuid, maxfid, maxvid);
		}
	}
	if (cstate->n_states) {
		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");
		k8pnow_current_state = cstate;
		cpu_setperf = k8_powernow_setperf;
		setperf_prio = 1;
		return;
	}
	free(cstate, M_DEVBUF, sizeof(*cstate));
}
示例#2
0
static int
pn_decode_pst(device_t dev)
{
	int maxpst;
	struct pn_softc *sc;
	u_int cpuid, maxfid, startvid;
	u_long sig;
	struct psb_header *psb;
	uint8_t *p;
	u_int regs[4];
	uint64_t status;

	sc = device_get_softc(dev);

	do_cpuid(0x80000001, regs);
	cpuid = regs[0];

	if ((cpuid & 0xfff) == 0x760)
		sc->errata |= A0_ERRATA;

	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);

	switch (sc->pn_type) {
	case PN7_TYPE:
		maxfid = PN7_STA_MFID(status);
		startvid = PN7_STA_SVID(status);
		break;
	case PN8_TYPE:
		maxfid = PN8_STA_MFID(status);
		/*
		 * we should actually use a variable named 'maxvid' if K8,
		 * but why introducing a new variable for that?
		 */
		startvid = PN8_STA_MVID(status);
		break;
	default:
		return (ENODEV);
	}

	if (bootverbose) {
		device_printf(dev, "STATUS: 0x%jx\n", status);
		device_printf(dev, "STATUS: maxfid: 0x%02x\n", maxfid);
		device_printf(dev, "STATUS: %s: 0x%02x\n",
		    sc->pn_type == PN7_TYPE ? "startvid" : "maxvid",
		    startvid);
	}

	sig = bios_sigsearch(PSB_START, PSB_SIG, PSB_LEN, PSB_STEP, PSB_OFF);
	if (sig) {
		struct pst_header *pst;

		psb = (struct psb_header*)(uintptr_t)BIOS_PADDRTOVADDR(sig);

		switch (psb->version) {
		default:
			return (ENODEV);
		case 0x14:
			/*
			 * We can't be picky about numpst since at least
			 * some systems have a value of 1 and some have 2.
			 * We trust that cpuid_is_k7() will be better at
			 * catching that we're on a K8 anyway.
			 */
			if (sc->pn_type != PN8_TYPE)
				return (EINVAL);
			sc->vst = psb->settlingtime;
			sc->rvo = PN8_PSB_TO_RVO(psb->res1),
			sc->irt = PN8_PSB_TO_IRT(psb->res1),
			sc->mvs = PN8_PSB_TO_MVS(psb->res1),
			sc->low = PN8_PSB_TO_BATT(psb->res1);
			if (bootverbose) {
				device_printf(dev, "PSB: VST: %d\n",
				    psb->settlingtime);
				device_printf(dev, "PSB: RVO %x IRT %d "
				    "MVS %d BATT %d\n",
				    sc->rvo,
				    sc->irt,
				    sc->mvs,
				    sc->low);
			}
			break;
		case 0x12:
			if (sc->pn_type != PN7_TYPE)
				return (EINVAL);
			sc->sgtc = psb->settlingtime * sc->fsb;
			if (sc->sgtc < 100 * sc->fsb)
				sc->sgtc = 100 * sc->fsb;
			break;
		}

		p = ((uint8_t *) psb) + sizeof(struct psb_header);
		pst = (struct pst_header*) p;

		maxpst = 200;

		do {
			struct pst_header *pst = (struct pst_header*) p;

			if (cpuid == pst->cpuid &&
			    maxfid == pst->maxfid &&
			    startvid == pst->startvid) {
				sc->powernow_max_states = pst->numpstates;
				switch (sc->pn_type) {
				case PN7_TYPE:
					if (abs(sc->fsb - pst->fsb) > 5)
						continue;
					break;
				case PN8_TYPE:
					break;
				}
				return (decode_pst(sc,
				    p + sizeof(struct pst_header),
				    sc->powernow_max_states));
			}

			p += sizeof(struct pst_header) + (2 * pst->numpstates);
		} while (cpuid_is_k7(pst->cpuid) && maxpst--);

		device_printf(dev, "no match for extended cpuid %.3x\n", cpuid);
	}

	return (ENODEV);
}
示例#3
0
static int
powernow_init(void)
{
	uint64_t	status;
	size_t		len    , freq_len;
	uint32_t	maxfid, maxvid, i;
	struct k8pnow_cpu_state *cstate;
	struct k8pnow_state *state;
	const char     *techname;
	u_int32_t	regs  [4];
	cpuspeed = 0;
	struct sysctl_oid *oid, *leaf;

	do_cpuid(0x80000000, regs);
	if (regs[0] < 0x80000007)
		return 1;
	do_cpuid(0x80000007, regs);
	if (!(regs[3] & AMD_PN_FID_VID))
		return 2;
	/* Extended CPUID signature value */
	do_cpuid(0x80000001, regs);
	cstate = kmalloc(sizeof(struct k8pnow_cpu_state), M_DEVBUF, M_WAITOK);
	cstate->n_states = 0;

	status = rdmsr(MSR_AMDK7_FIDVID_STATUS);
	maxfid = PN8_STA_MFID(status);
	maxvid = PN8_STA_MVID(status);

	if (PN8_STA_SFID(status) != PN8_STA_MFID(status))
		techname = "PowerNow!";
	else
		techname = "Cool`n'Quiet";
	k8pnow_states(cstate, regs[0], maxfid, maxvid);
	len = 0;
	if (cstate->n_states) {
		freq_len = cstate->n_states * (sizeof("9999 ") - 1) + 1;
		kprintf("%s speeds:",
			techname);
		for (i = cstate->n_states; i > 0; i--) {
			state = &cstate->state_table[i - 1];
			kprintf(" %d", state->freq);
			len += ksnprintf(freqs_available + len, freq_len - len, "%d%s",
					 state->freq,
					 i > 1 ? " " : "");
		}
		kprintf(" MHz\n");
		k8pnow_current_state = cstate;
		k8_powernow_setperf(k8_get_curfreq());
	} else {
		kfree(cstate, M_DEVBUF);
		kprintf("powernow: no power states found\n");
		return 3;
	}

	/*
	 * Setup the sysctl sub-tree machdep.powernow.*
	 */
	oid = SYSCTL_ADD_NODE(&machdep_powernow_ctx,
		     SYSCTL_STATIC_CHILDREN(_machdep), OID_AUTO, "powernow",
			      CTLFLAG_RD, NULL, "");
	if (oid == NULL)
		return (EOPNOTSUPP);
	oid = SYSCTL_ADD_NODE(&machdep_powernow_ctx, SYSCTL_CHILDREN(oid),
			      OID_AUTO, "frequency", CTLFLAG_RD, NULL, "");
	if (oid == NULL)
		return (EOPNOTSUPP);
	leaf = SYSCTL_ADD_PROC(&machdep_powernow_ctx, SYSCTL_CHILDREN(oid),
		      OID_AUTO, "target", CTLTYPE_INT | CTLFLAG_RW, NULL, 0,
			       powernow_sysctl_helper, "I",
			       "Target CPU frequency for AMD PowerNow!");
	if (leaf == NULL)
		return (EOPNOTSUPP);
	leaf = SYSCTL_ADD_PROC(&machdep_powernow_ctx, SYSCTL_CHILDREN(oid),
		     OID_AUTO, "current", CTLTYPE_INT | CTLFLAG_RD, NULL, 0,
			       powernow_sysctl_helper, "I",
			       "Current CPU frequency for AMD PowerNow!");
	if (leaf == NULL)
		return (EOPNOTSUPP);
	leaf = SYSCTL_ADD_STRING(&machdep_powernow_ctx, SYSCTL_CHILDREN(oid),
			 OID_AUTO, "available", CTLFLAG_RD, freqs_available,
				 sizeof(freqs_available),
			      "CPU frequencies supported by AMD PowerNow!");
	if (leaf == NULL)
		return (EOPNOTSUPP);
	return (0);
}