Exemplo n.º 1
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);
}
Exemplo n.º 2
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));
}