| /* |
| * This file is part of the coreboot project. |
| * |
| * Copyright (C) 2007 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. |
| */ |
| |
| #include "mct_d_gcc.h" |
| |
| inline void _WRMSR(u32 addr, u32 lo, u32 hi) |
| { |
| __asm__ volatile ( |
| "wrmsr" |
| : |
| :"c"(addr),"a"(lo), "d" (hi) |
| ); |
| } |
| |
| |
| inline void _RDMSR(u32 addr, u32 *lo, u32 *hi) |
| { |
| __asm__ volatile ( |
| "rdmsr" |
| :"=a"(*lo), "=d" (*hi) |
| :"c"(addr) |
| ); |
| } |
| |
| |
| inline void _RDTSC(u32 *lo, u32 *hi) |
| { |
| __asm__ volatile ( |
| "rdtsc" |
| : "=a" (*lo), "=d"(*hi) |
| ); |
| } |
| |
| |
| 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)); |
| |
| } |
| |
| |
| u32 bsr(u32 x) |
| { |
| u8 i; |
| u32 ret = 0; |
| |
| for (i = 31; i > 0; i--) { |
| if (x & (1<<i)) { |
| ret = i; |
| break; |
| } |
| } |
| |
| return ret; |
| |
| } |
| |
| |
| 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") |
| |
| #include <cpu/x86/cr.h> |
| |
| 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) |
| ); |
| } |
| |
| |
| 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) |
| ); |
| |
| } |
| |
| |
| 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 |
| |
| 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) |
| ); |
| |
| } |
| |
| |
| __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) |
| ); |
| } |
| |
| 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) |
| ); |
| |
| } |
| |
| 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) |
| ); |
| |
| } |
| |
| 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) |
| ); |
| |
| } |
| |
| 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) |
| ); |
| } |
| |
| 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) |
| ); |
| } |
| |
| u32 stream_to_int(u8 const *p) |
| { |
| int i; |
| u32 val; |
| u32 valx; |
| |
| val = 0; |
| |
| for (i = 3; i >= 0; i--) { |
| val <<= 8; |
| valx = *(p+i); |
| val |= valx; |
| } |
| |
| return val; |
| } |
| |
| u8 oemNodePresent_D(u8 Node, u8 *ret) |
| { |
| *ret = 0; |
| return 0; |
| } |