brintos

brintos / linux-shallow public Read only

0
0
Text · 25.4 KiB · bd6fe86 Raw
1002 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *  (C) 2001-2004  Dave Jones.4 *  (C) 2002  Padraig Brady. <padraig@antefacto.com>5 *6 *  Based upon datasheets & sample CPUs kindly provided by VIA.7 *8 *  VIA have currently 3 different versions of Longhaul.9 *  Version 1 (Longhaul) uses the BCR2 MSR at 0x1147.10 *   It is present only in Samuel 1 (C5A), Samuel 2 (C5B) stepping 0.11 *  Version 2 of longhaul is backward compatible with v1, but adds12 *   LONGHAUL MSR for purpose of both frequency and voltage scaling.13 *   Present in Samuel 2 (steppings 1-7 only) (C5B), and Ezra (C5C).14 *  Version 3 of longhaul got renamed to Powersaver and redesigned15 *   to use only the POWERSAVER MSR at 0x110a.16 *   It is present in Ezra-T (C5M), Nehemiah (C5X) and above.17 *   It's pretty much the same feature wise to longhaul v2, though18 *   there is provision for scaling FSB too, but this doesn't work19 *   too well in practice so we don't even try to use this.20 *21 *  BIG FAT DISCLAIMER: Work in progress code. Possibly *dangerous*22 */23 24#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt25 26#include <linux/kernel.h>27#include <linux/module.h>28#include <linux/moduleparam.h>29#include <linux/init.h>30#include <linux/cpufreq.h>31#include <linux/pci.h>32#include <linux/slab.h>33#include <linux/string.h>34#include <linux/delay.h>35#include <linux/timex.h>36#include <linux/io.h>37#include <linux/acpi.h>38 39#include <asm/msr.h>40#include <asm/cpu_device_id.h>41#include <acpi/processor.h>42 43#include "longhaul.h"44 45#define TYPE_LONGHAUL_V1	146#define TYPE_LONGHAUL_V2	247#define TYPE_POWERSAVER		348 49#define	CPU_SAMUEL	150#define	CPU_SAMUEL2	251#define	CPU_EZRA	352#define	CPU_EZRA_T	453#define	CPU_NEHEMIAH	554#define	CPU_NEHEMIAH_C	655 56/* Flags */57#define USE_ACPI_C3		(1 << 1)58#define USE_NORTHBRIDGE		(1 << 2)59 60static int cpu_model;61static unsigned int numscales = 16;62static unsigned int fsb;63 64static const struct mV_pos *vrm_mV_table;65static const unsigned char *mV_vrm_table;66 67static unsigned int highest_speed, lowest_speed; /* kHz */68static unsigned int minmult, maxmult;69static int can_scale_voltage;70static struct acpi_processor *pr;71static struct acpi_processor_cx *cx;72static u32 acpi_regs_addr;73static u8 longhaul_flags;74static unsigned int longhaul_index;75 76/* Module parameters */77static int scale_voltage;78static int disable_acpi_c3;79static int revid_errata;80static int enable;81 82/* Clock ratios multiplied by 10 */83static int mults[32];84static int eblcr[32];85static int longhaul_version;86static struct cpufreq_frequency_table *longhaul_table;87 88static char speedbuffer[8];89 90static char *print_speed(int speed)91{92	if (speed < 1000) {93		snprintf(speedbuffer, sizeof(speedbuffer), "%dMHz", speed);94		return speedbuffer;95	}96 97	if (speed%1000 == 0)98		snprintf(speedbuffer, sizeof(speedbuffer),99			"%dGHz", speed/1000);100	else101		snprintf(speedbuffer, sizeof(speedbuffer),102			"%d.%dGHz", speed/1000, (speed%1000)/100);103 104	return speedbuffer;105}106 107 108static unsigned int calc_speed(int mult)109{110	int khz;111	khz = (mult/10)*fsb;112	if (mult%10)113		khz += fsb/2;114	khz *= 1000;115	return khz;116}117 118 119static int longhaul_get_cpu_mult(void)120{121	unsigned long invalue = 0, lo, hi;122 123	rdmsr(MSR_IA32_EBL_CR_POWERON, lo, hi);124	invalue = (lo & (1<<22|1<<23|1<<24|1<<25))>>22;125	if (longhaul_version == TYPE_LONGHAUL_V2 ||126	    longhaul_version == TYPE_POWERSAVER) {127		if (lo & (1<<27))128			invalue += 16;129	}130	return eblcr[invalue];131}132 133/* For processor with BCR2 MSR */134 135static void do_longhaul1(unsigned int mults_index)136{137	union msr_bcr2 bcr2;138 139	rdmsrl(MSR_VIA_BCR2, bcr2.val);140	/* Enable software clock multiplier */141	bcr2.bits.ESOFTBF = 1;142	bcr2.bits.CLOCKMUL = mults_index & 0xff;143 144	/* Sync to timer tick */145	safe_halt();146	/* Change frequency on next halt or sleep */147	wrmsrl(MSR_VIA_BCR2, bcr2.val);148	/* Invoke transition */149	ACPI_FLUSH_CPU_CACHE();150	halt();151 152	/* Disable software clock multiplier */153	local_irq_disable();154	rdmsrl(MSR_VIA_BCR2, bcr2.val);155	bcr2.bits.ESOFTBF = 0;156	wrmsrl(MSR_VIA_BCR2, bcr2.val);157}158 159/* For processor with Longhaul MSR */160 161static void do_powersaver(int cx_address, unsigned int mults_index,162			  unsigned int dir)163{164	union msr_longhaul longhaul;165	u32 t;166 167	rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);168	/* Setup new frequency */169	if (!revid_errata)170		longhaul.bits.RevisionKey = longhaul.bits.RevisionID;171	else172		longhaul.bits.RevisionKey = 0;173	longhaul.bits.SoftBusRatio = mults_index & 0xf;174	longhaul.bits.SoftBusRatio4 = (mults_index & 0x10) >> 4;175	/* Setup new voltage */176	if (can_scale_voltage)177		longhaul.bits.SoftVID = (mults_index >> 8) & 0x1f;178	/* Sync to timer tick */179	safe_halt();180	/* Raise voltage if necessary */181	if (can_scale_voltage && dir) {182		longhaul.bits.EnableSoftVID = 1;183		wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);184		/* Change voltage */185		if (!cx_address) {186			ACPI_FLUSH_CPU_CACHE();187			halt();188		} else {189			ACPI_FLUSH_CPU_CACHE();190			/* Invoke C3 */191			inb(cx_address);192			/* Dummy op - must do something useless after P_LVL3193			 * read */194			t = inl(acpi_gbl_FADT.xpm_timer_block.address);195		}196		longhaul.bits.EnableSoftVID = 0;197		wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);198	}199 200	/* Change frequency on next halt or sleep */201	longhaul.bits.EnableSoftBusRatio = 1;202	wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);203	if (!cx_address) {204		ACPI_FLUSH_CPU_CACHE();205		halt();206	} else {207		ACPI_FLUSH_CPU_CACHE();208		/* Invoke C3 */209		inb(cx_address);210		/* Dummy op - must do something useless after P_LVL3 read */211		t = inl(acpi_gbl_FADT.xpm_timer_block.address);212	}213	/* Disable bus ratio bit */214	longhaul.bits.EnableSoftBusRatio = 0;215	wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);216 217	/* Reduce voltage if necessary */218	if (can_scale_voltage && !dir) {219		longhaul.bits.EnableSoftVID = 1;220		wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);221		/* Change voltage */222		if (!cx_address) {223			ACPI_FLUSH_CPU_CACHE();224			halt();225		} else {226			ACPI_FLUSH_CPU_CACHE();227			/* Invoke C3 */228			inb(cx_address);229			/* Dummy op - must do something useless after P_LVL3230			 * read */231			t = inl(acpi_gbl_FADT.xpm_timer_block.address);232		}233		longhaul.bits.EnableSoftVID = 0;234		wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);235	}236}237 238/**239 * longhaul_setstate()240 * @policy: cpufreq_policy structure containing the current policy.241 * @table_index: index of the frequency within the cpufreq_frequency_table.242 *243 * Sets a new clock ratio.244 */245 246static int longhaul_setstate(struct cpufreq_policy *policy,247		unsigned int table_index)248{249	unsigned int mults_index;250	int speed, mult;251	struct cpufreq_freqs freqs;252	unsigned long flags;253	unsigned int pic1_mask, pic2_mask;254	u16 bm_status = 0;255	u32 bm_timeout = 1000;256	unsigned int dir = 0;257 258	mults_index = longhaul_table[table_index].driver_data;259	/* Safety precautions */260	mult = mults[mults_index & 0x1f];261	if (mult == -1)262		return -EINVAL;263 264	speed = calc_speed(mult);265	if ((speed > highest_speed) || (speed < lowest_speed))266		return -EINVAL;267 268	/* Voltage transition before frequency transition? */269	if (can_scale_voltage && longhaul_index < table_index)270		dir = 1;271 272	freqs.old = calc_speed(longhaul_get_cpu_mult());273	freqs.new = speed;274 275	pr_debug("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",276			fsb, mult/10, mult%10, print_speed(speed/1000));277retry_loop:278	preempt_disable();279	local_irq_save(flags);280 281	pic2_mask = inb(0xA1);282	pic1_mask = inb(0x21);	/* works on C3. save mask. */283	outb(0xFF, 0xA1);	/* Overkill */284	outb(0xFE, 0x21);	/* TMR0 only */285 286	/* Wait while PCI bus is busy. */287	if (acpi_regs_addr && (longhaul_flags & USE_NORTHBRIDGE288	    || ((pr != NULL) && pr->flags.bm_control))) {289		bm_status = inw(acpi_regs_addr);290		bm_status &= 1 << 4;291		while (bm_status && bm_timeout) {292			outw(1 << 4, acpi_regs_addr);293			bm_timeout--;294			bm_status = inw(acpi_regs_addr);295			bm_status &= 1 << 4;296		}297	}298 299	if (longhaul_flags & USE_NORTHBRIDGE) {300		/* Disable AGP and PCI arbiters */301		outb(3, 0x22);302	} else if ((pr != NULL) && pr->flags.bm_control) {303		/* Disable bus master arbitration */304		acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1);305	}306	switch (longhaul_version) {307 308	/*309	 * Longhaul v1. (Samuel[C5A] and Samuel2 stepping 0[C5B])310	 * Software controlled multipliers only.311	 */312	case TYPE_LONGHAUL_V1:313		do_longhaul1(mults_index);314		break;315 316	/*317	 * Longhaul v2 appears in Samuel2 Steppings 1->7 [C5B] and Ezra [C5C]318	 *319	 * Longhaul v3 (aka Powersaver). (Ezra-T [C5M] & Nehemiah [C5N])320	 * Nehemiah can do FSB scaling too, but this has never been proven321	 * to work in practice.322	 */323	case TYPE_LONGHAUL_V2:324	case TYPE_POWERSAVER:325		if (longhaul_flags & USE_ACPI_C3) {326			/* Don't allow wakeup */327			acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, 0);328			do_powersaver(cx->address, mults_index, dir);329		} else {330			do_powersaver(0, mults_index, dir);331		}332		break;333	}334 335	if (longhaul_flags & USE_NORTHBRIDGE) {336		/* Enable arbiters */337		outb(0, 0x22);338	} else if ((pr != NULL) && pr->flags.bm_control) {339		/* Enable bus master arbitration */340		acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0);341	}342	outb(pic2_mask, 0xA1);	/* restore mask */343	outb(pic1_mask, 0x21);344 345	local_irq_restore(flags);346	preempt_enable();347 348	freqs.new = calc_speed(longhaul_get_cpu_mult());349	/* Check if requested frequency is set. */350	if (unlikely(freqs.new != speed)) {351		pr_info("Failed to set requested frequency!\n");352		/* Revision ID = 1 but processor is expecting revision key353		 * equal to 0. Jumpers at the bottom of processor will change354		 * multiplier and FSB, but will not change bits in Longhaul355		 * MSR nor enable voltage scaling. */356		if (!revid_errata) {357			pr_info("Enabling \"Ignore Revision ID\" option\n");358			revid_errata = 1;359			msleep(200);360			goto retry_loop;361		}362		/* Why ACPI C3 sometimes doesn't work is a mystery for me.363		 * But it does happen. Processor is entering ACPI C3 state,364		 * but it doesn't change frequency. I tried poking various365		 * bits in northbridge registers, but without success. */366		if (longhaul_flags & USE_ACPI_C3) {367			pr_info("Disabling ACPI C3 support\n");368			longhaul_flags &= ~USE_ACPI_C3;369			if (revid_errata) {370				pr_info("Disabling \"Ignore Revision ID\" option\n");371				revid_errata = 0;372			}373			msleep(200);374			goto retry_loop;375		}376		/* This shouldn't happen. Longhaul ver. 2 was reported not377		 * working on processors without voltage scaling, but with378		 * RevID = 1. RevID errata will make things right. Just379		 * to be 100% sure. */380		if (longhaul_version == TYPE_LONGHAUL_V2) {381			pr_info("Switching to Longhaul ver. 1\n");382			longhaul_version = TYPE_LONGHAUL_V1;383			msleep(200);384			goto retry_loop;385		}386	}387 388	if (!bm_timeout) {389		pr_info("Warning: Timeout while waiting for idle PCI bus\n");390		return -EBUSY;391	}392 393	return 0;394}395 396/*397 * Centaur decided to make life a little more tricky.398 * Only longhaul v1 is allowed to read EBLCR BSEL[0:1].399 * Samuel2 and above have to try and guess what the FSB is.400 * We do this by assuming we booted at maximum multiplier, and interpolate401 * between that value multiplied by possible FSBs and cpu_mhz which402 * was calculated at boot time. Really ugly, but no other way to do this.403 */404 405#define ROUNDING	0xf406 407static int guess_fsb(int mult)408{409	int speed = cpu_khz / 1000;410	int i;411	static const int speeds[] = { 666, 1000, 1333, 2000 };412	int f_max, f_min;413 414	for (i = 0; i < ARRAY_SIZE(speeds); i++) {415		f_max = ((speeds[i] * mult) + 50) / 100;416		f_max += (ROUNDING / 2);417		f_min = f_max - ROUNDING;418		if ((speed <= f_max) && (speed >= f_min))419			return speeds[i] / 10;420	}421	return 0;422}423 424 425static int longhaul_get_ranges(void)426{427	unsigned int i, j, k = 0;428	unsigned int ratio;429	int mult;430 431	/* Get current frequency */432	mult = longhaul_get_cpu_mult();433	if (mult == -1) {434		pr_info("Invalid (reserved) multiplier!\n");435		return -EINVAL;436	}437	fsb = guess_fsb(mult);438	if (fsb == 0) {439		pr_info("Invalid (reserved) FSB!\n");440		return -EINVAL;441	}442	/* Get max multiplier - as we always did.443	 * Longhaul MSR is useful only when voltage scaling is enabled.444	 * C3 is booting at max anyway. */445	maxmult = mult;446	/* Get min multiplier */447	switch (cpu_model) {448	case CPU_NEHEMIAH:449		minmult = 50;450		break;451	case CPU_NEHEMIAH_C:452		minmult = 40;453		break;454	default:455		minmult = 30;456		break;457	}458 459	pr_debug("MinMult:%d.%dx MaxMult:%d.%dx\n",460		 minmult/10, minmult%10, maxmult/10, maxmult%10);461 462	highest_speed = calc_speed(maxmult);463	lowest_speed = calc_speed(minmult);464	pr_debug("FSB:%dMHz  Lowest speed: %s   Highest speed:%s\n", fsb,465		 print_speed(lowest_speed/1000),466		 print_speed(highest_speed/1000));467 468	if (lowest_speed == highest_speed) {469		pr_info("highestspeed == lowest, aborting\n");470		return -EINVAL;471	}472	if (lowest_speed > highest_speed) {473		pr_info("nonsense! lowest (%d > %d) !\n",474			lowest_speed, highest_speed);475		return -EINVAL;476	}477 478	longhaul_table = kcalloc(numscales + 1, sizeof(*longhaul_table),479				 GFP_KERNEL);480	if (!longhaul_table)481		return -ENOMEM;482 483	for (j = 0; j < numscales; j++) {484		ratio = mults[j];485		if (ratio == -1)486			continue;487		if (ratio > maxmult || ratio < minmult)488			continue;489		longhaul_table[k].frequency = calc_speed(ratio);490		longhaul_table[k].driver_data	= j;491		k++;492	}493	if (k <= 1) {494		kfree(longhaul_table);495		return -ENODEV;496	}497	/* Sort */498	for (j = 0; j < k - 1; j++) {499		unsigned int min_f, min_i;500		min_f = longhaul_table[j].frequency;501		min_i = j;502		for (i = j + 1; i < k; i++) {503			if (longhaul_table[i].frequency < min_f) {504				min_f = longhaul_table[i].frequency;505				min_i = i;506			}507		}508		if (min_i != j) {509			swap(longhaul_table[j].frequency,510			     longhaul_table[min_i].frequency);511			swap(longhaul_table[j].driver_data,512			     longhaul_table[min_i].driver_data);513		}514	}515 516	longhaul_table[k].frequency = CPUFREQ_TABLE_END;517 518	/* Find index we are running on */519	for (j = 0; j < k; j++) {520		if (mults[longhaul_table[j].driver_data & 0x1f] == mult) {521			longhaul_index = j;522			break;523		}524	}525	return 0;526}527 528 529static void longhaul_setup_voltagescaling(void)530{531	struct cpufreq_frequency_table *freq_pos;532	union msr_longhaul longhaul;533	struct mV_pos minvid, maxvid, vid;534	unsigned int j, speed, pos, kHz_step, numvscales;535	int min_vid_speed;536 537	rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);538	if (!(longhaul.bits.RevisionID & 1)) {539		pr_info("Voltage scaling not supported by CPU\n");540		return;541	}542 543	if (!longhaul.bits.VRMRev) {544		pr_info("VRM 8.5\n");545		vrm_mV_table = &vrm85_mV[0];546		mV_vrm_table = &mV_vrm85[0];547	} else {548		pr_info("Mobile VRM\n");549		if (cpu_model < CPU_NEHEMIAH)550			return;551		vrm_mV_table = &mobilevrm_mV[0];552		mV_vrm_table = &mV_mobilevrm[0];553	}554 555	minvid = vrm_mV_table[longhaul.bits.MinimumVID];556	maxvid = vrm_mV_table[longhaul.bits.MaximumVID];557 558	if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) {559		pr_info("Bogus values Min:%d.%03d Max:%d.%03d - Voltage scaling disabled\n",560			minvid.mV/1000, minvid.mV%1000,561			maxvid.mV/1000, maxvid.mV%1000);562		return;563	}564 565	if (minvid.mV == maxvid.mV) {566		pr_info("Claims to support voltage scaling but min & max are both %d.%03d - Voltage scaling disabled\n",567			maxvid.mV/1000, maxvid.mV%1000);568		return;569	}570 571	/* How many voltage steps*/572	numvscales = maxvid.pos - minvid.pos + 1;573	pr_info("Max VID=%d.%03d  Min VID=%d.%03d, %d possible voltage scales\n",574		maxvid.mV/1000, maxvid.mV%1000,575		minvid.mV/1000, minvid.mV%1000,576		numvscales);577 578	/* Calculate max frequency at min voltage */579	j = longhaul.bits.MinMHzBR;580	if (longhaul.bits.MinMHzBR4)581		j += 16;582	min_vid_speed = eblcr[j];583	if (min_vid_speed == -1)584		return;585	switch (longhaul.bits.MinMHzFSB) {586	case 0:587		min_vid_speed *= 13333;588		break;589	case 1:590		min_vid_speed *= 10000;591		break;592	case 3:593		min_vid_speed *= 6666;594		break;595	default:596		return;597	}598	if (min_vid_speed >= highest_speed)599		return;600	/* Calculate kHz for one voltage step */601	kHz_step = (highest_speed - min_vid_speed) / numvscales;602 603	cpufreq_for_each_entry_idx(freq_pos, longhaul_table, j) {604		speed = freq_pos->frequency;605		if (speed > min_vid_speed)606			pos = (speed - min_vid_speed) / kHz_step + minvid.pos;607		else608			pos = minvid.pos;609		freq_pos->driver_data |= mV_vrm_table[pos] << 8;610		vid = vrm_mV_table[mV_vrm_table[pos]];611		pr_info("f: %d kHz, index: %d, vid: %d mV\n",612			speed, j, vid.mV);613	}614 615	can_scale_voltage = 1;616	pr_info("Voltage scaling enabled\n");617}618 619 620static int longhaul_target(struct cpufreq_policy *policy,621			    unsigned int table_index)622{623	unsigned int i;624	unsigned int dir = 0;625	u8 vid, current_vid;626	int retval = 0;627 628	if (!can_scale_voltage)629		retval = longhaul_setstate(policy, table_index);630	else {631		/* On test system voltage transitions exceeding single632		 * step up or down were turning motherboard off. Both633		 * "ondemand" and "userspace" are unsafe. C7 is doing634		 * this in hardware, C3 is old and we need to do this635		 * in software. */636		i = longhaul_index;637		current_vid = (longhaul_table[longhaul_index].driver_data >> 8);638		current_vid &= 0x1f;639		if (table_index > longhaul_index)640			dir = 1;641		while (i != table_index) {642			vid = (longhaul_table[i].driver_data >> 8) & 0x1f;643			if (vid != current_vid) {644				retval = longhaul_setstate(policy, i);645				current_vid = vid;646				msleep(200);647			}648			if (dir)649				i++;650			else651				i--;652		}653		retval = longhaul_setstate(policy, table_index);654	}655 656	longhaul_index = table_index;657	return retval;658}659 660 661static unsigned int longhaul_get(unsigned int cpu)662{663	if (cpu)664		return 0;665	return calc_speed(longhaul_get_cpu_mult());666}667 668static acpi_status longhaul_walk_callback(acpi_handle obj_handle,669					  u32 nesting_level,670					  void *context, void **return_value)671{672	struct acpi_device *d = acpi_fetch_acpi_dev(obj_handle);673 674	if (!d)675		return 0;676 677	*return_value = acpi_driver_data(d);678	return 1;679}680 681/* VIA don't support PM2 reg, but have something similar */682static int enable_arbiter_disable(void)683{684	struct pci_dev *dev;685	int status = 1;686	int reg;687	u8 pci_cmd;688 689	/* Find PLE133 host bridge */690	reg = 0x78;691	dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0,692			     NULL);693	/* Find PM133/VT8605 host bridge */694	if (dev == NULL)695		dev = pci_get_device(PCI_VENDOR_ID_VIA,696				     PCI_DEVICE_ID_VIA_8605_0, NULL);697	/* Find CLE266 host bridge */698	if (dev == NULL) {699		reg = 0x76;700		dev = pci_get_device(PCI_VENDOR_ID_VIA,701				     PCI_DEVICE_ID_VIA_862X_0, NULL);702		/* Find CN400 V-Link host bridge */703		if (dev == NULL)704			dev = pci_get_device(PCI_VENDOR_ID_VIA, 0x7259, NULL);705	}706	if (dev != NULL) {707		/* Enable access to port 0x22 */708		pci_read_config_byte(dev, reg, &pci_cmd);709		if (!(pci_cmd & 1<<7)) {710			pci_cmd |= 1<<7;711			pci_write_config_byte(dev, reg, pci_cmd);712			pci_read_config_byte(dev, reg, &pci_cmd);713			if (!(pci_cmd & 1<<7)) {714				pr_err("Can't enable access to port 0x22\n");715				status = 0;716			}717		}718		pci_dev_put(dev);719		return status;720	}721	return 0;722}723 724static int longhaul_setup_southbridge(void)725{726	struct pci_dev *dev;727	u8 pci_cmd;728 729	/* Find VT8235 southbridge */730	dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL);731	if (dev == NULL)732		/* Find VT8237 southbridge */733		dev = pci_get_device(PCI_VENDOR_ID_VIA,734				     PCI_DEVICE_ID_VIA_8237, NULL);735	if (dev != NULL) {736		/* Set transition time to max */737		pci_read_config_byte(dev, 0xec, &pci_cmd);738		pci_cmd &= ~(1 << 2);739		pci_write_config_byte(dev, 0xec, pci_cmd);740		pci_read_config_byte(dev, 0xe4, &pci_cmd);741		pci_cmd &= ~(1 << 7);742		pci_write_config_byte(dev, 0xe4, pci_cmd);743		pci_read_config_byte(dev, 0xe5, &pci_cmd);744		pci_cmd |= 1 << 7;745		pci_write_config_byte(dev, 0xe5, pci_cmd);746		/* Get address of ACPI registers block*/747		pci_read_config_byte(dev, 0x81, &pci_cmd);748		if (pci_cmd & 1 << 7) {749			pci_read_config_dword(dev, 0x88, &acpi_regs_addr);750			acpi_regs_addr &= 0xff00;751			pr_info("ACPI I/O at 0x%x\n", acpi_regs_addr);752		}753 754		pci_dev_put(dev);755		return 1;756	}757	return 0;758}759 760static int longhaul_cpu_init(struct cpufreq_policy *policy)761{762	struct cpuinfo_x86 *c = &cpu_data(0);763	char *cpuname = NULL;764	int ret;765	u32 lo, hi;766 767	/* Check what we have on this motherboard */768	switch (c->x86_model) {769	case 6:770		cpu_model = CPU_SAMUEL;771		cpuname = "C3 'Samuel' [C5A]";772		longhaul_version = TYPE_LONGHAUL_V1;773		memcpy(mults, samuel1_mults, sizeof(samuel1_mults));774		memcpy(eblcr, samuel1_eblcr, sizeof(samuel1_eblcr));775		break;776 777	case 7:778		switch (c->x86_stepping) {779		case 0:780			longhaul_version = TYPE_LONGHAUL_V1;781			cpu_model = CPU_SAMUEL2;782			cpuname = "C3 'Samuel 2' [C5B]";783			/* Note, this is not a typo, early Samuel2's had784			 * Samuel1 ratios. */785			memcpy(mults, samuel1_mults, sizeof(samuel1_mults));786			memcpy(eblcr, samuel2_eblcr, sizeof(samuel2_eblcr));787			break;788		case 1 ... 15:789			longhaul_version = TYPE_LONGHAUL_V2;790			if (c->x86_stepping < 8) {791				cpu_model = CPU_SAMUEL2;792				cpuname = "C3 'Samuel 2' [C5B]";793			} else {794				cpu_model = CPU_EZRA;795				cpuname = "C3 'Ezra' [C5C]";796			}797			memcpy(mults, ezra_mults, sizeof(ezra_mults));798			memcpy(eblcr, ezra_eblcr, sizeof(ezra_eblcr));799			break;800		}801		break;802 803	case 8:804		cpu_model = CPU_EZRA_T;805		cpuname = "C3 'Ezra-T' [C5M]";806		longhaul_version = TYPE_POWERSAVER;807		numscales = 32;808		memcpy(mults, ezrat_mults, sizeof(ezrat_mults));809		memcpy(eblcr, ezrat_eblcr, sizeof(ezrat_eblcr));810		break;811 812	case 9:813		longhaul_version = TYPE_POWERSAVER;814		numscales = 32;815		memcpy(mults, nehemiah_mults, sizeof(nehemiah_mults));816		memcpy(eblcr, nehemiah_eblcr, sizeof(nehemiah_eblcr));817		switch (c->x86_stepping) {818		case 0 ... 1:819			cpu_model = CPU_NEHEMIAH;820			cpuname = "C3 'Nehemiah A' [C5XLOE]";821			break;822		case 2 ... 4:823			cpu_model = CPU_NEHEMIAH;824			cpuname = "C3 'Nehemiah B' [C5XLOH]";825			break;826		case 5 ... 15:827			cpu_model = CPU_NEHEMIAH_C;828			cpuname = "C3 'Nehemiah C' [C5P]";829			break;830		}831		break;832 833	default:834		cpuname = "Unknown";835		break;836	}837	/* Check Longhaul ver. 2 */838	if (longhaul_version == TYPE_LONGHAUL_V2) {839		rdmsr(MSR_VIA_LONGHAUL, lo, hi);840		if (lo == 0 && hi == 0)841			/* Looks like MSR isn't present */842			longhaul_version = TYPE_LONGHAUL_V1;843	}844 845	pr_info("VIA %s CPU detected.  ", cpuname);846	switch (longhaul_version) {847	case TYPE_LONGHAUL_V1:848	case TYPE_LONGHAUL_V2:849		pr_cont("Longhaul v%d supported\n", longhaul_version);850		break;851	case TYPE_POWERSAVER:852		pr_cont("Powersaver supported\n");853		break;854	}855 856	/* Doesn't hurt */857	longhaul_setup_southbridge();858 859	/* Find ACPI data for processor */860	acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,861				ACPI_UINT32_MAX, &longhaul_walk_callback, NULL,862				NULL, (void *)&pr);863 864	/* Check ACPI support for C3 state */865	if (pr != NULL && longhaul_version == TYPE_POWERSAVER) {866		cx = &pr->power.states[ACPI_STATE_C3];867		if (cx->address > 0 && cx->latency <= 1000)868			longhaul_flags |= USE_ACPI_C3;869	}870	/* Disable if it isn't working */871	if (disable_acpi_c3)872		longhaul_flags &= ~USE_ACPI_C3;873	/* Check if northbridge is friendly */874	if (enable_arbiter_disable())875		longhaul_flags |= USE_NORTHBRIDGE;876 877	/* Check ACPI support for bus master arbiter disable */878	if (!(longhaul_flags & USE_ACPI_C3879	     || longhaul_flags & USE_NORTHBRIDGE)880	    && ((pr == NULL) || !(pr->flags.bm_control))) {881		pr_err("No ACPI support: Unsupported northbridge\n");882		return -ENODEV;883	}884 885	if (longhaul_flags & USE_NORTHBRIDGE)886		pr_info("Using northbridge support\n");887	if (longhaul_flags & USE_ACPI_C3)888		pr_info("Using ACPI support\n");889 890	ret = longhaul_get_ranges();891	if (ret != 0)892		return ret;893 894	if ((longhaul_version != TYPE_LONGHAUL_V1) && (scale_voltage != 0))895		longhaul_setup_voltagescaling();896 897	policy->transition_delay_us = 200000;	/* usec */898	policy->freq_table = longhaul_table;899 900	return 0;901}902 903static struct cpufreq_driver longhaul_driver = {904	.verify	= cpufreq_generic_frequency_table_verify,905	.target_index = longhaul_target,906	.get	= longhaul_get,907	.init	= longhaul_cpu_init,908	.name	= "longhaul",909	.attr	= cpufreq_generic_attr,910};911 912static const struct x86_cpu_id longhaul_id[] = {913	X86_MATCH_VENDOR_FAM(CENTAUR, 6, NULL),914	{}915};916MODULE_DEVICE_TABLE(x86cpu, longhaul_id);917 918static int __init longhaul_init(void)919{920	struct cpuinfo_x86 *c = &cpu_data(0);921 922	if (!x86_match_cpu(longhaul_id))923		return -ENODEV;924 925	if (!enable) {926		pr_err("Option \"enable\" not set - Aborting\n");927		return -ENODEV;928	}929#ifdef CONFIG_SMP930	if (num_online_cpus() > 1) {931		pr_err("More than 1 CPU detected, longhaul disabled\n");932		return -ENODEV;933	}934#endif935#ifdef CONFIG_X86_IO_APIC936	if (boot_cpu_has(X86_FEATURE_APIC)) {937		pr_err("APIC detected. Longhaul is currently broken in this configuration.\n");938		return -ENODEV;939	}940#endif941	switch (c->x86_model) {942	case 6 ... 9:943		return cpufreq_register_driver(&longhaul_driver);944	case 10:945		pr_err("Use acpi-cpufreq driver for VIA C7\n");946	}947 948	return -ENODEV;949}950 951 952static void __exit longhaul_exit(void)953{954	struct cpufreq_policy *policy = cpufreq_cpu_get(0);955	int i;956 957	for (i = 0; i < numscales; i++) {958		if (mults[i] == maxmult) {959			struct cpufreq_freqs freqs;960 961			freqs.old = policy->cur;962			freqs.new = longhaul_table[i].frequency;963			freqs.flags = 0;964 965			cpufreq_freq_transition_begin(policy, &freqs);966			longhaul_setstate(policy, i);967			cpufreq_freq_transition_end(policy, &freqs, 0);968			break;969		}970	}971 972	cpufreq_cpu_put(policy);973	cpufreq_unregister_driver(&longhaul_driver);974	kfree(longhaul_table);975}976 977/* Even if BIOS is exporting ACPI C3 state, and it is used978 * with success when CPU is idle, this state doesn't979 * trigger frequency transition in some cases. */980module_param(disable_acpi_c3, int, 0644);981MODULE_PARM_DESC(disable_acpi_c3, "Don't use ACPI C3 support");982/* Change CPU voltage with frequency. Very useful to save983 * power, but most VIA C3 processors aren't supporting it. */984module_param(scale_voltage, int, 0644);985MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor");986/* Force revision key to 0 for processors which doesn't987 * support voltage scaling, but are introducing itself as988 * such. */989module_param(revid_errata, int, 0644);990MODULE_PARM_DESC(revid_errata, "Ignore CPU Revision ID");991/* By default driver is disabled to prevent incompatible992 * system freeze. */993module_param(enable, int, 0644);994MODULE_PARM_DESC(enable, "Enable driver");995 996MODULE_AUTHOR("Dave Jones");997MODULE_DESCRIPTION("Longhaul driver for VIA Cyrix processors.");998MODULE_LICENSE("GPL");999 1000late_initcall(longhaul_init);1001module_exit(longhaul_exit);1002