Path: blob/master/arch/x86/kernel/cpu/mtrr/centaur.c
10775 views
#include <linux/init.h>1#include <linux/mm.h>23#include <asm/mtrr.h>4#include <asm/msr.h>56#include "mtrr.h"78static struct {9unsigned long high;10unsigned long low;11} centaur_mcr[8];1213static u8 centaur_mcr_reserved;14static u8 centaur_mcr_type; /* 0 for winchip, 1 for winchip2 */1516/**17* centaur_get_free_region - Get a free MTRR.18*19* @base: The starting (base) address of the region.20* @size: The size (in bytes) of the region.21*22* Returns: the index of the region on success, else -1 on error.23*/24static int25centaur_get_free_region(unsigned long base, unsigned long size, int replace_reg)26{27unsigned long lbase, lsize;28mtrr_type ltype;29int i, max;3031max = num_var_ranges;32if (replace_reg >= 0 && replace_reg < max)33return replace_reg;3435for (i = 0; i < max; ++i) {36if (centaur_mcr_reserved & (1 << i))37continue;38mtrr_if->get(i, &lbase, &lsize, <ype);39if (lsize == 0)40return i;41}4243return -ENOSPC;44}4546/*47* Report boot time MCR setups48*/49void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi)50{51centaur_mcr[mcr].low = lo;52centaur_mcr[mcr].high = hi;53}5455static void56centaur_get_mcr(unsigned int reg, unsigned long *base,57unsigned long *size, mtrr_type * type)58{59*base = centaur_mcr[reg].high >> PAGE_SHIFT;60*size = -(centaur_mcr[reg].low & 0xfffff000) >> PAGE_SHIFT;61*type = MTRR_TYPE_WRCOMB; /* write-combining */6263if (centaur_mcr_type == 1 && ((centaur_mcr[reg].low & 31) & 2))64*type = MTRR_TYPE_UNCACHABLE;65if (centaur_mcr_type == 1 && (centaur_mcr[reg].low & 31) == 25)66*type = MTRR_TYPE_WRBACK;67if (centaur_mcr_type == 0 && (centaur_mcr[reg].low & 31) == 31)68*type = MTRR_TYPE_WRBACK;69}7071static void72centaur_set_mcr(unsigned int reg, unsigned long base,73unsigned long size, mtrr_type type)74{75unsigned long low, high;7677if (size == 0) {78/* Disable */79high = low = 0;80} else {81high = base << PAGE_SHIFT;82if (centaur_mcr_type == 0) {83/* Only support write-combining... */84low = -size << PAGE_SHIFT | 0x1f;85} else {86if (type == MTRR_TYPE_UNCACHABLE)87low = -size << PAGE_SHIFT | 0x02; /* NC */88else89low = -size << PAGE_SHIFT | 0x09; /* WWO, WC */90}91}92centaur_mcr[reg].high = high;93centaur_mcr[reg].low = low;94wrmsr(MSR_IDT_MCR0 + reg, low, high);95}9697static int98centaur_validate_add_page(unsigned long base, unsigned long size, unsigned int type)99{100/*101* FIXME: Winchip2 supports uncached102*/103if (type != MTRR_TYPE_WRCOMB &&104(centaur_mcr_type == 0 || type != MTRR_TYPE_UNCACHABLE)) {105pr_warning("mtrr: only write-combining%s supported\n",106centaur_mcr_type ? " and uncacheable are" : " is");107return -EINVAL;108}109return 0;110}111112static const struct mtrr_ops centaur_mtrr_ops = {113.vendor = X86_VENDOR_CENTAUR,114.set = centaur_set_mcr,115.get = centaur_get_mcr,116.get_free_region = centaur_get_free_region,117.validate_add_page = centaur_validate_add_page,118.have_wrcomb = positive_have_wrcomb,119};120121int __init centaur_init_mtrr(void)122{123set_mtrr_ops(¢aur_mtrr_ops);124return 0;125}126127128