blob: 4e5bca278ab7e9735247d3db77c13c2520afb9c1 [file] [log] [blame]
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2010 Advanced Micro Devices, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
static inline void _WRMSR(u32 addr, u32 lo, u32 hi)
{
__asm__ volatile (
"wrmsr"
:
:"c"(addr),"a"(lo), "d" (hi)
);
}
static inline void _RDMSR(u32 addr, u32 *lo, u32 *hi)
{
__asm__ volatile (
"rdmsr"
:"=a"(*lo), "=d" (*hi)
:"c"(addr)
);
}
static inline void _RDTSC(u32 *lo, u32 *hi)
{
__asm__ volatile (
"rdtsc"
: "=a" (*lo), "=d"(*hi)
);
}
static inline void _cpu_id(u32 addr, u32 *val)
{
__asm__ volatile(
"cpuid"
: "=a" (val[0]),
"=b" (val[1]),
"=c" (val[2]),
"=d" (val[3])
: "0" (addr));
}
static u32 bsr(u32 x)
{
u8 i;
u32 ret = 0;
for(i=31; i>0; i--) {
if(x & (1<<i)) {
ret = i;
break;
}
}
return ret;
}
static u32 bsf(u32 x)
{
u8 i;
u32 ret = 32;
for(i=0; i<32; i++) {
if(x & (1<<i)) {
ret = i;
break;
}
}
return ret;
}
#define _MFENCE asm volatile ( "mfence")
#define _SFENCE asm volatile ( "sfence" )
/* prevent speculative execution of following instructions */
#define _EXECFENCE asm volatile ("outb %al, $0xed")
static inline u32 read_cr4(void)
{
u32 cr4;
__asm__ volatile ("movl %%cr4, %0" : "=r" (cr4));
return cr4;
}
static inline void write_cr4(u32 cr4)
{
__asm__ volatile ("movl %0, %%cr4" : : "r" (cr4));
}
u32 SetUpperFSbase(u32 addr_hi);
static void proc_CLFLUSH(u32 addr_hi)
{
SetUpperFSbase(addr_hi);
__asm__ volatile (
/* clflush fs:[eax] */
"outb %%al, $0xed\n\t" /* _EXECFENCE */
"clflush %%fs:(%0)\n\t"
"mfence\n\t"
::"a" (addr_hi<<8)
);
}
static void WriteLNTestPattern(u32 addr_lo, u8 *buf_a, u32 line_num)
{
__asm__ volatile (
/*prevent speculative execution of following instructions*/
/* FIXME: needed ? */
"outb %%al, $0xed\n\t" /* _EXECFENCE */
"1:\n\t"
"movdqa (%3), %%xmm0\n\t"
"movntdq %%xmm0, %%fs:(%0)\n\t" /* xmm0 is 128 bit */
"addl %1, %0\n\t"
"addl %1, %3\n\t"
"loop 1b\n\t"
"mfence\n\t"
:: "a" (addr_lo), "d" (16), "c" (line_num * 4), "b"(buf_a)
);
}
static u32 read32_fs(u32 addr_lo)
{
u32 value;
__asm__ volatile (
"outb %%al, $0xed\n\t" /* _EXECFENCE */
"movl %%fs:(%1), %0\n\t"
:"=b"(value): "a" (addr_lo)
);
return value;
}
#ifdef UNUSED_CODE
static u8 read8_fs(u32 addr_lo)
{
u8 byte;
__asm__ volatile (
"outb %%al, $0xed\n\t" /* _EXECFENCE */
"movb %%fs:(%1), %b0\n\t"
"mfence\n\t"
:"=b"(byte): "a" (addr_lo)
);
return byte;
}
#endif
static void FlushDQSTestPattern_L9(u32 addr_lo)
{
__asm__ volatile (
"outb %%al, $0xed\n\t" /* _EXECFENCE */
"clflush %%fs:-128(%%ecx)\n\t"
"clflush %%fs:-64(%%ecx)\n\t"
"clflush %%fs:(%%ecx)\n\t"
"clflush %%fs:64(%%ecx)\n\t"
"clflush %%fs:-128(%%eax)\n\t"
"clflush %%fs:-64(%%eax)\n\t"
"clflush %%fs:(%%eax)\n\t"
"clflush %%fs:64(%%eax)\n\t"
"clflush %%fs:-128(%%ebx)\n\t"
:: "b" (addr_lo+128+8*64), "c"(addr_lo+128),
"a"(addr_lo+128+4*64)
);
}
static __attribute__((noinline)) void FlushDQSTestPattern_L18(u32 addr_lo)
{
__asm__ volatile (
"outb %%al, $0xed\n\t" /* _EXECFENCE */
"clflush %%fs:-128(%%eax)\n\t"
"clflush %%fs:-64(%%eax)\n\t"
"clflush %%fs:(%%eax)\n\t"
"clflush %%fs:64(%%eax)\n\t"
"clflush %%fs:-128(%%edi)\n\t"
"clflush %%fs:-64(%%edi)\n\t"
"clflush %%fs:(%%edi)\n\t"
"clflush %%fs:64(%%edi)\n\t"
"clflush %%fs:-128(%%ebx)\n\t"
"clflush %%fs:-64(%%ebx)\n\t"
"clflush %%fs:(%%ebx)\n\t"
"clflush %%fs:64(%%ebx)\n\t"
"clflush %%fs:-128(%%ecx)\n\t"
"clflush %%fs:-64(%%ecx)\n\t"
"clflush %%fs:(%%ecx)\n\t"
"clflush %%fs:64(%%ecx)\n\t"
"clflush %%fs:-128(%%edx)\n\t"
"clflush %%fs:-64(%%edx)\n\t"
:: "b" (addr_lo+128+8*64), "c" (addr_lo+128+12*64),
"d" (addr_lo +128+16*64), "a"(addr_lo+128),
"D"(addr_lo+128+4*64)
);
}
static void ReadL18TestPattern(u32 addr_lo)
{
/* set fs and use fs prefix to access the mem */
__asm__ volatile (
"outb %%al, $0xed\n\t" /* _EXECFENCE */
"movl %%fs:-128(%%esi), %%eax\n\t" /* TestAddr cache line */
"movl %%fs:-64(%%esi), %%eax\n\t" /* +1 */
"movl %%fs:(%%esi), %%eax\n\t" /* +2 */
"movl %%fs:64(%%esi), %%eax\n\t" /* +3 */
"movl %%fs:-128(%%edi), %%eax\n\t" /* +4 */
"movl %%fs:-64(%%edi), %%eax\n\t" /* +5 */
"movl %%fs:(%%edi), %%eax\n\t" /* +6 */
"movl %%fs:64(%%edi), %%eax\n\t" /* +7 */
"movl %%fs:-128(%%ebx), %%eax\n\t" /* +8 */
"movl %%fs:-64(%%ebx), %%eax\n\t" /* +9 */
"movl %%fs:(%%ebx), %%eax\n\t" /* +10 */
"movl %%fs:64(%%ebx), %%eax\n\t" /* +11 */
"movl %%fs:-128(%%ecx), %%eax\n\t" /* +12 */
"movl %%fs:-64(%%ecx), %%eax\n\t" /* +13 */
"movl %%fs:(%%ecx), %%eax\n\t" /* +14 */
"movl %%fs:64(%%ecx), %%eax\n\t" /* +15 */
"movl %%fs:-128(%%edx), %%eax\n\t" /* +16 */
"movl %%fs:-64(%%edx), %%eax\n\t" /* +17 */
"mfence\n\t"
:: "a"(0), "b" (addr_lo+128+8*64), "c" (addr_lo+128+12*64),
"d" (addr_lo +128+16*64), "S"(addr_lo+128),
"D"(addr_lo+128+4*64)
);
}
static void ReadL9TestPattern(u32 addr_lo)
{
/* set fs and use fs prefix to access the mem */
__asm__ volatile (
"outb %%al, $0xed\n\t" /* _EXECFENCE */
"movl %%fs:-128(%%ecx), %%eax\n\t" /* TestAddr cache line */
"movl %%fs:-64(%%ecx), %%eax\n\t" /* +1 */
"movl %%fs:(%%ecx), %%eax\n\t" /* +2 */
"movl %%fs:64(%%ecx), %%eax\n\t" /* +3 */
"movl %%fs:-128(%%edx), %%eax\n\t" /* +4 */
"movl %%fs:-64(%%edx), %%eax\n\t" /* +5 */
"movl %%fs:(%%edx), %%eax\n\t" /* +6 */
"movl %%fs:64(%%edx), %%eax\n\t" /* +7 */
"movl %%fs:-128(%%ebx), %%eax\n\t" /* +8 */
"mfence\n\t"
:: "a"(0), "b" (addr_lo+128+8*64), "c"(addr_lo+128),
"d"(addr_lo+128+4*64)
);
}
static void ReadMaxRdLat1CLTestPattern_D(u32 addr)
{
SetUpperFSbase(addr);
__asm__ volatile (
"outb %%al, $0xed\n\t" /* _EXECFENCE */
"movl %%fs:-128(%%esi), %%eax\n\t" /* TestAddr cache line */
"movl %%fs:-64(%%esi), %%eax\n\t" /* +1 */
"movl %%fs:(%%esi), %%eax\n\t" /* +2 */
"mfence\n\t"
:: "a"(0), "S"((addr<<8)+128)
);
}
static void WriteMaxRdLat1CLTestPattern_D(u32 buf, u32 addr)
{
SetUpperFSbase(addr);
__asm__ volatile (
"outb %%al, $0xed\n\t" /* _EXECFENCE */
"1:\n\t"
"movdqa (%3), %%xmm0\n\t"
"movntdq %%xmm0, %%fs:(%0)\n\t" /* xmm0 is 128 bit */
"addl %1, %0\n\t"
"addl %1, %3\n\t"
"loop 1b\n\t"
"mfence\n\t"
:: "a" (addr<<8), "d" (16), "c" (3 * 4), "b"(buf)
);
}
static void FlushMaxRdLatTestPattern_D(u32 addr)
{
/* Flush a pattern of 72 bit times (per DQ) from cache.
* This procedure is used to ensure cache miss on the next read training.
*/
SetUpperFSbase(addr);
__asm__ volatile (
"outb %%al, $0xed\n\t" /* _EXECFENCE */
"clflush %%fs:-128(%%esi)\n\t" /* TestAddr cache line */
"clflush %%fs:-64(%%esi)\n\t" /* +1 */
"clflush %%fs:(%%esi)\n\t" /* +2 */
"mfence\n\t"
:: "S"((addr<<8)+128)
);
}
static u32 stream_to_int(u8 *p)
{
int i;
u32 val;
u32 valx;
val = 0;
for(i=3; i>=0; i--) {
val <<= 8;
valx = *(p+i);
val |= valx;
}
return val;
}
#ifdef UNUSED_CODE
static void oemSet_NB32(u32 addr, u32 val, u8 *valid)
{
}
static u32 oemGet_NB32(u32 addr, u8 *valid)
{
*valid = 0;
return 0xffffffff;
}
#endif
static u8 oemNodePresent_D(u8 Node, u8 *ret)
{
*ret = 0;
return 0;
}