| /* |
| * MemTest86+ V5 Specific code (GPL V2.0) |
| * By Samuel DEMEULEMEESTER, sdemeule@memtest.org |
| * http://www.canardpc.com - http://www.memtest.org |
| * |
| * Edited by David McInnis Oct 4, 2014 |
| */ |
| |
| //#include "defs.h" |
| #include "config.h" |
| //#include "test.h" |
| #include "pci.h" |
| #include "controller.h" |
| #include "spd.h" |
| #include "test.h" |
| #include "stdint.h" |
| #include "cpuid.h" |
| #include "msr.h" |
| #include "dmi.h" |
| |
| int col, col2; |
| int nhm_bus = 0x3F; |
| |
| extern ulong extclock; |
| extern unsigned long imc_type; |
| extern struct cpu_ident cpu_id; |
| /* |
| #define rdmsr(msr,val1,val2) \ |
| __asm__ __volatile__("rdmsr" \ |
| : "=a" (val1), "=d" (val2) \ |
| : "c" (msr) : "edi") |
| |
| #define wrmsr(msr,val1,val2) \ |
| __asm__ __volatile__("wrmsr" \ |
| : \ |
| : "c" (msr), "a" (val1), "d" (val2) : "edi") |
| */ |
| /* 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, |
| }; |
| |
| |
| void coretemp(void) |
| { |
| unsigned int msrl, msrh; |
| unsigned int tjunc, tabs, tnow; |
| unsigned long rtcr; |
| double amd_raw_temp; |
| |
| // Only enable coretemp if IMC is known |
| if(imc_type == 0) { return; } |
| |
| tnow = 0; |
| |
| // Intel CPU |
| if(cpu_id.vend_id.char_array[0] == 'G' && cpu_id.max_cpuid >= 6) |
| { |
| if(cpu_id.dts_pmp & 1){ |
| rdmsr(MSR_IA32_THERM_STATUS, msrl, msrh); |
| tabs = ((msrl >> 16) & 0x7F); |
| rdmsr(MSR_IA32_TEMPERATURE_TARGET, msrl, msrh); |
| tjunc = ((msrl >> 16) & 0x7F); |
| if(tjunc < 50 || tjunc > 125) { tjunc = 90; } // assume Tjunc = 90°C if boggus value received. |
| tnow = tjunc - tabs; |
| dprint(LINE_CPU+1, 30, v->check_temp, 3, 0); |
| v->check_temp = tnow; |
| } |
| return; |
| } |
| |
| // AMD CPU |
| if(cpu_id.vend_id.char_array[0] == 'A' && cpu_id.vers.bits.extendedFamily > 0) |
| { |
| pci_conf_read(0, 24, 3, 0xA4, 4, &rtcr); |
| amd_raw_temp = ((rtcr >> 21) & 0x7FF); |
| v->check_temp = (int)(amd_raw_temp / 8); |
| dprint(LINE_CPU+1, 30, v->check_temp, 3, 0); |
| } |
| |
| |
| } |
| |
| void print_cpu_line(float dram_freq, float fsb_freq, int ram_type) |
| { |
| int cur_col = COL_SPEC; |
| |
| cprint(LINE_CPU, cur_col, "RAM: "); |
| cur_col += 5; |
| dprint(LINE_CPU, cur_col, dram_freq, 4, 1); |
| cur_col += 4; |
| cprint(LINE_CPU, cur_col, "MHz ("); |
| cur_col += 5; |
| |
| switch(ram_type) |
| { |
| default: |
| case 1: |
| cprint(LINE_CPU, cur_col, "DDR-"); |
| cur_col += 4; |
| break; |
| case 2: |
| cprint(LINE_CPU, cur_col, "DDR2-"); |
| cur_col += 5; |
| break; |
| case 3: |
| cprint(LINE_CPU, cur_col, "DDR3-"); |
| cur_col += 5; |
| break; |
| } |
| |
| if(dram_freq < 500) |
| { |
| dprint(LINE_CPU, cur_col, dram_freq*2, 3, 0); |
| cur_col += 3; |
| } else { |
| dprint(LINE_CPU, cur_col, dram_freq*2, 4, 0); |
| cur_col += 4; |
| } |
| cprint(LINE_CPU, cur_col, ")"); |
| cur_col++; |
| |
| if(fsb_freq > 10) |
| { |
| cprint(LINE_CPU, cur_col, " - BCLK: "); |
| cur_col += 9; |
| |
| dprint(LINE_CPU, cur_col, fsb_freq, 3, 0); |
| } |
| |
| } |
| |
| void print_ram_line(float cas, int rcd, int rp, int ras, int chan) |
| { |
| int cur_col = COL_SPEC; |
| |
| cprint(LINE_RAM, cur_col, "Timings: CAS "); |
| cur_col += 13; |
| |
| // CAS Latency (tCAS) |
| if (cas == 1.5) { |
| cprint(LINE_RAM, cur_col, "1.5"); cur_col += 3; |
| } else if (cas == 2.5) { |
| cprint(LINE_RAM, cur_col, "2.5"); cur_col += 3; |
| } else if (cas < 10) { |
| dprint(LINE_RAM, cur_col, cas, 1, 0); cur_col += 1; |
| } else { |
| dprint(LINE_RAM, cur_col, cas, 2, 0); cur_col += 2; |
| } |
| cprint(LINE_RAM, cur_col, "-"); cur_col += 1; |
| |
| // RAS-To-CAS (tRCD) |
| if (rcd < 10) { |
| dprint(LINE_RAM, cur_col, rcd, 1, 0); |
| cur_col += 1; |
| } else { |
| dprint(LINE_RAM, cur_col, rcd, 2, 0); |
| cur_col += 2; |
| } |
| cprint(LINE_RAM, cur_col, "-"); cur_col += 1; |
| |
| // RAS Precharge (tRP) |
| if (rp < 10) { |
| dprint(LINE_RAM, cur_col, rp, 1, 0); |
| cur_col += 1; |
| } else { |
| dprint(LINE_RAM, cur_col, rp, 2, 0); |
| cur_col += 2; |
| } |
| cprint(LINE_RAM, cur_col, "-"); cur_col += 1; |
| |
| // RAS Active to precharge (tRAS) |
| if (ras < 10) { |
| dprint(LINE_RAM, cur_col, ras, 1, 0); |
| cur_col += 1; |
| } else { |
| dprint(LINE_RAM, cur_col, ras, 2, 0); |
| cur_col += 2; |
| } |
| |
| |
| switch(chan) |
| { |
| case 0: |
| break; |
| case 1: |
| cprint(LINE_RAM, cur_col, " @ 64-bit Mode"); |
| break; |
| case 2: |
| cprint(LINE_RAM, cur_col, " @ 128-bit Mode"); |
| break; |
| case 3: |
| cprint(LINE_RAM, cur_col, " @ 192-bit Mode"); |
| break; |
| case 4: |
| cprint(LINE_RAM, cur_col, " @ 256-bit Mode"); |
| break; |
| } |
| } |
| |
| static void poll_fsb_nothing(void) |
| { |
| |
| char *name; |
| |
| /* Print the controller name */ |
| name = controllers[ctrl.index].name; |
| cprint(LINE_CPU, COL_SPEC, "Chipset: "); |
| cprint(LINE_CPU, COL_SPEC+9, name); |
| return; |
| } |
| |
| static void poll_timings_nothing(void) |
| { |
| char *ram_type; |
| |
| /* Print the controller name */ |
| ram_type = controllers[ctrl.index].ram_type; |
| cprint(LINE_RAM, COL_SPEC, "RAM Type: "); |
| cprint(LINE_RAM, COL_SPEC+10, ram_type); |
| 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_wmr(void) |
| { |
| ulong dev0; |
| |
| // Activate MMR I/O |
| pci_conf_read( 0, 0, 0, 0x48, 4, &dev0); |
| if (!(dev0 & 0x1)) { |
| pci_conf_write( 0, 0, 0, 0x48, 1, dev0 | 1); |
| } |
| |
| } |
| |
| |
| static void setup_nhm(void) |
| { |
| static float possible_nhm_bus[] = {0xFF, 0x7F, 0x3F}; |
| unsigned long did, vid, mc_control, mc_ssrcontrol; |
| int i; |
| |
| //Nehalem supports Scrubbing */ |
| ctrl.cap = ECC_SCRUB; |
| ctrl.mode = ECC_NONE; |
| |
| /* First, locate the PCI bus where the MCH is located */ |
| |
| for(i = 0; i < sizeof(possible_nhm_bus) / sizeof(possible_nhm_bus[0]); i++) { |
| pci_conf_read( possible_nhm_bus[i], 3, 4, 0x00, 2, &vid); |
| pci_conf_read( possible_nhm_bus[i], 3, 4, 0x02, 2, &did); |
| vid &= 0xFFFF; |
| did &= 0xFF00; |
| if(vid == 0x8086 && did >= 0x2C00) { |
| nhm_bus = possible_nhm_bus[i]; |
| } |
| } |
| |
| /* Now, we have the last IMC bus number in nhm_bus */ |
| /* Check for ECC & Scrub */ |
| |
| pci_conf_read(nhm_bus, 3, 0, 0x4C, 2, &mc_control); |
| if((mc_control >> 4) & 1) { |
| ctrl.mode = ECC_CORRECT; |
| pci_conf_read(nhm_bus, 3, 2, 0x48, 2, &mc_ssrcontrol); |
| if(mc_ssrcontrol & 3) { |
| ctrl.mode = ECC_SCRUB; |
| } |
| } |
| |
| } |
| |
| static void setup_nhm32(void) |
| { |
| static float possible_nhm_bus[] = {0xFF, 0x7F, 0x3F}; |
| unsigned long did, vid, mc_control, mc_ssrcontrol; |
| int i; |
| |
| //Nehalem supports Scrubbing */ |
| ctrl.cap = ECC_SCRUB; |
| ctrl.mode = ECC_NONE; |
| |
| /* First, locate the PCI bus where the MCH is located */ |
| for(i = 0; i < sizeof(possible_nhm_bus) / sizeof(possible_nhm_bus[0]); i++) { |
| pci_conf_read( possible_nhm_bus[i], 3, 4, 0x00, 2, &vid); |
| pci_conf_read( possible_nhm_bus[i], 3, 4, 0x02, 2, &did); |
| vid &= 0xFFFF; |
| did &= 0xFF00; |
| if(vid == 0x8086 && did >= 0x2C00) { |
| nhm_bus = possible_nhm_bus[i]; |
| } |
| } |
| |
| /* Now, we have the last IMC bus number in nhm_bus */ |
| /* Check for ECC & Scrub */ |
| pci_conf_read(nhm_bus, 3, 0, 0x48, 2, &mc_control); |
| if((mc_control >> 1) & 1) { |
| ctrl.mode = ECC_CORRECT; |
| pci_conf_read(nhm_bus, 3, 2, 0x48, 2, &mc_ssrcontrol); |
| if(mc_ssrcontrol & 1) { |
| ctrl.mode = ECC_SCRUB; |
| } |
| } |
| |
| } |
| |
| 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.vers.bits.extendedModel >= 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 setup_k10(void) |
| { |
| static const int ddim[] = { ECC_NONE, ECC_CORRECT, ECC_CHIPKILL, ECC_CHIPKILL }; |
| unsigned long nbxcfg; |
| unsigned int mcgsrl; |
| unsigned int mcgsth; |
| unsigned long mcanb; |
| unsigned long dramcl; |
| ulong msr_low, msr_high; |
| |
| // 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 ((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 ); |
| |
| /* Enable ECS */ |
| rdmsr(0xC001001F, msr_low, msr_high); |
| wrmsr(0xC001001F, msr_low, (msr_high | 0x4000)); |
| rdmsr(0xC001001F, msr_low, msr_high); |
| |
| } |
| |
| static void setup_apu(void) |
| { |
| |
| ulong msr_low, msr_high; |
| |
| /* Enable ECS */ |
| rdmsr(0xC001001F, msr_low, msr_high); |
| wrmsr(0xC001001F, msr_low, (msr_high | 0x4000)); |
| rdmsr(0xC001001F, msr_low, msr_high); |
| |
| } |
| |
| /* |
| 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 datasheet |
| static 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_E5400(void) |
| { |
| unsigned long mcs; |
| |
| |
| /* Read the hardware capabilities */ |
| pci_conf_read(ctrl.bus, 16, 1, 0x40, 4, &mcs); |
| |
| /* Fill in the correct memory capabilities */ |
| ctrl.mode = 0; |
| ctrl.cap = ECC_SCRUB; |
| |
| /* Checking and correcting enabled */ |
| if (((mcs >> 5) & 1) == 1) { |
| ctrl.mode |= ECC_CORRECT; |
| } |
| |
| /* scrub enabled */ |
| if (((mcs >> 7) & 1) == 1) { |
| ctrl.mode |= __ECC_SCRUB; |
| } |
| } |
| |
| |
| 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); |
| |
| /* Fill in the correct memory capabilities */ |
| ctrl.mode = 0; |
| ctrl.cap = ECC_CORRECT; |
| |
| /* Checking and correcting enabled */ |
| if (((drc >> 20) & 3) != 0) { |
| ctrl.mode |= ECC_CORRECT; |
| } |
| |
| /* scrub enabled */ |
| ctrl.cap = ECC_SCRUB; |
| if ((mchscrb & 3) == 2) { |
| ctrl.mode |= __ECC_SCRUB; |
| } |
| |
| /* Now, we can activate Fun1 */ |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xF4, 1, &dvnp1); |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn , 0xF4, 1, (dvnp1 | 0x20)); |
| |
| /* Clear any prexisting error reports */ |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x80, 2, 0x4747); |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x82, 2, 0x4747); |
| |
| } |
| |
| /* |
| static void poll_iE7xxx(void) |
| { |
| unsigned long ferr; |
| unsigned long nerr; |
| |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x80, 1, &ferr); |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x82, 1, &nerr); |
| |
| if (ferr & 1) { |
| // Find out about the first correctable error |
| unsigned long celog_add; |
| unsigned long celog_syndrome; |
| unsigned long page; |
| |
| // Read the error location |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn +1, 0xA0, 4, &celog_add); |
| // Read the syndrome |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn +1, 0xD0, 2, &celog_syndrome); |
| |
| // Parse the error location |
| page = (celog_add & 0x0FFFFFC0) >> 6; |
| |
| // Report the error |
| print_ecc_err(page, 0, 1, celog_syndrome, 0); |
| |
| // Clear Bit |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x80, 1, ferr & 3); |
| } |
| |
| if (ferr & 2) { |
| // Found out about the first uncorrectable error |
| unsigned long uccelog_add; |
| unsigned long page; |
| |
| // Read the error location |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn +1, 0xB0, 4, &uccelog_add); |
| |
| // Parse the error location |
| page = (uccelog_add & 0x0FFFFFC0) >> 6; |
| |
| // Report the error |
| print_ecc_err(page, 0, 0, 0, 0); |
| |
| // Clear Bit |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x80, 1, ferr & 3); |
| } |
| |
| // Check if DRAM_NERR contains data |
| if (nerr & 3) { |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x82, 1, nerr & 3); |
| } |
| |
| } |
| */ |
| |
| static void setup_i440gx(void) |
| { |
| static const int ddim[] = { ECC_NONE, ECC_DETECT, ECC_CORRECT, ECC_CORRECT }; |
| unsigned long nbxcfg; |
| |
| /* Fill in the correct memory capabilites */ |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x50, 4, &nbxcfg); |
| ctrl.cap = ECC_CORRECT; |
| ctrl.mode = ddim[(nbxcfg >> 7)&3]; |
| } |
| |
| /* |
| static void poll_i440gx(void) |
| { |
| unsigned long errsts; |
| unsigned long page; |
| int bits; |
| // Read the error status |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x91, 2, &errsts); |
| if (errsts & 0x11) { |
| unsigned long eap; |
| // Read the error location |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x80, 4, &eap); |
| |
| // Parse the error location and error type |
| page = (eap & 0xFFFFF000) >> 12; |
| bits = 0; |
| if (eap &3) { |
| bits = ((eap & 3) == 1)?1:2; |
| } |
| |
| if (bits) { |
| // 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, 0x91, 2, 0x11); |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0x80, 4, 3); |
| } |
| |
| } |
| */ |
| |
| |
| static void setup_i840(void) |
| { |
| static const int ddim[] = { ECC_NONE, ECC_RESERVED, ECC_CORRECT, ECC_CORRECT }; |
| unsigned long mchcfg; |
| |
| /* Fill in the correct memory capabilites */ |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x50, 2, &mchcfg); |
| ctrl.cap = ECC_CORRECT; |
| ctrl.mode = ddim[(mchcfg >> 7)&3]; |
| } |
| |
| /* |
| static void poll_i840(void) |
| { |
| unsigned long errsts; |
| unsigned long page; |
| unsigned long syndrome; |
| int channel; |
| int bits; |
| // Read the error status |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, &errsts); |
| if (errsts & 3) { |
| unsigned long eap; |
| unsigned long derrctl_sts; |
| // Read the error location |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xE4, 4, &eap); |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xE2, 2, &derrctl_sts); |
| |
| // Parse the error location and error type |
| page = (eap & 0xFFFFF800) >> 11; |
| channel = eap & 1; |
| syndrome = derrctl_sts & 0xFF; |
| bits = ((errsts & 3) == 1)?1:2; |
| |
| // Report the error |
| print_ecc_err(page, 0, bits==1?1:0, syndrome, channel); |
| |
| // Clear the error status |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xE2, 2, 3 << 10); |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, 3); |
| } |
| } |
| */ |
| |
| |
| static void setup_i875(void) |
| { |
| |
| long *ptr; |
| ulong dev0, dev6 ; |
| |
| /* Fill in the correct memory capabilites */ |
| |
| ctrl.cap = ECC_CORRECT; |
| ctrl.mode = ECC_NONE; |
| |
| /* From my article : http://www.x86-secret.com/articles/tweak/pat/patsecrets-2.htm */ |
| /* Activate Device 6 */ |
| pci_conf_read( 0, 0, 0, 0xF4, 1, &dev0); |
| pci_conf_write( 0, 0, 0, 0xF4, 1, (dev0 | 0x2)); |
| |
| /* Activate Device 6 MMR */ |
| pci_conf_read( 0, 6, 0, 0x04, 2, &dev6); |
| pci_conf_write( 0, 6, 0, 0x04, 2, (dev6 | 0x2)); |
| |
| /* Read the MMR Base Address & Define the pointer*/ |
| pci_conf_read( 0, 6, 0, 0x10, 4, &dev6); |
| ptr=(long*)(dev6+0x68); |
| |
| if (((*ptr >> 18)&1) == 1) { ctrl.mode = ECC_CORRECT; } |
| |
| /* Reseting state */ |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, 0x81); |
| } |
| |
| static void setup_i925(void) |
| { |
| |
| // Activate MMR I/O |
| ulong dev0, drc; |
| unsigned long tolm; |
| long *ptr; |
| |
| pci_conf_read( 0, 0, 0, 0x54, 4, &dev0); |
| dev0 = dev0 | 0x10000000; |
| pci_conf_write( 0, 0, 0, 0x54, 4, dev0); |
| |
| // CDH start |
| pci_conf_read( 0, 0, 0, 0x44, 4, &dev0); |
| if (!(dev0 & 0xFFFFC000)) { |
| pci_conf_read( 0, 0, 0, 0x9C, 1, &tolm); |
| pci_conf_write( 0, 0, 0, 0x47, 1, tolm & 0xF8); |
| } |
| // CDH end |
| |
| // ECC Checking |
| ctrl.cap = ECC_CORRECT; |
| |
| dev0 &= 0xFFFFC000; |
| ptr=(long*)(dev0+0x120); |
| drc = *ptr & 0xFFFFFFFF; |
| |
| if (((drc >> 20) & 3) == 2) { |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, 3); |
| ctrl.mode = ECC_CORRECT; |
| } else { |
| ctrl.mode = ECC_NONE; |
| } |
| |
| } |
| |
| static void setup_p35(void) |
| { |
| |
| // Activate MMR I/O |
| ulong dev0, capid0; |
| |
| pci_conf_read( 0, 0, 0, 0x48, 4, &dev0); |
| if (!(dev0 & 0x1)) { |
| pci_conf_write( 0, 0, 0, 0x48, 1, dev0 | 1); |
| } |
| |
| // ECC Checking (No poll on X38/48 for now) |
| pci_conf_read( 0, 0, 0, 0xE4, 4, &capid0); |
| if ((capid0 >> 8) & 1) { |
| ctrl.cap = ECC_NONE; |
| } else { |
| ctrl.cap = ECC_CORRECT; |
| } |
| |
| ctrl.mode = ECC_NONE; |
| |
| /* |
| ulong toto; |
| pci_conf_write(0, 31, 3, 0x40, 1, 0x1); |
| pci_conf_read(0, 31, 3, 0x0, 4, &toto); |
| hprint(11,0,toto); |
| pci_conf_read(0, 31, 3, 0x10, 4, &toto); |
| hprint(11,10,toto) ; |
| pci_conf_read(0, 31, 3, 0x20, 4, &toto); |
| hprint(11,20,toto) ; |
| pci_conf_read(0, 28, 0, 0x0, 4, &toto); |
| hprint(11,30,toto); |
| pci_conf_read(0, 31, 0, 0x0, 4, &toto); |
| hprint(11,40,toto) ; |
| pci_conf_read(0, 31, 1, 0x0, 4, &toto); |
| hprint(11,50,toto) ; |
| pci_conf_read(0, 31, 2, 0x0, 4, &toto); |
| hprint(11,60,toto) ; |
| */ |
| } |
| |
| /* |
| static void poll_i875(void) |
| { |
| unsigned long errsts; |
| unsigned long page; |
| unsigned long des; |
| unsigned long syndrome; |
| int channel; |
| int bits; |
| // Read the error status |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, &errsts); |
| if (errsts & 0x81) { |
| unsigned long eap; |
| unsigned long derrsyn; |
| // Read the error location, syndrome and channel |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x58, 4, &eap); |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x5C, 1, &derrsyn); |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x5D, 1, &des); |
| |
| // Parse the error location and error type |
| page = (eap & 0xFFFFF000) >> 12; |
| syndrome = derrsyn; |
| channel = des & 1; |
| bits = (errsts & 0x80)?0:1; |
| |
| // Report the error |
| print_ecc_err(page, 0, bits, syndrome, channel); |
| |
| // Clear the error status |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, 0x81); |
| } |
| } |
| */ |
| |
| static void setup_i845(void) |
| { |
| static const int ddim[] = { ECC_NONE, ECC_RESERVED, ECC_CORRECT, ECC_RESERVED }; |
| unsigned long drc; |
| |
| // Fill in the correct memory capabilites |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x7C, 4, &drc); |
| ctrl.cap = ECC_CORRECT; |
| ctrl.mode = ddim[(drc >> 20)&3]; |
| } |
| |
| /* |
| static void poll_i845(void) |
| { |
| unsigned long errsts; |
| unsigned long page, offset; |
| unsigned long syndrome; |
| int bits; |
| // Read the error status |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, &errsts); |
| if (errsts & 3) { |
| unsigned long eap; |
| unsigned long derrsyn; |
| // Read the error location |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x8C, 4, &eap); |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x86, 1, &derrsyn); |
| |
| // Parse the error location and error type |
| offset = (eap & 0xFE) << 4; |
| page = (eap & 0x3FFFFFFE) >> 8; |
| syndrome = derrsyn; |
| bits = ((errsts & 3) == 1)?1:2; |
| |
| // Report the error |
| print_ecc_err(page, offset, bits==1?1:0, syndrome, 0); |
| |
| // Clear the error status |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, 3); |
| } |
| } |
| */ |
| |
| |
| static void setup_i820(void) |
| { |
| static const int ddim[] = { ECC_NONE, ECC_RESERVED, ECC_CORRECT, ECC_CORRECT }; |
| unsigned long mchcfg; |
| |
| // Fill in the correct memory capabilites |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xbe, 2, &mchcfg); |
| ctrl.cap = ECC_CORRECT; |
| ctrl.mode = ddim[(mchcfg >> 7)&3]; |
| } |
| |
| /* |
| static void poll_i820(void) |
| { |
| unsigned long errsts; |
| unsigned long page; |
| unsigned long syndrome; |
| int bits; |
| // Read the error status |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, &errsts); |
| if (errsts & 3) { |
| unsigned long eap; |
| // Read the error location |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xc4, 4, &eap); |
| |
| // Parse the error location and error type |
| page = (eap & 0xFFFFF000) >> 4; |
| syndrome = eap & 0xFF; |
| bits = ((errsts & 3) == 1)?1:2; |
| |
| // Report the error |
| print_ecc_err(page, 0, bits==1?1:0, syndrome, 0); |
| |
| // Clear the error status |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, 3); |
| } |
| } |
| */ |
| |
| static void setup_i850(void) |
| { |
| static const int ddim[] = { ECC_NONE, ECC_RESERVED, ECC_CORRECT, ECC_RESERVED }; |
| unsigned long mchcfg; |
| |
| // Fill in the correct memory capabilites |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x50, 2, &mchcfg); |
| ctrl.cap = ECC_CORRECT; |
| ctrl.mode = ddim[(mchcfg >> 7)&3]; |
| } |
| |
| /* |
| static void poll_i850(void) |
| { |
| unsigned long errsts; |
| unsigned long page; |
| unsigned long syndrome; |
| int channel; |
| int bits; |
| // Read the error status |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, &errsts); |
| if (errsts & 3) { |
| unsigned long eap; |
| unsigned long derrctl_sts; |
| // Read the error location |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xE4, 4, &eap); |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xE2, 2, &derrctl_sts); |
| |
| // Parse the error location and error type |
| page = (eap & 0xFFFFF800) >> 11; |
| channel = eap & 1; |
| syndrome = derrctl_sts & 0xFF; |
| bits = ((errsts & 3) == 1)?1:2; |
| |
| // Report the error |
| print_ecc_err(page, 0, bits==1?1:0, syndrome, channel); |
| |
| // Clear the error status |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, errsts & 3); |
| } |
| } |
| */ |
| |
| static void setup_i860(void) |
| { |
| static const int ddim[] = { ECC_NONE, ECC_RESERVED, ECC_CORRECT, ECC_RESERVED }; |
| unsigned long mchcfg; |
| unsigned long errsts; |
| |
| // Fill in the correct memory capabilites |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x50, 2, &mchcfg); |
| ctrl.cap = ECC_CORRECT; |
| ctrl.mode = ddim[(mchcfg >> 7)&3]; |
| |
| // Clear any prexisting error reports |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, &errsts); |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, errsts & 3); |
| } |
| |
| /* |
| static void poll_i860(void) |
| { |
| unsigned long errsts; |
| unsigned long page; |
| unsigned char syndrome; |
| int channel; |
| int bits; |
| // Read the error status |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, &errsts); |
| if (errsts & 3) { |
| unsigned long eap; |
| unsigned long derrctl_sts; |
| // Read the error location |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xE4, 4, &eap); |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xE2, 2, &derrctl_sts); |
| |
| // Parse the error location and error type |
| page = (eap & 0xFFFFFE00) >> 9; |
| channel = eap & 1; |
| syndrome = derrctl_sts & 0xFF; |
| bits = ((errsts & 3) == 1)?1:2; |
| |
| // Report the error |
| print_ecc_err(page, 0, bits==1?1:0, syndrome, channel); |
| |
| // Clear the error status |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, errsts & 3); |
| } |
| } |
| |
| |
| static void poll_iE7221(void) |
| { |
| unsigned long errsts; |
| unsigned long page; |
| unsigned char syndrome; |
| int channel; |
| int bits; |
| int errocc; |
| |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, &errsts); |
| |
| errocc = errsts & 3; |
| |
| if ((errocc == 1) || (errocc == 2)) { |
| unsigned long eap, offset; |
| unsigned long derrctl_sts; |
| |
| // Read the error location |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x58, 4, &eap); |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn, 0x5C, 1, &derrctl_sts); |
| |
| // Parse the error location and error type |
| channel = eap & 1; |
| eap = eap & 0xFFFFFF80; |
| page = eap >> 12; |
| offset = eap & 0xFFF; |
| syndrome = derrctl_sts & 0xFF; |
| bits = errocc & 1; |
| |
| // Report the error |
| print_ecc_err(page, offset, bits, syndrome, channel); |
| |
| // Clear the error status |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, errsts & 3); |
| } |
| |
| else if (errocc == 3) { |
| |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn, 0xC8, 2, errsts & 3); |
| |
| } |
| } |
| |
| |
| static void poll_iE7520(void) |
| { |
| unsigned long ferr; |
| unsigned long nerr; |
| |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x80, 2, &ferr); |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x82, 2, &nerr); |
| |
| if (ferr & 0x0101) { |
| // Find out about the first correctable error |
| unsigned long celog_add; |
| unsigned long celog_syndrome; |
| unsigned long page; |
| |
| // Read the error location |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn +1, 0xA0, 4,&celog_add); |
| // Read the syndrome |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn +1, 0xC4, 2, &celog_syndrome); |
| |
| // Parse the error location |
| page = (celog_add & 0x7FFFFFFC) >> 2; |
| |
| // Report the error |
| print_ecc_err(page, 0, 1, celog_syndrome, 0); |
| |
| // Clear Bit |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x80, 2, ferr& 0x0101); |
| } |
| |
| if (ferr & 0x4646) { |
| // Found out about the first uncorrectable error |
| unsigned long uccelog_add; |
| unsigned long page; |
| |
| // Read the error location |
| pci_conf_read(ctrl.bus, ctrl.dev, ctrl.fn +1, 0xA4, 4, &uccelog_add); |
| |
| // Parse the error location |
| page = (uccelog_add & 0x7FFFFFFC) >> 2; |
| |
| // Report the error |
| print_ecc_err(page, 0, 0, 0, 0); |
| |
| // Clear Bit |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x80, 2, ferr & 0x4646); |
| } |
| |
| // Check if DRAM_NERR contains data |
| if (nerr & 0x4747) { |
| pci_conf_write(ctrl.bus, ctrl.dev, ctrl.fn +1, 0x82, 2, nerr & 0x4747); |
| } |
| } |
| */ |
| |
| |
| |
| /* ----------------- Here's the code for FSB detection ----------------- */ |
| /* --------------------------------------------------------------------- */ |
| |
| static float athloncoef[] = {11, 11.5, 12.0, 12.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0, 10.5}; |
| static float athloncoef2[] = {12, 19.0, 12.0, 20.0, 13.0, 13.5, 14.0, 21.0, 15.0, 22, 16.0, 16.5, 17.0, 18.0, 23.0, 24.0}; |
| static float p4model1ratios[] = {16, 17, 18, 19, 20, 21, 22, 23, 8, 9, 10, 11, 12, 13, 14, 15}; |
| |
| static float getP4PMmultiplier(void) |
| { |
| //unsigned int msr_lo, msr_hi; |
| int msr_lo, msr_hi; |
| float coef; |
| |
| |
| /* Find multiplier (by MSR) */ |
| if (cpu_id.vers.bits.family == 6) |
| { |
| if(cpu_id.fid.bits.eist & 1) |
| { |
| rdmsr(0x198, msr_lo, msr_hi); |
| coef = ((msr_lo) >> 8) & 0x1F; |
| if ((msr_lo >> 14) & 0x1) { coef += 0.5f; } |
| // Atom Fix |
| if(coef == 6) |
| { |
| coef = ((msr_hi) >> 8) & 0x1F; |
| if ((msr_hi >> 14) & 0x1) { coef += 0.5f; } |
| } |
| } else { |
| rdmsr(0x2A, msr_lo, msr_hi); |
| coef = (msr_lo >> 22) & 0x1F; |
| } |
| } |
| else |
| { |
| if (cpu_id.vers.bits.model < 2) |
| { |
| rdmsr(0x2A, msr_lo, msr_hi); |
| coef = (msr_lo >> 8) & 0xF; |
| coef = p4model1ratios[(int)coef]; |
| } |
| else |
| { |
| rdmsr(0x2C, msr_lo, msr_hi); |
| coef = (msr_lo >> 24) & 0x1F; |
| } |
| } |
| |
| return coef; |
| } |
| |
| static float getNHMmultiplier(void) |
| { |
| unsigned int msr_lo, msr_hi; |
| float coef; |
| |
| /* Find multiplier (by MSR) */ |
| /* First, check if Flexible Ratio is Enabled */ |
| rdmsr(0x194, msr_lo, msr_hi); |
| if((msr_lo >> 16) & 1){ |
| coef = (msr_lo >> 8) & 0xFF; |
| } else { |
| rdmsr(0xCE, msr_lo, msr_hi); |
| coef = (msr_lo >> 8) & 0xFF; |
| } |
| |
| return coef; |
| } |
| static float getSNBmultiplier(void) |
| { |
| unsigned int msr_lo, msr_hi; |
| float coef; |
| |
| rdmsr(0xCE, msr_lo, msr_hi); |
| coef = (msr_lo >> 8) & 0xFF; |
| |
| return coef; |
| } |
| |
| static void poll_fsb_ct(void) |
| { |
| unsigned long mcr, mdr; |
| double dramratio, dramclock, fsb; |
| float coef = getP4PMmultiplier(); |
| |
| /* Build the MCR Message*/ |
| mcr = (0x10 << 24); // 10h = Read - 11h = Write |
| mcr += (0x01 << 16); // DRAM Registers located on port 01h |
| mcr += (0x01 << 8); // DRP = 00h, DTR0 = 01h, DTR1 = 02h, DTR2 = 03h |
| mcr &= 0xFFFFFFF0; // bit 03:00 RSVD |
| |
| /* Send Message to GMCH */ |
| pci_conf_write(0, 0, 0, 0xD0, 4, mcr); |
| |
| /* Read Answer from Sideband bus */ |
| pci_conf_read(0, 0, 0, 0xD4, 4, &mdr); |
| |
| /* Get RAM ratio */ |
| switch (mdr & 0x3) { |
| default: |
| case 0: dramratio = 3.0f; break; |
| case 1: dramratio = 4.0f; break; |
| case 2: dramratio = 5.0f; break; |
| case 3: dramratio = 6.0f; break; |
| } |
| |
| // Compute FSB & RAM Frequency |
| fsb = ((extclock / 1000) / coef); |
| dramclock = fsb * dramratio; |
| |
| // Print'em all. Whoa ! |
| print_cpu_line(dramclock, fsb, 3); |
| |
| } |
| |
| static void poll_fsb_amd64(void) { |
| |
| unsigned int mcgsrl; |
| unsigned int mcgsth; |
| unsigned long fid, temp2; |
| unsigned long dramchr; |
| float clockratio; |
| double dramclock; |
| unsigned int dummy[4]; |
| int ram_type; |
| |
| float coef = 10; |
| |
| cpuid(0x80000007, &dummy[0], &dummy[1], &dummy[2], &dummy[3]); |
| |
| /* First, got the FID by MSR */ |
| /* First look if Cool 'n Quiet is supported to choose the best msr */ |
| if (((dummy[3] >> 1) & 1) == 1) { |
| rdmsr(0xc0010042, mcgsrl, mcgsth); |
| fid = (mcgsrl & 0x3F); |
| } else { |
| rdmsr(0xc0010015, mcgsrl, mcgsth); |
| fid = ((mcgsrl >> 24)& 0x3F); |
| } |
| |
| /* Extreme simplification. */ |
| coef = ( fid / 2 ) + 4.0; |
| |
| /* Support for .5 coef */ |
| if (fid & 1) { coef = coef + 0.5; } |
| |
| /* Next, we need the clock ratio */ |
| if (cpu_id.vers.bits.extendedModel >= 4) { |
| /* K8 0FH */ |
| pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); |
| temp2 = (dramchr & 0x7); |
| clockratio = coef; |
| ram_type = 2; |
| |
| switch (temp2) { |
| case 0x0: |
| clockratio = (int)(coef); |
| break; |
| case 0x1: |
| clockratio = (int)(coef * 3.0f/4.0f); |
| break; |
| case 0x2: |
| clockratio = (int)(coef * 3.0f/5.0f); |
| break; |
| case 0x3: |
| clockratio = (int)(coef * 3.0f/6.0f); |
| break; |
| } |
| |
| } else { |
| /* OLD K8 */ |
| pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); |
| temp2 = (dramchr >> 20) & 0x7; |
| ram_type = 1; |
| clockratio = coef; |
| |
| switch (temp2) { |
| case 0x0: |
| clockratio = (int)(coef * 2.0f); |
| break; |
| case 0x2: |
| clockratio = (int)((coef * 3.0f/2.0f) + 0.81f); |
| break; |
| case 0x4: |
| clockratio = (int)((coef * 4.0f/3.0f) + 0.81f); |
| break; |
| case 0x5: |
| clockratio = (int)((coef * 6.0f/5.0f) + 0.81f); |
| break; |
| case 0x6: |
| clockratio = (int)((coef * 10.0f/9.0f) + 0.81f); |
| break; |
| case 0x7: |
| clockratio = (int)(coef + 0.81f); |
| break; |
| } |
| } |
| |
| /* Compute the final DRAM Clock */ |
| dramclock = (extclock / 1000) / clockratio; |
| |
| /* ...and print */ |
| print_cpu_line(dramclock, (extclock / 1000 / coef), ram_type); |
| |
| } |
| |
| static void poll_fsb_k10(void) { |
| |
| unsigned int mcgsrl; |
| unsigned int mcgsth; |
| unsigned long temp2; |
| unsigned long dramchr; |
| unsigned long mainPllId; |
| double dramclock; |
| ulong offset = 0; |
| int ram_type = 2; |
| |
| /* First, we need the clock ratio */ |
| pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); |
| temp2 = (dramchr & 0x7); |
| |
| switch (temp2) { |
| case 0x7: temp2++; |
| case 0x6: temp2++; |
| case 0x5: temp2++; |
| case 0x4: temp2++; |
| default: temp2 += 3; |
| } |
| |
| /* Compute the final DRAM Clock */ |
| if (((cpu_id.vers.bits.extendedModel >> 4) & 0xFF) == 1) { |
| dramclock = ((temp2 * 200) / 3.0) + 0.25; |
| } else { |
| unsigned long target; |
| unsigned long dx; |
| unsigned divisor; |
| |
| target = temp2 * 400; |
| |
| /* Get the FID by MSR */ |
| rdmsr(0xc0010071, mcgsrl, mcgsth); |
| |
| pci_conf_read(0, 24, 3, 0xD4, 4, &mainPllId); |
| |
| if ( mainPllId & 0x40 ) |
| mainPllId &= 0x3F; |
| else |
| mainPllId = 8; /* FID for 1600 */ |
| |
| mcgsth = (mcgsth >> 17) & 0x3F; |
| if ( mcgsth ) { |
| if ( mainPllId > mcgsth ) |
| mainPllId = mcgsth; |
| } |
| |
| dx = (mainPllId + 8) * 1200; |
| for ( divisor = 3; divisor < 100; divisor++ ) |
| if ( (dx / divisor) <= target ) |
| break; |
| |
| |
| pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); |
| |
| // If Channel A not enabled, switch to channel B |
| if(((dramchr>>14) & 0x1)) |
| { |
| offset = 0x100; |
| pci_conf_read(0, 24, 2, 0x94+offset, 4, &dramchr); |
| } |
| |
| //DDR2 or DDR3 |
| if ((dramchr >> 8)&1) { |
| ram_type = 3; |
| } else { |
| ram_type = 2;; |
| } |
| |
| dramclock = ((dx / divisor) / 6.0) + 0.25; |
| } |
| |
| /* ...and print */ |
| print_cpu_line(dramclock, 0, ram_type); |
| |
| } |
| |
| static void poll_fsb_k12(void) { |
| |
| unsigned long temp2; |
| unsigned long dramchr; |
| double dramratio, dramclock, fsb, did; |
| unsigned int mcgsrl,mcgsth, fid, did_raw; |
| |
| // Get current FID & DID |
| rdmsr(0xc0010071, mcgsrl, mcgsth); |
| did_raw = mcgsrl & 0xF; |
| fid = (mcgsrl >> 4) & 0xF; |
| |
| switch(did_raw) |
| { |
| default: |
| case 0x0: |
| did = 1.0f; |
| break; |
| case 0x1: |
| did = 1.5f; |
| break; |
| case 0x2: |
| did = 2.0f; |
| break; |
| case 0x3: |
| did = 3.0f; |
| break; |
| case 0x4: |
| did = 4.0f; |
| break; |
| case 0x5: |
| did = 6.0f; |
| break; |
| case 0x6: |
| did = 8.0f; |
| break; |
| case 0x7: |
| did = 12.0f; |
| break; |
| case 0x8: |
| did = 16.0f; |
| break; |
| } |
| |
| fsb = ((extclock / 1000.0f) / ((fid + 16.0f) / did)); |
| |
| /* Finaly, we need the clock ratio */ |
| pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); |
| |
| if(((dramchr >> 14) & 0x1) == 1) |
| { |
| pci_conf_read(0, 24, 2, 0x194, 4, &dramchr); |
| } |
| |
| temp2 = (dramchr & 0x1F); |
| |
| switch (temp2) { |
| default: |
| case 0x06: |
| dramratio = 4.0f; |
| break; |
| case 0x0A: |
| dramratio = 16.0f / 3.0f; |
| break; |
| case 0x0E: |
| dramratio = 20.0f / 3.0f; |
| break; |
| case 0x12: |
| dramratio = 8.0f; |
| break; |
| case 0x16: |
| dramratio = 28.0f / 3.0f; |
| break; |
| } |
| |
| dramclock = fsb * dramratio; |
| |
| /* print */ |
| print_cpu_line(dramclock, fsb, 3); |
| |
| } |
| |
| static void poll_fsb_k16(void) |
| { |
| |
| unsigned long dramchr; |
| double dramratio, dramclock, fsb; |
| |
| // FIXME: Unable to find a real way to detect multiplier. |
| fsb = 100.0f; |
| |
| /* Clock ratio */ |
| pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); |
| |
| switch (dramchr & 0x1F) { |
| default: |
| case 0x04: /* 333 */ |
| dramratio = 10.0f / 3.0f; |
| break; |
| case 0x06: /* 400 */ |
| dramratio = 4.0f; |
| break; |
| case 0x0A: /* 533 */ |
| dramratio = 16.0f / 3.0f; |
| break; |
| case 0x0E: /* 667 */ |
| dramratio = 20.0f / 3.0f; |
| break; |
| case 0x12: /* 800 */ |
| dramratio = 8.0f; |
| break; |
| case 0x16: /* 933 */ |
| dramratio = 28.0f / 3.0f; |
| break; |
| case 0x19: /* 1050 */ |
| dramratio = 21.0f / 2.0f; |
| break; |
| case 0x1A: /* 1066 */ |
| dramratio = 32.0f / 3.0f; |
| break; |
| } |
| |
| dramclock = fsb * dramratio; |
| |
| /* print */ |
| print_cpu_line(dramclock, fsb, 3); |
| |
| } |
| |
| static void poll_fsb_k15(void) { |
| |
| unsigned long temp2; |
| unsigned long dramchr; |
| double dramratio, dramclock, fsb; |
| unsigned int mcgsrl,mcgsth, fid, did; |
| |
| // Get current FID & DID |
| rdmsr(0xc0010071, mcgsrl, mcgsth); |
| fid = mcgsrl & 0x3F; |
| did = (mcgsrl >> 6) & 0x7; |
| |
| fsb = ((extclock / 1000.0f) / ((fid + 16.0f) / (2^did)) / 2); |
| |
| /* Finaly, we need the clock ratio */ |
| pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); |
| |
| if(((dramchr >> 14) & 0x1) == 1) |
| { |
| pci_conf_read(0, 24, 2, 0x194, 4, &dramchr); |
| } |
| |
| temp2 = (dramchr & 0x1F); |
| |
| switch (temp2) { |
| case 0x04: |
| dramratio = 10.0f / 3.0f; |
| break; |
| default: |
| case 0x06: |
| dramratio = 4.0f; |
| break; |
| case 0x0A: |
| dramratio = 16.0f / 3.0f; |
| break; |
| case 0x0E: |
| dramratio = 20.0f / 3.0f; |
| break; |
| case 0x12: |
| dramratio = 8.0f; |
| break; |
| case 0x16: |
| dramratio = 28.0f / 3.0f; |
| break; |
| case 0x1A: |
| dramratio = 32.0f / 3.0f; |
| break; |
| case 0x1F: |
| dramratio = 36.0f / 3.0f; |
| break; |
| } |
| |
| dramclock = fsb * dramratio; |
| |
| /* print */ |
| print_cpu_line(dramclock, fsb, 3); |
| |
| } |
| |
| static void poll_fsb_k14(void) |
| { |
| |
| unsigned long dramchr; |
| double dramratio, dramclock, fsb; |
| |
| // FIXME: Unable to find a real way to detect multiplier. |
| fsb = 100.0f; |
| |
| /* Clock ratio */ |
| pci_conf_read(0, 24, 2, 0x94, 4, &dramchr); |
| |
| switch (dramchr & 0x1F) { |
| default: |
| case 0x06: |
| dramratio = 4.0f; |
| break; |
| case 0x0A: |
| dramratio = 16.0f / 3.0f; |
| break; |
| case 0x0E: |
| dramratio = 20.0f / 3.0f; |
| break; |
| case 0x12: |
| dramratio = 8.0f; |
| break; |
| } |
| |
| dramclock = fsb * dramratio; |
| |
| /* print */ |
| print_cpu_line(dramclock, fsb, 3); |
| |
| } |
| |
| |
| static void poll_fsb_i925(void) { |
| |
| double dramclock, dramratio, fsb; |
| unsigned long mchcfg, mchcfg2, dev0, drc, idetect; |
| float coef = getP4PMmultiplier(); |
| long *ptr; |
| int ddr_type; |
| |
| pci_conf_read( 0, 0, 0, 0x02, 2, &idetect); |
| |
| /* Find dramratio */ |
| pci_conf_read( 0, 0, 0, 0x44, 4, &dev0); |
| dev0 = dev0 & 0xFFFFC000; |
| ptr=(long*)(dev0+0xC00); |
| mchcfg = *ptr & 0xFFFF; |
| ptr=(long*)(dev0+0x120); |
| drc = *ptr & 0xFFFF; |
| dramratio = 1; |
| |
| mchcfg2 = (mchcfg >> 4)&3; |
| |
| if ((drc&3) != 2) { |
| // We are in DDR1 Mode |
| if (mchcfg2 == 1) { dramratio = 0.8; } else { dramratio = 1; } |
| ddr_type = 1; |
| } else { |
| // We are in DDR2 Mode |
| ddr_type = 2; |
| if ((mchcfg >> 2)&1) { |
| // We are in FSB1066 Mode |
| if (mchcfg2 == 2) { dramratio = 0.75; } else { dramratio = 1; } |
| } else { |
| switch (mchcfg2) { |
| case 1: |
| dramratio = 0.66667; |
| break; |
| case 2: |
| if (idetect != 0x2590) { dramratio = 1; } else { dramratio = 1.5; } |
| break; |
| case 3: |
| // Checking for FSB533 Mode & Alviso |
| if ((mchcfg & 1) == 0) { dramratio = 1.33334; } |
| else if (idetect == 0x2590) { dramratio = 2; } |
| else { dramratio = 1.5; } |
| } |
| } |
| } |
| // Compute RAM Frequency |
| fsb = ((extclock / 1000) / coef); |
| dramclock = fsb * dramratio; |
| |
| |
| print_cpu_line(dramclock, fsb, ddr_type); |
| |
| } |
| |
| static void poll_fsb_i945(void) { |
| |
| double dramclock, dramratio, fsb; |
| unsigned long mchcfg, dev0; |
| float coef = getP4PMmultiplier(); |
| long *ptr; |
| |
| /* Find dramratio */ |
| pci_conf_read( 0, 0, 0, 0x44, 4, &dev0); |
| dev0 &= 0xFFFFC000; |
| ptr=(long*)(dev0+0xC00); |
| mchcfg = *ptr & 0xFFFF; |
| dramratio = 1; |
| |
| switch ((mchcfg >> 4)&7) { |
| case 1: dramratio = 1.0; break; |
| case 2: dramratio = 1.33334; break; |
| case 3: dramratio = 1.66667; break; |
| case 4: dramratio = 2.0; break; |
| } |
| |
| // Compute RAM Frequency |
| fsb = ((extclock / 1000) / coef); |
| |
| dramclock = fsb * dramratio; |
| |
| // Print |
| print_cpu_line(dramclock, fsb, 2); |
| |
| } |
| |
| static void poll_fsb_i945gme(void) { |
| |
| double dramclock, dramratio, fsb; |
| unsigned long mchcfg, dev0, fsb_mch; |
| float coef = getP4PMmultiplier(); |
| long *ptr; |
| |
| /* Find dramratio */ |
| pci_conf_read( 0, 0, 0, 0x44, 4, &dev0); |
| dev0 &= 0xFFFFC000; |
| ptr=(long*)(dev0+0xC00); |
| mchcfg = *ptr & 0xFFFF; |
| dramratio = 1; |
| |
| switch (mchcfg & 7) { |
| case 0: fsb_mch = 400; break; |
| default: |
| case 1: fsb_mch = 533; break; |
| case 2: fsb_mch = 667; break; |
| } |
| |
| |
| switch (fsb_mch) { |
| case 400: |
| switch ((mchcfg >> 4)&7) { |
| case 2: dramratio = 1.0f; break; |
| case 3: dramratio = 4.0f/3.0f; break; |
| case 4: dramratio = 5.0f/3.0f; break; |
| } |
| break; |
| |
| default: |
| case 533: |
| switch ((mchcfg >> 4)&7) { |
| case 2: dramratio = 3.0f/4.0f; break; |
| case 3: dramratio = 1.0f; break; |
| case 4: dramratio = 5.0f/4.0f; break; |
| } |
| break; |
| |
| case 667: |
| switch ((mchcfg >> 4)&7) { |
| case 2: dramratio = 3.0f/5.0f; break; |
| case 3: dramratio = 4.0f/5.0f; break; |
| case 4: dramratio = 1.0f; break; |
| } |
| break; |
| } |
| |
| // Compute RAM Frequency |
| fsb = ((extclock / 1000) / coef); |
| dramclock = fsb * dramratio * 2; |
| |
| print_cpu_line(dramclock, fsb, 2); |
| |
| } |
| |
| |
| static void poll_fsb_i975(void) { |
| |
| double dramclock, dramratio, fsb; |
| unsigned long mchcfg, dev0, fsb_mch; |
| float coef = getP4PMmultiplier(); |
| long *ptr; |
| |
| /* Find dramratio */ |
| pci_conf_read( 0, 0, 0, 0x44, 4, &dev0); |
| dev0 &= 0xFFFFC000; |
| ptr=(long*)(dev0+0xC00); |
| mchcfg = *ptr & 0xFFFF; |
| dramratio = 1; |
| |
| switch (mchcfg & 7) { |
| case 1: fsb_mch = 533; break; |
| case 2: fsb_mch = 800; break; |
| case 3: fsb_mch = 667; break; |
| default: fsb_mch = 1066; break; |
| } |
| |
| |
| switch (fsb_mch) { |
| case 533: |
| switch ((mchcfg >> 4)&7) { |
| case 0: dramratio = 1.25; break; |
| case 1: dramratio = 1.5; break; |
| case 2: dramratio = 2.0; break; |
| } |
| break; |
| |
| default: |
| case 800: |
| switch ((mchcfg >> 4)&7) { |
| case 1: dramratio = 1.0; break; |
| case 2: dramratio = 1.33334; break; |
| case 3: dramratio = 1.66667; break; |
| case 4: dramratio = 2.0; break; |
| } |
| break; |
| |
| case 1066: |
| switch ((mchcfg >> 4)&7) { |
| case 1: dramratio = 0.75; break; |
| case 2: dramratio = 1.0; break; |
| case 3: dramratio = 1.25; break; |
| case 4: dramratio = 1.5; break; |
| } |
| break; |
| } |
| |
| // Compute RAM Frequency |
| fsb = ((extclock / 1000) / coef); |
| dramclock = fsb * dramratio; |
| |
| print_cpu_line(dramclock, fsb, 2); |
| |
| } |
| |
| static void poll_fsb_i965(void) { |
| |
| double dramclock, dramratio, fsb; |
| unsigned long mchcfg, dev0, fsb_mch; |
| float coef = getP4PMmultiplier(); |
| long *ptr; |
| |
| /* Find dramratio */ |
| pci_conf_read( 0, 0, 0, 0x48, 4, &dev0); |
| dev0 &= 0xFFFFC000; |
| ptr=(long*)(dev0+0xC00); |
| mchcfg = *ptr & 0xFFFF; |
| dramratio = 1; |
| |
| switch (mchcfg & 7) { |
| case 0: fsb_mch = 1066; break; |
| case 1: fsb_mch = 533; break; |
| default: case 2: fsb_mch = 800; break; |
| case 3: fsb_mch = 667; break; |
| case 4: fsb_mch = 1333; break; |
| case 6: fsb_mch = 1600; break; |
| } |
| |
| |
| switch (fsb_mch) { |
| case 533: |
| switch ((mchcfg >> 4)&7) { |
| case 1: dramratio = 2.0; break; |
| case 2: dramratio = 2.5; break; |
| case 3: dramratio = 3.0; break; |
| } |
| break; |
| |
| default: |
| case 800: |
| switch ((mchcfg >> 4)&7) { |
| case 0: dramratio = 1.0; break; |
| case 1: dramratio = 5.0f/4.0f; break; |
| case 2: dramratio = 5.0f/3.0f; break; |
| case 3: dramratio = 2.0f; break; |
| case 4: dramratio = 8.0f/3.0f; break; |
| case 5: dramratio = 10.0f/3.0f; break; |
| } |
| break; |
| |
| case 1066: |
| switch ((mchcfg >> 4)&7) { |
| case 1: dramratio = 1.0f; break; |
| case 2: dramratio = 5.0f/4.0f; break; |
| case 3: dramratio = 3.0f/2.0f; break; |
| case 4: dramratio = 2.0f; break; |
| case 5: dramratio = 5.0f/2.0f; break; |
| } |
| break; |
| |
| case 1333: |
| switch ((mchcfg >> 4)&7) { |
| case 2: dramratio = 1.0f; break; |
| case 3: dramratio = 6.0f/5.0f; break; |
| case 4: dramratio = 8.0f/5.0f; break; |
| case 5: dramratio = 2.0f; break; |
| } |
| break; |
| |
| case 1600: |
| switch ((mchcfg >> 4)&7) { |
| case 3: dramratio = 1.0f; break; |
| case 4: dramratio = 4.0f/3.0f; break; |
| case 5: dramratio = 3.0f/2.0f; break; |
| case 6: dramratio = 2.0f; break; |
| } |
| break; |
| |
| } |
| |
| // Compute RAM Frequency |
| fsb = ((extclock / 1000) / coef); |
| dramclock = fsb * dramratio; |
| |
| // Print DRAM Freq |
| print_cpu_line(dramclock, fsb, 2); |
| |
| } |
| |
| static void poll_fsb_p35(void) { |
| |
| double dramclock, dramratio, fsb; |
| unsigned long mchcfg, dev0, fsb_mch, Device_ID, Memory_Check, c0ckectrl, offset; |
| float coef = getP4PMmultiplier(); |
| long *ptr; |
| int ram_type; |
| |
| pci_conf_read( 0, 0, 0, 0x02, 2, &Device_ID); |
| Device_ID &= 0xFFFF; |
| |
| /* Find dramratio */ |
| pci_conf_read( 0, 0, 0, 0x48, 4, &dev0); |
| dev0 &= 0xFFFFC000; |
| |
| ptr = (long*)(dev0+0x260); |
| c0ckectrl = *ptr & 0xFFFFFFFF; |
| |
| |
| // If DIMM 0 not populated, check DIMM 1 |
| ((c0ckectrl) >> 20 & 0xF)?(offset = 0):(offset = 0x400); |
| |
| ptr=(long*)(dev0+0xC00); |
| mchcfg = *ptr & 0xFFFF; |
| dramratio = 1; |
| |
| switch (mchcfg & 7) { |
| case 0: fsb_mch = 1066; break; |
| case 1: fsb_mch = 533; break; |
| default: case 2: fsb_mch = 800; break; |
| case 3: fsb_mch = 667; break; |
| case 4: fsb_mch = 1333; break; |
| case 6: fsb_mch = 1600; break; |
| } |
| |
| |
| switch (fsb_mch) { |
| case 533: |
| switch ((mchcfg >> 4)&7) { |
| case 1: dramratio = 2.0; break; |
| case 2: dramratio = 2.5; break; |
| case 3: dramratio = 3.0; break; |
| } |
| break; |
| |
| default: |
| case 800: |
| switch ((mchcfg >> 4)&7) { |
| case 0: dramratio = 1.0; break; |
| case 1: dramratio = 5.0f/4.0f; break; |
| case 2: dramratio = 5.0f/3.0f; break; |
| case 3: dramratio = 2.0; break; |
| case 4: dramratio = 8.0f/3.0f; break; |
| case 5: dramratio = 10.0f/3.0f; break; |
| } |
| break; |
| |
| case 1066: |
| switch ((mchcfg >> 4)&7) { |
| case 1: dramratio = 1.0f; break; |
| case 2: dramratio = 5.0f/4.0f; break; |
| case 3: dramratio = 3.0f/2.0f; break; |
| case 4: dramratio = 2.0f; break; |
| case 5: dramratio = 5.0f/2.0f; break; |
| } |
| break; |
| |
| case 1333: |
| switch ((mchcfg >> 4)&7) { |
| case 2: dramratio = 1.0f; break; |
| case 3: dramratio = 6.0f/5.0f; break; |
| case 4: dramratio = 8.0f/5.0f; break; |
| case 5: dramratio = 2.0f; break; |
| } |
| break; |
| |
| case 1600: |
| switch ((mchcfg >> 4)&7) { |
| case 3: dramratio = 1.0f; break; |
| case 4: dramratio = 4.0f/3.0f; break; |
| case 5: dramratio = 3.0f/2.0f; break; |
| case 6: dramratio = 2.0f; break; |
| } |
| break; |
| |
| } |
| |
| // On P45, check 1A8 |
| if(Device_ID > 0x2E00 && imc_type != 8) { |
| ptr = (long*)(dev0+offset+0x1A8); |
| Memory_Check = *ptr & 0xFFFFFFFF; |
| Memory_Check >>= 2; |
| Memory_Check &= 1; |
| Memory_Check = !Memory_Check; |
| } else if (imc_type == 8) { |
| ptr = (long*)(dev0+offset+0x224); |
| Memory_Check = *ptr & 0xFFFFFFFF; |
| Memory_Check &= 1; |
| Memory_Check = !Memory_Check; |
| } else { |
| ptr = (long*)(dev0+offset+0x1E8); |
| Memory_Check = *ptr & 0xFFFFFFFF; |
| } |
| |
| //Determine DDR-II or DDR-III |
| if (Memory_Check & 1) { |
| ram_type = 2; |
| } else { |
| ram_type = 3; |
| } |
| |
| // Compute RAM Frequency |
| fsb = ((extclock / 1000) / coef); |
| dramclock = fsb * dramratio; |
| |
| // Print DRAM Freq |
| print_cpu_line(dramclock, fsb, ram_type); |
| |
| } |
| |
| static void poll_fsb_im965(void) { |
| |
| double dramclock, dramratio, fsb; |
| unsigned long mchcfg, dev0, fsb_mch; |
| float coef = getP4PMmultiplier(); |
| long *ptr; |
| |
| /* Find dramratio */ |
| pci_conf_read( 0, 0, 0, 0x48, 4, &dev0); |
| dev0 &= 0xFFFFC000; |
| ptr=(long*)(dev0+0xC00); |
| mchcfg = *ptr & 0xFFFF; |
| dramratio = 1; |
| |
| switch (mchcfg & 7) { |
| case 1: fsb_mch = 533; break; |
| default: case 2: fsb_mch = 800; break; |
| case 3: fsb_mch = 667; break; |
| case 6: fsb_mch = 1066; break; |
| } |
| |
| |
| switch (fsb_mch) { |
| case 533: |
| switch ((mchcfg >> 4)&7) { |
| case 1: dramratio = 5.0f/4.0f; break; |
| case 2: dramratio = 3.0f/2.0f; break; |
| case 3: dramratio = 2.0f; break; |
| } |
| break; |
| |
| case 667: |
| switch ((mchcfg >> 4)&7) { |
| case 1: dramratio = 1.0f; break; |
| case 2: dramratio = 6.0f/5.0f; break; |
| case 3: dramratio = 8.0f/5.0f; break; |
| case 4: dramratio = 2.0f; break; |
| case 5: dramratio = 12.0f/5.0f; break; |
| } |
| break; |
| default: |
| case 800: |
| switch ((mchcfg >> 4)&7) { |
| case 1: dramratio = 5.0f/6.0f; break; |
| case 2: dramratio = 1.0f; break; |
| case 3: dramratio = 4.0f/3.0f; break; |
| case 4: dramratio = 5.0f/3.0f; break; |
| case 5: dramratio = 2.0f; break; |
| } |
| break; |
| case 1066: |
| switch ((mchcfg >> 4)&7) { |
| case 5: dramratio = 3.0f/2.0f; break; |
| case 6: dramratio = 2.0f; break; |
| } |
| break; |
| } |
| |
| // Compute RAM Frequency |
| fsb = ((extclock / 1000) / coef); |
| dramclock = fsb * dramratio; |
| |
| // Print DRAM Freq |
| print_cpu_line(dramclock, fsb, 2); |
| |
| } |
| |
| |
| static void poll_fsb_5400(void) { |
| |
| double dramclock, dramratio, fsb; |
| unsigned long ambase_low, ambase_high, ddrfrq; |
| float coef = getP4PMmultiplier(); |
| |
| /* Find dramratio */ |
| pci_conf_read( 0, 16, 0, 0x48, 4, &ambase_low); |
| ambase_low &= 0xFFFE0000; |
| pci_conf_read( 0, 16, 0, 0x4C, 4, &ambase_high); |
| ambase_high &= 0xFF; |
| pci_conf_read( 0, 16, 1, 0x56, 1, &ddrfrq); |
| ddrfrq &= 7; |
| dramratio = 1; |
| |
| switch (ddrfrq) { |
| case 0: |
| case 1: |
| case 4: |
| dramratio = 1.0; |
| break; |
| case 2: |
| dramratio = 5.0f/4.0f; |
| break; |
| case 3: |
| case 7: |
| dramratio = 4.0f/5.0f; |
| break; |
| } |
| |
| |
| // Compute RAM Frequency |
| fsb = ((extclock / 1000) / coef); |
| dramclock = fsb * dramratio; |
| |
| // Print DRAM Freq |
| print_cpu_line(dramclock, fsb, 2); |
| |
| } |
| |
| |
| static void poll_fsb_nf4ie(void) { |
| |
| double dramclock, dramratio, fsb; |
| float mratio, nratio; |
| unsigned long reg74, reg60; |
| float coef = getP4PMmultiplier(); |
| |
| /* Find dramratio */ |
| pci_conf_read(0, 0, 2, 0x74, 2, ®74); |
| pci_conf_read(0, 0, 2, 0x60, 4, ®60); |
| mratio = reg74 & 0xF; |
| nratio = (reg74 >> 4) & 0xF; |
| |
| // If M or N = 0, then M or N = 16 |
| if (mratio == 0) { mratio = 16; } |
| if (nratio == 0) { nratio = 16; } |
| |
| // Check if synchro or pseudo-synchro mode |
| if((reg60 >> 22) & 1) { |
| dramratio = 1; |
| } else { |
| dramratio = nratio / mratio; |
| } |
| |
| /* Compute RAM Frequency */ |
| fsb = ((extclock /1000) / coef); |
| dramclock = fsb * dramratio; |
| |
| // Print DRAM Freq |
| print_cpu_line(dramclock, fsb, 2); |
| |
| } |
| |
| static void poll_fsb_i875(void) { |
| |
| double dramclock, dramratio, fsb; |
| unsigned long mchcfg, smfs; |
| float coef = getP4PMmultiplier(); |
| |
| /* Find dramratio */ |
| pci_conf_read(0, 0, 0, 0xC6, 2, &mchcfg); |
| smfs = (mchcfg >> 10)&3; |
| dramratio = 1; |
| |
| if ((mchcfg&3) == 3) { dramratio = 1; } |
| if ((mchcfg&3) == 2) { |
| if (smfs == 2) { dramratio = 1; } |
| if (smfs == 1) { dramratio = 1.25; } |
| if (smfs == 0) { dramratio = 1.5; } |
| } |
| if ((mchcfg&3) == 1) { |
| if (smfs == 2) { dramratio = 0.6666666666; } |
| if (smfs == 1) { dramratio = 0.8; } |
| if (smfs == 0) { dramratio = 1; } |
| } |
| if ((mchcfg&3) == 0) { dramratio = 0.75; } |
| |
| |
| /* Compute RAM Frequency */ |
| dramclock = ((extclock /1000) / coef) / dramratio; |
| fsb = ((extclock /1000) / coef); |
| |
| /* Print DRAM Freq */ |
| print_cpu_line(dramclock, fsb, 2); |
| } |
| |
| static void poll_fsb_p4(void) { |
| |
| ulong fsb, idetect; |
| float coef = getP4PMmultiplier(); |
| char *name; |
| int col,temp; |
| |
| fsb = ((extclock /1000) / coef); |
| |
| /* For synchro only chipsets */ |
| pci_conf_read( 0, 0, 0, 0x02, 2, &idetect); |
| if (idetect == 0x2540 || idetect == 0x254C) |
| { |
| print_cpu_line(fsb, fsb, 1); |
| } else { |
| /* Print the controller name */ |
| col = COL_SPEC; |
| cprint(LINE_CPU, col, "Chipset: "); |
| col += 9; |
| /* Print the controller name */ |
| name = controllers[ctrl.index].name; |
| cprint(LINE_CPU, col, name); |
| /* Now figure out how much I just printed */ |
| temp = 20; |
| while(name[temp - 20] != '\0') { |
| col++; |
| temp++; |
| } |
| |
| if(temp < 36){ |
| cprint(LINE_CPU, col +1, "- FSB : "); |
| col += 9; |
| dprint(LINE_CPU, col, fsb, 3,0); |
| col += 3; |
| } |
| |
| } |
| } |
| |
| static void poll_fsb_i855(void) { |
| |
| |
| double dramclock, dramratio, fsb ; |
| unsigned int msr_lo, msr_hi; |
| ulong mchcfg, idetect; |
| int coef; |
| |
| pci_conf_read( 0, 0, 0, 0x02, 2, &idetect); |
| |
| /* Find multiplier (by MSR) */ |
| |
| /* Is it a Pentium M ? */ |
| if (cpu_id.vers.bits.family == 6) { |
| rdmsr(0x2A, msr_lo, msr_hi); |
| coef = (msr_lo >> 22) & 0x1F; |
| } else { |
| rdmsr(0x2C, msr_lo, msr_hi); |
| coef = (msr_lo >> 24) & 0x1F; |
| } |
| |
| fsb = ((extclock /1000) / coef); |
| |
| |
| /* Compute DRAM Clock */ |
| |
| dramratio = 1; |
| if (idetect == 0x3580) { |
| pci_conf_read( 0, 0, 3, 0xC0, 2, &mchcfg); |
| mchcfg = mchcfg & 0x7; |
| |
| if (mchcfg == 1 || mchcfg == 2 || mchcfg == 4 || mchcfg == 5) { dramratio = 1; } |
| if (mchcfg == 0 || mchcfg == 3) { dramratio = 1.333333333; } |
| if (mchcfg == 6) { dramratio = 1.25; } |
| if (mchcfg == 7) { dramratio = 1.666666667; } |
| |
| } else { |
| pci_conf_read( 0, 0, 0, 0xC6, 2, &mchcfg); |
| if (((mchcfg >> 10)&3) == 0) { dramratio = 1; } |
| else if (((mchcfg >> 10)&3) == 1) { dramratio = 1.666667; } |
| else { dramratio = 1.333333333; } |
| } |
| |
| |
| dramclock = fsb * dramratio; |
| |
| /* ...and print */ |
| print_cpu_line(dramclock, fsb, 1); |
| |
| } |
| |
| static void poll_fsb_amd32(void) { |
| |
| unsigned int mcgsrl; |
| unsigned int mcgsth; |
| unsigned long temp; |
| double dramclock; |
| double coef2; |
| int col; |
| char *name; |
| |
| /* First, got the FID */ |
| rdmsr(0x0c0010015, mcgsrl, mcgsth); |
| temp = (mcgsrl >> 24)&0x0F; |
| |
| if ((mcgsrl >> 19)&1) { coef2 = athloncoef2[temp]; } |
| else { coef2 = athloncoef[temp]; } |
| |
| if (coef2 == 0) { coef2 = 1; }; |
| |
| /* Compute the final FSB Clock */ |
| dramclock = (extclock /1000) / coef2; |
| |
| /* Print the controller name */ |
| col = COL_SPEC; |
| cprint(LINE_CPU, col, "Chipset: "); |
| col += 9; |
| /* Print the controller name */ |
| name = controllers[ctrl.index].name; |
| cprint(LINE_CPU, col, name); |
| /* Now figure out how much I just printed */ |
| temp = 20; |
| while(name[temp - 20] != '\0') { |
| col++; |
| temp++; |
| } |
| |
| if(temp < 36){ |
| cprint(LINE_CPU, col +1, "- FSB : "); |
| col += 9; |
| dprint(LINE_CPU, col, dramclock, 3,0); |
| col += 3; |
| } |
| |
| |
| } |
| |
| static void poll_fsb_nf2(void) { |
| |
| unsigned int mcgsrl; |
| unsigned int mcgsth; |
| unsigned long temp, mempll; |
| double dramclock, fsb; |
| double mem_m, mem_n; |
| float coef; |
| coef = 10; |
| |
| /* First, got the FID */ |
| rdmsr(0x0c0010015, mcgsrl, mcgsth); |
| temp = (mcgsrl >> 24)&0x0F; |
| |
| if ((mcgsrl >> 19)&1) { coef = athloncoef2[temp]; } |
| else { coef = athloncoef[temp]; } |
| |
| /* Get the coef (COEF = N/M) - Here is for Crush17 */ |
| pci_conf_read(0, 0, 3, 0x70, 4, &mempll); |
| mem_m = (mempll&0x0F); |
| mem_n = ((mempll >> 4) & 0x0F); |
| |
| /* If something goes wrong, the chipset is probably a Crush18 */ |
| if ( mem_m == 0 || mem_n == 0 ) { |
| pci_conf_read(0, 0, 3, 0x7C, 4, &mempll); |
| mem_m = (mempll&0x0F); |
| mem_n = ((mempll >> 4) & 0x0F); |
| } |
| |
| /* Compute the final FSB Clock */ |
| dramclock = ((extclock /1000) / coef) * (mem_n/mem_m); |
| fsb = ((extclock /1000) / coef); |
| |
| /* ...and print */ |
| print_cpu_line(dramclock, fsb, 1); |
| |
| } |
| |
| static void poll_fsb_us15w(void) { |
| |
| double dramclock, dramratio, fsb; |
| unsigned long msr; |
| |
| /* Find dramratio */ |
| /* D0 MsgRd, 05 Zunit, 03 MSR */ |
| pci_conf_write(0, 0, 0, 0xD0, 4, 0xD0050300 ); |
| pci_conf_read(0, 0, 0, 0xD4, 4, &msr ); |
| fsb = ( msr >> 3 ) & 1; |
| |
| dramratio = 0.5; |
| |
| // Compute RAM Frequency |
| if (( msr >> 3 ) & 1) { |
| fsb = 533; |
| } else { |
| fsb = 400; |
| } |
| |
| /* |
| switch (( msr >> 0 ) & 7) { |
| case 0: |
| gfx = 100; |
| break; |
| case 1: |
| gfx = 133; |
| break; |
| case 2: |
| gfx = 150; |
| break; |
| case 3: |
| gfx = 178; |
| break; |
| case 4: |
| gfx = 200; |
| break; |
| case 5: |
| gfx = 266; |
| break; |
| default: |
| gfx = 0; |
| break; |
| } |
| */ |
| |
| dramclock = fsb * dramratio; |
| |
| // Print DRAM Freq |
| print_cpu_line(dramclock, fsb, 1); |
| |
| } |
| |
| static void poll_fsb_nhm(void) { |
| |
| double dramclock, dramratio, fsb; |
| unsigned long mc_dimm_clk_ratio; |
| float coef = getNHMmultiplier(); |
| //unsigned long qpi_pll_status; |
| //float qpi_speed; |
| |
| |
| fsb = ((extclock /1000) / coef); |
| |
| /* Print QPI Speed (if ECC not supported) */ |
| /* |
| if(ctrl.mode == ECC_NONE && cpu_id.vers.bits.model == 10) { |
| pci_conf_read(nhm_bus, 2, 1, 0x50, 2, &qpi_pll_status); |
| qpi_speed = (qpi_pll_status & 0x7F) * ((extclock / 1000) / coef) * 2; |
| cprint(LINE_CPU+5, col +1, "/ QPI : "); |
| col += 9; |
| dprint(LINE_CPU+5, col, qpi_speed/1000, 1,0); |
| col += 1; |
| cprint(LINE_CPU+5, col, "."); |
| col += 1; |
| qpi_speed = ((qpi_speed / 1000) - (int)(qpi_speed / 1000)) * 10; |
| dprint(LINE_CPU+5, col, qpi_speed, 1,0); |
| col += 1; |
| cprint(LINE_CPU+5, col +1, "GT/s"); |
| col += 5; |
| } |
| */ |
| |
| /* Get the clock ratio */ |
| |
| pci_conf_read(nhm_bus, 3, 4, 0x54, 2, &mc_dimm_clk_ratio); |
| dramratio = (mc_dimm_clk_ratio & 0x1F); |
| |
| // Compute RAM Frequency |
| fsb = ((extclock / 1000) / coef); |
| dramclock = fsb * dramratio / 2; |
| |
| // Print DRAM Freq |
| print_cpu_line(dramclock, fsb, 3); |
| |
| } |
| |
| static void poll_fsb_nhm32(void) { |
| |
| double dramclock, dramratio, fsb; |
| unsigned long mc_dimm_clk_ratio; |
| float coef = getNHMmultiplier(); |
| //unsigned long qpi_pll_status; |
| //float qpi_speed; |
| |
| fsb = ((extclock /1000) / coef); |
| |
| /* Print QPI Speed (if ECC not supported) */ |
| /* |
| if(ctrl.mode == ECC_NONE && cpu_id.vers.bits.model == 12) { |
| pci_conf_read(nhm_bus, 2, 1, 0x50, 2, &qpi_pll_status); |
| qpi_speed = (qpi_pll_status & 0x7F) * ((extclock / 1000) / coef) * 2; |
| cprint(LINE_CPU+5, col +1, "/ QPI : "); |
| col += 9; |
| dprint(LINE_CPU+5, col, qpi_speed/1000, 1,0); |
| col += 1; |
| cprint(LINE_CPU+5, col, "."); |
| col += 1; |
| qpi_speed = ((qpi_speed / 1000) - (int)(qpi_speed / 1000)) * 10; |
| dprint(LINE_CPU+5, col, qpi_speed, 1,0); |
| col += 1; |
| cprint(LINE_CPU+5, col +1, "GT/s"); |
| col += 5; |
| } |
| */ |
| |
| /* Get the clock ratio */ |
| |
| pci_conf_read(nhm_bus, 3, 4, 0x50, 2, &mc_dimm_clk_ratio); |
| dramratio = (mc_dimm_clk_ratio & 0x1F); |
| |
| // Compute RAM Frequency |
| fsb = ((extclock / 1000) / coef); |
| dramclock = fsb * dramratio / 2; |
| |
| // Print DRAM Freq |
| print_cpu_line(dramclock, fsb, 3); |
| |
| } |
| |
| static void poll_fsb_wmr(void) { |
| |
| double dramclock, dramratio, fsb; |
| unsigned long dev0; |
| float coef = getNHMmultiplier(); |
| long *ptr; |
| |
| fsb = ((extclock / 1000) / coef); |
| |
| /* Find dramratio */ |
| pci_conf_read( 0, 0, 0, 0x48, 4, &dev0); |
| dev0 &= 0xFFFFC000; |
| ptr=(long*)(dev0+0x2C20); |
| dramratio = 1; |
| |
| /* Get the clock ratio */ |
| dramratio = 0.25 * (float)(*ptr & 0x1F); |
| |
| // Compute RAM Frequency |
| dramclock = fsb * dramratio; |
| |
| // Print DRAM Freq |
| print_cpu_line(dramclock, fsb, 3); |
| |
| } |
| |
| static void poll_fsb_snb(void) { |
| |
| double dramclock, dramratio, fsb; |
| unsigned long dev0; |
| float coef = getSNBmultiplier(); |
| long *ptr; |
| |
| fsb = ((extclock / 1000) / coef); |
| |
| /* Find dramratio */ |
| pci_conf_read( 0, 0, 0, 0x48, 4, &dev0); |
| dev0 &= 0xFFFFC000; |
| ptr=(long*)(dev0+0x5E04); |
| dramratio = 1; |
| |
| /* Get the clock ratio */ |
| dramratio = (float)(*ptr & 0x1F) * (133.34f / 100.0f); |
| |
| // Compute RAM Frequency |
| dramclock = fsb * dramratio; |
| |
| // Print DRAM Freq |
|