1*fcaf780bSMauro Carvalho Chehab /* 2*fcaf780bSMauro Carvalho Chehab * Intel 7300 class Memory Controllers kernel module (Clarksboro) 3*fcaf780bSMauro Carvalho Chehab * 4*fcaf780bSMauro Carvalho Chehab * This file may be distributed under the terms of the 5*fcaf780bSMauro Carvalho Chehab * GNU General Public License version 2 only. 6*fcaf780bSMauro Carvalho Chehab * 7*fcaf780bSMauro Carvalho Chehab * Copyright (c) 2010 by: 8*fcaf780bSMauro Carvalho Chehab * Mauro Carvalho Chehab <mchehab@redhat.com> 9*fcaf780bSMauro Carvalho Chehab * 10*fcaf780bSMauro Carvalho Chehab * Red Hat Inc. http://www.redhat.com 11*fcaf780bSMauro Carvalho Chehab * 12*fcaf780bSMauro Carvalho Chehab * Intel 7300 Chipset Memory Controller Hub (MCH) - Datasheet 13*fcaf780bSMauro Carvalho Chehab * http://www.intel.com/Assets/PDF/datasheet/318082.pdf 14*fcaf780bSMauro Carvalho Chehab * 15*fcaf780bSMauro Carvalho Chehab * TODO: The chipset allow checking for PCI Express errors also. Currently, 16*fcaf780bSMauro Carvalho Chehab * the driver covers only memory error errors 17*fcaf780bSMauro Carvalho Chehab * 18*fcaf780bSMauro Carvalho Chehab * This driver uses "csrows" EDAC attribute to represent DIMM slot# 19*fcaf780bSMauro Carvalho Chehab */ 20*fcaf780bSMauro Carvalho Chehab 21*fcaf780bSMauro Carvalho Chehab #include <linux/module.h> 22*fcaf780bSMauro Carvalho Chehab #include <linux/init.h> 23*fcaf780bSMauro Carvalho Chehab #include <linux/pci.h> 24*fcaf780bSMauro Carvalho Chehab #include <linux/pci_ids.h> 25*fcaf780bSMauro Carvalho Chehab #include <linux/slab.h> 26*fcaf780bSMauro Carvalho Chehab #include <linux/edac.h> 27*fcaf780bSMauro Carvalho Chehab #include <linux/mmzone.h> 28*fcaf780bSMauro Carvalho Chehab 29*fcaf780bSMauro Carvalho Chehab #include "edac_core.h" 30*fcaf780bSMauro Carvalho Chehab 31*fcaf780bSMauro Carvalho Chehab /* 32*fcaf780bSMauro Carvalho Chehab * Alter this version for the I7300 module when modifications are made 33*fcaf780bSMauro Carvalho Chehab */ 34*fcaf780bSMauro Carvalho Chehab #define I7300_REVISION " Ver: 1.0.0 " __DATE__ 35*fcaf780bSMauro Carvalho Chehab 36*fcaf780bSMauro Carvalho Chehab #define EDAC_MOD_STR "i7300_edac" 37*fcaf780bSMauro Carvalho Chehab 38*fcaf780bSMauro Carvalho Chehab #define i7300_printk(level, fmt, arg...) \ 39*fcaf780bSMauro Carvalho Chehab edac_printk(level, "i7300", fmt, ##arg) 40*fcaf780bSMauro Carvalho Chehab 41*fcaf780bSMauro Carvalho Chehab #define i7300_mc_printk(mci, level, fmt, arg...) \ 42*fcaf780bSMauro Carvalho Chehab edac_mc_chipset_printk(mci, level, "i7300", fmt, ##arg) 43*fcaf780bSMauro Carvalho Chehab 44*fcaf780bSMauro Carvalho Chehab /* 45*fcaf780bSMauro Carvalho Chehab * Memory topology is organized as: 46*fcaf780bSMauro Carvalho Chehab * Branch 0 - 2 channels: channels 0 and 1 (FDB0 PCI dev 21.0) 47*fcaf780bSMauro Carvalho Chehab * Branch 1 - 2 channels: channels 2 and 3 (FDB1 PCI dev 22.0) 48*fcaf780bSMauro Carvalho Chehab * Each channel can have to 8 DIMM sets (called as SLOTS) 49*fcaf780bSMauro Carvalho Chehab * Slots should generally be filled in pairs 50*fcaf780bSMauro Carvalho Chehab * Except on Single Channel mode of operation 51*fcaf780bSMauro Carvalho Chehab * just slot 0/channel0 filled on this mode 52*fcaf780bSMauro Carvalho Chehab * On normal operation mode, the two channels on a branch should be 53*fcaf780bSMauro Carvalho Chehab filled together for the same SLOT# 54*fcaf780bSMauro Carvalho Chehab * When in mirrored mode, Branch 1 replicate memory at Branch 0, so, the four 55*fcaf780bSMauro Carvalho Chehab * channels on both branches should be filled 56*fcaf780bSMauro Carvalho Chehab */ 57*fcaf780bSMauro Carvalho Chehab 58*fcaf780bSMauro Carvalho Chehab /* Limits for i7300 */ 59*fcaf780bSMauro Carvalho Chehab #define MAX_SLOTS 8 60*fcaf780bSMauro Carvalho Chehab #define MAX_BRANCHES 2 61*fcaf780bSMauro Carvalho Chehab #define MAX_CH_PER_BRANCH 2 62*fcaf780bSMauro Carvalho Chehab #define MAX_CHANNELS (MAX_CH_PER_BRANCH * MAX_BRANCHES) 63*fcaf780bSMauro Carvalho Chehab #define MAX_MIR 3 64*fcaf780bSMauro Carvalho Chehab 65*fcaf780bSMauro Carvalho Chehab #define to_channel(ch, branch) ((((branch)) << 1) | (ch)) 66*fcaf780bSMauro Carvalho Chehab 67*fcaf780bSMauro Carvalho Chehab #define to_csrow(slot, ch, branch) \ 68*fcaf780bSMauro Carvalho Chehab (to_channel(ch, branch) | ((slot) << 2)) 69*fcaf780bSMauro Carvalho Chehab 70*fcaf780bSMauro Carvalho Chehab 71*fcaf780bSMauro Carvalho Chehab /* Device 16, 72*fcaf780bSMauro Carvalho Chehab * Function 0: System Address (not documented) 73*fcaf780bSMauro Carvalho Chehab * Function 1: Memory Branch Map, Control, Errors Register 74*fcaf780bSMauro Carvalho Chehab * Function 2: FSB Error Registers 75*fcaf780bSMauro Carvalho Chehab * 76*fcaf780bSMauro Carvalho Chehab * All 3 functions of Device 16 (0,1,2) share the SAME DID and 77*fcaf780bSMauro Carvalho Chehab * uses PCI_DEVICE_ID_INTEL_I7300_MCH_ERR for device 16 (0,1,2), 78*fcaf780bSMauro Carvalho Chehab * PCI_DEVICE_ID_INTEL_I7300_MCH_FB0 and PCI_DEVICE_ID_INTEL_I7300_MCH_FB1 79*fcaf780bSMauro Carvalho Chehab * for device 21 (0,1). 80*fcaf780bSMauro Carvalho Chehab */ 81*fcaf780bSMauro Carvalho Chehab 82*fcaf780bSMauro Carvalho Chehab /* OFFSETS for Function 0 */ 83*fcaf780bSMauro Carvalho Chehab #define AMBASE 0x48 /* AMB Mem Mapped Reg Region Base */ 84*fcaf780bSMauro Carvalho Chehab #define MAXCH 0x56 /* Max Channel Number */ 85*fcaf780bSMauro Carvalho Chehab #define MAXDIMMPERCH 0x57 /* Max DIMM PER Channel Number */ 86*fcaf780bSMauro Carvalho Chehab 87*fcaf780bSMauro Carvalho Chehab /* OFFSETS for Function 1 */ 88*fcaf780bSMauro Carvalho Chehab #define TOLM 0x6C 89*fcaf780bSMauro Carvalho Chehab #define REDMEMB 0x7C 90*fcaf780bSMauro Carvalho Chehab 91*fcaf780bSMauro Carvalho Chehab #define MIR0 0x80 92*fcaf780bSMauro Carvalho Chehab #define MIR1 0x84 93*fcaf780bSMauro Carvalho Chehab #define MIR2 0x88 94*fcaf780bSMauro Carvalho Chehab 95*fcaf780bSMauro Carvalho Chehab #if 0 96*fcaf780bSMauro Carvalho Chehab #define AMIR0 0x8c 97*fcaf780bSMauro Carvalho Chehab #define AMIR1 0x90 98*fcaf780bSMauro Carvalho Chehab #define AMIR2 0x94 99*fcaf780bSMauro Carvalho Chehab 100*fcaf780bSMauro Carvalho Chehab /*TODO: double check it */ 101*fcaf780bSMauro Carvalho Chehab #define REC_ECC_LOCATOR_ODD(x) ((x) & 0x3fe00) /* bits [17:9] indicate ODD, [8:0] indicate EVEN */ 102*fcaf780bSMauro Carvalho Chehab 103*fcaf780bSMauro Carvalho Chehab /* Fatal error registers */ 104*fcaf780bSMauro Carvalho Chehab #define FERR_FAT_FBD 0x98 105*fcaf780bSMauro Carvalho Chehab 106*fcaf780bSMauro Carvalho Chehab /*TODO: double check it */ 107*fcaf780bSMauro Carvalho Chehab #define FERR_FAT_FBDCHAN (3<<28) /* channel index where the highest-order error occurred */ 108*fcaf780bSMauro Carvalho Chehab 109*fcaf780bSMauro Carvalho Chehab #define NERR_FAT_FBD 0x9c 110*fcaf780bSMauro Carvalho Chehab #define FERR_NF_FBD 0xa0 111*fcaf780bSMauro Carvalho Chehab 112*fcaf780bSMauro Carvalho Chehab /* Non-fatal error register */ 113*fcaf780bSMauro Carvalho Chehab #define NERR_NF_FBD 0xa4 114*fcaf780bSMauro Carvalho Chehab 115*fcaf780bSMauro Carvalho Chehab /* Enable error mask */ 116*fcaf780bSMauro Carvalho Chehab #define EMASK_FBD 0xa8 117*fcaf780bSMauro Carvalho Chehab 118*fcaf780bSMauro Carvalho Chehab #define ERR0_FBD 0xac 119*fcaf780bSMauro Carvalho Chehab #define ERR1_FBD 0xb0 120*fcaf780bSMauro Carvalho Chehab #define ERR2_FBD 0xb4 121*fcaf780bSMauro Carvalho Chehab #define MCERR_FBD 0xb8 122*fcaf780bSMauro Carvalho Chehab 123*fcaf780bSMauro Carvalho Chehab #endif 124*fcaf780bSMauro Carvalho Chehab 125*fcaf780bSMauro Carvalho Chehab /* TODO: Dev 16 fn1 allows memory error injection - offsets 0x100-0x10b */ 126*fcaf780bSMauro Carvalho Chehab 127*fcaf780bSMauro Carvalho Chehab /* TODO: OFFSETS for Device 16 Function 2 */ 128*fcaf780bSMauro Carvalho Chehab 129*fcaf780bSMauro Carvalho Chehab /* 130*fcaf780bSMauro Carvalho Chehab * Device 21, 131*fcaf780bSMauro Carvalho Chehab * Function 0: Memory Map Branch 0 132*fcaf780bSMauro Carvalho Chehab * 133*fcaf780bSMauro Carvalho Chehab * Device 22, 134*fcaf780bSMauro Carvalho Chehab * Function 0: Memory Map Branch 1 135*fcaf780bSMauro Carvalho Chehab */ 136*fcaf780bSMauro Carvalho Chehab 137*fcaf780bSMauro Carvalho Chehab /* OFFSETS for Function 0 */ 138*fcaf780bSMauro Carvalho Chehab 139*fcaf780bSMauro Carvalho Chehab /* 140*fcaf780bSMauro Carvalho Chehab * Note: Other Intel EDAC drivers use AMBPRESENT to identify if the available 141*fcaf780bSMauro Carvalho Chehab * memory. From datasheet item 7.3.1 (FB-DIMM technology & organization), it 142*fcaf780bSMauro Carvalho Chehab * seems that we cannot use this information directly for the same usage. 143*fcaf780bSMauro Carvalho Chehab * Each memory slot may have up to 2 AMB interfaces, one for income and another 144*fcaf780bSMauro Carvalho Chehab * for outcome interface to the next slot. 145*fcaf780bSMauro Carvalho Chehab * For now, the driver just stores the AMB present registers, but rely only at 146*fcaf780bSMauro Carvalho Chehab * the MTR info to detect memory. 147*fcaf780bSMauro Carvalho Chehab * Datasheet is also not clear about how to map each AMBPRESENT registers to 148*fcaf780bSMauro Carvalho Chehab * one of the 4 available channels. 149*fcaf780bSMauro Carvalho Chehab */ 150*fcaf780bSMauro Carvalho Chehab #define AMBPRESENT_0 0x64 151*fcaf780bSMauro Carvalho Chehab #define AMBPRESENT_1 0x66 152*fcaf780bSMauro Carvalho Chehab 153*fcaf780bSMauro Carvalho Chehab const static u16 mtr_regs [MAX_SLOTS] = { 154*fcaf780bSMauro Carvalho Chehab 0x80, 0x84, 0x88, 0x8c, 155*fcaf780bSMauro Carvalho Chehab 0x82, 0x86, 0x8a, 0x8e 156*fcaf780bSMauro Carvalho Chehab }; 157*fcaf780bSMauro Carvalho Chehab 158*fcaf780bSMauro Carvalho Chehab /* Defines to extract the vaious fields from the 159*fcaf780bSMauro Carvalho Chehab * MTRx - Memory Technology Registers 160*fcaf780bSMauro Carvalho Chehab */ 161*fcaf780bSMauro Carvalho Chehab #define MTR_DIMMS_PRESENT(mtr) ((mtr) & (1 << 8)) 162*fcaf780bSMauro Carvalho Chehab #define MTR_DIMMS_ETHROTTLE(mtr) ((mtr) & (1 << 7)) 163*fcaf780bSMauro Carvalho Chehab #define MTR_DRAM_WIDTH(mtr) (((mtr) & (1 << 6)) ? 8 : 4) 164*fcaf780bSMauro Carvalho Chehab #define MTR_DRAM_BANKS(mtr) (((mtr) & (1 << 5)) ? 8 : 4) 165*fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_RANKS(mtr) (((mtr) & (1 << 4)) ? 1 : 0) 166*fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_ROWS(mtr) (((mtr) >> 2) & 0x3) 167*fcaf780bSMauro Carvalho Chehab #define MTR_DRAM_BANKS_ADDR_BITS 2 168*fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_ROWS_ADDR_BITS(mtr) (MTR_DIMM_ROWS(mtr) + 13) 169*fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_COLS(mtr) ((mtr) & 0x3) 170*fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_COLS_ADDR_BITS(mtr) (MTR_DIMM_COLS(mtr) + 10) 171*fcaf780bSMauro Carvalho Chehab 172*fcaf780bSMauro Carvalho Chehab #if 0 173*fcaf780bSMauro Carvalho Chehab /* OFFSETS for Function 1 */ 174*fcaf780bSMauro Carvalho Chehab 175*fcaf780bSMauro Carvalho Chehab /* TODO */ 176*fcaf780bSMauro Carvalho Chehab #define NRECFGLOG 0x74 177*fcaf780bSMauro Carvalho Chehab #define RECFGLOG 0x78 178*fcaf780bSMauro Carvalho Chehab #define NRECMEMA 0xbe 179*fcaf780bSMauro Carvalho Chehab #define NRECMEMB 0xc0 180*fcaf780bSMauro Carvalho Chehab #define NRECFB_DIMMA 0xc4 181*fcaf780bSMauro Carvalho Chehab #define NRECFB_DIMMB 0xc8 182*fcaf780bSMauro Carvalho Chehab #define NRECFB_DIMMC 0xcc 183*fcaf780bSMauro Carvalho Chehab #define NRECFB_DIMMD 0xd0 184*fcaf780bSMauro Carvalho Chehab #define NRECFB_DIMME 0xd4 185*fcaf780bSMauro Carvalho Chehab #define NRECFB_DIMMF 0xd8 186*fcaf780bSMauro Carvalho Chehab #define REDMEMA 0xdC 187*fcaf780bSMauro Carvalho Chehab #define RECMEMA 0xf0 188*fcaf780bSMauro Carvalho Chehab #define RECMEMB 0xf4 189*fcaf780bSMauro Carvalho Chehab #define RECFB_DIMMA 0xf8 190*fcaf780bSMauro Carvalho Chehab #define RECFB_DIMMB 0xec 191*fcaf780bSMauro Carvalho Chehab #define RECFB_DIMMC 0xf0 192*fcaf780bSMauro Carvalho Chehab #define RECFB_DIMMD 0xf4 193*fcaf780bSMauro Carvalho Chehab #define RECFB_DIMME 0xf8 194*fcaf780bSMauro Carvalho Chehab #define RECFB_DIMMF 0xfC 195*fcaf780bSMauro Carvalho Chehab 196*fcaf780bSMauro Carvalho Chehab /* This applies to FERR_NF_FB-DIMM as well as FERR_FAT_FB-DIMM */ 197*fcaf780bSMauro Carvalho Chehab static inline int extract_fbdchan_indx(u32 x) 198*fcaf780bSMauro Carvalho Chehab { 199*fcaf780bSMauro Carvalho Chehab return (x>>28) & 0x3; 200*fcaf780bSMauro Carvalho Chehab } 201*fcaf780bSMauro Carvalho Chehab #endif 202*fcaf780bSMauro Carvalho Chehab 203*fcaf780bSMauro Carvalho Chehab #ifdef CONFIG_EDAC_DEBUG 204*fcaf780bSMauro Carvalho Chehab /* MTR NUMROW */ 205*fcaf780bSMauro Carvalho Chehab static const char *numrow_toString[] = { 206*fcaf780bSMauro Carvalho Chehab "8,192 - 13 rows", 207*fcaf780bSMauro Carvalho Chehab "16,384 - 14 rows", 208*fcaf780bSMauro Carvalho Chehab "32,768 - 15 rows", 209*fcaf780bSMauro Carvalho Chehab "65,536 - 16 rows" 210*fcaf780bSMauro Carvalho Chehab }; 211*fcaf780bSMauro Carvalho Chehab 212*fcaf780bSMauro Carvalho Chehab /* MTR NUMCOL */ 213*fcaf780bSMauro Carvalho Chehab static const char *numcol_toString[] = { 214*fcaf780bSMauro Carvalho Chehab "1,024 - 10 columns", 215*fcaf780bSMauro Carvalho Chehab "2,048 - 11 columns", 216*fcaf780bSMauro Carvalho Chehab "4,096 - 12 columns", 217*fcaf780bSMauro Carvalho Chehab "reserved" 218*fcaf780bSMauro Carvalho Chehab }; 219*fcaf780bSMauro Carvalho Chehab #endif 220*fcaf780bSMauro Carvalho Chehab 221*fcaf780bSMauro Carvalho Chehab #if 0 222*fcaf780bSMauro Carvalho Chehab 223*fcaf780bSMauro Carvalho Chehab /* 224*fcaf780bSMauro Carvalho Chehab * Error indicator bits and masks 225*fcaf780bSMauro Carvalho Chehab * Error masks are according with Table 5-17 of i7300 datasheet 226*fcaf780bSMauro Carvalho Chehab */ 227*fcaf780bSMauro Carvalho Chehab 228*fcaf780bSMauro Carvalho Chehab enum error_mask { 229*fcaf780bSMauro Carvalho Chehab EMASK_M1 = 1<<0, /* Memory Write error on non-redundant retry */ 230*fcaf780bSMauro Carvalho Chehab EMASK_M2 = 1<<1, /* Memory or FB-DIMM configuration CRC read error */ 231*fcaf780bSMauro Carvalho Chehab EMASK_M3 = 1<<2, /* Reserved */ 232*fcaf780bSMauro Carvalho Chehab EMASK_M4 = 1<<3, /* Uncorrectable Data ECC on Replay */ 233*fcaf780bSMauro Carvalho Chehab EMASK_M5 = 1<<4, /* Aliased Uncorrectable Non-Mirrored Demand Data ECC */ 234*fcaf780bSMauro Carvalho Chehab EMASK_M6 = 1<<5, /* Unsupported on i7300 */ 235*fcaf780bSMauro Carvalho Chehab EMASK_M7 = 1<<6, /* Aliased Uncorrectable Resilver- or Spare-Copy Data ECC */ 236*fcaf780bSMauro Carvalho Chehab EMASK_M8 = 1<<7, /* Aliased Uncorrectable Patrol Data ECC */ 237*fcaf780bSMauro Carvalho Chehab EMASK_M9 = 1<<8, /* Non-Aliased Uncorrectable Non-Mirrored Demand Data ECC */ 238*fcaf780bSMauro Carvalho Chehab EMASK_M10 = 1<<9, /* Unsupported on i7300 */ 239*fcaf780bSMauro Carvalho Chehab EMASK_M11 = 1<<10, /* Non-Aliased Uncorrectable Resilver- or Spare-Copy Data ECC */ 240*fcaf780bSMauro Carvalho Chehab EMASK_M12 = 1<<11, /* Non-Aliased Uncorrectable Patrol Data ECC */ 241*fcaf780bSMauro Carvalho Chehab EMASK_M13 = 1<<12, /* Memory Write error on first attempt */ 242*fcaf780bSMauro Carvalho Chehab EMASK_M14 = 1<<13, /* FB-DIMM Configuration Write error on first attempt */ 243*fcaf780bSMauro Carvalho Chehab EMASK_M15 = 1<<14, /* Memory or FB-DIMM configuration CRC read error */ 244*fcaf780bSMauro Carvalho Chehab EMASK_M16 = 1<<15, /* Channel Failed-Over Occurred */ 245*fcaf780bSMauro Carvalho Chehab EMASK_M17 = 1<<16, /* Correctable Non-Mirrored Demand Data ECC */ 246*fcaf780bSMauro Carvalho Chehab EMASK_M18 = 1<<17, /* Unsupported on i7300 */ 247*fcaf780bSMauro Carvalho Chehab EMASK_M19 = 1<<18, /* Correctable Resilver- or Spare-Copy Data ECC */ 248*fcaf780bSMauro Carvalho Chehab EMASK_M20 = 1<<19, /* Correctable Patrol Data ECC */ 249*fcaf780bSMauro Carvalho Chehab EMASK_M21 = 1<<20, /* FB-DIMM Northbound parity error on FB-DIMM Sync Status */ 250*fcaf780bSMauro Carvalho Chehab EMASK_M22 = 1<<21, /* SPD protocol Error */ 251*fcaf780bSMauro Carvalho Chehab EMASK_M23 = 1<<22, /* Non-Redundant Fast Reset Timeout */ 252*fcaf780bSMauro Carvalho Chehab EMASK_M24 = 1<<23, /* Refresh error */ 253*fcaf780bSMauro Carvalho Chehab EMASK_M25 = 1<<24, /* Memory Write error on redundant retry */ 254*fcaf780bSMauro Carvalho Chehab EMASK_M26 = 1<<25, /* Redundant Fast Reset Timeout */ 255*fcaf780bSMauro Carvalho Chehab EMASK_M27 = 1<<26, /* Correctable Counter Threshold Exceeded */ 256*fcaf780bSMauro Carvalho Chehab EMASK_M28 = 1<<27, /* DIMM-Spare Copy Completed */ 257*fcaf780bSMauro Carvalho Chehab EMASK_M29 = 1<<28, /* DIMM-Isolation Completed */ 258*fcaf780bSMauro Carvalho Chehab }; 259*fcaf780bSMauro Carvalho Chehab 260*fcaf780bSMauro Carvalho Chehab /* 261*fcaf780bSMauro Carvalho Chehab * Names to translate bit error into something useful 262*fcaf780bSMauro Carvalho Chehab */ 263*fcaf780bSMauro Carvalho Chehab static const char *error_name[] = { 264*fcaf780bSMauro Carvalho Chehab [0] = "Memory Write error on non-redundant retry", 265*fcaf780bSMauro Carvalho Chehab [1] = "Memory or FB-DIMM configuration CRC read error", 266*fcaf780bSMauro Carvalho Chehab /* Reserved */ 267*fcaf780bSMauro Carvalho Chehab [3] = "Uncorrectable Data ECC on Replay", 268*fcaf780bSMauro Carvalho Chehab [4] = "Aliased Uncorrectable Non-Mirrored Demand Data ECC", 269*fcaf780bSMauro Carvalho Chehab /* M6 Unsupported on i7300 */ 270*fcaf780bSMauro Carvalho Chehab [6] = "Aliased Uncorrectable Resilver- or Spare-Copy Data ECC", 271*fcaf780bSMauro Carvalho Chehab [7] = "Aliased Uncorrectable Patrol Data ECC", 272*fcaf780bSMauro Carvalho Chehab [8] = "Non-Aliased Uncorrectable Non-Mirrored Demand Data ECC", 273*fcaf780bSMauro Carvalho Chehab /* M10 Unsupported on i7300 */ 274*fcaf780bSMauro Carvalho Chehab [10] = "Non-Aliased Uncorrectable Resilver- or Spare-Copy Data ECC", 275*fcaf780bSMauro Carvalho Chehab [11] = "Non-Aliased Uncorrectable Patrol Data ECC", 276*fcaf780bSMauro Carvalho Chehab [12] = "Memory Write error on first attempt", 277*fcaf780bSMauro Carvalho Chehab [13] = "FB-DIMM Configuration Write error on first attempt", 278*fcaf780bSMauro Carvalho Chehab [14] = "Memory or FB-DIMM configuration CRC read error", 279*fcaf780bSMauro Carvalho Chehab [15] = "Channel Failed-Over Occurred", 280*fcaf780bSMauro Carvalho Chehab [16] = "Correctable Non-Mirrored Demand Data ECC", 281*fcaf780bSMauro Carvalho Chehab /* M18 Unsupported on i7300 */ 282*fcaf780bSMauro Carvalho Chehab [18] = "Correctable Resilver- or Spare-Copy Data ECC", 283*fcaf780bSMauro Carvalho Chehab [19] = "Correctable Patrol Data ECC", 284*fcaf780bSMauro Carvalho Chehab [20] = "FB-DIMM Northbound parity error on FB-DIMM Sync Status", 285*fcaf780bSMauro Carvalho Chehab [21] = "SPD protocol Error", 286*fcaf780bSMauro Carvalho Chehab [22] = "Non-Redundant Fast Reset Timeout", 287*fcaf780bSMauro Carvalho Chehab [23] = "Refresh error", 288*fcaf780bSMauro Carvalho Chehab [24] = "Memory Write error on redundant retry", 289*fcaf780bSMauro Carvalho Chehab [25] = "Redundant Fast Reset Timeout", 290*fcaf780bSMauro Carvalho Chehab [26] = "Correctable Counter Threshold Exceeded", 291*fcaf780bSMauro Carvalho Chehab [27] = "DIMM-Spare Copy Completed", 292*fcaf780bSMauro Carvalho Chehab [28] = "DIMM-Isolation Completed", 293*fcaf780bSMauro Carvalho Chehab }; 294*fcaf780bSMauro Carvalho Chehab 295*fcaf780bSMauro Carvalho Chehab /* Fatal errors */ 296*fcaf780bSMauro Carvalho Chehab #define ERROR_FAT_MASK (EMASK_M1 | \ 297*fcaf780bSMauro Carvalho Chehab EMASK_M2 | \ 298*fcaf780bSMauro Carvalho Chehab EMASK_M23) 299*fcaf780bSMauro Carvalho Chehab 300*fcaf780bSMauro Carvalho Chehab /* Correctable errors */ 301*fcaf780bSMauro Carvalho Chehab #define ERROR_NF_CORRECTABLE (EMASK_M27 | \ 302*fcaf780bSMauro Carvalho Chehab EMASK_M20 | \ 303*fcaf780bSMauro Carvalho Chehab EMASK_M19 | \ 304*fcaf780bSMauro Carvalho Chehab EMASK_M18 | \ 305*fcaf780bSMauro Carvalho Chehab EMASK_M17 | \ 306*fcaf780bSMauro Carvalho Chehab EMASK_M16) 307*fcaf780bSMauro Carvalho Chehab #define ERROR_NF_DIMM_SPARE (EMASK_M29 | \ 308*fcaf780bSMauro Carvalho Chehab EMASK_M28) 309*fcaf780bSMauro Carvalho Chehab #define ERROR_NF_SPD_PROTOCOL (EMASK_M22) 310*fcaf780bSMauro Carvalho Chehab #define ERROR_NF_NORTH_CRC (EMASK_M21) 311*fcaf780bSMauro Carvalho Chehab 312*fcaf780bSMauro Carvalho Chehab /* Recoverable errors */ 313*fcaf780bSMauro Carvalho Chehab #define ERROR_NF_RECOVERABLE (EMASK_M26 | \ 314*fcaf780bSMauro Carvalho Chehab EMASK_M25 | \ 315*fcaf780bSMauro Carvalho Chehab EMASK_M24 | \ 316*fcaf780bSMauro Carvalho Chehab EMASK_M15 | \ 317*fcaf780bSMauro Carvalho Chehab EMASK_M14 | \ 318*fcaf780bSMauro Carvalho Chehab EMASK_M13 | \ 319*fcaf780bSMauro Carvalho Chehab EMASK_M12 | \ 320*fcaf780bSMauro Carvalho Chehab EMASK_M11 | \ 321*fcaf780bSMauro Carvalho Chehab EMASK_M9 | \ 322*fcaf780bSMauro Carvalho Chehab EMASK_M8 | \ 323*fcaf780bSMauro Carvalho Chehab EMASK_M7 | \ 324*fcaf780bSMauro Carvalho Chehab EMASK_M5) 325*fcaf780bSMauro Carvalho Chehab 326*fcaf780bSMauro Carvalho Chehab /* uncorrectable errors */ 327*fcaf780bSMauro Carvalho Chehab #define ERROR_NF_UNCORRECTABLE (EMASK_M4) 328*fcaf780bSMauro Carvalho Chehab 329*fcaf780bSMauro Carvalho Chehab /* mask to all non-fatal errors */ 330*fcaf780bSMauro Carvalho Chehab #define ERROR_NF_MASK (ERROR_NF_CORRECTABLE | \ 331*fcaf780bSMauro Carvalho Chehab ERROR_NF_UNCORRECTABLE | \ 332*fcaf780bSMauro Carvalho Chehab ERROR_NF_RECOVERABLE | \ 333*fcaf780bSMauro Carvalho Chehab ERROR_NF_DIMM_SPARE | \ 334*fcaf780bSMauro Carvalho Chehab ERROR_NF_SPD_PROTOCOL | \ 335*fcaf780bSMauro Carvalho Chehab ERROR_NF_NORTH_CRC) 336*fcaf780bSMauro Carvalho Chehab 337*fcaf780bSMauro Carvalho Chehab /* 338*fcaf780bSMauro Carvalho Chehab * Define error masks for the several registers 339*fcaf780bSMauro Carvalho Chehab */ 340*fcaf780bSMauro Carvalho Chehab 341*fcaf780bSMauro Carvalho Chehab /* Enable all fatal and non fatal errors */ 342*fcaf780bSMauro Carvalho Chehab #define ENABLE_EMASK_ALL (ERROR_FAT_MASK | ERROR_NF_MASK) 343*fcaf780bSMauro Carvalho Chehab 344*fcaf780bSMauro Carvalho Chehab /* mask for fatal error registers */ 345*fcaf780bSMauro Carvalho Chehab #define FERR_FAT_MASK ERROR_FAT_MASK 346*fcaf780bSMauro Carvalho Chehab 347*fcaf780bSMauro Carvalho Chehab /* masks for non-fatal error register */ 348*fcaf780bSMauro Carvalho Chehab static inline int to_nf_mask(unsigned int mask) 349*fcaf780bSMauro Carvalho Chehab { 350*fcaf780bSMauro Carvalho Chehab return (mask & EMASK_M29) | (mask >> 3); 351*fcaf780bSMauro Carvalho Chehab }; 352*fcaf780bSMauro Carvalho Chehab 353*fcaf780bSMauro Carvalho Chehab static inline int from_nf_ferr(unsigned int mask) 354*fcaf780bSMauro Carvalho Chehab { 355*fcaf780bSMauro Carvalho Chehab return (mask & EMASK_M29) | /* Bit 28 */ 356*fcaf780bSMauro Carvalho Chehab (mask & ((1 << 28) - 1) << 3); /* Bits 0 to 27 */ 357*fcaf780bSMauro Carvalho Chehab }; 358*fcaf780bSMauro Carvalho Chehab 359*fcaf780bSMauro Carvalho Chehab #define FERR_NF_MASK to_nf_mask(ERROR_NF_MASK) 360*fcaf780bSMauro Carvalho Chehab #define FERR_NF_CORRECTABLE to_nf_mask(ERROR_NF_CORRECTABLE) 361*fcaf780bSMauro Carvalho Chehab #define FERR_NF_DIMM_SPARE to_nf_mask(ERROR_NF_DIMM_SPARE) 362*fcaf780bSMauro Carvalho Chehab #define FERR_NF_SPD_PROTOCOL to_nf_mask(ERROR_NF_SPD_PROTOCOL) 363*fcaf780bSMauro Carvalho Chehab #define FERR_NF_NORTH_CRC to_nf_mask(ERROR_NF_NORTH_CRC) 364*fcaf780bSMauro Carvalho Chehab #define FERR_NF_RECOVERABLE to_nf_mask(ERROR_NF_RECOVERABLE) 365*fcaf780bSMauro Carvalho Chehab #define FERR_NF_UNCORRECTABLE to_nf_mask(ERROR_NF_UNCORRECTABLE) 366*fcaf780bSMauro Carvalho Chehab 367*fcaf780bSMauro Carvalho Chehab #endif 368*fcaf780bSMauro Carvalho Chehab 369*fcaf780bSMauro Carvalho Chehab /* Device name and register DID (Device ID) */ 370*fcaf780bSMauro Carvalho Chehab struct i7300_dev_info { 371*fcaf780bSMauro Carvalho Chehab const char *ctl_name; /* name for this device */ 372*fcaf780bSMauro Carvalho Chehab u16 fsb_mapping_errors; /* DID for the branchmap,control */ 373*fcaf780bSMauro Carvalho Chehab }; 374*fcaf780bSMauro Carvalho Chehab 375*fcaf780bSMauro Carvalho Chehab /* Table of devices attributes supported by this driver */ 376*fcaf780bSMauro Carvalho Chehab static const struct i7300_dev_info i7300_devs[] = { 377*fcaf780bSMauro Carvalho Chehab { 378*fcaf780bSMauro Carvalho Chehab .ctl_name = "I7300", 379*fcaf780bSMauro Carvalho Chehab .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, 380*fcaf780bSMauro Carvalho Chehab }, 381*fcaf780bSMauro Carvalho Chehab }; 382*fcaf780bSMauro Carvalho Chehab 383*fcaf780bSMauro Carvalho Chehab struct i7300_dimm_info { 384*fcaf780bSMauro Carvalho Chehab int megabytes; /* size, 0 means not present */ 385*fcaf780bSMauro Carvalho Chehab }; 386*fcaf780bSMauro Carvalho Chehab 387*fcaf780bSMauro Carvalho Chehab /* driver private data structure */ 388*fcaf780bSMauro Carvalho Chehab struct i7300_pvt { 389*fcaf780bSMauro Carvalho Chehab struct pci_dev *system_address; /* 16.0 */ 390*fcaf780bSMauro Carvalho Chehab struct pci_dev *branchmap_werrors; /* 16.1 */ 391*fcaf780bSMauro Carvalho Chehab struct pci_dev *fsb_error_regs; /* 16.2 */ 392*fcaf780bSMauro Carvalho Chehab struct pci_dev *branch_pci[MAX_BRANCHES]; /* 21.0 and 22.0 */ 393*fcaf780bSMauro Carvalho Chehab 394*fcaf780bSMauro Carvalho Chehab u16 tolm; /* top of low memory */ 395*fcaf780bSMauro Carvalho Chehab u64 ambase; /* AMB BAR */ 396*fcaf780bSMauro Carvalho Chehab 397*fcaf780bSMauro Carvalho Chehab u16 mir[MAX_MIR]; 398*fcaf780bSMauro Carvalho Chehab 399*fcaf780bSMauro Carvalho Chehab u16 mtr[MAX_SLOTS][MAX_BRANCHES]; /* Memory Technlogy Reg */ 400*fcaf780bSMauro Carvalho Chehab u16 ambpresent[MAX_CHANNELS]; /* AMB present regs */ 401*fcaf780bSMauro Carvalho Chehab 402*fcaf780bSMauro Carvalho Chehab /* DIMM information matrix, allocating architecture maximums */ 403*fcaf780bSMauro Carvalho Chehab struct i7300_dimm_info dimm_info[MAX_SLOTS][MAX_CHANNELS]; 404*fcaf780bSMauro Carvalho Chehab }; 405*fcaf780bSMauro Carvalho Chehab 406*fcaf780bSMauro Carvalho Chehab #if 0 407*fcaf780bSMauro Carvalho Chehab /* I7300 MCH error information retrieved from Hardware */ 408*fcaf780bSMauro Carvalho Chehab struct i7300_error_info { 409*fcaf780bSMauro Carvalho Chehab /* These registers are always read from the MC */ 410*fcaf780bSMauro Carvalho Chehab u32 ferr_fat_fbd; /* First Errors Fatal */ 411*fcaf780bSMauro Carvalho Chehab u32 nerr_fat_fbd; /* Next Errors Fatal */ 412*fcaf780bSMauro Carvalho Chehab u32 ferr_nf_fbd; /* First Errors Non-Fatal */ 413*fcaf780bSMauro Carvalho Chehab u32 nerr_nf_fbd; /* Next Errors Non-Fatal */ 414*fcaf780bSMauro Carvalho Chehab 415*fcaf780bSMauro Carvalho Chehab /* These registers are input ONLY if there was a Recoverable Error */ 416*fcaf780bSMauro Carvalho Chehab u32 redmemb; /* Recoverable Mem Data Error log B */ 417*fcaf780bSMauro Carvalho Chehab u16 recmema; /* Recoverable Mem Error log A */ 418*fcaf780bSMauro Carvalho Chehab u32 recmemb; /* Recoverable Mem Error log B */ 419*fcaf780bSMauro Carvalho Chehab 420*fcaf780bSMauro Carvalho Chehab /* These registers are input ONLY if there was a Non-Rec Error */ 421*fcaf780bSMauro Carvalho Chehab u16 nrecmema; /* Non-Recoverable Mem log A */ 422*fcaf780bSMauro Carvalho Chehab u16 nrecmemb; /* Non-Recoverable Mem log B */ 423*fcaf780bSMauro Carvalho Chehab 424*fcaf780bSMauro Carvalho Chehab }; 425*fcaf780bSMauro Carvalho Chehab #endif 426*fcaf780bSMauro Carvalho Chehab 427*fcaf780bSMauro Carvalho Chehab /* FIXME: Why do we need to have this static? */ 428*fcaf780bSMauro Carvalho Chehab static struct edac_pci_ctl_info *i7300_pci; 429*fcaf780bSMauro Carvalho Chehab 430*fcaf780bSMauro Carvalho Chehab 431*fcaf780bSMauro Carvalho Chehab #if 0 432*fcaf780bSMauro Carvalho Chehab /* note that nrec_rdwr changed from NRECMEMA to NRECMEMB between the 5000 and 433*fcaf780bSMauro Carvalho Chehab 5400 better to use an inline function than a macro in this case */ 434*fcaf780bSMauro Carvalho Chehab static inline int nrec_bank(struct i7300_error_info *info) 435*fcaf780bSMauro Carvalho Chehab { 436*fcaf780bSMauro Carvalho Chehab return ((info->nrecmema) >> 12) & 0x7; 437*fcaf780bSMauro Carvalho Chehab } 438*fcaf780bSMauro Carvalho Chehab static inline int nrec_rank(struct i7300_error_info *info) 439*fcaf780bSMauro Carvalho Chehab { 440*fcaf780bSMauro Carvalho Chehab return ((info->nrecmema) >> 8) & 0xf; 441*fcaf780bSMauro Carvalho Chehab } 442*fcaf780bSMauro Carvalho Chehab static inline int nrec_buf_id(struct i7300_error_info *info) 443*fcaf780bSMauro Carvalho Chehab { 444*fcaf780bSMauro Carvalho Chehab return ((info->nrecmema)) & 0xff; 445*fcaf780bSMauro Carvalho Chehab } 446*fcaf780bSMauro Carvalho Chehab static inline int nrec_rdwr(struct i7300_error_info *info) 447*fcaf780bSMauro Carvalho Chehab { 448*fcaf780bSMauro Carvalho Chehab return (info->nrecmemb) >> 31; 449*fcaf780bSMauro Carvalho Chehab } 450*fcaf780bSMauro Carvalho Chehab /* This applies to both NREC and REC string so it can be used with nrec_rdwr 451*fcaf780bSMauro Carvalho Chehab and rec_rdwr */ 452*fcaf780bSMauro Carvalho Chehab static inline const char *rdwr_str(int rdwr) 453*fcaf780bSMauro Carvalho Chehab { 454*fcaf780bSMauro Carvalho Chehab return rdwr ? "Write" : "Read"; 455*fcaf780bSMauro Carvalho Chehab } 456*fcaf780bSMauro Carvalho Chehab static inline int nrec_cas(struct i7300_error_info *info) 457*fcaf780bSMauro Carvalho Chehab { 458*fcaf780bSMauro Carvalho Chehab return ((info->nrecmemb) >> 16) & 0x1fff; 459*fcaf780bSMauro Carvalho Chehab } 460*fcaf780bSMauro Carvalho Chehab static inline int nrec_ras(struct i7300_error_info *info) 461*fcaf780bSMauro Carvalho Chehab { 462*fcaf780bSMauro Carvalho Chehab return (info->nrecmemb) & 0xffff; 463*fcaf780bSMauro Carvalho Chehab } 464*fcaf780bSMauro Carvalho Chehab static inline int rec_bank(struct i7300_error_info *info) 465*fcaf780bSMauro Carvalho Chehab { 466*fcaf780bSMauro Carvalho Chehab return ((info->recmema) >> 12) & 0x7; 467*fcaf780bSMauro Carvalho Chehab } 468*fcaf780bSMauro Carvalho Chehab static inline int rec_rank(struct i7300_error_info *info) 469*fcaf780bSMauro Carvalho Chehab { 470*fcaf780bSMauro Carvalho Chehab return ((info->recmema) >> 8) & 0xf; 471*fcaf780bSMauro Carvalho Chehab } 472*fcaf780bSMauro Carvalho Chehab static inline int rec_rdwr(struct i7300_error_info *info) 473*fcaf780bSMauro Carvalho Chehab { 474*fcaf780bSMauro Carvalho Chehab return (info->recmemb) >> 31; 475*fcaf780bSMauro Carvalho Chehab } 476*fcaf780bSMauro Carvalho Chehab static inline int rec_cas(struct i7300_error_info *info) 477*fcaf780bSMauro Carvalho Chehab { 478*fcaf780bSMauro Carvalho Chehab return ((info->recmemb) >> 16) & 0x1fff; 479*fcaf780bSMauro Carvalho Chehab } 480*fcaf780bSMauro Carvalho Chehab static inline int rec_ras(struct i7300_error_info *info) 481*fcaf780bSMauro Carvalho Chehab { 482*fcaf780bSMauro Carvalho Chehab return (info->recmemb) & 0xffff; 483*fcaf780bSMauro Carvalho Chehab } 484*fcaf780bSMauro Carvalho Chehab 485*fcaf780bSMauro Carvalho Chehab /* 486*fcaf780bSMauro Carvalho Chehab * i7300_get_error_info Retrieve the hardware error information from 487*fcaf780bSMauro Carvalho Chehab * the hardware and cache it in the 'info' 488*fcaf780bSMauro Carvalho Chehab * structure 489*fcaf780bSMauro Carvalho Chehab */ 490*fcaf780bSMauro Carvalho Chehab static void i7300_get_error_info(struct mem_ctl_info *mci, 491*fcaf780bSMauro Carvalho Chehab struct i7300_error_info *info) 492*fcaf780bSMauro Carvalho Chehab { 493*fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 494*fcaf780bSMauro Carvalho Chehab u32 value; 495*fcaf780bSMauro Carvalho Chehab 496*fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 497*fcaf780bSMauro Carvalho Chehab 498*fcaf780bSMauro Carvalho Chehab /* read in the 1st FATAL error register */ 499*fcaf780bSMauro Carvalho Chehab pci_read_config_dword(pvt->branchmap_werrors, FERR_FAT_FBD, &value); 500*fcaf780bSMauro Carvalho Chehab 501*fcaf780bSMauro Carvalho Chehab /* Mask only the bits that the doc says are valid 502*fcaf780bSMauro Carvalho Chehab */ 503*fcaf780bSMauro Carvalho Chehab value &= (FERR_FAT_FBDCHAN | FERR_FAT_MASK); 504*fcaf780bSMauro Carvalho Chehab 505*fcaf780bSMauro Carvalho Chehab /* If there is an error, then read in the 506*fcaf780bSMauro Carvalho Chehab NEXT FATAL error register and the Memory Error Log Register A 507*fcaf780bSMauro Carvalho Chehab */ 508*fcaf780bSMauro Carvalho Chehab if (value & FERR_FAT_MASK) { 509*fcaf780bSMauro Carvalho Chehab info->ferr_fat_fbd = value; 510*fcaf780bSMauro Carvalho Chehab 511*fcaf780bSMauro Carvalho Chehab /* harvest the various error data we need */ 512*fcaf780bSMauro Carvalho Chehab pci_read_config_dword(pvt->branchmap_werrors, 513*fcaf780bSMauro Carvalho Chehab NERR_FAT_FBD, &info->nerr_fat_fbd); 514*fcaf780bSMauro Carvalho Chehab pci_read_config_word(pvt->branchmap_werrors, 515*fcaf780bSMauro Carvalho Chehab NRECMEMA, &info->nrecmema); 516*fcaf780bSMauro Carvalho Chehab pci_read_config_word(pvt->branchmap_werrors, 517*fcaf780bSMauro Carvalho Chehab NRECMEMB, &info->nrecmemb); 518*fcaf780bSMauro Carvalho Chehab 519*fcaf780bSMauro Carvalho Chehab /* Clear the error bits, by writing them back */ 520*fcaf780bSMauro Carvalho Chehab pci_write_config_dword(pvt->branchmap_werrors, 521*fcaf780bSMauro Carvalho Chehab FERR_FAT_FBD, value); 522*fcaf780bSMauro Carvalho Chehab } else { 523*fcaf780bSMauro Carvalho Chehab info->ferr_fat_fbd = 0; 524*fcaf780bSMauro Carvalho Chehab info->nerr_fat_fbd = 0; 525*fcaf780bSMauro Carvalho Chehab info->nrecmema = 0; 526*fcaf780bSMauro Carvalho Chehab info->nrecmemb = 0; 527*fcaf780bSMauro Carvalho Chehab } 528*fcaf780bSMauro Carvalho Chehab 529*fcaf780bSMauro Carvalho Chehab /* read in the 1st NON-FATAL error register */ 530*fcaf780bSMauro Carvalho Chehab pci_read_config_dword(pvt->branchmap_werrors, FERR_NF_FBD, &value); 531*fcaf780bSMauro Carvalho Chehab 532*fcaf780bSMauro Carvalho Chehab /* If there is an error, then read in the 1st NON-FATAL error 533*fcaf780bSMauro Carvalho Chehab * register as well */ 534*fcaf780bSMauro Carvalho Chehab if (value & FERR_NF_MASK) { 535*fcaf780bSMauro Carvalho Chehab info->ferr_nf_fbd = value; 536*fcaf780bSMauro Carvalho Chehab 537*fcaf780bSMauro Carvalho Chehab /* harvest the various error data we need */ 538*fcaf780bSMauro Carvalho Chehab pci_read_config_dword(pvt->branchmap_werrors, 539*fcaf780bSMauro Carvalho Chehab NERR_NF_FBD, &info->nerr_nf_fbd); 540*fcaf780bSMauro Carvalho Chehab pci_read_config_word(pvt->branchmap_werrors, 541*fcaf780bSMauro Carvalho Chehab RECMEMA, &info->recmema); 542*fcaf780bSMauro Carvalho Chehab pci_read_config_dword(pvt->branchmap_werrors, 543*fcaf780bSMauro Carvalho Chehab RECMEMB, &info->recmemb); 544*fcaf780bSMauro Carvalho Chehab pci_read_config_dword(pvt->branchmap_werrors, 545*fcaf780bSMauro Carvalho Chehab REDMEMB, &info->redmemb); 546*fcaf780bSMauro Carvalho Chehab 547*fcaf780bSMauro Carvalho Chehab /* Clear the error bits, by writing them back */ 548*fcaf780bSMauro Carvalho Chehab pci_write_config_dword(pvt->branchmap_werrors, 549*fcaf780bSMauro Carvalho Chehab FERR_NF_FBD, value); 550*fcaf780bSMauro Carvalho Chehab } else { 551*fcaf780bSMauro Carvalho Chehab info->ferr_nf_fbd = 0; 552*fcaf780bSMauro Carvalho Chehab info->nerr_nf_fbd = 0; 553*fcaf780bSMauro Carvalho Chehab info->recmema = 0; 554*fcaf780bSMauro Carvalho Chehab info->recmemb = 0; 555*fcaf780bSMauro Carvalho Chehab info->redmemb = 0; 556*fcaf780bSMauro Carvalho Chehab } 557*fcaf780bSMauro Carvalho Chehab } 558*fcaf780bSMauro Carvalho Chehab 559*fcaf780bSMauro Carvalho Chehab /* 560*fcaf780bSMauro Carvalho Chehab * i7300_proccess_non_recoverable_info(struct mem_ctl_info *mci, 561*fcaf780bSMauro Carvalho Chehab * struct i7300_error_info *info, 562*fcaf780bSMauro Carvalho Chehab * int handle_errors); 563*fcaf780bSMauro Carvalho Chehab * 564*fcaf780bSMauro Carvalho Chehab * handle the Intel FATAL and unrecoverable errors, if any 565*fcaf780bSMauro Carvalho Chehab */ 566*fcaf780bSMauro Carvalho Chehab static void i7300_proccess_non_recoverable_info(struct mem_ctl_info *mci, 567*fcaf780bSMauro Carvalho Chehab struct i7300_error_info *info, 568*fcaf780bSMauro Carvalho Chehab unsigned long allErrors) 569*fcaf780bSMauro Carvalho Chehab { 570*fcaf780bSMauro Carvalho Chehab char msg[EDAC_MC_LABEL_LEN + 1 + 90 + 80]; 571*fcaf780bSMauro Carvalho Chehab int branch; 572*fcaf780bSMauro Carvalho Chehab int channel; 573*fcaf780bSMauro Carvalho Chehab int bank; 574*fcaf780bSMauro Carvalho Chehab int buf_id; 575*fcaf780bSMauro Carvalho Chehab int rank; 576*fcaf780bSMauro Carvalho Chehab int rdwr; 577*fcaf780bSMauro Carvalho Chehab int ras, cas; 578*fcaf780bSMauro Carvalho Chehab int errnum; 579*fcaf780bSMauro Carvalho Chehab char *type = NULL; 580*fcaf780bSMauro Carvalho Chehab 581*fcaf780bSMauro Carvalho Chehab if (!allErrors) 582*fcaf780bSMauro Carvalho Chehab return; /* if no error, return now */ 583*fcaf780bSMauro Carvalho Chehab 584*fcaf780bSMauro Carvalho Chehab if (allErrors & ERROR_FAT_MASK) 585*fcaf780bSMauro Carvalho Chehab type = "FATAL"; 586*fcaf780bSMauro Carvalho Chehab else if (allErrors & FERR_NF_UNCORRECTABLE) 587*fcaf780bSMauro Carvalho Chehab type = "NON-FATAL uncorrected"; 588*fcaf780bSMauro Carvalho Chehab else 589*fcaf780bSMauro Carvalho Chehab type = "NON-FATAL recoverable"; 590*fcaf780bSMauro Carvalho Chehab 591*fcaf780bSMauro Carvalho Chehab /* ONLY ONE of the possible error bits will be set, as per the docs */ 592*fcaf780bSMauro Carvalho Chehab 593*fcaf780bSMauro Carvalho Chehab branch = extract_fbdchan_indx(info->ferr_fat_fbd); 594*fcaf780bSMauro Carvalho Chehab channel = branch; 595*fcaf780bSMauro Carvalho Chehab 596*fcaf780bSMauro Carvalho Chehab /* Use the NON-Recoverable macros to extract data */ 597*fcaf780bSMauro Carvalho Chehab bank = nrec_bank(info); 598*fcaf780bSMauro Carvalho Chehab rank = nrec_rank(info); 599*fcaf780bSMauro Carvalho Chehab buf_id = nrec_buf_id(info); 600*fcaf780bSMauro Carvalho Chehab rdwr = nrec_rdwr(info); 601*fcaf780bSMauro Carvalho Chehab ras = nrec_ras(info); 602*fcaf780bSMauro Carvalho Chehab cas = nrec_cas(info); 603*fcaf780bSMauro Carvalho Chehab 604*fcaf780bSMauro Carvalho Chehab debugf0("\t\tCSROW= %d Channels= %d,%d (Branch= %d " 605*fcaf780bSMauro Carvalho Chehab "DRAM Bank= %d Buffer ID = %d rdwr= %s ras= %d cas= %d)\n", 606*fcaf780bSMauro Carvalho Chehab rank, channel, channel + 1, branch >> 1, bank, 607*fcaf780bSMauro Carvalho Chehab buf_id, rdwr_str(rdwr), ras, cas); 608*fcaf780bSMauro Carvalho Chehab 609*fcaf780bSMauro Carvalho Chehab /* Only 1 bit will be on */ 610*fcaf780bSMauro Carvalho Chehab errnum = find_first_bit(&allErrors, ARRAY_SIZE(error_name)); 611*fcaf780bSMauro Carvalho Chehab 612*fcaf780bSMauro Carvalho Chehab /* Form out message */ 613*fcaf780bSMauro Carvalho Chehab snprintf(msg, sizeof(msg), 614*fcaf780bSMauro Carvalho Chehab "%s (Branch=%d DRAM-Bank=%d Buffer ID = %d RDWR=%s " 615*fcaf780bSMauro Carvalho Chehab "RAS=%d CAS=%d %s Err=0x%lx (%s))", 616*fcaf780bSMauro Carvalho Chehab type, branch >> 1, bank, buf_id, rdwr_str(rdwr), ras, cas, 617*fcaf780bSMauro Carvalho Chehab type, allErrors, error_name[errnum]); 618*fcaf780bSMauro Carvalho Chehab 619*fcaf780bSMauro Carvalho Chehab /* Call the helper to output message */ 620*fcaf780bSMauro Carvalho Chehab edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg); 621*fcaf780bSMauro Carvalho Chehab } 622*fcaf780bSMauro Carvalho Chehab 623*fcaf780bSMauro Carvalho Chehab /* 624*fcaf780bSMauro Carvalho Chehab * i7300_process_fatal_error_info(struct mem_ctl_info *mci, 625*fcaf780bSMauro Carvalho Chehab * struct i7300_error_info *info, 626*fcaf780bSMauro Carvalho Chehab * int handle_errors); 627*fcaf780bSMauro Carvalho Chehab * 628*fcaf780bSMauro Carvalho Chehab * handle the Intel NON-FATAL errors, if any 629*fcaf780bSMauro Carvalho Chehab */ 630*fcaf780bSMauro Carvalho Chehab static void i7300_process_nonfatal_error_info(struct mem_ctl_info *mci, 631*fcaf780bSMauro Carvalho Chehab struct i7300_error_info *info) 632*fcaf780bSMauro Carvalho Chehab { 633*fcaf780bSMauro Carvalho Chehab char msg[EDAC_MC_LABEL_LEN + 1 + 90 + 80]; 634*fcaf780bSMauro Carvalho Chehab unsigned long allErrors; 635*fcaf780bSMauro Carvalho Chehab int branch; 636*fcaf780bSMauro Carvalho Chehab int channel; 637*fcaf780bSMauro Carvalho Chehab int bank; 638*fcaf780bSMauro Carvalho Chehab int rank; 639*fcaf780bSMauro Carvalho Chehab int rdwr; 640*fcaf780bSMauro Carvalho Chehab int ras, cas; 641*fcaf780bSMauro Carvalho Chehab int errnum; 642*fcaf780bSMauro Carvalho Chehab 643*fcaf780bSMauro Carvalho Chehab /* mask off the Error bits that are possible */ 644*fcaf780bSMauro Carvalho Chehab allErrors = from_nf_ferr(info->ferr_nf_fbd & FERR_NF_MASK); 645*fcaf780bSMauro Carvalho Chehab if (!allErrors) 646*fcaf780bSMauro Carvalho Chehab return; /* if no error, return now */ 647*fcaf780bSMauro Carvalho Chehab 648*fcaf780bSMauro Carvalho Chehab /* ONLY ONE of the possible error bits will be set, as per the docs */ 649*fcaf780bSMauro Carvalho Chehab 650*fcaf780bSMauro Carvalho Chehab if (allErrors & (ERROR_NF_UNCORRECTABLE | ERROR_NF_RECOVERABLE)) { 651*fcaf780bSMauro Carvalho Chehab i7300_proccess_non_recoverable_info(mci, info, allErrors); 652*fcaf780bSMauro Carvalho Chehab return; 653*fcaf780bSMauro Carvalho Chehab } 654*fcaf780bSMauro Carvalho Chehab 655*fcaf780bSMauro Carvalho Chehab /* Correctable errors */ 656*fcaf780bSMauro Carvalho Chehab if (allErrors & ERROR_NF_CORRECTABLE) { 657*fcaf780bSMauro Carvalho Chehab debugf0("\tCorrected bits= 0x%lx\n", allErrors); 658*fcaf780bSMauro Carvalho Chehab 659*fcaf780bSMauro Carvalho Chehab branch = extract_fbdchan_indx(info->ferr_nf_fbd); 660*fcaf780bSMauro Carvalho Chehab 661*fcaf780bSMauro Carvalho Chehab channel = 0; 662*fcaf780bSMauro Carvalho Chehab if (REC_ECC_LOCATOR_ODD(info->redmemb)) 663*fcaf780bSMauro Carvalho Chehab channel = 1; 664*fcaf780bSMauro Carvalho Chehab 665*fcaf780bSMauro Carvalho Chehab /* Convert channel to be based from zero, instead of 666*fcaf780bSMauro Carvalho Chehab * from branch base of 0 */ 667*fcaf780bSMauro Carvalho Chehab channel += branch; 668*fcaf780bSMauro Carvalho Chehab 669*fcaf780bSMauro Carvalho Chehab bank = rec_bank(info); 670*fcaf780bSMauro Carvalho Chehab rank = rec_rank(info); 671*fcaf780bSMauro Carvalho Chehab rdwr = rec_rdwr(info); 672*fcaf780bSMauro Carvalho Chehab ras = rec_ras(info); 673*fcaf780bSMauro Carvalho Chehab cas = rec_cas(info); 674*fcaf780bSMauro Carvalho Chehab 675*fcaf780bSMauro Carvalho Chehab /* Only 1 bit will be on */ 676*fcaf780bSMauro Carvalho Chehab errnum = find_first_bit(&allErrors, ARRAY_SIZE(error_name)); 677*fcaf780bSMauro Carvalho Chehab 678*fcaf780bSMauro Carvalho Chehab debugf0("\t\tCSROW= %d Channel= %d (Branch %d " 679*fcaf780bSMauro Carvalho Chehab "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n", 680*fcaf780bSMauro Carvalho Chehab rank, channel, branch >> 1, bank, 681*fcaf780bSMauro Carvalho Chehab rdwr_str(rdwr), ras, cas); 682*fcaf780bSMauro Carvalho Chehab 683*fcaf780bSMauro Carvalho Chehab /* Form out message */ 684*fcaf780bSMauro Carvalho Chehab snprintf(msg, sizeof(msg), 685*fcaf780bSMauro Carvalho Chehab "Corrected error (Branch=%d DRAM-Bank=%d RDWR=%s " 686*fcaf780bSMauro Carvalho Chehab "RAS=%d CAS=%d, CE Err=0x%lx (%s))", 687*fcaf780bSMauro Carvalho Chehab branch >> 1, bank, rdwr_str(rdwr), ras, cas, 688*fcaf780bSMauro Carvalho Chehab allErrors, error_name[errnum]); 689*fcaf780bSMauro Carvalho Chehab 690*fcaf780bSMauro Carvalho Chehab /* Call the helper to output message */ 691*fcaf780bSMauro Carvalho Chehab edac_mc_handle_fbd_ce(mci, rank, channel, msg); 692*fcaf780bSMauro Carvalho Chehab 693*fcaf780bSMauro Carvalho Chehab return; 694*fcaf780bSMauro Carvalho Chehab } 695*fcaf780bSMauro Carvalho Chehab 696*fcaf780bSMauro Carvalho Chehab /* Miscelaneous errors */ 697*fcaf780bSMauro Carvalho Chehab errnum = find_first_bit(&allErrors, ARRAY_SIZE(error_name)); 698*fcaf780bSMauro Carvalho Chehab 699*fcaf780bSMauro Carvalho Chehab branch = extract_fbdchan_indx(info->ferr_nf_fbd); 700*fcaf780bSMauro Carvalho Chehab 701*fcaf780bSMauro Carvalho Chehab i7300_mc_printk(mci, KERN_EMERG, 702*fcaf780bSMauro Carvalho Chehab "Non-Fatal misc error (Branch=%d Err=%#lx (%s))", 703*fcaf780bSMauro Carvalho Chehab branch >> 1, allErrors, error_name[errnum]); 704*fcaf780bSMauro Carvalho Chehab } 705*fcaf780bSMauro Carvalho Chehab 706*fcaf780bSMauro Carvalho Chehab /* 707*fcaf780bSMauro Carvalho Chehab * i7300_process_error_info Process the error info that is 708*fcaf780bSMauro Carvalho Chehab * in the 'info' structure, previously retrieved from hardware 709*fcaf780bSMauro Carvalho Chehab */ 710*fcaf780bSMauro Carvalho Chehab static void i7300_process_error_info(struct mem_ctl_info *mci, 711*fcaf780bSMauro Carvalho Chehab struct i7300_error_info *info) 712*fcaf780bSMauro Carvalho Chehab { u32 allErrors; 713*fcaf780bSMauro Carvalho Chehab 714*fcaf780bSMauro Carvalho Chehab /* First handle any fatal errors that occurred */ 715*fcaf780bSMauro Carvalho Chehab allErrors = (info->ferr_fat_fbd & FERR_FAT_MASK); 716*fcaf780bSMauro Carvalho Chehab i7300_proccess_non_recoverable_info(mci, info, allErrors); 717*fcaf780bSMauro Carvalho Chehab 718*fcaf780bSMauro Carvalho Chehab /* now handle any non-fatal errors that occurred */ 719*fcaf780bSMauro Carvalho Chehab i7300_process_nonfatal_error_info(mci, info); 720*fcaf780bSMauro Carvalho Chehab } 721*fcaf780bSMauro Carvalho Chehab 722*fcaf780bSMauro Carvalho Chehab /* 723*fcaf780bSMauro Carvalho Chehab * i7300_clear_error Retrieve any error from the hardware 724*fcaf780bSMauro Carvalho Chehab * but do NOT process that error. 725*fcaf780bSMauro Carvalho Chehab * Used for 'clearing' out of previous errors 726*fcaf780bSMauro Carvalho Chehab * Called by the Core module. 727*fcaf780bSMauro Carvalho Chehab */ 728*fcaf780bSMauro Carvalho Chehab static void i7300_clear_error(struct mem_ctl_info *mci) 729*fcaf780bSMauro Carvalho Chehab { 730*fcaf780bSMauro Carvalho Chehab struct i7300_error_info info; 731*fcaf780bSMauro Carvalho Chehab 732*fcaf780bSMauro Carvalho Chehab i7300_get_error_info(mci, &info); 733*fcaf780bSMauro Carvalho Chehab } 734*fcaf780bSMauro Carvalho Chehab 735*fcaf780bSMauro Carvalho Chehab /* 736*fcaf780bSMauro Carvalho Chehab * i7300_check_error Retrieve and process errors reported by the 737*fcaf780bSMauro Carvalho Chehab * hardware. Called by the Core module. 738*fcaf780bSMauro Carvalho Chehab */ 739*fcaf780bSMauro Carvalho Chehab static void i7300_check_error(struct mem_ctl_info *mci) 740*fcaf780bSMauro Carvalho Chehab { 741*fcaf780bSMauro Carvalho Chehab struct i7300_error_info info; 742*fcaf780bSMauro Carvalho Chehab debugf4("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__); 743*fcaf780bSMauro Carvalho Chehab i7300_get_error_info(mci, &info); 744*fcaf780bSMauro Carvalho Chehab i7300_process_error_info(mci, &info); 745*fcaf780bSMauro Carvalho Chehab } 746*fcaf780bSMauro Carvalho Chehab 747*fcaf780bSMauro Carvalho Chehab /* 748*fcaf780bSMauro Carvalho Chehab * i7300_enable_error_reporting 749*fcaf780bSMauro Carvalho Chehab * Turn on the memory reporting features of the hardware 750*fcaf780bSMauro Carvalho Chehab */ 751*fcaf780bSMauro Carvalho Chehab static void i7300_enable_error_reporting(struct mem_ctl_info *mci) 752*fcaf780bSMauro Carvalho Chehab { 753*fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 754*fcaf780bSMauro Carvalho Chehab u32 fbd_error_mask; 755*fcaf780bSMauro Carvalho Chehab 756*fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 757*fcaf780bSMauro Carvalho Chehab 758*fcaf780bSMauro Carvalho Chehab /* Read the FBD Error Mask Register */ 759*fcaf780bSMauro Carvalho Chehab pci_read_config_dword(pvt->branchmap_werrors, EMASK_FBD, 760*fcaf780bSMauro Carvalho Chehab &fbd_error_mask); 761*fcaf780bSMauro Carvalho Chehab 762*fcaf780bSMauro Carvalho Chehab /* Enable with a '0' */ 763*fcaf780bSMauro Carvalho Chehab fbd_error_mask &= ~(ENABLE_EMASK_ALL); 764*fcaf780bSMauro Carvalho Chehab 765*fcaf780bSMauro Carvalho Chehab pci_write_config_dword(pvt->branchmap_werrors, EMASK_FBD, 766*fcaf780bSMauro Carvalho Chehab fbd_error_mask); 767*fcaf780bSMauro Carvalho Chehab } 768*fcaf780bSMauro Carvalho Chehab #endif 769*fcaf780bSMauro Carvalho Chehab 770*fcaf780bSMauro Carvalho Chehab /* 771*fcaf780bSMauro Carvalho Chehab * determine_mtr(pvt, csrow, channel) 772*fcaf780bSMauro Carvalho Chehab * 773*fcaf780bSMauro Carvalho Chehab * return the proper MTR register as determine by the csrow and desired channel 774*fcaf780bSMauro Carvalho Chehab */ 775*fcaf780bSMauro Carvalho Chehab static int decode_mtr(struct i7300_pvt *pvt, 776*fcaf780bSMauro Carvalho Chehab int slot, int ch, int branch, 777*fcaf780bSMauro Carvalho Chehab struct i7300_dimm_info *dinfo, 778*fcaf780bSMauro Carvalho Chehab struct csrow_info *p_csrow) 779*fcaf780bSMauro Carvalho Chehab { 780*fcaf780bSMauro Carvalho Chehab int mtr, ans, addrBits, channel; 781*fcaf780bSMauro Carvalho Chehab 782*fcaf780bSMauro Carvalho Chehab channel = to_channel(ch, branch); 783*fcaf780bSMauro Carvalho Chehab 784*fcaf780bSMauro Carvalho Chehab mtr = pvt->mtr[slot][branch]; 785*fcaf780bSMauro Carvalho Chehab ans = MTR_DIMMS_PRESENT(mtr) ? 1 : 0; 786*fcaf780bSMauro Carvalho Chehab 787*fcaf780bSMauro Carvalho Chehab debugf2("\tMTR%d CH%d: DIMMs are %s (mtr)\n", 788*fcaf780bSMauro Carvalho Chehab slot, channel, 789*fcaf780bSMauro Carvalho Chehab ans ? "Present" : "NOT Present"); 790*fcaf780bSMauro Carvalho Chehab 791*fcaf780bSMauro Carvalho Chehab /* Determine if there is a DIMM present in this DIMM slot */ 792*fcaf780bSMauro Carvalho Chehab 793*fcaf780bSMauro Carvalho Chehab #if 0 794*fcaf780bSMauro Carvalho Chehab if (!amb_present || !ans) 795*fcaf780bSMauro Carvalho Chehab return 0; 796*fcaf780bSMauro Carvalho Chehab #else 797*fcaf780bSMauro Carvalho Chehab if (!ans) 798*fcaf780bSMauro Carvalho Chehab return 0; 799*fcaf780bSMauro Carvalho Chehab #endif 800*fcaf780bSMauro Carvalho Chehab 801*fcaf780bSMauro Carvalho Chehab /* Start with the number of bits for a Bank 802*fcaf780bSMauro Carvalho Chehab * on the DRAM */ 803*fcaf780bSMauro Carvalho Chehab addrBits = MTR_DRAM_BANKS_ADDR_BITS; 804*fcaf780bSMauro Carvalho Chehab /* Add thenumber of ROW bits */ 805*fcaf780bSMauro Carvalho Chehab addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr); 806*fcaf780bSMauro Carvalho Chehab /* add the number of COLUMN bits */ 807*fcaf780bSMauro Carvalho Chehab addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr); 808*fcaf780bSMauro Carvalho Chehab /* add the number of RANK bits */ 809*fcaf780bSMauro Carvalho Chehab addrBits += MTR_DIMM_RANKS(mtr); 810*fcaf780bSMauro Carvalho Chehab 811*fcaf780bSMauro Carvalho Chehab addrBits += 6; /* add 64 bits per DIMM */ 812*fcaf780bSMauro Carvalho Chehab addrBits -= 20; /* divide by 2^^20 */ 813*fcaf780bSMauro Carvalho Chehab addrBits -= 3; /* 8 bits per bytes */ 814*fcaf780bSMauro Carvalho Chehab 815*fcaf780bSMauro Carvalho Chehab dinfo->megabytes = 1 << addrBits; 816*fcaf780bSMauro Carvalho Chehab 817*fcaf780bSMauro Carvalho Chehab debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr)); 818*fcaf780bSMauro Carvalho Chehab 819*fcaf780bSMauro Carvalho Chehab debugf2("\t\tELECTRICAL THROTTLING is %s\n", 820*fcaf780bSMauro Carvalho Chehab MTR_DIMMS_ETHROTTLE(mtr) ? "enabled" : "disabled"); 821*fcaf780bSMauro Carvalho Chehab 822*fcaf780bSMauro Carvalho Chehab debugf2("\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr)); 823*fcaf780bSMauro Carvalho Chehab debugf2("\t\tNUMRANK: %s\n", MTR_DIMM_RANKS(mtr) ? "double" : "single"); 824*fcaf780bSMauro Carvalho Chehab debugf2("\t\tNUMROW: %s\n", numrow_toString[MTR_DIMM_ROWS(mtr)]); 825*fcaf780bSMauro Carvalho Chehab debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]); 826*fcaf780bSMauro Carvalho Chehab debugf2("\t\tSIZE: %d MB\n", dinfo->megabytes); 827*fcaf780bSMauro Carvalho Chehab 828*fcaf780bSMauro Carvalho Chehab p_csrow->grain = 8; 829*fcaf780bSMauro Carvalho Chehab p_csrow->nr_pages = dinfo->megabytes << 8; 830*fcaf780bSMauro Carvalho Chehab p_csrow->mtype = MEM_FB_DDR2; 831*fcaf780bSMauro Carvalho Chehab p_csrow->edac_mode = EDAC_S8ECD8ED; 832*fcaf780bSMauro Carvalho Chehab 833*fcaf780bSMauro Carvalho Chehab /* ask what device type on this row */ 834*fcaf780bSMauro Carvalho Chehab if (MTR_DRAM_WIDTH(mtr)) 835*fcaf780bSMauro Carvalho Chehab p_csrow->dtype = DEV_X8; 836*fcaf780bSMauro Carvalho Chehab else 837*fcaf780bSMauro Carvalho Chehab p_csrow->dtype = DEV_X4; 838*fcaf780bSMauro Carvalho Chehab 839*fcaf780bSMauro Carvalho Chehab return mtr; 840*fcaf780bSMauro Carvalho Chehab } 841*fcaf780bSMauro Carvalho Chehab 842*fcaf780bSMauro Carvalho Chehab /* 843*fcaf780bSMauro Carvalho Chehab * print_dimm_size 844*fcaf780bSMauro Carvalho Chehab * 845*fcaf780bSMauro Carvalho Chehab * also will output a DIMM matrix map, if debug is enabled, for viewing 846*fcaf780bSMauro Carvalho Chehab * how the DIMMs are populated 847*fcaf780bSMauro Carvalho Chehab */ 848*fcaf780bSMauro Carvalho Chehab static void print_dimm_size(struct i7300_pvt *pvt) 849*fcaf780bSMauro Carvalho Chehab { 850*fcaf780bSMauro Carvalho Chehab struct i7300_dimm_info *dinfo; 851*fcaf780bSMauro Carvalho Chehab char *p, *mem_buffer; 852*fcaf780bSMauro Carvalho Chehab int space, n; 853*fcaf780bSMauro Carvalho Chehab int channel, slot; 854*fcaf780bSMauro Carvalho Chehab 855*fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 856*fcaf780bSMauro Carvalho Chehab mem_buffer = p = kmalloc(space, GFP_KERNEL); 857*fcaf780bSMauro Carvalho Chehab if (p == NULL) { 858*fcaf780bSMauro Carvalho Chehab i7300_printk(KERN_ERR, "MC: %s:%s() kmalloc() failed\n", 859*fcaf780bSMauro Carvalho Chehab __FILE__, __func__); 860*fcaf780bSMauro Carvalho Chehab return; 861*fcaf780bSMauro Carvalho Chehab } 862*fcaf780bSMauro Carvalho Chehab 863*fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, " "); 864*fcaf780bSMauro Carvalho Chehab p += n; 865*fcaf780bSMauro Carvalho Chehab space -= n; 866*fcaf780bSMauro Carvalho Chehab for (channel = 0; channel < MAX_CHANNELS; channel++) { 867*fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "channel %d | ", channel); 868*fcaf780bSMauro Carvalho Chehab p += n; 869*fcaf780bSMauro Carvalho Chehab space -= n; 870*fcaf780bSMauro Carvalho Chehab } 871*fcaf780bSMauro Carvalho Chehab debugf2("%s\n", mem_buffer); 872*fcaf780bSMauro Carvalho Chehab p = mem_buffer; 873*fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 874*fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "-------------------------------" 875*fcaf780bSMauro Carvalho Chehab "------------------------------"); 876*fcaf780bSMauro Carvalho Chehab p += n; 877*fcaf780bSMauro Carvalho Chehab space -= n; 878*fcaf780bSMauro Carvalho Chehab debugf2("%s\n", mem_buffer); 879*fcaf780bSMauro Carvalho Chehab p = mem_buffer; 880*fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 881*fcaf780bSMauro Carvalho Chehab 882*fcaf780bSMauro Carvalho Chehab for (slot = 0; slot < MAX_SLOTS; slot++) { 883*fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "csrow/SLOT %d ", slot); 884*fcaf780bSMauro Carvalho Chehab p += n; 885*fcaf780bSMauro Carvalho Chehab space -= n; 886*fcaf780bSMauro Carvalho Chehab 887*fcaf780bSMauro Carvalho Chehab for (channel = 0; channel < MAX_CHANNELS; channel++) { 888*fcaf780bSMauro Carvalho Chehab dinfo = &pvt->dimm_info[slot][channel]; 889*fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "%4d MB | ", dinfo->megabytes); 890*fcaf780bSMauro Carvalho Chehab p += n; 891*fcaf780bSMauro Carvalho Chehab space -= n; 892*fcaf780bSMauro Carvalho Chehab } 893*fcaf780bSMauro Carvalho Chehab 894*fcaf780bSMauro Carvalho Chehab debugf2("%s\n", mem_buffer); 895*fcaf780bSMauro Carvalho Chehab p = mem_buffer; 896*fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 897*fcaf780bSMauro Carvalho Chehab } 898*fcaf780bSMauro Carvalho Chehab 899*fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "-------------------------------" 900*fcaf780bSMauro Carvalho Chehab "------------------------------"); 901*fcaf780bSMauro Carvalho Chehab p += n; 902*fcaf780bSMauro Carvalho Chehab space -= n; 903*fcaf780bSMauro Carvalho Chehab debugf2("%s\n", mem_buffer); 904*fcaf780bSMauro Carvalho Chehab p = mem_buffer; 905*fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 906*fcaf780bSMauro Carvalho Chehab 907*fcaf780bSMauro Carvalho Chehab kfree(mem_buffer); 908*fcaf780bSMauro Carvalho Chehab } 909*fcaf780bSMauro Carvalho Chehab 910*fcaf780bSMauro Carvalho Chehab /* 911*fcaf780bSMauro Carvalho Chehab * i7300_init_csrows Initialize the 'csrows' table within 912*fcaf780bSMauro Carvalho Chehab * the mci control structure with the 913*fcaf780bSMauro Carvalho Chehab * addressing of memory. 914*fcaf780bSMauro Carvalho Chehab * 915*fcaf780bSMauro Carvalho Chehab * return: 916*fcaf780bSMauro Carvalho Chehab * 0 success 917*fcaf780bSMauro Carvalho Chehab * 1 no actual memory found on this MC 918*fcaf780bSMauro Carvalho Chehab */ 919*fcaf780bSMauro Carvalho Chehab static int i7300_init_csrows(struct mem_ctl_info *mci) 920*fcaf780bSMauro Carvalho Chehab { 921*fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 922*fcaf780bSMauro Carvalho Chehab struct i7300_dimm_info *dinfo; 923*fcaf780bSMauro Carvalho Chehab struct csrow_info *p_csrow; 924*fcaf780bSMauro Carvalho Chehab int empty; 925*fcaf780bSMauro Carvalho Chehab int mtr; 926*fcaf780bSMauro Carvalho Chehab int ch, branch, slot, channel; 927*fcaf780bSMauro Carvalho Chehab 928*fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 929*fcaf780bSMauro Carvalho Chehab 930*fcaf780bSMauro Carvalho Chehab empty = 1; /* Assume NO memory */ 931*fcaf780bSMauro Carvalho Chehab 932*fcaf780bSMauro Carvalho Chehab debugf2("Memory Technology Registers:\n"); 933*fcaf780bSMauro Carvalho Chehab 934*fcaf780bSMauro Carvalho Chehab /* Get the AMB present registers for the four channels */ 935*fcaf780bSMauro Carvalho Chehab for (branch = 0; branch < MAX_BRANCHES; branch++) { 936*fcaf780bSMauro Carvalho Chehab /* Read and dump branch 0's MTRs */ 937*fcaf780bSMauro Carvalho Chehab channel = to_channel(0, branch); 938*fcaf780bSMauro Carvalho Chehab pci_read_config_word(pvt->branch_pci[branch], AMBPRESENT_0, 939*fcaf780bSMauro Carvalho Chehab &pvt->ambpresent[channel]); 940*fcaf780bSMauro Carvalho Chehab debugf2("\t\tAMB-present CH%d = 0x%x:\n", 941*fcaf780bSMauro Carvalho Chehab channel, pvt->ambpresent[channel]); 942*fcaf780bSMauro Carvalho Chehab 943*fcaf780bSMauro Carvalho Chehab channel = to_channel(1, branch); 944*fcaf780bSMauro Carvalho Chehab pci_read_config_word(pvt->branch_pci[branch], AMBPRESENT_1, 945*fcaf780bSMauro Carvalho Chehab &pvt->ambpresent[channel]); 946*fcaf780bSMauro Carvalho Chehab debugf2("\t\tAMB-present CH%d = 0x%x:\n", 947*fcaf780bSMauro Carvalho Chehab channel, pvt->ambpresent[channel]); 948*fcaf780bSMauro Carvalho Chehab } 949*fcaf780bSMauro Carvalho Chehab 950*fcaf780bSMauro Carvalho Chehab /* Get the set of MTR[0-7] regs by each branch */ 951*fcaf780bSMauro Carvalho Chehab for (slot = 0; slot < MAX_SLOTS; slot++) { 952*fcaf780bSMauro Carvalho Chehab int where = mtr_regs[slot]; 953*fcaf780bSMauro Carvalho Chehab for (branch = 0; branch < MAX_BRANCHES; branch++) { 954*fcaf780bSMauro Carvalho Chehab pci_read_config_word(pvt->branch_pci[branch], 955*fcaf780bSMauro Carvalho Chehab where, 956*fcaf780bSMauro Carvalho Chehab &pvt->mtr[slot][branch]); 957*fcaf780bSMauro Carvalho Chehab for (ch = 0; ch < MAX_BRANCHES; ch++) { 958*fcaf780bSMauro Carvalho Chehab int channel = to_channel(ch, branch); 959*fcaf780bSMauro Carvalho Chehab 960*fcaf780bSMauro Carvalho Chehab dinfo = &pvt->dimm_info[slot][channel]; 961*fcaf780bSMauro Carvalho Chehab p_csrow = &mci->csrows[slot]; 962*fcaf780bSMauro Carvalho Chehab 963*fcaf780bSMauro Carvalho Chehab mtr = decode_mtr(pvt, slot, ch, branch, 964*fcaf780bSMauro Carvalho Chehab dinfo, p_csrow); 965*fcaf780bSMauro Carvalho Chehab /* if no DIMMS on this row, continue */ 966*fcaf780bSMauro Carvalho Chehab if (!MTR_DIMMS_PRESENT(mtr)) 967*fcaf780bSMauro Carvalho Chehab continue; 968*fcaf780bSMauro Carvalho Chehab 969*fcaf780bSMauro Carvalho Chehab p_csrow->csrow_idx = slot; 970*fcaf780bSMauro Carvalho Chehab 971*fcaf780bSMauro Carvalho Chehab /* FAKE OUT VALUES, FIXME */ 972*fcaf780bSMauro Carvalho Chehab p_csrow->first_page = 0 + slot * 20; 973*fcaf780bSMauro Carvalho Chehab p_csrow->last_page = 9 + slot * 20; 974*fcaf780bSMauro Carvalho Chehab p_csrow->page_mask = 0xfff; 975*fcaf780bSMauro Carvalho Chehab 976*fcaf780bSMauro Carvalho Chehab empty = 0; 977*fcaf780bSMauro Carvalho Chehab } 978*fcaf780bSMauro Carvalho Chehab } 979*fcaf780bSMauro Carvalho Chehab } 980*fcaf780bSMauro Carvalho Chehab 981*fcaf780bSMauro Carvalho Chehab return empty; 982*fcaf780bSMauro Carvalho Chehab } 983*fcaf780bSMauro Carvalho Chehab 984*fcaf780bSMauro Carvalho Chehab static void decode_mir(int mir_no, u16 mir[MAX_MIR]) 985*fcaf780bSMauro Carvalho Chehab { 986*fcaf780bSMauro Carvalho Chehab if (mir[mir_no] & 3) 987*fcaf780bSMauro Carvalho Chehab debugf2("MIR%d: limit= 0x%x Branch(es) that participate: %s %s\n", 988*fcaf780bSMauro Carvalho Chehab mir_no, 989*fcaf780bSMauro Carvalho Chehab (mir[mir_no] >> 4) & 0xfff, 990*fcaf780bSMauro Carvalho Chehab (mir[mir_no] & 1) ? "B0" : "", 991*fcaf780bSMauro Carvalho Chehab (mir[mir_no] & 2) ? "B1": ""); 992*fcaf780bSMauro Carvalho Chehab } 993*fcaf780bSMauro Carvalho Chehab 994*fcaf780bSMauro Carvalho Chehab /* 995*fcaf780bSMauro Carvalho Chehab * i7300_get_mc_regs read in the necessary registers and 996*fcaf780bSMauro Carvalho Chehab * cache locally 997*fcaf780bSMauro Carvalho Chehab * 998*fcaf780bSMauro Carvalho Chehab * Fills in the private data members 999*fcaf780bSMauro Carvalho Chehab */ 1000*fcaf780bSMauro Carvalho Chehab static int i7300_get_mc_regs(struct mem_ctl_info *mci) 1001*fcaf780bSMauro Carvalho Chehab { 1002*fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 1003*fcaf780bSMauro Carvalho Chehab u32 actual_tolm; 1004*fcaf780bSMauro Carvalho Chehab int i, rc; 1005*fcaf780bSMauro Carvalho Chehab 1006*fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 1007*fcaf780bSMauro Carvalho Chehab 1008*fcaf780bSMauro Carvalho Chehab pci_read_config_dword(pvt->system_address, AMBASE, 1009*fcaf780bSMauro Carvalho Chehab (u32 *) &pvt->ambase); 1010*fcaf780bSMauro Carvalho Chehab 1011*fcaf780bSMauro Carvalho Chehab debugf2("AMBASE= 0x%lx\n", (long unsigned int)pvt->ambase); 1012*fcaf780bSMauro Carvalho Chehab 1013*fcaf780bSMauro Carvalho Chehab /* Get the Branch Map regs */ 1014*fcaf780bSMauro Carvalho Chehab pci_read_config_word(pvt->branchmap_werrors, TOLM, &pvt->tolm); 1015*fcaf780bSMauro Carvalho Chehab pvt->tolm >>= 12; 1016*fcaf780bSMauro Carvalho Chehab debugf2("TOLM (number of 256M regions) =%u (0x%x)\n", pvt->tolm, 1017*fcaf780bSMauro Carvalho Chehab pvt->tolm); 1018*fcaf780bSMauro Carvalho Chehab 1019*fcaf780bSMauro Carvalho Chehab actual_tolm = (u32) ((1000l * pvt->tolm) >> (30 - 28)); 1020*fcaf780bSMauro Carvalho Chehab debugf2("Actual TOLM byte addr=%u.%03u GB (0x%x)\n", 1021*fcaf780bSMauro Carvalho Chehab actual_tolm/1000, actual_tolm % 1000, pvt->tolm << 28); 1022*fcaf780bSMauro Carvalho Chehab 1023*fcaf780bSMauro Carvalho Chehab pci_read_config_word(pvt->branchmap_werrors, MIR0, &pvt->mir[0]); 1024*fcaf780bSMauro Carvalho Chehab pci_read_config_word(pvt->branchmap_werrors, MIR1, &pvt->mir[1]); 1025*fcaf780bSMauro Carvalho Chehab pci_read_config_word(pvt->branchmap_werrors, MIR2, &pvt->mir[2]); 1026*fcaf780bSMauro Carvalho Chehab 1027*fcaf780bSMauro Carvalho Chehab /* Decode the MIR regs */ 1028*fcaf780bSMauro Carvalho Chehab for (i = 0; i < MAX_MIR; i++) 1029*fcaf780bSMauro Carvalho Chehab decode_mir(i, pvt->mir); 1030*fcaf780bSMauro Carvalho Chehab 1031*fcaf780bSMauro Carvalho Chehab rc = i7300_init_csrows(mci); 1032*fcaf780bSMauro Carvalho Chehab if (rc < 0) 1033*fcaf780bSMauro Carvalho Chehab return rc; 1034*fcaf780bSMauro Carvalho Chehab 1035*fcaf780bSMauro Carvalho Chehab /* Go and determine the size of each DIMM and place in an 1036*fcaf780bSMauro Carvalho Chehab * orderly matrix */ 1037*fcaf780bSMauro Carvalho Chehab print_dimm_size(pvt); 1038*fcaf780bSMauro Carvalho Chehab 1039*fcaf780bSMauro Carvalho Chehab return 0; 1040*fcaf780bSMauro Carvalho Chehab } 1041*fcaf780bSMauro Carvalho Chehab 1042*fcaf780bSMauro Carvalho Chehab /* 1043*fcaf780bSMauro Carvalho Chehab * i7300_put_devices 'put' all the devices that we have 1044*fcaf780bSMauro Carvalho Chehab * reserved via 'get' 1045*fcaf780bSMauro Carvalho Chehab */ 1046*fcaf780bSMauro Carvalho Chehab static void i7300_put_devices(struct mem_ctl_info *mci) 1047*fcaf780bSMauro Carvalho Chehab { 1048*fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 1049*fcaf780bSMauro Carvalho Chehab int branch; 1050*fcaf780bSMauro Carvalho Chehab 1051*fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 1052*fcaf780bSMauro Carvalho Chehab 1053*fcaf780bSMauro Carvalho Chehab /* Decrement usage count for devices */ 1054*fcaf780bSMauro Carvalho Chehab for (branch = 0; branch < MAX_CH_PER_BRANCH; branch++) 1055*fcaf780bSMauro Carvalho Chehab pci_dev_put(pvt->branch_pci[branch]); 1056*fcaf780bSMauro Carvalho Chehab pci_dev_put(pvt->fsb_error_regs); 1057*fcaf780bSMauro Carvalho Chehab pci_dev_put(pvt->branchmap_werrors); 1058*fcaf780bSMauro Carvalho Chehab } 1059*fcaf780bSMauro Carvalho Chehab 1060*fcaf780bSMauro Carvalho Chehab /* 1061*fcaf780bSMauro Carvalho Chehab * i7300_get_devices Find and perform 'get' operation on the MCH's 1062*fcaf780bSMauro Carvalho Chehab * device/functions we want to reference for this driver 1063*fcaf780bSMauro Carvalho Chehab * 1064*fcaf780bSMauro Carvalho Chehab * Need to 'get' device 16 func 1 and func 2 1065*fcaf780bSMauro Carvalho Chehab */ 1066*fcaf780bSMauro Carvalho Chehab static int i7300_get_devices(struct mem_ctl_info *mci, int dev_idx) 1067*fcaf780bSMauro Carvalho Chehab { 1068*fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 1069*fcaf780bSMauro Carvalho Chehab struct pci_dev *pdev; 1070*fcaf780bSMauro Carvalho Chehab 1071*fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 1072*fcaf780bSMauro Carvalho Chehab 1073*fcaf780bSMauro Carvalho Chehab /* Attempt to 'get' the MCH register we want */ 1074*fcaf780bSMauro Carvalho Chehab pdev = NULL; 1075*fcaf780bSMauro Carvalho Chehab while (!pvt->branchmap_werrors || !pvt->fsb_error_regs) { 1076*fcaf780bSMauro Carvalho Chehab pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 1077*fcaf780bSMauro Carvalho Chehab PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, pdev); 1078*fcaf780bSMauro Carvalho Chehab if (!pdev) { 1079*fcaf780bSMauro Carvalho Chehab /* End of list, leave */ 1080*fcaf780bSMauro Carvalho Chehab i7300_printk(KERN_ERR, 1081*fcaf780bSMauro Carvalho Chehab "'system address,Process Bus' " 1082*fcaf780bSMauro Carvalho Chehab "device not found:" 1083*fcaf780bSMauro Carvalho Chehab "vendor 0x%x device 0x%x ERR funcs " 1084*fcaf780bSMauro Carvalho Chehab "(broken BIOS?)\n", 1085*fcaf780bSMauro Carvalho Chehab PCI_VENDOR_ID_INTEL, 1086*fcaf780bSMauro Carvalho Chehab PCI_DEVICE_ID_INTEL_I7300_MCH_ERR); 1087*fcaf780bSMauro Carvalho Chehab goto error; 1088*fcaf780bSMauro Carvalho Chehab } 1089*fcaf780bSMauro Carvalho Chehab 1090*fcaf780bSMauro Carvalho Chehab /* Store device 16 funcs 1 and 2 */ 1091*fcaf780bSMauro Carvalho Chehab switch (PCI_FUNC(pdev->devfn)) { 1092*fcaf780bSMauro Carvalho Chehab case 1: 1093*fcaf780bSMauro Carvalho Chehab pvt->branchmap_werrors = pdev; 1094*fcaf780bSMauro Carvalho Chehab break; 1095*fcaf780bSMauro Carvalho Chehab case 2: 1096*fcaf780bSMauro Carvalho Chehab pvt->fsb_error_regs = pdev; 1097*fcaf780bSMauro Carvalho Chehab break; 1098*fcaf780bSMauro Carvalho Chehab } 1099*fcaf780bSMauro Carvalho Chehab } 1100*fcaf780bSMauro Carvalho Chehab 1101*fcaf780bSMauro Carvalho Chehab debugf1("System Address, processor bus- PCI Bus ID: %s %x:%x\n", 1102*fcaf780bSMauro Carvalho Chehab pci_name(pvt->system_address), 1103*fcaf780bSMauro Carvalho Chehab pvt->system_address->vendor, pvt->system_address->device); 1104*fcaf780bSMauro Carvalho Chehab debugf1("Branchmap, control and errors - PCI Bus ID: %s %x:%x\n", 1105*fcaf780bSMauro Carvalho Chehab pci_name(pvt->branchmap_werrors), 1106*fcaf780bSMauro Carvalho Chehab pvt->branchmap_werrors->vendor, pvt->branchmap_werrors->device); 1107*fcaf780bSMauro Carvalho Chehab debugf1("FSB Error Regs - PCI Bus ID: %s %x:%x\n", 1108*fcaf780bSMauro Carvalho Chehab pci_name(pvt->fsb_error_regs), 1109*fcaf780bSMauro Carvalho Chehab pvt->fsb_error_regs->vendor, pvt->fsb_error_regs->device); 1110*fcaf780bSMauro Carvalho Chehab 1111*fcaf780bSMauro Carvalho Chehab pvt->branch_pci[0] = pci_get_device(PCI_VENDOR_ID_INTEL, 1112*fcaf780bSMauro Carvalho Chehab PCI_DEVICE_ID_INTEL_I7300_MCH_FB0, 1113*fcaf780bSMauro Carvalho Chehab NULL); 1114*fcaf780bSMauro Carvalho Chehab if (!pvt->branch_pci[0]) { 1115*fcaf780bSMauro Carvalho Chehab i7300_printk(KERN_ERR, 1116*fcaf780bSMauro Carvalho Chehab "MC: 'BRANCH 0' device not found:" 1117*fcaf780bSMauro Carvalho Chehab "vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n", 1118*fcaf780bSMauro Carvalho Chehab PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_FB0); 1119*fcaf780bSMauro Carvalho Chehab goto error; 1120*fcaf780bSMauro Carvalho Chehab } 1121*fcaf780bSMauro Carvalho Chehab 1122*fcaf780bSMauro Carvalho Chehab pvt->branch_pci[1] = pci_get_device(PCI_VENDOR_ID_INTEL, 1123*fcaf780bSMauro Carvalho Chehab PCI_DEVICE_ID_INTEL_I7300_MCH_FB1, 1124*fcaf780bSMauro Carvalho Chehab NULL); 1125*fcaf780bSMauro Carvalho Chehab if (!pvt->branch_pci[1]) { 1126*fcaf780bSMauro Carvalho Chehab i7300_printk(KERN_ERR, 1127*fcaf780bSMauro Carvalho Chehab "MC: 'BRANCH 1' device not found:" 1128*fcaf780bSMauro Carvalho Chehab "vendor 0x%x device 0x%x Func 0 " 1129*fcaf780bSMauro Carvalho Chehab "(broken BIOS?)\n", 1130*fcaf780bSMauro Carvalho Chehab PCI_VENDOR_ID_INTEL, 1131*fcaf780bSMauro Carvalho Chehab PCI_DEVICE_ID_INTEL_I7300_MCH_FB1); 1132*fcaf780bSMauro Carvalho Chehab goto error; 1133*fcaf780bSMauro Carvalho Chehab } 1134*fcaf780bSMauro Carvalho Chehab 1135*fcaf780bSMauro Carvalho Chehab return 0; 1136*fcaf780bSMauro Carvalho Chehab 1137*fcaf780bSMauro Carvalho Chehab error: 1138*fcaf780bSMauro Carvalho Chehab i7300_put_devices(mci); 1139*fcaf780bSMauro Carvalho Chehab return -ENODEV; 1140*fcaf780bSMauro Carvalho Chehab } 1141*fcaf780bSMauro Carvalho Chehab 1142*fcaf780bSMauro Carvalho Chehab /* 1143*fcaf780bSMauro Carvalho Chehab * i7300_probe1 Probe for ONE instance of device to see if it is 1144*fcaf780bSMauro Carvalho Chehab * present. 1145*fcaf780bSMauro Carvalho Chehab * return: 1146*fcaf780bSMauro Carvalho Chehab * 0 for FOUND a device 1147*fcaf780bSMauro Carvalho Chehab * < 0 for error code 1148*fcaf780bSMauro Carvalho Chehab */ 1149*fcaf780bSMauro Carvalho Chehab static int i7300_probe1(struct pci_dev *pdev, int dev_idx) 1150*fcaf780bSMauro Carvalho Chehab { 1151*fcaf780bSMauro Carvalho Chehab struct mem_ctl_info *mci; 1152*fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 1153*fcaf780bSMauro Carvalho Chehab int num_channels; 1154*fcaf780bSMauro Carvalho Chehab int num_dimms_per_channel; 1155*fcaf780bSMauro Carvalho Chehab int num_csrows; 1156*fcaf780bSMauro Carvalho Chehab 1157*fcaf780bSMauro Carvalho Chehab if (dev_idx >= ARRAY_SIZE(i7300_devs)) 1158*fcaf780bSMauro Carvalho Chehab return -EINVAL; 1159*fcaf780bSMauro Carvalho Chehab 1160*fcaf780bSMauro Carvalho Chehab debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n", 1161*fcaf780bSMauro Carvalho Chehab __func__, 1162*fcaf780bSMauro Carvalho Chehab pdev->bus->number, 1163*fcaf780bSMauro Carvalho Chehab PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); 1164*fcaf780bSMauro Carvalho Chehab 1165*fcaf780bSMauro Carvalho Chehab /* We only are looking for func 0 of the set */ 1166*fcaf780bSMauro Carvalho Chehab if (PCI_FUNC(pdev->devfn) != 0) 1167*fcaf780bSMauro Carvalho Chehab return -ENODEV; 1168*fcaf780bSMauro Carvalho Chehab 1169*fcaf780bSMauro Carvalho Chehab /* As we don't have a motherboard identification routine to determine 1170*fcaf780bSMauro Carvalho Chehab * actual number of slots/dimms per channel, we thus utilize the 1171*fcaf780bSMauro Carvalho Chehab * resource as specified by the chipset. Thus, we might have 1172*fcaf780bSMauro Carvalho Chehab * have more DIMMs per channel than actually on the mobo, but this 1173*fcaf780bSMauro Carvalho Chehab * allows the driver to support upto the chipset max, without 1174*fcaf780bSMauro Carvalho Chehab * some fancy mobo determination. 1175*fcaf780bSMauro Carvalho Chehab */ 1176*fcaf780bSMauro Carvalho Chehab num_dimms_per_channel = MAX_SLOTS; 1177*fcaf780bSMauro Carvalho Chehab num_channels = MAX_CHANNELS; 1178*fcaf780bSMauro Carvalho Chehab num_csrows = MAX_SLOTS * MAX_CHANNELS; 1179*fcaf780bSMauro Carvalho Chehab 1180*fcaf780bSMauro Carvalho Chehab debugf0("MC: %s(): Number of - Channels= %d DIMMS= %d CSROWS= %d\n", 1181*fcaf780bSMauro Carvalho Chehab __func__, num_channels, num_dimms_per_channel, num_csrows); 1182*fcaf780bSMauro Carvalho Chehab 1183*fcaf780bSMauro Carvalho Chehab /* allocate a new MC control structure */ 1184*fcaf780bSMauro Carvalho Chehab mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); 1185*fcaf780bSMauro Carvalho Chehab 1186*fcaf780bSMauro Carvalho Chehab if (mci == NULL) 1187*fcaf780bSMauro Carvalho Chehab return -ENOMEM; 1188*fcaf780bSMauro Carvalho Chehab 1189*fcaf780bSMauro Carvalho Chehab debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); 1190*fcaf780bSMauro Carvalho Chehab 1191*fcaf780bSMauro Carvalho Chehab mci->dev = &pdev->dev; /* record ptr to the generic device */ 1192*fcaf780bSMauro Carvalho Chehab 1193*fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 1194*fcaf780bSMauro Carvalho Chehab pvt->system_address = pdev; /* Record this device in our private */ 1195*fcaf780bSMauro Carvalho Chehab 1196*fcaf780bSMauro Carvalho Chehab /* 'get' the pci devices we want to reserve for our use */ 1197*fcaf780bSMauro Carvalho Chehab if (i7300_get_devices(mci, dev_idx)) 1198*fcaf780bSMauro Carvalho Chehab goto fail0; 1199*fcaf780bSMauro Carvalho Chehab 1200*fcaf780bSMauro Carvalho Chehab mci->mc_idx = 0; 1201*fcaf780bSMauro Carvalho Chehab mci->mtype_cap = MEM_FLAG_FB_DDR2; 1202*fcaf780bSMauro Carvalho Chehab mci->edac_ctl_cap = EDAC_FLAG_NONE; 1203*fcaf780bSMauro Carvalho Chehab mci->edac_cap = EDAC_FLAG_NONE; 1204*fcaf780bSMauro Carvalho Chehab mci->mod_name = "i7300_edac.c"; 1205*fcaf780bSMauro Carvalho Chehab mci->mod_ver = I7300_REVISION; 1206*fcaf780bSMauro Carvalho Chehab mci->ctl_name = i7300_devs[dev_idx].ctl_name; 1207*fcaf780bSMauro Carvalho Chehab mci->dev_name = pci_name(pdev); 1208*fcaf780bSMauro Carvalho Chehab mci->ctl_page_to_phys = NULL; 1209*fcaf780bSMauro Carvalho Chehab 1210*fcaf780bSMauro Carvalho Chehab #if 0 1211*fcaf780bSMauro Carvalho Chehab /* Set the function pointer to an actual operation function */ 1212*fcaf780bSMauro Carvalho Chehab mci->edac_check = i7300_check_error; 1213*fcaf780bSMauro Carvalho Chehab #endif 1214*fcaf780bSMauro Carvalho Chehab 1215*fcaf780bSMauro Carvalho Chehab /* initialize the MC control structure 'csrows' table 1216*fcaf780bSMauro Carvalho Chehab * with the mapping and control information */ 1217*fcaf780bSMauro Carvalho Chehab if (i7300_get_mc_regs(mci)) { 1218*fcaf780bSMauro Carvalho Chehab debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n" 1219*fcaf780bSMauro Carvalho Chehab " because i7300_init_csrows() returned nonzero " 1220*fcaf780bSMauro Carvalho Chehab "value\n"); 1221*fcaf780bSMauro Carvalho Chehab mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */ 1222*fcaf780bSMauro Carvalho Chehab } else { 1223*fcaf780bSMauro Carvalho Chehab #if 0 1224*fcaf780bSMauro Carvalho Chehab debugf1("MC: Enable error reporting now\n"); 1225*fcaf780bSMauro Carvalho Chehab i7300_enable_error_reporting(mci); 1226*fcaf780bSMauro Carvalho Chehab #endif 1227*fcaf780bSMauro Carvalho Chehab } 1228*fcaf780bSMauro Carvalho Chehab 1229*fcaf780bSMauro Carvalho Chehab /* add this new MC control structure to EDAC's list of MCs */ 1230*fcaf780bSMauro Carvalho Chehab if (edac_mc_add_mc(mci)) { 1231*fcaf780bSMauro Carvalho Chehab debugf0("MC: " __FILE__ 1232*fcaf780bSMauro Carvalho Chehab ": %s(): failed edac_mc_add_mc()\n", __func__); 1233*fcaf780bSMauro Carvalho Chehab /* FIXME: perhaps some code should go here that disables error 1234*fcaf780bSMauro Carvalho Chehab * reporting if we just enabled it 1235*fcaf780bSMauro Carvalho Chehab */ 1236*fcaf780bSMauro Carvalho Chehab goto fail1; 1237*fcaf780bSMauro Carvalho Chehab } 1238*fcaf780bSMauro Carvalho Chehab 1239*fcaf780bSMauro Carvalho Chehab #if 0 1240*fcaf780bSMauro Carvalho Chehab i7300_clear_error(mci); 1241*fcaf780bSMauro Carvalho Chehab #endif 1242*fcaf780bSMauro Carvalho Chehab 1243*fcaf780bSMauro Carvalho Chehab /* allocating generic PCI control info */ 1244*fcaf780bSMauro Carvalho Chehab i7300_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); 1245*fcaf780bSMauro Carvalho Chehab if (!i7300_pci) { 1246*fcaf780bSMauro Carvalho Chehab printk(KERN_WARNING 1247*fcaf780bSMauro Carvalho Chehab "%s(): Unable to create PCI control\n", 1248*fcaf780bSMauro Carvalho Chehab __func__); 1249*fcaf780bSMauro Carvalho Chehab printk(KERN_WARNING 1250*fcaf780bSMauro Carvalho Chehab "%s(): PCI error report via EDAC not setup\n", 1251*fcaf780bSMauro Carvalho Chehab __func__); 1252*fcaf780bSMauro Carvalho Chehab } 1253*fcaf780bSMauro Carvalho Chehab 1254*fcaf780bSMauro Carvalho Chehab return 0; 1255*fcaf780bSMauro Carvalho Chehab 1256*fcaf780bSMauro Carvalho Chehab /* Error exit unwinding stack */ 1257*fcaf780bSMauro Carvalho Chehab fail1: 1258*fcaf780bSMauro Carvalho Chehab 1259*fcaf780bSMauro Carvalho Chehab i7300_put_devices(mci); 1260*fcaf780bSMauro Carvalho Chehab 1261*fcaf780bSMauro Carvalho Chehab fail0: 1262*fcaf780bSMauro Carvalho Chehab edac_mc_free(mci); 1263*fcaf780bSMauro Carvalho Chehab return -ENODEV; 1264*fcaf780bSMauro Carvalho Chehab } 1265*fcaf780bSMauro Carvalho Chehab 1266*fcaf780bSMauro Carvalho Chehab /* 1267*fcaf780bSMauro Carvalho Chehab * i7300_init_one constructor for one instance of device 1268*fcaf780bSMauro Carvalho Chehab * 1269*fcaf780bSMauro Carvalho Chehab * returns: 1270*fcaf780bSMauro Carvalho Chehab * negative on error 1271*fcaf780bSMauro Carvalho Chehab * count (>= 0) 1272*fcaf780bSMauro Carvalho Chehab */ 1273*fcaf780bSMauro Carvalho Chehab static int __devinit i7300_init_one(struct pci_dev *pdev, 1274*fcaf780bSMauro Carvalho Chehab const struct pci_device_id *id) 1275*fcaf780bSMauro Carvalho Chehab { 1276*fcaf780bSMauro Carvalho Chehab int rc; 1277*fcaf780bSMauro Carvalho Chehab 1278*fcaf780bSMauro Carvalho Chehab debugf0("MC: " __FILE__ ": %s()\n", __func__); 1279*fcaf780bSMauro Carvalho Chehab 1280*fcaf780bSMauro Carvalho Chehab /* wake up device */ 1281*fcaf780bSMauro Carvalho Chehab rc = pci_enable_device(pdev); 1282*fcaf780bSMauro Carvalho Chehab if (rc == -EIO) 1283*fcaf780bSMauro Carvalho Chehab return rc; 1284*fcaf780bSMauro Carvalho Chehab 1285*fcaf780bSMauro Carvalho Chehab /* now probe and enable the device */ 1286*fcaf780bSMauro Carvalho Chehab return i7300_probe1(pdev, id->driver_data); 1287*fcaf780bSMauro Carvalho Chehab } 1288*fcaf780bSMauro Carvalho Chehab 1289*fcaf780bSMauro Carvalho Chehab /* 1290*fcaf780bSMauro Carvalho Chehab * i7300_remove_one destructor for one instance of device 1291*fcaf780bSMauro Carvalho Chehab * 1292*fcaf780bSMauro Carvalho Chehab */ 1293*fcaf780bSMauro Carvalho Chehab static void __devexit i7300_remove_one(struct pci_dev *pdev) 1294*fcaf780bSMauro Carvalho Chehab { 1295*fcaf780bSMauro Carvalho Chehab struct mem_ctl_info *mci; 1296*fcaf780bSMauro Carvalho Chehab 1297*fcaf780bSMauro Carvalho Chehab debugf0(__FILE__ ": %s()\n", __func__); 1298*fcaf780bSMauro Carvalho Chehab 1299*fcaf780bSMauro Carvalho Chehab if (i7300_pci) 1300*fcaf780bSMauro Carvalho Chehab edac_pci_release_generic_ctl(i7300_pci); 1301*fcaf780bSMauro Carvalho Chehab 1302*fcaf780bSMauro Carvalho Chehab mci = edac_mc_del_mc(&pdev->dev); 1303*fcaf780bSMauro Carvalho Chehab if (!mci) 1304*fcaf780bSMauro Carvalho Chehab return; 1305*fcaf780bSMauro Carvalho Chehab 1306*fcaf780bSMauro Carvalho Chehab /* retrieve references to resources, and free those resources */ 1307*fcaf780bSMauro Carvalho Chehab i7300_put_devices(mci); 1308*fcaf780bSMauro Carvalho Chehab 1309*fcaf780bSMauro Carvalho Chehab edac_mc_free(mci); 1310*fcaf780bSMauro Carvalho Chehab } 1311*fcaf780bSMauro Carvalho Chehab 1312*fcaf780bSMauro Carvalho Chehab /* 1313*fcaf780bSMauro Carvalho Chehab * pci_device_id table for which devices we are looking for 1314*fcaf780bSMauro Carvalho Chehab * 1315*fcaf780bSMauro Carvalho Chehab * The "E500P" device is the first device supported. 1316*fcaf780bSMauro Carvalho Chehab */ 1317*fcaf780bSMauro Carvalho Chehab static const struct pci_device_id i7300_pci_tbl[] __devinitdata = { 1318*fcaf780bSMauro Carvalho Chehab {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_ERR)}, 1319*fcaf780bSMauro Carvalho Chehab {0,} /* 0 terminated list. */ 1320*fcaf780bSMauro Carvalho Chehab }; 1321*fcaf780bSMauro Carvalho Chehab 1322*fcaf780bSMauro Carvalho Chehab MODULE_DEVICE_TABLE(pci, i7300_pci_tbl); 1323*fcaf780bSMauro Carvalho Chehab 1324*fcaf780bSMauro Carvalho Chehab /* 1325*fcaf780bSMauro Carvalho Chehab * i7300_driver pci_driver structure for this module 1326*fcaf780bSMauro Carvalho Chehab * 1327*fcaf780bSMauro Carvalho Chehab */ 1328*fcaf780bSMauro Carvalho Chehab static struct pci_driver i7300_driver = { 1329*fcaf780bSMauro Carvalho Chehab .name = "i7300_edac", 1330*fcaf780bSMauro Carvalho Chehab .probe = i7300_init_one, 1331*fcaf780bSMauro Carvalho Chehab .remove = __devexit_p(i7300_remove_one), 1332*fcaf780bSMauro Carvalho Chehab .id_table = i7300_pci_tbl, 1333*fcaf780bSMauro Carvalho Chehab }; 1334*fcaf780bSMauro Carvalho Chehab 1335*fcaf780bSMauro Carvalho Chehab /* 1336*fcaf780bSMauro Carvalho Chehab * i7300_init Module entry function 1337*fcaf780bSMauro Carvalho Chehab * Try to initialize this module for its devices 1338*fcaf780bSMauro Carvalho Chehab */ 1339*fcaf780bSMauro Carvalho Chehab static int __init i7300_init(void) 1340*fcaf780bSMauro Carvalho Chehab { 1341*fcaf780bSMauro Carvalho Chehab int pci_rc; 1342*fcaf780bSMauro Carvalho Chehab 1343*fcaf780bSMauro Carvalho Chehab debugf2("MC: " __FILE__ ": %s()\n", __func__); 1344*fcaf780bSMauro Carvalho Chehab 1345*fcaf780bSMauro Carvalho Chehab /* Ensure that the OPSTATE is set correctly for POLL or NMI */ 1346*fcaf780bSMauro Carvalho Chehab opstate_init(); 1347*fcaf780bSMauro Carvalho Chehab 1348*fcaf780bSMauro Carvalho Chehab pci_rc = pci_register_driver(&i7300_driver); 1349*fcaf780bSMauro Carvalho Chehab 1350*fcaf780bSMauro Carvalho Chehab return (pci_rc < 0) ? pci_rc : 0; 1351*fcaf780bSMauro Carvalho Chehab } 1352*fcaf780bSMauro Carvalho Chehab 1353*fcaf780bSMauro Carvalho Chehab /* 1354*fcaf780bSMauro Carvalho Chehab * i7300_exit() Module exit function 1355*fcaf780bSMauro Carvalho Chehab * Unregister the driver 1356*fcaf780bSMauro Carvalho Chehab */ 1357*fcaf780bSMauro Carvalho Chehab static void __exit i7300_exit(void) 1358*fcaf780bSMauro Carvalho Chehab { 1359*fcaf780bSMauro Carvalho Chehab debugf2("MC: " __FILE__ ": %s()\n", __func__); 1360*fcaf780bSMauro Carvalho Chehab pci_unregister_driver(&i7300_driver); 1361*fcaf780bSMauro Carvalho Chehab } 1362*fcaf780bSMauro Carvalho Chehab 1363*fcaf780bSMauro Carvalho Chehab module_init(i7300_init); 1364*fcaf780bSMauro Carvalho Chehab module_exit(i7300_exit); 1365*fcaf780bSMauro Carvalho Chehab 1366*fcaf780bSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 1367*fcaf780bSMauro Carvalho Chehab MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); 1368*fcaf780bSMauro Carvalho Chehab MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); 1369*fcaf780bSMauro Carvalho Chehab MODULE_DESCRIPTION("MC Driver for Intel I7300 memory controllers - " 1370*fcaf780bSMauro Carvalho Chehab I7300_REVISION); 1371*fcaf780bSMauro Carvalho Chehab 1372*fcaf780bSMauro Carvalho Chehab module_param(edac_op_state, int, 0444); 1373*fcaf780bSMauro Carvalho Chehab MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); 1374