📄 controller.c
字号:
/* controller.c - MemTest-86 Version 3.0 * * Released under version 2 of the Gnu Public License. * By Chris Brady, cbrady@sgi.com * ---------------------------------------------------- * MemTest86+ V1.70 Specific code (GPL V2.0) * By Samuel DEMEULEMEESTER, sdemeule@memtest.org * http://www.x86-secret.com - http://www.memtest.org */#include "defs.h"#include "config.h"#include "test.h"#include "pci.h"#include "controller.h"int col, col2;extern ulong extclock;extern struct cpu_ident cpu_id;#define rdmsr(msr,val1,val2) \ __asm__ __volatile__("rdmsr" \ : "=a" (val1), "=d" (val2) \ : "c" (msr))#define wrmsr(msr,val1,val2) \ __asm__ __volatile__("wrmsr" \ : /* no outputs */ \ : "c" (msr), "a" (val1), "d" (val2))/* controller ECC capabilities and mode */#define __ECC_UNEXPECTED 1 /* Unknown ECC capability present */#define __ECC_DETECT 2 /* Can detect ECC errors */#define __ECC_CORRECT 4 /* Can correct some ECC errors */#define __ECC_SCRUB 8 /* Can scrub corrected ECC errors */#define __ECC_CHIPKILL 16 /* Can corrected multi-errors */#define ECC_UNKNOWN (~0UL) /* Unknown error correcting ability/status */#define ECC_NONE 0 /* Doesnt support ECC (or is BIOS disabled) */#define ECC_RESERVED __ECC_UNEXPECTED /* Reserved ECC type */#define ECC_DETECT __ECC_DETECT#define ECC_CORRECT (__ECC_DETECT | __ECC_CORRECT)#define ECC_CHIPKILL (__ECC_DETECT | __ECC_CORRECT | __ECC_CHIPKILL)#define ECC_SCRUB (__ECC_DETECT | __ECC_CORRECT | __ECC_SCRUB)static struct ecc_info { int index; int poll; unsigned bus; unsigned dev; unsigned fn; unsigned cap; unsigned mode;} ctrl ={ .index = 0, /* I know of no case where the memory controller is not on the * host bridge, and the host bridge is not on bus 0 device 0 * fn 0. But just in case leave these as variables. */ .bus = 0, .dev = 0, .fn = 0, /* Properties of the current memory controller */ .cap = ECC_UNKNOWN, .mode = ECC_UNKNOWN,};struct pci_memory_controller { unsigned vendor; unsigned device; char *name; int tested; void (*poll_fsb)(void); void (*poll_timings)(void); void (*setup_ecc)(void); void (*poll_errors)(void);};void print_timings_info(float cas, int rcd, int rp, int ras) { /* Now, we could print some additionnals timings infos) */ cprint(LINE_CPU+5, col2 +1, "/ CAS : "); col2 += 9; // CAS Latency (tCAS) if (cas == 1.5) { cprint(LINE_CPU+5, col2, "1.5"); col2 += 3; } else if (cas == 2.5) { cprint(LINE_CPU+5, col2, "2.5"); col2 += 3; } else { dprint(LINE_CPU+5, col2, cas, 1, 0); col2 += 1; } cprint(LINE_CPU+5, col2, "-"); col2 += 1; // RAS-To-CAS (tRCD) dprint(LINE_CPU+5, col2, rcd, 1, 0); cprint(LINE_CPU+5, col2+1, "-"); col2 +=2; // RAS Precharge (tRP) dprint(LINE_CPU+5, col2, rp, 1, 0); cprint(LINE_CPU+5, col2+1, "-"); col2 +=2; // RAS Active to precharge (tRAS) if (ras < 9) { dprint(LINE_CPU+5, col2, ras, 1, 0); col2 += 2; } else { dprint(LINE_CPU+5, col2, ras, 2, 0); col2 += 3; }}void print_fsb_info(float val, const char *text_fsb) { cprint(LINE_CPU+5, col2, "Settings: "); col2 += 10; cprint(LINE_CPU+5, col2, text_fsb); col2 += 6; dprint(LINE_CPU+5, col2, val ,3 ,0); col2 += 3; cprint(LINE_CPU+5, col2 +1, "MHz "); col2 += 5; cprint(LINE_CPU+5, col2, "(DDR"); col2 += 4; dprint(LINE_CPU+5, col2, val*2 ,3 ,0); col2 += 3; cprint(LINE_CPU+5, col2, ")"); col2 += 1;}static void poll_fsb_nothing(void){/* Code to run for no specific fsb detection */ return;}static void poll_timings_nothing(void){/* Code to run for no specific timings detection */ return;}static void setup_nothing(void){ ctrl.cap = ECC_NONE; ctrl.mode = ECC_NONE;}static void poll_nothing(void){/* Code to run when we don't know how, or can't ask the memory * controller about memory errors. */ return;}static void setup_amd64(void){ static const int ddim[] = { ECC_NONE, ECC_CORRECT, ECC_RESERVED, ECC_CHIPKILL }; unsigned long nbxcfg; unsigned int mcgsrl; unsigned int mcgsth; unsigned long mcanb; unsigned long dramcl; /* All AMD64 support Chipkill */ ctrl.cap = ECC_CHIPKILL; /* Check First if ECC DRAM Modules are used */ pci_conf_read(0, 24, 2, 0x90, 4, &dramcl); if (((cpu_id.ext >> 16) & 0xF) >= 4) { /* NEW K8 0Fh Family 90 nm */ if ((dramcl >> 19)&1){ /* Fill in the correct memory capabilites */ pci_conf_read(0, 24, 3, 0x44, 4, &nbxcfg); ctrl.mode = ddim[(nbxcfg >> 22)&3]; } else { ctrl.mode = ECC_NONE; } /* Enable NB ECC Logging by MSR Write */ rdmsr(0x017B, mcgsrl, mcgsth); wrmsr(0x017B, 0x10, mcgsth); /* Clear any previous error */ pci_conf_read(0, 24, 3, 0x4C, 4, &mcanb); pci_conf_write(0, 24, 3, 0x4C, 4, mcanb & 0x7FFFFFFF ); } else { /* OLD K8 130 nm */ if ((dramcl >> 17)&1){ /* Fill in the correct memory capabilites */ pci_conf_read(0, 24, 3, 0x44, 4, &nbxcfg); ctrl.mode = ddim[(nbxcfg >> 22)&3]; } else { ctrl.mode = ECC_NONE; } /* Enable NB ECC Logging by MSR Write */ rdmsr(0x017B, mcgsrl, mcgsth); wrmsr(0x017B, 0x10, mcgsth); /* Clear any previous error */ pci_conf_read(0, 24, 3, 0x4C, 4, &mcanb); pci_conf_write(0, 24, 3, 0x4C, 4, mcanb & 0x7F801EFC ); }}static void poll_amd64(void){ unsigned long mcanb; unsigned long page, offset; unsigned long celog_syndrome; unsigned long mcanb_add; pci_conf_read(0, 24, 3, 0x4C, 4, &mcanb); if (((mcanb >> 31)&1) && ((mcanb >> 14)&1)) { /* Find out about the first correctable error */ /* Syndrome code -> bits use a complex matrix. Will add this later */ /* Read the error location */ pci_conf_read(0, 24, 3, 0x50, 4, &mcanb_add); /* Read the syndrome */ celog_syndrome = (mcanb >> 15)&0xFF; /* Parse the error location */ page = (mcanb_add >> 12); offset = (mcanb_add >> 3) & 0xFFF; /* Report the error */ print_ecc_err(page, offset, 1, celog_syndrome, 0); /* Clear the error registers */ pci_conf_write(0, 24, 3, 0x4C, 4, mcanb & 0x7FFFFFFF ); } if (((mcanb >> 31)&1) && ((mcanb >> 13)&1)) { /* Found out about the first uncorrectable error */ /* Read the error location */ pci_conf_read(0, 24, 3, 0x50, 4, &mcanb_add); /* Parse the error location */ page = (mcanb_add >> 12); offset = (mcanb_add >> 3) & 0xFFF; /* Report the error */ print_ecc_err(page, offset, 0, 0, 0); /* Clear the error registers */ pci_conf_write(0, 24, 3, 0x4C, 4, mcanb & 0x7FFFFFF ); }}static void setup_amd751(void){ unsigned long dram_status; /* Fill in the correct memory capabilites */ pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x5a, 2, &dram_status); ctrl.cap = ECC_CORRECT; ctrl.mode = (dram_status & (1 << 2))?ECC_CORRECT: ECC_NONE;}static void poll_amd751(void){ unsigned long ecc_status; unsigned long bank_addr; unsigned long bank_info; unsigned long page; int bits; int i; /* Read the error status */ pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x58, 2, &ecc_status); if (ecc_status & (3 << 8)) { for(i = 0; i < 6; i++) { if (!(ecc_status & (1 << i))) { continue; } /* Find the bank the error occured on */ bank_addr = 0x40 + (i << 1); /* Now get the information on the erroring bank */ pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, bank_addr, 2, &bank_info); /* Parse the error location and error type */ page = (bank_info & 0xFF80) << 4; bits = (((ecc_status >> 8) &3) == 2)?1:2; /* Report the error */ print_ecc_err(page, 0, bits==1?1:0, 0, 0); } /* Clear the error status */ pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0x58, 2, 0); }}/* Still waiting for the CORRECT intel datasheetstatic void setup_i85x(void){ unsigned long drc; ctrl.cap = ECC_CORRECT; pci_conf_read(ctrl.bus, ctrl.dev, 1, 0x70, 4, &drc); ctrl.mode = ((drc>>20)&1)?ECC_CORRECT:ECC_NONE;}*/static void setup_amd76x(void){ static const int ddim[] = { ECC_NONE, ECC_DETECT, ECC_CORRECT, ECC_CORRECT }; unsigned long ecc_mode_status; /* Fill in the correct memory capabilites */ pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x48, 4, &ecc_mode_status); ctrl.cap = ECC_CORRECT; ctrl.mode = ddim[(ecc_mode_status >> 10)&3];}static void poll_amd76x(void){ unsigned long ecc_mode_status; unsigned long bank_addr; unsigned long bank_info; unsigned long page; /* Read the error status */ pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x48, 4, &ecc_mode_status); /* Multibit error */ if (ecc_mode_status & (1 << 9)) { /* Find the bank the error occured on */ bank_addr = 0xC0 + (((ecc_mode_status >> 4) & 0xf) << 2); /* Now get the information on the erroring bank */ pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, bank_addr, 4, &bank_info); /* Parse the error location and error type */ page = (bank_info & 0xFF800000) >> 12; /* Report the error */ print_ecc_err(page, 0, 1, 0, 0); } /* Singlebit error */ if (ecc_mode_status & (1 << 8)) { /* Find the bank the error occured on */ bank_addr = 0xC0 + (((ecc_mode_status >> 0) & 0xf) << 2); /* Now get the information on the erroring bank */ pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, bank_addr, 4, &bank_info); /* Parse the error location and error type */ page = (bank_info & 0xFF800000) >> 12; /* Report the error */ print_ecc_err(page, 0, 0, 0, 0); } /* Clear the error status */ if (ecc_mode_status & (3 << 8)) { pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0x48, 4, ecc_mode_status); }}static void setup_cnb20(void){ /* Fill in the correct memory capabilites */ ctrl.cap = ECC_CORRECT; /* FIXME add ECC error polling. I don't have the documentation * do it right now. */}static void setup_iE7xxx(void){ unsigned long mchcfgns; unsigned long drc; unsigned long device; unsigned long dvnp; /* Read the hardare capabilities */ pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x52, 2, &mchcfgns); pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x7C, 4, &drc); /* This is a check for E7205 */ pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x02, 2, &device); /* Fill in the correct memory capabilities */ ctrl.mode = 0; ctrl.cap = ECC_CORRECT; /* checking and correcting enabled */ if (((drc >> 20) & 3) == 2) { ctrl.mode |= ECC_CORRECT; } /* E7205 doesn't support scrubbing */ if (device != 0x255d) { /* scrub enabled */ /* For E7501, valid SCRUB operations is bit 0 / D0:F0:R70-73 */ ctrl.cap = ECC_SCRUB; if (mchcfgns & 1) { ctrl.mode |= __ECC_SCRUB; } /* Now, we can active Dev1/Fun1 */ /* Thanks to Tyan for providing us the board to solve this */ pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xE0, 2, &dvnp); pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn , 0xE0, 2, (dvnp & 0xFE)); /* Clear any routing of ECC errors to interrupts that the BIOS might have set up */ pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x88, 1, 0x0); pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x8A, 1, 0x0); pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x8C, 1, 0x0); } /* Clear any prexisting error reports */ pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x80, 1, 3); pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x82, 1, 3);}static void setup_iE7520(void){ unsigned long mchscrb; unsigned long drc; unsigned long dvnp1; /* Read the hardare capabilities */ pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x52, 2, &mchscrb); pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x7C, 4, &drc);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -