cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

longhaul.c (25882B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      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 adds
     12 *   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 redesigned
     15 *   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, though
     18 *   there is provision for scaling FSB too, but this doesn't work
     19 *   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 ": " fmt
     25
     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	1
     46#define TYPE_LONGHAUL_V2	2
     47#define TYPE_POWERSAVER		3
     48
     49#define	CPU_SAMUEL	1
     50#define	CPU_SAMUEL2	2
     51#define	CPU_EZRA	3
     52#define	CPU_EZRA_T	4
     53#define	CPU_NEHEMIAH	5
     54#define	CPU_NEHEMIAH_C	6
     55
     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	else
    101		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	else
    172		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_LVL3
    193			 * 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_LVL3
    230			 * 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_set_cpu_frequency()
    240 * @mults_index : bitpattern of the new multiplier.
    241 *
    242 * Sets a new clock ratio.
    243 */
    244
    245static int longhaul_setstate(struct cpufreq_policy *policy,
    246		unsigned int table_index)
    247{
    248	unsigned int mults_index;
    249	int speed, mult;
    250	struct cpufreq_freqs freqs;
    251	unsigned long flags;
    252	unsigned int pic1_mask, pic2_mask;
    253	u16 bm_status = 0;
    254	u32 bm_timeout = 1000;
    255	unsigned int dir = 0;
    256
    257	mults_index = longhaul_table[table_index].driver_data;
    258	/* Safety precautions */
    259	mult = mults[mults_index & 0x1f];
    260	if (mult == -1)
    261		return -EINVAL;
    262
    263	speed = calc_speed(mult);
    264	if ((speed > highest_speed) || (speed < lowest_speed))
    265		return -EINVAL;
    266
    267	/* Voltage transition before frequency transition? */
    268	if (can_scale_voltage && longhaul_index < table_index)
    269		dir = 1;
    270
    271	freqs.old = calc_speed(longhaul_get_cpu_mult());
    272	freqs.new = speed;
    273
    274	pr_debug("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
    275			fsb, mult/10, mult%10, print_speed(speed/1000));
    276retry_loop:
    277	preempt_disable();
    278	local_irq_save(flags);
    279
    280	pic2_mask = inb(0xA1);
    281	pic1_mask = inb(0x21);	/* works on C3. save mask. */
    282	outb(0xFF, 0xA1);	/* Overkill */
    283	outb(0xFE, 0x21);	/* TMR0 only */
    284
    285	/* Wait while PCI bus is busy. */
    286	if (acpi_regs_addr && (longhaul_flags & USE_NORTHBRIDGE
    287	    || ((pr != NULL) && pr->flags.bm_control))) {
    288		bm_status = inw(acpi_regs_addr);
    289		bm_status &= 1 << 4;
    290		while (bm_status && bm_timeout) {
    291			outw(1 << 4, acpi_regs_addr);
    292			bm_timeout--;
    293			bm_status = inw(acpi_regs_addr);
    294			bm_status &= 1 << 4;
    295		}
    296	}
    297
    298	if (longhaul_flags & USE_NORTHBRIDGE) {
    299		/* Disable AGP and PCI arbiters */
    300		outb(3, 0x22);
    301	} else if ((pr != NULL) && pr->flags.bm_control) {
    302		/* Disable bus master arbitration */
    303		acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1);
    304	}
    305	switch (longhaul_version) {
    306
    307	/*
    308	 * Longhaul v1. (Samuel[C5A] and Samuel2 stepping 0[C5B])
    309	 * Software controlled multipliers only.
    310	 */
    311	case TYPE_LONGHAUL_V1:
    312		do_longhaul1(mults_index);
    313		break;
    314
    315	/*
    316	 * Longhaul v2 appears in Samuel2 Steppings 1->7 [C5B] and Ezra [C5C]
    317	 *
    318	 * Longhaul v3 (aka Powersaver). (Ezra-T [C5M] & Nehemiah [C5N])
    319	 * Nehemiah can do FSB scaling too, but this has never been proven
    320	 * to work in practice.
    321	 */
    322	case TYPE_LONGHAUL_V2:
    323	case TYPE_POWERSAVER:
    324		if (longhaul_flags & USE_ACPI_C3) {
    325			/* Don't allow wakeup */
    326			acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
    327			do_powersaver(cx->address, mults_index, dir);
    328		} else {
    329			do_powersaver(0, mults_index, dir);
    330		}
    331		break;
    332	}
    333
    334	if (longhaul_flags & USE_NORTHBRIDGE) {
    335		/* Enable arbiters */
    336		outb(0, 0x22);
    337	} else if ((pr != NULL) && pr->flags.bm_control) {
    338		/* Enable bus master arbitration */
    339		acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0);
    340	}
    341	outb(pic2_mask, 0xA1);	/* restore mask */
    342	outb(pic1_mask, 0x21);
    343
    344	local_irq_restore(flags);
    345	preempt_enable();
    346
    347	freqs.new = calc_speed(longhaul_get_cpu_mult());
    348	/* Check if requested frequency is set. */
    349	if (unlikely(freqs.new != speed)) {
    350		pr_info("Failed to set requested frequency!\n");
    351		/* Revision ID = 1 but processor is expecting revision key
    352		 * equal to 0. Jumpers at the bottom of processor will change
    353		 * multiplier and FSB, but will not change bits in Longhaul
    354		 * MSR nor enable voltage scaling. */
    355		if (!revid_errata) {
    356			pr_info("Enabling \"Ignore Revision ID\" option\n");
    357			revid_errata = 1;
    358			msleep(200);
    359			goto retry_loop;
    360		}
    361		/* Why ACPI C3 sometimes doesn't work is a mystery for me.
    362		 * But it does happen. Processor is entering ACPI C3 state,
    363		 * but it doesn't change frequency. I tried poking various
    364		 * bits in northbridge registers, but without success. */
    365		if (longhaul_flags & USE_ACPI_C3) {
    366			pr_info("Disabling ACPI C3 support\n");
    367			longhaul_flags &= ~USE_ACPI_C3;
    368			if (revid_errata) {
    369				pr_info("Disabling \"Ignore Revision ID\" option\n");
    370				revid_errata = 0;
    371			}
    372			msleep(200);
    373			goto retry_loop;
    374		}
    375		/* This shouldn't happen. Longhaul ver. 2 was reported not
    376		 * working on processors without voltage scaling, but with
    377		 * RevID = 1. RevID errata will make things right. Just
    378		 * to be 100% sure. */
    379		if (longhaul_version == TYPE_LONGHAUL_V2) {
    380			pr_info("Switching to Longhaul ver. 1\n");
    381			longhaul_version = TYPE_LONGHAUL_V1;
    382			msleep(200);
    383			goto retry_loop;
    384		}
    385	}
    386
    387	if (!bm_timeout) {
    388		pr_info("Warning: Timeout while waiting for idle PCI bus\n");
    389		return -EBUSY;
    390	}
    391
    392	return 0;
    393}
    394
    395/*
    396 * Centaur decided to make life a little more tricky.
    397 * Only longhaul v1 is allowed to read EBLCR BSEL[0:1].
    398 * Samuel2 and above have to try and guess what the FSB is.
    399 * We do this by assuming we booted at maximum multiplier, and interpolate
    400 * between that value multiplied by possible FSBs and cpu_mhz which
    401 * was calculated at boot time. Really ugly, but no other way to do this.
    402 */
    403
    404#define ROUNDING	0xf
    405
    406static int guess_fsb(int mult)
    407{
    408	int speed = cpu_khz / 1000;
    409	int i;
    410	int speeds[] = { 666, 1000, 1333, 2000 };
    411	int f_max, f_min;
    412
    413	for (i = 0; i < 4; i++) {
    414		f_max = ((speeds[i] * mult) + 50) / 100;
    415		f_max += (ROUNDING / 2);
    416		f_min = f_max - ROUNDING;
    417		if ((speed <= f_max) && (speed >= f_min))
    418			return speeds[i] / 10;
    419	}
    420	return 0;
    421}
    422
    423
    424static int longhaul_get_ranges(void)
    425{
    426	unsigned int i, j, k = 0;
    427	unsigned int ratio;
    428	int mult;
    429
    430	/* Get current frequency */
    431	mult = longhaul_get_cpu_mult();
    432	if (mult == -1) {
    433		pr_info("Invalid (reserved) multiplier!\n");
    434		return -EINVAL;
    435	}
    436	fsb = guess_fsb(mult);
    437	if (fsb == 0) {
    438		pr_info("Invalid (reserved) FSB!\n");
    439		return -EINVAL;
    440	}
    441	/* Get max multiplier - as we always did.
    442	 * Longhaul MSR is useful only when voltage scaling is enabled.
    443	 * C3 is booting at max anyway. */
    444	maxmult = mult;
    445	/* Get min multiplier */
    446	switch (cpu_model) {
    447	case CPU_NEHEMIAH:
    448		minmult = 50;
    449		break;
    450	case CPU_NEHEMIAH_C:
    451		minmult = 40;
    452		break;
    453	default:
    454		minmult = 30;
    455		break;
    456	}
    457
    458	pr_debug("MinMult:%d.%dx MaxMult:%d.%dx\n",
    459		 minmult/10, minmult%10, maxmult/10, maxmult%10);
    460
    461	highest_speed = calc_speed(maxmult);
    462	lowest_speed = calc_speed(minmult);
    463	pr_debug("FSB:%dMHz  Lowest speed: %s   Highest speed:%s\n", fsb,
    464		 print_speed(lowest_speed/1000),
    465		 print_speed(highest_speed/1000));
    466
    467	if (lowest_speed == highest_speed) {
    468		pr_info("highestspeed == lowest, aborting\n");
    469		return -EINVAL;
    470	}
    471	if (lowest_speed > highest_speed) {
    472		pr_info("nonsense! lowest (%d > %d) !\n",
    473			lowest_speed, highest_speed);
    474		return -EINVAL;
    475	}
    476
    477	longhaul_table = kcalloc(numscales + 1, sizeof(*longhaul_table),
    478				 GFP_KERNEL);
    479	if (!longhaul_table)
    480		return -ENOMEM;
    481
    482	for (j = 0; j < numscales; j++) {
    483		ratio = mults[j];
    484		if (ratio == -1)
    485			continue;
    486		if (ratio > maxmult || ratio < minmult)
    487			continue;
    488		longhaul_table[k].frequency = calc_speed(ratio);
    489		longhaul_table[k].driver_data	= j;
    490		k++;
    491	}
    492	if (k <= 1) {
    493		kfree(longhaul_table);
    494		return -ENODEV;
    495	}
    496	/* Sort */
    497	for (j = 0; j < k - 1; j++) {
    498		unsigned int min_f, min_i;
    499		min_f = longhaul_table[j].frequency;
    500		min_i = j;
    501		for (i = j + 1; i < k; i++) {
    502			if (longhaul_table[i].frequency < min_f) {
    503				min_f = longhaul_table[i].frequency;
    504				min_i = i;
    505			}
    506		}
    507		if (min_i != j) {
    508			swap(longhaul_table[j].frequency,
    509			     longhaul_table[min_i].frequency);
    510			swap(longhaul_table[j].driver_data,
    511			     longhaul_table[min_i].driver_data);
    512		}
    513	}
    514
    515	longhaul_table[k].frequency = CPUFREQ_TABLE_END;
    516
    517	/* Find index we are running on */
    518	for (j = 0; j < k; j++) {
    519		if (mults[longhaul_table[j].driver_data & 0x1f] == mult) {
    520			longhaul_index = j;
    521			break;
    522		}
    523	}
    524	return 0;
    525}
    526
    527
    528static void longhaul_setup_voltagescaling(void)
    529{
    530	struct cpufreq_frequency_table *freq_pos;
    531	union msr_longhaul longhaul;
    532	struct mV_pos minvid, maxvid, vid;
    533	unsigned int j, speed, pos, kHz_step, numvscales;
    534	int min_vid_speed;
    535
    536	rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
    537	if (!(longhaul.bits.RevisionID & 1)) {
    538		pr_info("Voltage scaling not supported by CPU\n");
    539		return;
    540	}
    541
    542	if (!longhaul.bits.VRMRev) {
    543		pr_info("VRM 8.5\n");
    544		vrm_mV_table = &vrm85_mV[0];
    545		mV_vrm_table = &mV_vrm85[0];
    546	} else {
    547		pr_info("Mobile VRM\n");
    548		if (cpu_model < CPU_NEHEMIAH)
    549			return;
    550		vrm_mV_table = &mobilevrm_mV[0];
    551		mV_vrm_table = &mV_mobilevrm[0];
    552	}
    553
    554	minvid = vrm_mV_table[longhaul.bits.MinimumVID];
    555	maxvid = vrm_mV_table[longhaul.bits.MaximumVID];
    556
    557	if (minvid.mV == 0 || maxvid.mV == 0 || minvid.mV > maxvid.mV) {
    558		pr_info("Bogus values Min:%d.%03d Max:%d.%03d - Voltage scaling disabled\n",
    559			minvid.mV/1000, minvid.mV%1000,
    560			maxvid.mV/1000, maxvid.mV%1000);
    561		return;
    562	}
    563
    564	if (minvid.mV == maxvid.mV) {
    565		pr_info("Claims to support voltage scaling but min & max are both %d.%03d - Voltage scaling disabled\n",
    566			maxvid.mV/1000, maxvid.mV%1000);
    567		return;
    568	}
    569
    570	/* How many voltage steps*/
    571	numvscales = maxvid.pos - minvid.pos + 1;
    572	pr_info("Max VID=%d.%03d  Min VID=%d.%03d, %d possible voltage scales\n",
    573		maxvid.mV/1000, maxvid.mV%1000,
    574		minvid.mV/1000, minvid.mV%1000,
    575		numvscales);
    576
    577	/* Calculate max frequency at min voltage */
    578	j = longhaul.bits.MinMHzBR;
    579	if (longhaul.bits.MinMHzBR4)
    580		j += 16;
    581	min_vid_speed = eblcr[j];
    582	if (min_vid_speed == -1)
    583		return;
    584	switch (longhaul.bits.MinMHzFSB) {
    585	case 0:
    586		min_vid_speed *= 13333;
    587		break;
    588	case 1:
    589		min_vid_speed *= 10000;
    590		break;
    591	case 3:
    592		min_vid_speed *= 6666;
    593		break;
    594	default:
    595		return;
    596	}
    597	if (min_vid_speed >= highest_speed)
    598		return;
    599	/* Calculate kHz for one voltage step */
    600	kHz_step = (highest_speed - min_vid_speed) / numvscales;
    601
    602	cpufreq_for_each_entry_idx(freq_pos, longhaul_table, j) {
    603		speed = freq_pos->frequency;
    604		if (speed > min_vid_speed)
    605			pos = (speed - min_vid_speed) / kHz_step + minvid.pos;
    606		else
    607			pos = minvid.pos;
    608		freq_pos->driver_data |= mV_vrm_table[pos] << 8;
    609		vid = vrm_mV_table[mV_vrm_table[pos]];
    610		pr_info("f: %d kHz, index: %d, vid: %d mV\n",
    611			speed, j, vid.mV);
    612	}
    613
    614	can_scale_voltage = 1;
    615	pr_info("Voltage scaling enabled\n");
    616}
    617
    618
    619static int longhaul_target(struct cpufreq_policy *policy,
    620			    unsigned int table_index)
    621{
    622	unsigned int i;
    623	unsigned int dir = 0;
    624	u8 vid, current_vid;
    625	int retval = 0;
    626
    627	if (!can_scale_voltage)
    628		retval = longhaul_setstate(policy, table_index);
    629	else {
    630		/* On test system voltage transitions exceeding single
    631		 * step up or down were turning motherboard off. Both
    632		 * "ondemand" and "userspace" are unsafe. C7 is doing
    633		 * this in hardware, C3 is old and we need to do this
    634		 * in software. */
    635		i = longhaul_index;
    636		current_vid = (longhaul_table[longhaul_index].driver_data >> 8);
    637		current_vid &= 0x1f;
    638		if (table_index > longhaul_index)
    639			dir = 1;
    640		while (i != table_index) {
    641			vid = (longhaul_table[i].driver_data >> 8) & 0x1f;
    642			if (vid != current_vid) {
    643				retval = longhaul_setstate(policy, i);
    644				current_vid = vid;
    645				msleep(200);
    646			}
    647			if (dir)
    648				i++;
    649			else
    650				i--;
    651		}
    652		retval = longhaul_setstate(policy, table_index);
    653	}
    654
    655	longhaul_index = table_index;
    656	return retval;
    657}
    658
    659
    660static unsigned int longhaul_get(unsigned int cpu)
    661{
    662	if (cpu)
    663		return 0;
    664	return calc_speed(longhaul_get_cpu_mult());
    665}
    666
    667static acpi_status longhaul_walk_callback(acpi_handle obj_handle,
    668					  u32 nesting_level,
    669					  void *context, void **return_value)
    670{
    671	struct acpi_device *d = acpi_fetch_acpi_dev(obj_handle);
    672
    673	if (!d)
    674		return 0;
    675
    676	*return_value = acpi_driver_data(d);
    677	return 1;
    678}
    679
    680/* VIA don't support PM2 reg, but have something similar */
    681static int enable_arbiter_disable(void)
    682{
    683	struct pci_dev *dev;
    684	int status = 1;
    685	int reg;
    686	u8 pci_cmd;
    687
    688	/* Find PLE133 host bridge */
    689	reg = 0x78;
    690	dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0,
    691			     NULL);
    692	/* Find PM133/VT8605 host bridge */
    693	if (dev == NULL)
    694		dev = pci_get_device(PCI_VENDOR_ID_VIA,
    695				     PCI_DEVICE_ID_VIA_8605_0, NULL);
    696	/* Find CLE266 host bridge */
    697	if (dev == NULL) {
    698		reg = 0x76;
    699		dev = pci_get_device(PCI_VENDOR_ID_VIA,
    700				     PCI_DEVICE_ID_VIA_862X_0, NULL);
    701		/* Find CN400 V-Link host bridge */
    702		if (dev == NULL)
    703			dev = pci_get_device(PCI_VENDOR_ID_VIA, 0x7259, NULL);
    704	}
    705	if (dev != NULL) {
    706		/* Enable access to port 0x22 */
    707		pci_read_config_byte(dev, reg, &pci_cmd);
    708		if (!(pci_cmd & 1<<7)) {
    709			pci_cmd |= 1<<7;
    710			pci_write_config_byte(dev, reg, pci_cmd);
    711			pci_read_config_byte(dev, reg, &pci_cmd);
    712			if (!(pci_cmd & 1<<7)) {
    713				pr_err("Can't enable access to port 0x22\n");
    714				status = 0;
    715			}
    716		}
    717		pci_dev_put(dev);
    718		return status;
    719	}
    720	return 0;
    721}
    722
    723static int longhaul_setup_southbridge(void)
    724{
    725	struct pci_dev *dev;
    726	u8 pci_cmd;
    727
    728	/* Find VT8235 southbridge */
    729	dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL);
    730	if (dev == NULL)
    731		/* Find VT8237 southbridge */
    732		dev = pci_get_device(PCI_VENDOR_ID_VIA,
    733				     PCI_DEVICE_ID_VIA_8237, NULL);
    734	if (dev != NULL) {
    735		/* Set transition time to max */
    736		pci_read_config_byte(dev, 0xec, &pci_cmd);
    737		pci_cmd &= ~(1 << 2);
    738		pci_write_config_byte(dev, 0xec, pci_cmd);
    739		pci_read_config_byte(dev, 0xe4, &pci_cmd);
    740		pci_cmd &= ~(1 << 7);
    741		pci_write_config_byte(dev, 0xe4, pci_cmd);
    742		pci_read_config_byte(dev, 0xe5, &pci_cmd);
    743		pci_cmd |= 1 << 7;
    744		pci_write_config_byte(dev, 0xe5, pci_cmd);
    745		/* Get address of ACPI registers block*/
    746		pci_read_config_byte(dev, 0x81, &pci_cmd);
    747		if (pci_cmd & 1 << 7) {
    748			pci_read_config_dword(dev, 0x88, &acpi_regs_addr);
    749			acpi_regs_addr &= 0xff00;
    750			pr_info("ACPI I/O at 0x%x\n", acpi_regs_addr);
    751		}
    752
    753		pci_dev_put(dev);
    754		return 1;
    755	}
    756	return 0;
    757}
    758
    759static int longhaul_cpu_init(struct cpufreq_policy *policy)
    760{
    761	struct cpuinfo_x86 *c = &cpu_data(0);
    762	char *cpuname = NULL;
    763	int ret;
    764	u32 lo, hi;
    765
    766	/* Check what we have on this motherboard */
    767	switch (c->x86_model) {
    768	case 6:
    769		cpu_model = CPU_SAMUEL;
    770		cpuname = "C3 'Samuel' [C5A]";
    771		longhaul_version = TYPE_LONGHAUL_V1;
    772		memcpy(mults, samuel1_mults, sizeof(samuel1_mults));
    773		memcpy(eblcr, samuel1_eblcr, sizeof(samuel1_eblcr));
    774		break;
    775
    776	case 7:
    777		switch (c->x86_stepping) {
    778		case 0:
    779			longhaul_version = TYPE_LONGHAUL_V1;
    780			cpu_model = CPU_SAMUEL2;
    781			cpuname = "C3 'Samuel 2' [C5B]";
    782			/* Note, this is not a typo, early Samuel2's had
    783			 * Samuel1 ratios. */
    784			memcpy(mults, samuel1_mults, sizeof(samuel1_mults));
    785			memcpy(eblcr, samuel2_eblcr, sizeof(samuel2_eblcr));
    786			break;
    787		case 1 ... 15:
    788			longhaul_version = TYPE_LONGHAUL_V2;
    789			if (c->x86_stepping < 8) {
    790				cpu_model = CPU_SAMUEL2;
    791				cpuname = "C3 'Samuel 2' [C5B]";
    792			} else {
    793				cpu_model = CPU_EZRA;
    794				cpuname = "C3 'Ezra' [C5C]";
    795			}
    796			memcpy(mults, ezra_mults, sizeof(ezra_mults));
    797			memcpy(eblcr, ezra_eblcr, sizeof(ezra_eblcr));
    798			break;
    799		}
    800		break;
    801
    802	case 8:
    803		cpu_model = CPU_EZRA_T;
    804		cpuname = "C3 'Ezra-T' [C5M]";
    805		longhaul_version = TYPE_POWERSAVER;
    806		numscales = 32;
    807		memcpy(mults, ezrat_mults, sizeof(ezrat_mults));
    808		memcpy(eblcr, ezrat_eblcr, sizeof(ezrat_eblcr));
    809		break;
    810
    811	case 9:
    812		longhaul_version = TYPE_POWERSAVER;
    813		numscales = 32;
    814		memcpy(mults, nehemiah_mults, sizeof(nehemiah_mults));
    815		memcpy(eblcr, nehemiah_eblcr, sizeof(nehemiah_eblcr));
    816		switch (c->x86_stepping) {
    817		case 0 ... 1:
    818			cpu_model = CPU_NEHEMIAH;
    819			cpuname = "C3 'Nehemiah A' [C5XLOE]";
    820			break;
    821		case 2 ... 4:
    822			cpu_model = CPU_NEHEMIAH;
    823			cpuname = "C3 'Nehemiah B' [C5XLOH]";
    824			break;
    825		case 5 ... 15:
    826			cpu_model = CPU_NEHEMIAH_C;
    827			cpuname = "C3 'Nehemiah C' [C5P]";
    828			break;
    829		}
    830		break;
    831
    832	default:
    833		cpuname = "Unknown";
    834		break;
    835	}
    836	/* Check Longhaul ver. 2 */
    837	if (longhaul_version == TYPE_LONGHAUL_V2) {
    838		rdmsr(MSR_VIA_LONGHAUL, lo, hi);
    839		if (lo == 0 && hi == 0)
    840			/* Looks like MSR isn't present */
    841			longhaul_version = TYPE_LONGHAUL_V1;
    842	}
    843
    844	pr_info("VIA %s CPU detected.  ", cpuname);
    845	switch (longhaul_version) {
    846	case TYPE_LONGHAUL_V1:
    847	case TYPE_LONGHAUL_V2:
    848		pr_cont("Longhaul v%d supported\n", longhaul_version);
    849		break;
    850	case TYPE_POWERSAVER:
    851		pr_cont("Powersaver supported\n");
    852		break;
    853	}
    854
    855	/* Doesn't hurt */
    856	longhaul_setup_southbridge();
    857
    858	/* Find ACPI data for processor */
    859	acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
    860				ACPI_UINT32_MAX, &longhaul_walk_callback, NULL,
    861				NULL, (void *)&pr);
    862
    863	/* Check ACPI support for C3 state */
    864	if (pr != NULL && longhaul_version == TYPE_POWERSAVER) {
    865		cx = &pr->power.states[ACPI_STATE_C3];
    866		if (cx->address > 0 && cx->latency <= 1000)
    867			longhaul_flags |= USE_ACPI_C3;
    868	}
    869	/* Disable if it isn't working */
    870	if (disable_acpi_c3)
    871		longhaul_flags &= ~USE_ACPI_C3;
    872	/* Check if northbridge is friendly */
    873	if (enable_arbiter_disable())
    874		longhaul_flags |= USE_NORTHBRIDGE;
    875
    876	/* Check ACPI support for bus master arbiter disable */
    877	if (!(longhaul_flags & USE_ACPI_C3
    878	     || longhaul_flags & USE_NORTHBRIDGE)
    879	    && ((pr == NULL) || !(pr->flags.bm_control))) {
    880		pr_err("No ACPI support: Unsupported northbridge\n");
    881		return -ENODEV;
    882	}
    883
    884	if (longhaul_flags & USE_NORTHBRIDGE)
    885		pr_info("Using northbridge support\n");
    886	if (longhaul_flags & USE_ACPI_C3)
    887		pr_info("Using ACPI support\n");
    888
    889	ret = longhaul_get_ranges();
    890	if (ret != 0)
    891		return ret;
    892
    893	if ((longhaul_version != TYPE_LONGHAUL_V1) && (scale_voltage != 0))
    894		longhaul_setup_voltagescaling();
    895
    896	policy->transition_delay_us = 200000;	/* usec */
    897	policy->freq_table = longhaul_table;
    898
    899	return 0;
    900}
    901
    902static struct cpufreq_driver longhaul_driver = {
    903	.verify	= cpufreq_generic_frequency_table_verify,
    904	.target_index = longhaul_target,
    905	.get	= longhaul_get,
    906	.init	= longhaul_cpu_init,
    907	.name	= "longhaul",
    908	.attr	= cpufreq_generic_attr,
    909};
    910
    911static const struct x86_cpu_id longhaul_id[] = {
    912	X86_MATCH_VENDOR_FAM(CENTAUR, 6, NULL),
    913	{}
    914};
    915MODULE_DEVICE_TABLE(x86cpu, longhaul_id);
    916
    917static int __init longhaul_init(void)
    918{
    919	struct cpuinfo_x86 *c = &cpu_data(0);
    920
    921	if (!x86_match_cpu(longhaul_id))
    922		return -ENODEV;
    923
    924	if (!enable) {
    925		pr_err("Option \"enable\" not set - Aborting\n");
    926		return -ENODEV;
    927	}
    928#ifdef CONFIG_SMP
    929	if (num_online_cpus() > 1) {
    930		pr_err("More than 1 CPU detected, longhaul disabled\n");
    931		return -ENODEV;
    932	}
    933#endif
    934#ifdef CONFIG_X86_IO_APIC
    935	if (boot_cpu_has(X86_FEATURE_APIC)) {
    936		pr_err("APIC detected. Longhaul is currently broken in this configuration.\n");
    937		return -ENODEV;
    938	}
    939#endif
    940	switch (c->x86_model) {
    941	case 6 ... 9:
    942		return cpufreq_register_driver(&longhaul_driver);
    943	case 10:
    944		pr_err("Use acpi-cpufreq driver for VIA C7\n");
    945	}
    946
    947	return -ENODEV;
    948}
    949
    950
    951static void __exit longhaul_exit(void)
    952{
    953	struct cpufreq_policy *policy = cpufreq_cpu_get(0);
    954	int i;
    955
    956	for (i = 0; i < numscales; i++) {
    957		if (mults[i] == maxmult) {
    958			struct cpufreq_freqs freqs;
    959
    960			freqs.old = policy->cur;
    961			freqs.new = longhaul_table[i].frequency;
    962			freqs.flags = 0;
    963
    964			cpufreq_freq_transition_begin(policy, &freqs);
    965			longhaul_setstate(policy, i);
    966			cpufreq_freq_transition_end(policy, &freqs, 0);
    967			break;
    968		}
    969	}
    970
    971	cpufreq_cpu_put(policy);
    972	cpufreq_unregister_driver(&longhaul_driver);
    973	kfree(longhaul_table);
    974}
    975
    976/* Even if BIOS is exporting ACPI C3 state, and it is used
    977 * with success when CPU is idle, this state doesn't
    978 * trigger frequency transition in some cases. */
    979module_param(disable_acpi_c3, int, 0644);
    980MODULE_PARM_DESC(disable_acpi_c3, "Don't use ACPI C3 support");
    981/* Change CPU voltage with frequency. Very useful to save
    982 * power, but most VIA C3 processors aren't supporting it. */
    983module_param(scale_voltage, int, 0644);
    984MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor");
    985/* Force revision key to 0 for processors which doesn't
    986 * support voltage scaling, but are introducing itself as
    987 * such. */
    988module_param(revid_errata, int, 0644);
    989MODULE_PARM_DESC(revid_errata, "Ignore CPU Revision ID");
    990/* By default driver is disabled to prevent incompatible
    991 * system freeze. */
    992module_param(enable, int, 0644);
    993MODULE_PARM_DESC(enable, "Enable driver");
    994
    995MODULE_AUTHOR("Dave Jones");
    996MODULE_DESCRIPTION("Longhaul driver for VIA Cyrix processors.");
    997MODULE_LICENSE("GPL");
    998
    999late_initcall(longhaul_init);
   1000module_exit(longhaul_exit);