1420390f0SRanganathan Desikan /* 2420390f0SRanganathan Desikan * Intel 82975X Memory Controller kernel module 3420390f0SRanganathan Desikan * (C) 2007 aCarLab (India) Pvt. Ltd. (http://acarlab.com) 4420390f0SRanganathan Desikan * (C) 2007 jetzbroadband (http://jetzbroadband.com) 5420390f0SRanganathan Desikan * This file may be distributed under the terms of the 6420390f0SRanganathan Desikan * GNU General Public License. 7420390f0SRanganathan Desikan * 8420390f0SRanganathan Desikan * Written by Arvind R. 9420390f0SRanganathan Desikan * Copied from i82875p_edac.c source: 10420390f0SRanganathan Desikan */ 11420390f0SRanganathan Desikan 12420390f0SRanganathan Desikan #include <linux/module.h> 13420390f0SRanganathan Desikan #include <linux/init.h> 14420390f0SRanganathan Desikan #include <linux/pci.h> 15420390f0SRanganathan Desikan #include <linux/pci_ids.h> 16c3c52bceSHitoshi Mitake #include <linux/edac.h> 17420390f0SRanganathan Desikan #include "edac_core.h" 18420390f0SRanganathan Desikan 19420390f0SRanganathan Desikan #define I82975X_REVISION " Ver: 1.0.0 " __DATE__ 20420390f0SRanganathan Desikan #define EDAC_MOD_STR "i82975x_edac" 21420390f0SRanganathan Desikan 22420390f0SRanganathan Desikan #define i82975x_printk(level, fmt, arg...) \ 23420390f0SRanganathan Desikan edac_printk(level, "i82975x", fmt, ##arg) 24420390f0SRanganathan Desikan 25420390f0SRanganathan Desikan #define i82975x_mc_printk(mci, level, fmt, arg...) \ 26420390f0SRanganathan Desikan edac_mc_chipset_printk(mci, level, "i82975x", fmt, ##arg) 27420390f0SRanganathan Desikan 28420390f0SRanganathan Desikan #ifndef PCI_DEVICE_ID_INTEL_82975_0 29420390f0SRanganathan Desikan #define PCI_DEVICE_ID_INTEL_82975_0 0x277c 30420390f0SRanganathan Desikan #endif /* PCI_DEVICE_ID_INTEL_82975_0 */ 31420390f0SRanganathan Desikan 32420390f0SRanganathan Desikan #define I82975X_NR_CSROWS(nr_chans) (8/(nr_chans)) 33420390f0SRanganathan Desikan 34420390f0SRanganathan Desikan /* Intel 82975X register addresses - device 0 function 0 - DRAM Controller */ 35420390f0SRanganathan Desikan #define I82975X_EAP 0x58 /* Dram Error Address Pointer (32b) 36420390f0SRanganathan Desikan * 37420390f0SRanganathan Desikan * 31:7 128 byte cache-line address 38420390f0SRanganathan Desikan * 6:1 reserved 39420390f0SRanganathan Desikan * 0 0: CH0; 1: CH1 40420390f0SRanganathan Desikan */ 41420390f0SRanganathan Desikan 42420390f0SRanganathan Desikan #define I82975X_DERRSYN 0x5c /* Dram Error SYNdrome (8b) 43420390f0SRanganathan Desikan * 44420390f0SRanganathan Desikan * 7:0 DRAM ECC Syndrome 45420390f0SRanganathan Desikan */ 46420390f0SRanganathan Desikan 47420390f0SRanganathan Desikan #define I82975X_DES 0x5d /* Dram ERRor DeSTination (8b) 48420390f0SRanganathan Desikan * 0h: Processor Memory Reads 49420390f0SRanganathan Desikan * 1h:7h reserved 50420390f0SRanganathan Desikan * More - See Page 65 of Intel DocSheet. 51420390f0SRanganathan Desikan */ 52420390f0SRanganathan Desikan 53420390f0SRanganathan Desikan #define I82975X_ERRSTS 0xc8 /* Error Status Register (16b) 54420390f0SRanganathan Desikan * 55420390f0SRanganathan Desikan * 15:12 reserved 56420390f0SRanganathan Desikan * 11 Thermal Sensor Event 57420390f0SRanganathan Desikan * 10 reserved 58420390f0SRanganathan Desikan * 9 non-DRAM lock error (ndlock) 59420390f0SRanganathan Desikan * 8 Refresh Timeout 60420390f0SRanganathan Desikan * 7:2 reserved 61420390f0SRanganathan Desikan * 1 ECC UE (multibit DRAM error) 62420390f0SRanganathan Desikan * 0 ECC CE (singlebit DRAM error) 63420390f0SRanganathan Desikan */ 64420390f0SRanganathan Desikan 65420390f0SRanganathan Desikan /* Error Reporting is supported by 3 mechanisms: 66420390f0SRanganathan Desikan 1. DMI SERR generation ( ERRCMD ) 67420390f0SRanganathan Desikan 2. SMI DMI generation ( SMICMD ) 68420390f0SRanganathan Desikan 3. SCI DMI generation ( SCICMD ) 69420390f0SRanganathan Desikan NOTE: Only ONE of the three must be enabled 70420390f0SRanganathan Desikan */ 71420390f0SRanganathan Desikan #define I82975X_ERRCMD 0xca /* Error Command (16b) 72420390f0SRanganathan Desikan * 73420390f0SRanganathan Desikan * 15:12 reserved 74420390f0SRanganathan Desikan * 11 Thermal Sensor Event 75420390f0SRanganathan Desikan * 10 reserved 76420390f0SRanganathan Desikan * 9 non-DRAM lock error (ndlock) 77420390f0SRanganathan Desikan * 8 Refresh Timeout 78420390f0SRanganathan Desikan * 7:2 reserved 79420390f0SRanganathan Desikan * 1 ECC UE (multibit DRAM error) 80420390f0SRanganathan Desikan * 0 ECC CE (singlebit DRAM error) 81420390f0SRanganathan Desikan */ 82420390f0SRanganathan Desikan 83420390f0SRanganathan Desikan #define I82975X_SMICMD 0xcc /* Error Command (16b) 84420390f0SRanganathan Desikan * 85420390f0SRanganathan Desikan * 15:2 reserved 86420390f0SRanganathan Desikan * 1 ECC UE (multibit DRAM error) 87420390f0SRanganathan Desikan * 0 ECC CE (singlebit DRAM error) 88420390f0SRanganathan Desikan */ 89420390f0SRanganathan Desikan 90420390f0SRanganathan Desikan #define I82975X_SCICMD 0xce /* Error Command (16b) 91420390f0SRanganathan Desikan * 92420390f0SRanganathan Desikan * 15:2 reserved 93420390f0SRanganathan Desikan * 1 ECC UE (multibit DRAM error) 94420390f0SRanganathan Desikan * 0 ECC CE (singlebit DRAM error) 95420390f0SRanganathan Desikan */ 96420390f0SRanganathan Desikan 97420390f0SRanganathan Desikan #define I82975X_XEAP 0xfc /* Extended Dram Error Address Pointer (8b) 98420390f0SRanganathan Desikan * 99420390f0SRanganathan Desikan * 7:1 reserved 100420390f0SRanganathan Desikan * 0 Bit32 of the Dram Error Address 101420390f0SRanganathan Desikan */ 102420390f0SRanganathan Desikan 103420390f0SRanganathan Desikan #define I82975X_MCHBAR 0x44 /* 104420390f0SRanganathan Desikan * 105420390f0SRanganathan Desikan * 31:14 Base Addr of 16K memory-mapped 106420390f0SRanganathan Desikan * configuration space 107420390f0SRanganathan Desikan * 13:1 reserverd 108420390f0SRanganathan Desikan * 0 mem-mapped config space enable 109420390f0SRanganathan Desikan */ 110420390f0SRanganathan Desikan 111420390f0SRanganathan Desikan /* NOTE: Following addresses have to indexed using MCHBAR offset (44h, 32b) */ 112420390f0SRanganathan Desikan /* Intel 82975x memory mapped register space */ 113420390f0SRanganathan Desikan 114420390f0SRanganathan Desikan #define I82975X_DRB_SHIFT 25 /* fixed 32MiB grain */ 115420390f0SRanganathan Desikan 116420390f0SRanganathan Desikan #define I82975X_DRB 0x100 /* DRAM Row Boundary (8b x 8) 117420390f0SRanganathan Desikan * 118420390f0SRanganathan Desikan * 7 set to 1 in highest DRB of 119420390f0SRanganathan Desikan * channel if 4GB in ch. 120420390f0SRanganathan Desikan * 6:2 upper boundary of rank in 121420390f0SRanganathan Desikan * 32MB grains 122420390f0SRanganathan Desikan * 1:0 set to 0 123420390f0SRanganathan Desikan */ 124420390f0SRanganathan Desikan #define I82975X_DRB_CH0R0 0x100 125420390f0SRanganathan Desikan #define I82975X_DRB_CH0R1 0x101 126420390f0SRanganathan Desikan #define I82975X_DRB_CH0R2 0x102 127420390f0SRanganathan Desikan #define I82975X_DRB_CH0R3 0x103 128420390f0SRanganathan Desikan #define I82975X_DRB_CH1R0 0x180 129420390f0SRanganathan Desikan #define I82975X_DRB_CH1R1 0x181 130420390f0SRanganathan Desikan #define I82975X_DRB_CH1R2 0x182 131420390f0SRanganathan Desikan #define I82975X_DRB_CH1R3 0x183 132420390f0SRanganathan Desikan 133420390f0SRanganathan Desikan 134420390f0SRanganathan Desikan #define I82975X_DRA 0x108 /* DRAM Row Attribute (4b x 8) 135420390f0SRanganathan Desikan * defines the PAGE SIZE to be used 136420390f0SRanganathan Desikan * for the rank 137420390f0SRanganathan Desikan * 7 reserved 138420390f0SRanganathan Desikan * 6:4 row attr of odd rank, i.e. 1 139420390f0SRanganathan Desikan * 3 reserved 140420390f0SRanganathan Desikan * 2:0 row attr of even rank, i.e. 0 141420390f0SRanganathan Desikan * 142420390f0SRanganathan Desikan * 000 = unpopulated 143420390f0SRanganathan Desikan * 001 = reserved 144420390f0SRanganathan Desikan * 010 = 4KiB 145420390f0SRanganathan Desikan * 011 = 8KiB 146420390f0SRanganathan Desikan * 100 = 16KiB 147420390f0SRanganathan Desikan * others = reserved 148420390f0SRanganathan Desikan */ 149420390f0SRanganathan Desikan #define I82975X_DRA_CH0R01 0x108 150420390f0SRanganathan Desikan #define I82975X_DRA_CH0R23 0x109 151420390f0SRanganathan Desikan #define I82975X_DRA_CH1R01 0x188 152420390f0SRanganathan Desikan #define I82975X_DRA_CH1R23 0x189 153420390f0SRanganathan Desikan 154420390f0SRanganathan Desikan 155420390f0SRanganathan Desikan #define I82975X_BNKARC 0x10e /* Type of device in each rank - Bank Arch (16b) 156420390f0SRanganathan Desikan * 157420390f0SRanganathan Desikan * 15:8 reserved 158420390f0SRanganathan Desikan * 7:6 Rank 3 architecture 159420390f0SRanganathan Desikan * 5:4 Rank 2 architecture 160420390f0SRanganathan Desikan * 3:2 Rank 1 architecture 161420390f0SRanganathan Desikan * 1:0 Rank 0 architecture 162420390f0SRanganathan Desikan * 1637ba99575SArvind R * 00 => 4 banks 1647ba99575SArvind R * 01 => 8 banks 165420390f0SRanganathan Desikan */ 166420390f0SRanganathan Desikan #define I82975X_C0BNKARC 0x10e 167420390f0SRanganathan Desikan #define I82975X_C1BNKARC 0x18e 168420390f0SRanganathan Desikan 169420390f0SRanganathan Desikan 170420390f0SRanganathan Desikan 171420390f0SRanganathan Desikan #define I82975X_DRC 0x120 /* DRAM Controller Mode0 (32b) 172420390f0SRanganathan Desikan * 173420390f0SRanganathan Desikan * 31:30 reserved 174420390f0SRanganathan Desikan * 29 init complete 175420390f0SRanganathan Desikan * 28:11 reserved, according to Intel 176420390f0SRanganathan Desikan * 22:21 number of channels 177420390f0SRanganathan Desikan * 00=1 01=2 in 82875 178420390f0SRanganathan Desikan * seems to be ECC mode 179420390f0SRanganathan Desikan * bits in 82975 in Asus 180420390f0SRanganathan Desikan * P5W 181420390f0SRanganathan Desikan * 19:18 Data Integ Mode 182420390f0SRanganathan Desikan * 00=none 01=ECC in 82875 183420390f0SRanganathan Desikan * 10:8 refresh mode 184420390f0SRanganathan Desikan * 7 reserved 185420390f0SRanganathan Desikan * 6:4 mode select 186420390f0SRanganathan Desikan * 3:2 reserved 187420390f0SRanganathan Desikan * 1:0 DRAM type 10=Second Revision 188420390f0SRanganathan Desikan * DDR2 SDRAM 189420390f0SRanganathan Desikan * 00, 01, 11 reserved 190420390f0SRanganathan Desikan */ 191420390f0SRanganathan Desikan #define I82975X_DRC_CH0M0 0x120 192420390f0SRanganathan Desikan #define I82975X_DRC_CH1M0 0x1A0 193420390f0SRanganathan Desikan 194420390f0SRanganathan Desikan 195420390f0SRanganathan Desikan #define I82975X_DRC_M1 0x124 /* DRAM Controller Mode1 (32b) 196420390f0SRanganathan Desikan * 31 0=Standard Address Map 197420390f0SRanganathan Desikan * 1=Enhanced Address Map 198420390f0SRanganathan Desikan * 30:0 reserved 199420390f0SRanganathan Desikan */ 200420390f0SRanganathan Desikan 201420390f0SRanganathan Desikan #define I82975X_DRC_CH0M1 0x124 202420390f0SRanganathan Desikan #define I82975X_DRC_CH1M1 0x1A4 203420390f0SRanganathan Desikan 204420390f0SRanganathan Desikan enum i82975x_chips { 205420390f0SRanganathan Desikan I82975X = 0, 206420390f0SRanganathan Desikan }; 207420390f0SRanganathan Desikan 208420390f0SRanganathan Desikan struct i82975x_pvt { 209420390f0SRanganathan Desikan void __iomem *mch_window; 210420390f0SRanganathan Desikan }; 211420390f0SRanganathan Desikan 212420390f0SRanganathan Desikan struct i82975x_dev_info { 213420390f0SRanganathan Desikan const char *ctl_name; 214420390f0SRanganathan Desikan }; 215420390f0SRanganathan Desikan 216420390f0SRanganathan Desikan struct i82975x_error_info { 217420390f0SRanganathan Desikan u16 errsts; 218420390f0SRanganathan Desikan u32 eap; 219420390f0SRanganathan Desikan u8 des; 220420390f0SRanganathan Desikan u8 derrsyn; 221420390f0SRanganathan Desikan u16 errsts2; 222420390f0SRanganathan Desikan u8 chan; /* the channel is bit 0 of EAP */ 223420390f0SRanganathan Desikan u8 xeap; /* extended eap bit */ 224420390f0SRanganathan Desikan }; 225420390f0SRanganathan Desikan 226420390f0SRanganathan Desikan static const struct i82975x_dev_info i82975x_devs[] = { 227420390f0SRanganathan Desikan [I82975X] = { 228420390f0SRanganathan Desikan .ctl_name = "i82975x" 229420390f0SRanganathan Desikan }, 230420390f0SRanganathan Desikan }; 231420390f0SRanganathan Desikan 232420390f0SRanganathan Desikan static struct pci_dev *mci_pdev; /* init dev: in case that AGP code has 233420390f0SRanganathan Desikan * already registered driver 234420390f0SRanganathan Desikan */ 235420390f0SRanganathan Desikan 236420390f0SRanganathan Desikan static int i82975x_registered = 1; 237420390f0SRanganathan Desikan 238420390f0SRanganathan Desikan static void i82975x_get_error_info(struct mem_ctl_info *mci, 239420390f0SRanganathan Desikan struct i82975x_error_info *info) 240420390f0SRanganathan Desikan { 241420390f0SRanganathan Desikan struct pci_dev *pdev; 242420390f0SRanganathan Desikan 243420390f0SRanganathan Desikan pdev = to_pci_dev(mci->dev); 244420390f0SRanganathan Desikan 245420390f0SRanganathan Desikan /* 246420390f0SRanganathan Desikan * This is a mess because there is no atomic way to read all the 247420390f0SRanganathan Desikan * registers at once and the registers can transition from CE being 248420390f0SRanganathan Desikan * overwritten by UE. 249420390f0SRanganathan Desikan */ 250420390f0SRanganathan Desikan pci_read_config_word(pdev, I82975X_ERRSTS, &info->errsts); 251420390f0SRanganathan Desikan pci_read_config_dword(pdev, I82975X_EAP, &info->eap); 252420390f0SRanganathan Desikan pci_read_config_byte(pdev, I82975X_XEAP, &info->xeap); 253420390f0SRanganathan Desikan pci_read_config_byte(pdev, I82975X_DES, &info->des); 254420390f0SRanganathan Desikan pci_read_config_byte(pdev, I82975X_DERRSYN, &info->derrsyn); 255420390f0SRanganathan Desikan pci_read_config_word(pdev, I82975X_ERRSTS, &info->errsts2); 256420390f0SRanganathan Desikan 257420390f0SRanganathan Desikan pci_write_bits16(pdev, I82975X_ERRSTS, 0x0003, 0x0003); 258420390f0SRanganathan Desikan 259420390f0SRanganathan Desikan /* 260420390f0SRanganathan Desikan * If the error is the same then we can for both reads then 261420390f0SRanganathan Desikan * the first set of reads is valid. If there is a change then 262420390f0SRanganathan Desikan * there is a CE no info and the second set of reads is valid 263420390f0SRanganathan Desikan * and should be UE info. 264420390f0SRanganathan Desikan */ 265420390f0SRanganathan Desikan if (!(info->errsts2 & 0x0003)) 266420390f0SRanganathan Desikan return; 267420390f0SRanganathan Desikan 268420390f0SRanganathan Desikan if ((info->errsts ^ info->errsts2) & 0x0003) { 269420390f0SRanganathan Desikan pci_read_config_dword(pdev, I82975X_EAP, &info->eap); 270420390f0SRanganathan Desikan pci_read_config_byte(pdev, I82975X_XEAP, &info->xeap); 271420390f0SRanganathan Desikan pci_read_config_byte(pdev, I82975X_DES, &info->des); 272420390f0SRanganathan Desikan pci_read_config_byte(pdev, I82975X_DERRSYN, 273420390f0SRanganathan Desikan &info->derrsyn); 274420390f0SRanganathan Desikan } 275420390f0SRanganathan Desikan } 276420390f0SRanganathan Desikan 277420390f0SRanganathan Desikan static int i82975x_process_error_info(struct mem_ctl_info *mci, 278420390f0SRanganathan Desikan struct i82975x_error_info *info, int handle_errors) 279420390f0SRanganathan Desikan { 280420390f0SRanganathan Desikan int row, multi_chan, chan; 281420390f0SRanganathan Desikan 282420390f0SRanganathan Desikan multi_chan = mci->csrows[0].nr_channels - 1; 283420390f0SRanganathan Desikan 284420390f0SRanganathan Desikan if (!(info->errsts2 & 0x0003)) 285420390f0SRanganathan Desikan return 0; 286420390f0SRanganathan Desikan 287420390f0SRanganathan Desikan if (!handle_errors) 288420390f0SRanganathan Desikan return 1; 289420390f0SRanganathan Desikan 290420390f0SRanganathan Desikan if ((info->errsts ^ info->errsts2) & 0x0003) { 291420390f0SRanganathan Desikan edac_mc_handle_ce_no_info(mci, "UE overwrote CE"); 292420390f0SRanganathan Desikan info->errsts = info->errsts2; 293420390f0SRanganathan Desikan } 294420390f0SRanganathan Desikan 295420390f0SRanganathan Desikan chan = info->eap & 1; 296420390f0SRanganathan Desikan info->eap >>= 1; 297420390f0SRanganathan Desikan if (info->xeap ) 298420390f0SRanganathan Desikan info->eap |= 0x80000000; 299420390f0SRanganathan Desikan info->eap >>= PAGE_SHIFT; 300420390f0SRanganathan Desikan row = edac_mc_find_csrow_by_page(mci, info->eap); 301420390f0SRanganathan Desikan 302420390f0SRanganathan Desikan if (info->errsts & 0x0002) 303420390f0SRanganathan Desikan edac_mc_handle_ue(mci, info->eap, 0, row, "i82975x UE"); 304420390f0SRanganathan Desikan else 305420390f0SRanganathan Desikan edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row, 306420390f0SRanganathan Desikan multi_chan ? chan : 0, 307420390f0SRanganathan Desikan "i82975x CE"); 308420390f0SRanganathan Desikan 309420390f0SRanganathan Desikan return 1; 310420390f0SRanganathan Desikan } 311420390f0SRanganathan Desikan 312420390f0SRanganathan Desikan static void i82975x_check(struct mem_ctl_info *mci) 313420390f0SRanganathan Desikan { 314420390f0SRanganathan Desikan struct i82975x_error_info info; 315420390f0SRanganathan Desikan 316420390f0SRanganathan Desikan debugf1("MC%d: %s()\n", mci->mc_idx, __func__); 317420390f0SRanganathan Desikan i82975x_get_error_info(mci, &info); 318420390f0SRanganathan Desikan i82975x_process_error_info(mci, &info, 1); 319420390f0SRanganathan Desikan } 320420390f0SRanganathan Desikan 321420390f0SRanganathan Desikan /* Return 1 if dual channel mode is active. Else return 0. */ 322420390f0SRanganathan Desikan static int dual_channel_active(void __iomem *mch_window) 323420390f0SRanganathan Desikan { 324420390f0SRanganathan Desikan /* 325420390f0SRanganathan Desikan * We treat interleaved-symmetric configuration as dual-channel - EAP's 326420390f0SRanganathan Desikan * bit-0 giving the channel of the error location. 327420390f0SRanganathan Desikan * 328420390f0SRanganathan Desikan * All other configurations are treated as single channel - the EAP's 329420390f0SRanganathan Desikan * bit-0 will resolve ok in symmetric area of mixed 330420390f0SRanganathan Desikan * (symmetric/asymmetric) configurations 331420390f0SRanganathan Desikan */ 332420390f0SRanganathan Desikan u8 drb[4][2]; 333420390f0SRanganathan Desikan int row; 334420390f0SRanganathan Desikan int dualch; 335420390f0SRanganathan Desikan 336420390f0SRanganathan Desikan for (dualch = 1, row = 0; dualch && (row < 4); row++) { 337420390f0SRanganathan Desikan drb[row][0] = readb(mch_window + I82975X_DRB + row); 338420390f0SRanganathan Desikan drb[row][1] = readb(mch_window + I82975X_DRB + row + 0x80); 339420390f0SRanganathan Desikan dualch = dualch && (drb[row][0] == drb[row][1]); 340420390f0SRanganathan Desikan } 341420390f0SRanganathan Desikan return dualch; 342420390f0SRanganathan Desikan } 343420390f0SRanganathan Desikan 344420390f0SRanganathan Desikan static enum dev_type i82975x_dram_type(void __iomem *mch_window, int rank) 345420390f0SRanganathan Desikan { 346420390f0SRanganathan Desikan /* 3477ba99575SArvind R * ECC is possible on i92975x ONLY with DEV_X8 348420390f0SRanganathan Desikan */ 349420390f0SRanganathan Desikan return DEV_X8; 350420390f0SRanganathan Desikan } 351420390f0SRanganathan Desikan 352420390f0SRanganathan Desikan static void i82975x_init_csrows(struct mem_ctl_info *mci, 353420390f0SRanganathan Desikan struct pci_dev *pdev, void __iomem *mch_window) 354420390f0SRanganathan Desikan { 355420390f0SRanganathan Desikan struct csrow_info *csrow; 356420390f0SRanganathan Desikan unsigned long last_cumul_size; 357420390f0SRanganathan Desikan u8 value; 358420390f0SRanganathan Desikan u32 cumul_size; 359420390f0SRanganathan Desikan int index; 360420390f0SRanganathan Desikan 361420390f0SRanganathan Desikan last_cumul_size = 0; 362420390f0SRanganathan Desikan 363420390f0SRanganathan Desikan /* 364420390f0SRanganathan Desikan * 82875 comment: 365420390f0SRanganathan Desikan * The dram row boundary (DRB) reg values are boundary address 366420390f0SRanganathan Desikan * for each DRAM row with a granularity of 32 or 64MB (single/dual 367420390f0SRanganathan Desikan * channel operation). DRB regs are cumulative; therefore DRB7 will 368420390f0SRanganathan Desikan * contain the total memory contained in all eight rows. 369420390f0SRanganathan Desikan * 370420390f0SRanganathan Desikan * FIXME: 371420390f0SRanganathan Desikan * EDAC currently works for Dual-channel Interleaved configuration. 372420390f0SRanganathan Desikan * Other configurations, which the chip supports, need fixing/testing. 373420390f0SRanganathan Desikan * 374420390f0SRanganathan Desikan */ 375420390f0SRanganathan Desikan 376420390f0SRanganathan Desikan for (index = 0; index < mci->nr_csrows; index++) { 377420390f0SRanganathan Desikan csrow = &mci->csrows[index]; 378420390f0SRanganathan Desikan 379420390f0SRanganathan Desikan value = readb(mch_window + I82975X_DRB + index + 380420390f0SRanganathan Desikan ((index >= 4) ? 0x80 : 0)); 381420390f0SRanganathan Desikan cumul_size = value; 382420390f0SRanganathan Desikan cumul_size <<= (I82975X_DRB_SHIFT - PAGE_SHIFT); 383420390f0SRanganathan Desikan debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index, 384420390f0SRanganathan Desikan cumul_size); 385420390f0SRanganathan Desikan if (cumul_size == last_cumul_size) 386420390f0SRanganathan Desikan continue; /* not populated */ 387420390f0SRanganathan Desikan 388420390f0SRanganathan Desikan csrow->first_page = last_cumul_size; 389420390f0SRanganathan Desikan csrow->last_page = cumul_size - 1; 390420390f0SRanganathan Desikan csrow->nr_pages = cumul_size - last_cumul_size; 391420390f0SRanganathan Desikan last_cumul_size = cumul_size; 392420390f0SRanganathan Desikan csrow->grain = 1 << 7; /* I82975X_EAP has 128B resolution */ 393420390f0SRanganathan Desikan csrow->mtype = MEM_DDR; /* i82975x supports only DDR2 */ 394420390f0SRanganathan Desikan csrow->dtype = i82975x_dram_type(mch_window, index); 395420390f0SRanganathan Desikan csrow->edac_mode = EDAC_SECDED; /* only supported */ 396420390f0SRanganathan Desikan } 397420390f0SRanganathan Desikan } 398420390f0SRanganathan Desikan 399420390f0SRanganathan Desikan /* #define i82975x_DEBUG_IOMEM */ 400420390f0SRanganathan Desikan 401420390f0SRanganathan Desikan #ifdef i82975x_DEBUG_IOMEM 402420390f0SRanganathan Desikan static void i82975x_print_dram_timings(void __iomem *mch_window) 403420390f0SRanganathan Desikan { 404420390f0SRanganathan Desikan /* 405420390f0SRanganathan Desikan * The register meanings are from Intel specs; 406420390f0SRanganathan Desikan * (shows 13-5-5-5 for 800-DDR2) 407420390f0SRanganathan Desikan * Asus P5W Bios reports 15-5-4-4 408420390f0SRanganathan Desikan * What's your religion? 409420390f0SRanganathan Desikan */ 410420390f0SRanganathan Desikan static const int caslats[4] = { 5, 4, 3, 6 }; 411420390f0SRanganathan Desikan u32 dtreg[2]; 412420390f0SRanganathan Desikan 413420390f0SRanganathan Desikan dtreg[0] = readl(mch_window + 0x114); 414420390f0SRanganathan Desikan dtreg[1] = readl(mch_window + 0x194); 415420390f0SRanganathan Desikan i82975x_printk(KERN_INFO, "DRAM Timings : Ch0 Ch1\n" 416420390f0SRanganathan Desikan " RAS Active Min = %d %d\n" 417420390f0SRanganathan Desikan " CAS latency = %d %d\n" 418420390f0SRanganathan Desikan " RAS to CAS = %d %d\n" 419420390f0SRanganathan Desikan " RAS precharge = %d %d\n", 420420390f0SRanganathan Desikan (dtreg[0] >> 19 ) & 0x0f, 421420390f0SRanganathan Desikan (dtreg[1] >> 19) & 0x0f, 422420390f0SRanganathan Desikan caslats[(dtreg[0] >> 8) & 0x03], 423420390f0SRanganathan Desikan caslats[(dtreg[1] >> 8) & 0x03], 424420390f0SRanganathan Desikan ((dtreg[0] >> 4) & 0x07) + 2, 425420390f0SRanganathan Desikan ((dtreg[1] >> 4) & 0x07) + 2, 426420390f0SRanganathan Desikan (dtreg[0] & 0x07) + 2, 427420390f0SRanganathan Desikan (dtreg[1] & 0x07) + 2 428420390f0SRanganathan Desikan ); 429420390f0SRanganathan Desikan 430420390f0SRanganathan Desikan } 431420390f0SRanganathan Desikan #endif 432420390f0SRanganathan Desikan 433420390f0SRanganathan Desikan static int i82975x_probe1(struct pci_dev *pdev, int dev_idx) 434420390f0SRanganathan Desikan { 435420390f0SRanganathan Desikan int rc = -ENODEV; 436420390f0SRanganathan Desikan struct mem_ctl_info *mci; 437420390f0SRanganathan Desikan struct i82975x_pvt *pvt; 438420390f0SRanganathan Desikan void __iomem *mch_window; 439420390f0SRanganathan Desikan u32 mchbar; 440420390f0SRanganathan Desikan u32 drc[2]; 441420390f0SRanganathan Desikan struct i82975x_error_info discard; 442420390f0SRanganathan Desikan int chans; 443420390f0SRanganathan Desikan #ifdef i82975x_DEBUG_IOMEM 444420390f0SRanganathan Desikan u8 c0drb[4]; 445420390f0SRanganathan Desikan u8 c1drb[4]; 446420390f0SRanganathan Desikan #endif 447420390f0SRanganathan Desikan 448420390f0SRanganathan Desikan debugf0("%s()\n", __func__); 449420390f0SRanganathan Desikan 450420390f0SRanganathan Desikan pci_read_config_dword(pdev, I82975X_MCHBAR, &mchbar); 451420390f0SRanganathan Desikan if (!(mchbar & 1)) { 452420390f0SRanganathan Desikan debugf3("%s(): failed, MCHBAR disabled!\n", __func__); 453420390f0SRanganathan Desikan goto fail0; 454420390f0SRanganathan Desikan } 455420390f0SRanganathan Desikan mchbar &= 0xffffc000; /* bits 31:14 used for 16K window */ 456420390f0SRanganathan Desikan mch_window = ioremap_nocache(mchbar, 0x1000); 457420390f0SRanganathan Desikan 458420390f0SRanganathan Desikan #ifdef i82975x_DEBUG_IOMEM 459420390f0SRanganathan Desikan i82975x_printk(KERN_INFO, "MCHBAR real = %0x, remapped = %p\n", 460420390f0SRanganathan Desikan mchbar, mch_window); 461420390f0SRanganathan Desikan 462420390f0SRanganathan Desikan c0drb[0] = readb(mch_window + I82975X_DRB_CH0R0); 463420390f0SRanganathan Desikan c0drb[1] = readb(mch_window + I82975X_DRB_CH0R1); 464420390f0SRanganathan Desikan c0drb[2] = readb(mch_window + I82975X_DRB_CH0R2); 465420390f0SRanganathan Desikan c0drb[3] = readb(mch_window + I82975X_DRB_CH0R3); 466420390f0SRanganathan Desikan c1drb[0] = readb(mch_window + I82975X_DRB_CH1R0); 467420390f0SRanganathan Desikan c1drb[1] = readb(mch_window + I82975X_DRB_CH1R1); 468420390f0SRanganathan Desikan c1drb[2] = readb(mch_window + I82975X_DRB_CH1R2); 469420390f0SRanganathan Desikan c1drb[3] = readb(mch_window + I82975X_DRB_CH1R3); 470420390f0SRanganathan Desikan i82975x_printk(KERN_INFO, "DRBCH0R0 = 0x%02x\n", c0drb[0]); 471420390f0SRanganathan Desikan i82975x_printk(KERN_INFO, "DRBCH0R1 = 0x%02x\n", c0drb[1]); 472420390f0SRanganathan Desikan i82975x_printk(KERN_INFO, "DRBCH0R2 = 0x%02x\n", c0drb[2]); 473420390f0SRanganathan Desikan i82975x_printk(KERN_INFO, "DRBCH0R3 = 0x%02x\n", c0drb[3]); 474420390f0SRanganathan Desikan i82975x_printk(KERN_INFO, "DRBCH1R0 = 0x%02x\n", c1drb[0]); 475420390f0SRanganathan Desikan i82975x_printk(KERN_INFO, "DRBCH1R1 = 0x%02x\n", c1drb[1]); 476420390f0SRanganathan Desikan i82975x_printk(KERN_INFO, "DRBCH1R2 = 0x%02x\n", c1drb[2]); 477420390f0SRanganathan Desikan i82975x_printk(KERN_INFO, "DRBCH1R3 = 0x%02x\n", c1drb[3]); 478420390f0SRanganathan Desikan #endif 479420390f0SRanganathan Desikan 480420390f0SRanganathan Desikan drc[0] = readl(mch_window + I82975X_DRC_CH0M0); 481420390f0SRanganathan Desikan drc[1] = readl(mch_window + I82975X_DRC_CH1M0); 482420390f0SRanganathan Desikan #ifdef i82975x_DEBUG_IOMEM 483420390f0SRanganathan Desikan i82975x_printk(KERN_INFO, "DRC_CH0 = %0x, %s\n", drc[0], 484420390f0SRanganathan Desikan ((drc[0] >> 21) & 3) == 1 ? 485420390f0SRanganathan Desikan "ECC enabled" : "ECC disabled"); 486420390f0SRanganathan Desikan i82975x_printk(KERN_INFO, "DRC_CH1 = %0x, %s\n", drc[1], 487420390f0SRanganathan Desikan ((drc[1] >> 21) & 3) == 1 ? 488420390f0SRanganathan Desikan "ECC enabled" : "ECC disabled"); 489420390f0SRanganathan Desikan 490420390f0SRanganathan Desikan i82975x_printk(KERN_INFO, "C0 BNKARC = %0x\n", 491420390f0SRanganathan Desikan readw(mch_window + I82975X_C0BNKARC)); 492420390f0SRanganathan Desikan i82975x_printk(KERN_INFO, "C1 BNKARC = %0x\n", 493420390f0SRanganathan Desikan readw(mch_window + I82975X_C1BNKARC)); 494420390f0SRanganathan Desikan i82975x_print_dram_timings(mch_window); 495420390f0SRanganathan Desikan goto fail1; 496420390f0SRanganathan Desikan #endif 497420390f0SRanganathan Desikan if (!(((drc[0] >> 21) & 3) == 1 || ((drc[1] >> 21) & 3) == 1)) { 498420390f0SRanganathan Desikan i82975x_printk(KERN_INFO, "ECC disabled on both channels.\n"); 499420390f0SRanganathan Desikan goto fail1; 500420390f0SRanganathan Desikan } 501420390f0SRanganathan Desikan 502420390f0SRanganathan Desikan chans = dual_channel_active(mch_window) + 1; 503420390f0SRanganathan Desikan 504420390f0SRanganathan Desikan /* assuming only one controller, index thus is 0 */ 505420390f0SRanganathan Desikan mci = edac_mc_alloc(sizeof(*pvt), I82975X_NR_CSROWS(chans), 506420390f0SRanganathan Desikan chans, 0); 507420390f0SRanganathan Desikan if (!mci) { 508420390f0SRanganathan Desikan rc = -ENOMEM; 509420390f0SRanganathan Desikan goto fail1; 510420390f0SRanganathan Desikan } 511420390f0SRanganathan Desikan 512420390f0SRanganathan Desikan debugf3("%s(): init mci\n", __func__); 513420390f0SRanganathan Desikan mci->dev = &pdev->dev; 514*da95b3d2SArvind R mci->mtype_cap = MEM_FLAG_DDR2; 515420390f0SRanganathan Desikan mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; 516420390f0SRanganathan Desikan mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; 517420390f0SRanganathan Desikan mci->mod_name = EDAC_MOD_STR; 518420390f0SRanganathan Desikan mci->mod_ver = I82975X_REVISION; 519420390f0SRanganathan Desikan mci->ctl_name = i82975x_devs[dev_idx].ctl_name; 520*da95b3d2SArvind R mci->dev_name = pci_name(pdev); 521420390f0SRanganathan Desikan mci->edac_check = i82975x_check; 522420390f0SRanganathan Desikan mci->ctl_page_to_phys = NULL; 523420390f0SRanganathan Desikan debugf3("%s(): init pvt\n", __func__); 524420390f0SRanganathan Desikan pvt = (struct i82975x_pvt *) mci->pvt_info; 525420390f0SRanganathan Desikan pvt->mch_window = mch_window; 526420390f0SRanganathan Desikan i82975x_init_csrows(mci, pdev, mch_window); 527*da95b3d2SArvind R mci->scrub_mode = SCRUB_HW_SRC; 528420390f0SRanganathan Desikan i82975x_get_error_info(mci, &discard); /* clear counters */ 529420390f0SRanganathan Desikan 530420390f0SRanganathan Desikan /* finalize this instance of memory controller with edac core */ 531420390f0SRanganathan Desikan if (edac_mc_add_mc(mci)) { 532420390f0SRanganathan Desikan debugf3("%s(): failed edac_mc_add_mc()\n", __func__); 533420390f0SRanganathan Desikan goto fail2; 534420390f0SRanganathan Desikan } 535420390f0SRanganathan Desikan 536420390f0SRanganathan Desikan /* get this far and it's successful */ 537420390f0SRanganathan Desikan debugf3("%s(): success\n", __func__); 538420390f0SRanganathan Desikan return 0; 539420390f0SRanganathan Desikan 540420390f0SRanganathan Desikan fail2: 541420390f0SRanganathan Desikan edac_mc_free(mci); 542420390f0SRanganathan Desikan 543420390f0SRanganathan Desikan fail1: 544420390f0SRanganathan Desikan iounmap(mch_window); 545420390f0SRanganathan Desikan fail0: 546420390f0SRanganathan Desikan return rc; 547420390f0SRanganathan Desikan } 548420390f0SRanganathan Desikan 549420390f0SRanganathan Desikan /* returns count (>= 0), or negative on error */ 550420390f0SRanganathan Desikan static int __devinit i82975x_init_one(struct pci_dev *pdev, 551420390f0SRanganathan Desikan const struct pci_device_id *ent) 552420390f0SRanganathan Desikan { 553420390f0SRanganathan Desikan int rc; 554420390f0SRanganathan Desikan 555420390f0SRanganathan Desikan debugf0("%s()\n", __func__); 556420390f0SRanganathan Desikan 557420390f0SRanganathan Desikan if (pci_enable_device(pdev) < 0) 558420390f0SRanganathan Desikan return -EIO; 559420390f0SRanganathan Desikan 560420390f0SRanganathan Desikan rc = i82975x_probe1(pdev, ent->driver_data); 561420390f0SRanganathan Desikan 562420390f0SRanganathan Desikan if (mci_pdev == NULL) 563420390f0SRanganathan Desikan mci_pdev = pci_dev_get(pdev); 564420390f0SRanganathan Desikan 565420390f0SRanganathan Desikan return rc; 566420390f0SRanganathan Desikan } 567420390f0SRanganathan Desikan 568420390f0SRanganathan Desikan static void __devexit i82975x_remove_one(struct pci_dev *pdev) 569420390f0SRanganathan Desikan { 570420390f0SRanganathan Desikan struct mem_ctl_info *mci; 571420390f0SRanganathan Desikan struct i82975x_pvt *pvt; 572420390f0SRanganathan Desikan 573420390f0SRanganathan Desikan debugf0("%s()\n", __func__); 574420390f0SRanganathan Desikan 575420390f0SRanganathan Desikan mci = edac_mc_del_mc(&pdev->dev); 576420390f0SRanganathan Desikan if (mci == NULL) 577420390f0SRanganathan Desikan return; 578420390f0SRanganathan Desikan 579420390f0SRanganathan Desikan pvt = mci->pvt_info; 580420390f0SRanganathan Desikan if (pvt->mch_window) 581420390f0SRanganathan Desikan iounmap( pvt->mch_window ); 582420390f0SRanganathan Desikan 583420390f0SRanganathan Desikan edac_mc_free(mci); 584420390f0SRanganathan Desikan } 585420390f0SRanganathan Desikan 586420390f0SRanganathan Desikan static const struct pci_device_id i82975x_pci_tbl[] __devinitdata = { 587420390f0SRanganathan Desikan { 588420390f0SRanganathan Desikan PCI_VEND_DEV(INTEL, 82975_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, 589420390f0SRanganathan Desikan I82975X 590420390f0SRanganathan Desikan }, 591420390f0SRanganathan Desikan { 592420390f0SRanganathan Desikan 0, 593420390f0SRanganathan Desikan } /* 0 terminated list. */ 594420390f0SRanganathan Desikan }; 595420390f0SRanganathan Desikan 596420390f0SRanganathan Desikan MODULE_DEVICE_TABLE(pci, i82975x_pci_tbl); 597420390f0SRanganathan Desikan 598420390f0SRanganathan Desikan static struct pci_driver i82975x_driver = { 599420390f0SRanganathan Desikan .name = EDAC_MOD_STR, 600420390f0SRanganathan Desikan .probe = i82975x_init_one, 601420390f0SRanganathan Desikan .remove = __devexit_p(i82975x_remove_one), 602420390f0SRanganathan Desikan .id_table = i82975x_pci_tbl, 603420390f0SRanganathan Desikan }; 604420390f0SRanganathan Desikan 605420390f0SRanganathan Desikan static int __init i82975x_init(void) 606420390f0SRanganathan Desikan { 607420390f0SRanganathan Desikan int pci_rc; 608420390f0SRanganathan Desikan 609420390f0SRanganathan Desikan debugf3("%s()\n", __func__); 610420390f0SRanganathan Desikan 611c3c52bceSHitoshi Mitake /* Ensure that the OPSTATE is set correctly for POLL or NMI */ 612c3c52bceSHitoshi Mitake opstate_init(); 613c3c52bceSHitoshi Mitake 614420390f0SRanganathan Desikan pci_rc = pci_register_driver(&i82975x_driver); 615420390f0SRanganathan Desikan if (pci_rc < 0) 616420390f0SRanganathan Desikan goto fail0; 617420390f0SRanganathan Desikan 618420390f0SRanganathan Desikan if (mci_pdev == NULL) { 619420390f0SRanganathan Desikan mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 620420390f0SRanganathan Desikan PCI_DEVICE_ID_INTEL_82975_0, NULL); 621420390f0SRanganathan Desikan 622420390f0SRanganathan Desikan if (!mci_pdev) { 623420390f0SRanganathan Desikan debugf0("i82975x pci_get_device fail\n"); 624420390f0SRanganathan Desikan pci_rc = -ENODEV; 625420390f0SRanganathan Desikan goto fail1; 626420390f0SRanganathan Desikan } 627420390f0SRanganathan Desikan 628420390f0SRanganathan Desikan pci_rc = i82975x_init_one(mci_pdev, i82975x_pci_tbl); 629420390f0SRanganathan Desikan 630420390f0SRanganathan Desikan if (pci_rc < 0) { 631420390f0SRanganathan Desikan debugf0("i82975x init fail\n"); 632420390f0SRanganathan Desikan pci_rc = -ENODEV; 633420390f0SRanganathan Desikan goto fail1; 634420390f0SRanganathan Desikan } 635420390f0SRanganathan Desikan } 636420390f0SRanganathan Desikan 637420390f0SRanganathan Desikan return 0; 638420390f0SRanganathan Desikan 639420390f0SRanganathan Desikan fail1: 640420390f0SRanganathan Desikan pci_unregister_driver(&i82975x_driver); 641420390f0SRanganathan Desikan 642420390f0SRanganathan Desikan fail0: 643420390f0SRanganathan Desikan if (mci_pdev != NULL) 644420390f0SRanganathan Desikan pci_dev_put(mci_pdev); 645420390f0SRanganathan Desikan 646420390f0SRanganathan Desikan return pci_rc; 647420390f0SRanganathan Desikan } 648420390f0SRanganathan Desikan 649420390f0SRanganathan Desikan static void __exit i82975x_exit(void) 650420390f0SRanganathan Desikan { 651420390f0SRanganathan Desikan debugf3("%s()\n", __func__); 652420390f0SRanganathan Desikan 653420390f0SRanganathan Desikan pci_unregister_driver(&i82975x_driver); 654420390f0SRanganathan Desikan 655420390f0SRanganathan Desikan if (!i82975x_registered) { 656420390f0SRanganathan Desikan i82975x_remove_one(mci_pdev); 657420390f0SRanganathan Desikan pci_dev_put(mci_pdev); 658420390f0SRanganathan Desikan } 659420390f0SRanganathan Desikan } 660420390f0SRanganathan Desikan 661420390f0SRanganathan Desikan module_init(i82975x_init); 662420390f0SRanganathan Desikan module_exit(i82975x_exit); 663420390f0SRanganathan Desikan 664420390f0SRanganathan Desikan MODULE_LICENSE("GPL"); 66525527885SArvind R MODULE_AUTHOR("Arvind R. <arvino55@gmail.com>"); 666420390f0SRanganathan Desikan MODULE_DESCRIPTION("MC support for Intel 82975 memory hub controllers"); 667c3c52bceSHitoshi Mitake 668c3c52bceSHitoshi Mitake module_param(edac_op_state, int, 0444); 669c3c52bceSHitoshi Mitake MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); 670