1fcaf780bSMauro Carvalho Chehab /* 2fcaf780bSMauro Carvalho Chehab * Intel 7300 class Memory Controllers kernel module (Clarksboro) 3fcaf780bSMauro Carvalho Chehab * 4fcaf780bSMauro Carvalho Chehab * This file may be distributed under the terms of the 5fcaf780bSMauro Carvalho Chehab * GNU General Public License version 2 only. 6fcaf780bSMauro Carvalho Chehab * 7fcaf780bSMauro Carvalho Chehab * Copyright (c) 2010 by: 8fcaf780bSMauro Carvalho Chehab * Mauro Carvalho Chehab <mchehab@redhat.com> 9fcaf780bSMauro Carvalho Chehab * 10fcaf780bSMauro Carvalho Chehab * Red Hat Inc. http://www.redhat.com 11fcaf780bSMauro Carvalho Chehab * 12fcaf780bSMauro Carvalho Chehab * Intel 7300 Chipset Memory Controller Hub (MCH) - Datasheet 13fcaf780bSMauro Carvalho Chehab * http://www.intel.com/Assets/PDF/datasheet/318082.pdf 14fcaf780bSMauro Carvalho Chehab * 15fcaf780bSMauro Carvalho Chehab * TODO: The chipset allow checking for PCI Express errors also. Currently, 16fcaf780bSMauro Carvalho Chehab * the driver covers only memory error errors 17fcaf780bSMauro Carvalho Chehab * 18fcaf780bSMauro Carvalho Chehab * This driver uses "csrows" EDAC attribute to represent DIMM slot# 19fcaf780bSMauro Carvalho Chehab */ 20fcaf780bSMauro Carvalho Chehab 21fcaf780bSMauro Carvalho Chehab #include <linux/module.h> 22fcaf780bSMauro Carvalho Chehab #include <linux/init.h> 23fcaf780bSMauro Carvalho Chehab #include <linux/pci.h> 24fcaf780bSMauro Carvalho Chehab #include <linux/pci_ids.h> 25fcaf780bSMauro Carvalho Chehab #include <linux/slab.h> 26fcaf780bSMauro Carvalho Chehab #include <linux/edac.h> 27fcaf780bSMauro Carvalho Chehab #include <linux/mmzone.h> 28fcaf780bSMauro Carvalho Chehab 29fcaf780bSMauro Carvalho Chehab #include "edac_core.h" 30fcaf780bSMauro Carvalho Chehab 31fcaf780bSMauro Carvalho Chehab /* 32fcaf780bSMauro Carvalho Chehab * Alter this version for the I7300 module when modifications are made 33fcaf780bSMauro Carvalho Chehab */ 34fcaf780bSMauro Carvalho Chehab #define I7300_REVISION " Ver: 1.0.0 " __DATE__ 35fcaf780bSMauro Carvalho Chehab 36fcaf780bSMauro Carvalho Chehab #define EDAC_MOD_STR "i7300_edac" 37fcaf780bSMauro Carvalho Chehab 38fcaf780bSMauro Carvalho Chehab #define i7300_printk(level, fmt, arg...) \ 39fcaf780bSMauro Carvalho Chehab edac_printk(level, "i7300", fmt, ##arg) 40fcaf780bSMauro Carvalho Chehab 41fcaf780bSMauro Carvalho Chehab #define i7300_mc_printk(mci, level, fmt, arg...) \ 42fcaf780bSMauro Carvalho Chehab edac_mc_chipset_printk(mci, level, "i7300", fmt, ##arg) 43fcaf780bSMauro Carvalho Chehab 44fcaf780bSMauro Carvalho Chehab /* 45fcaf780bSMauro Carvalho Chehab * Memory topology is organized as: 46fcaf780bSMauro Carvalho Chehab * Branch 0 - 2 channels: channels 0 and 1 (FDB0 PCI dev 21.0) 47fcaf780bSMauro Carvalho Chehab * Branch 1 - 2 channels: channels 2 and 3 (FDB1 PCI dev 22.0) 48fcaf780bSMauro Carvalho Chehab * Each channel can have to 8 DIMM sets (called as SLOTS) 49fcaf780bSMauro Carvalho Chehab * Slots should generally be filled in pairs 50fcaf780bSMauro Carvalho Chehab * Except on Single Channel mode of operation 51fcaf780bSMauro Carvalho Chehab * just slot 0/channel0 filled on this mode 52fcaf780bSMauro Carvalho Chehab * On normal operation mode, the two channels on a branch should be 53c3af2eafSMauro Carvalho Chehab * filled together for the same SLOT# 54fcaf780bSMauro Carvalho Chehab * When in mirrored mode, Branch 1 replicate memory at Branch 0, so, the four 55fcaf780bSMauro Carvalho Chehab * channels on both branches should be filled 56fcaf780bSMauro Carvalho Chehab */ 57fcaf780bSMauro Carvalho Chehab 58fcaf780bSMauro Carvalho Chehab /* Limits for i7300 */ 59fcaf780bSMauro Carvalho Chehab #define MAX_SLOTS 8 60fcaf780bSMauro Carvalho Chehab #define MAX_BRANCHES 2 61fcaf780bSMauro Carvalho Chehab #define MAX_CH_PER_BRANCH 2 62fcaf780bSMauro Carvalho Chehab #define MAX_CHANNELS (MAX_CH_PER_BRANCH * MAX_BRANCHES) 63fcaf780bSMauro Carvalho Chehab #define MAX_MIR 3 64fcaf780bSMauro Carvalho Chehab 65fcaf780bSMauro Carvalho Chehab #define to_channel(ch, branch) ((((branch)) << 1) | (ch)) 66fcaf780bSMauro Carvalho Chehab 67fcaf780bSMauro Carvalho Chehab #define to_csrow(slot, ch, branch) \ 68fcaf780bSMauro Carvalho Chehab (to_channel(ch, branch) | ((slot) << 2)) 69fcaf780bSMauro Carvalho Chehab 70c3af2eafSMauro Carvalho Chehab /* 71c3af2eafSMauro Carvalho Chehab * I7300 devices 72fcaf780bSMauro Carvalho Chehab * All 3 functions of Device 16 (0,1,2) share the SAME DID and 73fcaf780bSMauro Carvalho Chehab * uses PCI_DEVICE_ID_INTEL_I7300_MCH_ERR for device 16 (0,1,2), 74fcaf780bSMauro Carvalho Chehab * PCI_DEVICE_ID_INTEL_I7300_MCH_FB0 and PCI_DEVICE_ID_INTEL_I7300_MCH_FB1 75fcaf780bSMauro Carvalho Chehab * for device 21 (0,1). 76fcaf780bSMauro Carvalho Chehab */ 77fcaf780bSMauro Carvalho Chehab 78c3af2eafSMauro Carvalho Chehab /**************************************************** 79c3af2eafSMauro Carvalho Chehab * i7300 Register definitions for memory enumberation 80c3af2eafSMauro Carvalho Chehab ****************************************************/ 81c3af2eafSMauro Carvalho Chehab 82c3af2eafSMauro Carvalho Chehab /* 83c3af2eafSMauro Carvalho Chehab * Device 16, 84c3af2eafSMauro Carvalho Chehab * Function 0: System Address (not documented) 85c3af2eafSMauro Carvalho Chehab * Function 1: Memory Branch Map, Control, Errors Register 86c3af2eafSMauro Carvalho Chehab */ 87c3af2eafSMauro Carvalho Chehab 88fcaf780bSMauro Carvalho Chehab /* OFFSETS for Function 0 */ 89fcaf780bSMauro Carvalho Chehab #define AMBASE 0x48 /* AMB Mem Mapped Reg Region Base */ 90fcaf780bSMauro Carvalho Chehab #define MAXCH 0x56 /* Max Channel Number */ 91fcaf780bSMauro Carvalho Chehab #define MAXDIMMPERCH 0x57 /* Max DIMM PER Channel Number */ 92fcaf780bSMauro Carvalho Chehab 93fcaf780bSMauro Carvalho Chehab /* OFFSETS for Function 1 */ 94af3d8831SMauro Carvalho Chehab #define MC_SETTINGS 0x40 95d7de2bdbSMauro Carvalho Chehab #define IS_MIRRORED(mc) ((mc) & (1 << 16)) 96d7de2bdbSMauro Carvalho Chehab #define IS_ECC_ENABLED(mc) ((mc) & (1 << 5)) 97d7de2bdbSMauro Carvalho Chehab #define IS_RETRY_ENABLED(mc) ((mc) & (1 << 31)) 98d7de2bdbSMauro Carvalho Chehab #define IS_SCRBALGO_ENHANCED(mc) ((mc) & (1 << 8)) 99d7de2bdbSMauro Carvalho Chehab 100bb81a216SMauro Carvalho Chehab #define MC_SETTINGS_A 0x58 101bb81a216SMauro Carvalho Chehab #define IS_SINGLE_MODE(mca) ((mca) & (1 << 14)) 102d7de2bdbSMauro Carvalho Chehab 103fcaf780bSMauro Carvalho Chehab #define TOLM 0x6C 104fcaf780bSMauro Carvalho Chehab #define REDMEMB 0x7C 105fcaf780bSMauro Carvalho Chehab 106fcaf780bSMauro Carvalho Chehab #define MIR0 0x80 107fcaf780bSMauro Carvalho Chehab #define MIR1 0x84 108fcaf780bSMauro Carvalho Chehab #define MIR2 0x88 109fcaf780bSMauro Carvalho Chehab 110fcaf780bSMauro Carvalho Chehab /* 111fcaf780bSMauro Carvalho Chehab * Note: Other Intel EDAC drivers use AMBPRESENT to identify if the available 112fcaf780bSMauro Carvalho Chehab * memory. From datasheet item 7.3.1 (FB-DIMM technology & organization), it 113fcaf780bSMauro Carvalho Chehab * seems that we cannot use this information directly for the same usage. 114fcaf780bSMauro Carvalho Chehab * Each memory slot may have up to 2 AMB interfaces, one for income and another 115fcaf780bSMauro Carvalho Chehab * for outcome interface to the next slot. 116fcaf780bSMauro Carvalho Chehab * For now, the driver just stores the AMB present registers, but rely only at 117fcaf780bSMauro Carvalho Chehab * the MTR info to detect memory. 118fcaf780bSMauro Carvalho Chehab * Datasheet is also not clear about how to map each AMBPRESENT registers to 119fcaf780bSMauro Carvalho Chehab * one of the 4 available channels. 120fcaf780bSMauro Carvalho Chehab */ 121fcaf780bSMauro Carvalho Chehab #define AMBPRESENT_0 0x64 122fcaf780bSMauro Carvalho Chehab #define AMBPRESENT_1 0x66 123fcaf780bSMauro Carvalho Chehab 124fcaf780bSMauro Carvalho Chehab const static u16 mtr_regs [MAX_SLOTS] = { 125fcaf780bSMauro Carvalho Chehab 0x80, 0x84, 0x88, 0x8c, 126fcaf780bSMauro Carvalho Chehab 0x82, 0x86, 0x8a, 0x8e 127fcaf780bSMauro Carvalho Chehab }; 128fcaf780bSMauro Carvalho Chehab 129fcaf780bSMauro Carvalho Chehab /* Defines to extract the vaious fields from the 130fcaf780bSMauro Carvalho Chehab * MTRx - Memory Technology Registers 131fcaf780bSMauro Carvalho Chehab */ 132fcaf780bSMauro Carvalho Chehab #define MTR_DIMMS_PRESENT(mtr) ((mtr) & (1 << 8)) 133fcaf780bSMauro Carvalho Chehab #define MTR_DIMMS_ETHROTTLE(mtr) ((mtr) & (1 << 7)) 134fcaf780bSMauro Carvalho Chehab #define MTR_DRAM_WIDTH(mtr) (((mtr) & (1 << 6)) ? 8 : 4) 135fcaf780bSMauro Carvalho Chehab #define MTR_DRAM_BANKS(mtr) (((mtr) & (1 << 5)) ? 8 : 4) 136fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_RANKS(mtr) (((mtr) & (1 << 4)) ? 1 : 0) 137fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_ROWS(mtr) (((mtr) >> 2) & 0x3) 138fcaf780bSMauro Carvalho Chehab #define MTR_DRAM_BANKS_ADDR_BITS 2 139fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_ROWS_ADDR_BITS(mtr) (MTR_DIMM_ROWS(mtr) + 13) 140fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_COLS(mtr) ((mtr) & 0x3) 141fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_COLS_ADDR_BITS(mtr) (MTR_DIMM_COLS(mtr) + 10) 142fcaf780bSMauro Carvalho Chehab 143fcaf780bSMauro Carvalho Chehab #ifdef CONFIG_EDAC_DEBUG 144fcaf780bSMauro Carvalho Chehab /* MTR NUMROW */ 145fcaf780bSMauro Carvalho Chehab static const char *numrow_toString[] = { 146fcaf780bSMauro Carvalho Chehab "8,192 - 13 rows", 147fcaf780bSMauro Carvalho Chehab "16,384 - 14 rows", 148fcaf780bSMauro Carvalho Chehab "32,768 - 15 rows", 149fcaf780bSMauro Carvalho Chehab "65,536 - 16 rows" 150fcaf780bSMauro Carvalho Chehab }; 151fcaf780bSMauro Carvalho Chehab 152fcaf780bSMauro Carvalho Chehab /* MTR NUMCOL */ 153fcaf780bSMauro Carvalho Chehab static const char *numcol_toString[] = { 154fcaf780bSMauro Carvalho Chehab "1,024 - 10 columns", 155fcaf780bSMauro Carvalho Chehab "2,048 - 11 columns", 156fcaf780bSMauro Carvalho Chehab "4,096 - 12 columns", 157fcaf780bSMauro Carvalho Chehab "reserved" 158fcaf780bSMauro Carvalho Chehab }; 159fcaf780bSMauro Carvalho Chehab #endif 160fcaf780bSMauro Carvalho Chehab 161c3af2eafSMauro Carvalho Chehab /************************************************ 162c3af2eafSMauro Carvalho Chehab * i7300 Register definitions for error detection 163c3af2eafSMauro Carvalho Chehab ************************************************/ 16457021918SMauro Carvalho Chehab 16557021918SMauro Carvalho Chehab /* 16657021918SMauro Carvalho Chehab * Device 16.1: FBD Error Registers 16757021918SMauro Carvalho Chehab */ 16857021918SMauro Carvalho Chehab #define FERR_FAT_FBD 0x98 16957021918SMauro Carvalho Chehab static const char *ferr_fat_fbd_name[] = { 17057021918SMauro Carvalho Chehab [22] = "Non-Redundant Fast Reset Timeout", 17157021918SMauro Carvalho Chehab [2] = ">Tmid Thermal event with intelligent throttling disabled", 17257021918SMauro Carvalho Chehab [1] = "Memory or FBD configuration CRC read error", 17357021918SMauro Carvalho Chehab [0] = "Memory Write error on non-redundant retry or " 17457021918SMauro Carvalho Chehab "FBD configuration Write error on retry", 17557021918SMauro Carvalho Chehab }; 17657021918SMauro Carvalho Chehab #define GET_FBD_FAT_IDX(fbderr) (fbderr & (3 << 28)) 17757021918SMauro Carvalho Chehab #define FERR_FAT_FBD_ERR_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)) 17857021918SMauro Carvalho Chehab 17957021918SMauro Carvalho Chehab #define FERR_NF_FBD 0xa0 18057021918SMauro Carvalho Chehab static const char *ferr_nf_fbd_name[] = { 18157021918SMauro Carvalho Chehab [24] = "DIMM-Spare Copy Completed", 18257021918SMauro Carvalho Chehab [23] = "DIMM-Spare Copy Initiated", 18357021918SMauro Carvalho Chehab [22] = "Redundant Fast Reset Timeout", 18457021918SMauro Carvalho Chehab [21] = "Memory Write error on redundant retry", 18557021918SMauro Carvalho Chehab [18] = "SPD protocol Error", 18657021918SMauro Carvalho Chehab [17] = "FBD Northbound parity error on FBD Sync Status", 18757021918SMauro Carvalho Chehab [16] = "Correctable Patrol Data ECC", 18857021918SMauro Carvalho Chehab [15] = "Correctable Resilver- or Spare-Copy Data ECC", 18957021918SMauro Carvalho Chehab [14] = "Correctable Mirrored Demand Data ECC", 19057021918SMauro Carvalho Chehab [13] = "Correctable Non-Mirrored Demand Data ECC", 19157021918SMauro Carvalho Chehab [11] = "Memory or FBD configuration CRC read error", 19257021918SMauro Carvalho Chehab [10] = "FBD Configuration Write error on first attempt", 19357021918SMauro Carvalho Chehab [9] = "Memory Write error on first attempt", 19457021918SMauro Carvalho Chehab [8] = "Non-Aliased Uncorrectable Patrol Data ECC", 19557021918SMauro Carvalho Chehab [7] = "Non-Aliased Uncorrectable Resilver- or Spare-Copy Data ECC", 19657021918SMauro Carvalho Chehab [6] = "Non-Aliased Uncorrectable Mirrored Demand Data ECC", 19757021918SMauro Carvalho Chehab [5] = "Non-Aliased Uncorrectable Non-Mirrored Demand Data ECC", 19857021918SMauro Carvalho Chehab [4] = "Aliased Uncorrectable Patrol Data ECC", 19957021918SMauro Carvalho Chehab [3] = "Aliased Uncorrectable Resilver- or Spare-Copy Data ECC", 20057021918SMauro Carvalho Chehab [2] = "Aliased Uncorrectable Mirrored Demand Data ECC", 20157021918SMauro Carvalho Chehab [1] = "Aliased Uncorrectable Non-Mirrored Demand Data ECC", 20257021918SMauro Carvalho Chehab [0] = "Uncorrectable Data ECC on Replay", 20357021918SMauro Carvalho Chehab }; 20457021918SMauro Carvalho Chehab #define GET_FBD_NF_IDX(fbderr) (fbderr & (3 << 28)) 20557021918SMauro Carvalho Chehab #define FERR_NF_FBD_ERR_MASK ((1 << 24) | (1 << 23) | (1 << 22) | (1 << 21) |\ 20657021918SMauro Carvalho Chehab (1 << 18) | (1 << 17) | (1 << 16) | (1 << 15) |\ 20757021918SMauro Carvalho Chehab (1 << 14) | (1 << 13) | (1 << 11) | (1 << 10) |\ 20857021918SMauro Carvalho Chehab (1 << 9) | (1 << 8) | (1 << 7) | (1 << 6) |\ 20957021918SMauro Carvalho Chehab (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) |\ 21057021918SMauro Carvalho Chehab (1 << 1) | (1 << 0)) 21157021918SMauro Carvalho Chehab 21257021918SMauro Carvalho Chehab #define EMASK_FBD 0xa8 21357021918SMauro Carvalho Chehab #define EMASK_FBD_ERR_MASK ((1 << 27) | (1 << 26) | (1 << 25) | (1 << 24) |\ 21457021918SMauro Carvalho Chehab (1 << 22) | (1 << 21) | (1 << 20) | (1 << 19) |\ 21557021918SMauro Carvalho Chehab (1 << 18) | (1 << 17) | (1 << 16) | (1 << 14) |\ 21657021918SMauro Carvalho Chehab (1 << 13) | (1 << 12) | (1 << 11) | (1 << 10) |\ 21757021918SMauro Carvalho Chehab (1 << 9) | (1 << 8) | (1 << 7) | (1 << 6) |\ 21857021918SMauro Carvalho Chehab (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) |\ 21957021918SMauro Carvalho Chehab (1 << 1) | (1 << 0)) 22057021918SMauro Carvalho Chehab 221c3af2eafSMauro Carvalho Chehab /* 222c3af2eafSMauro Carvalho Chehab * Device 16.2: Global Error Registers 223c3af2eafSMauro Carvalho Chehab */ 224c3af2eafSMauro Carvalho Chehab 2255de6e07eSMauro Carvalho Chehab #define FERR_GLOBAL_HI 0x48 2265de6e07eSMauro Carvalho Chehab static const char *ferr_global_hi_name[] = { 2275de6e07eSMauro Carvalho Chehab [3] = "FSB 3 Fatal Error", 2285de6e07eSMauro Carvalho Chehab [2] = "FSB 2 Fatal Error", 2295de6e07eSMauro Carvalho Chehab [1] = "FSB 1 Fatal Error", 2305de6e07eSMauro Carvalho Chehab [0] = "FSB 0 Fatal Error", 2315de6e07eSMauro Carvalho Chehab }; 2325de6e07eSMauro Carvalho Chehab #define ferr_global_hi_is_fatal(errno) 1 2335de6e07eSMauro Carvalho Chehab 234c3af2eafSMauro Carvalho Chehab #define FERR_GLOBAL_LO 0x40 2355de6e07eSMauro Carvalho Chehab static const char *ferr_global_lo_name[] = { 236c3af2eafSMauro Carvalho Chehab [31] = "Internal MCH Fatal Error", 237c3af2eafSMauro Carvalho Chehab [30] = "Intel QuickData Technology Device Fatal Error", 238c3af2eafSMauro Carvalho Chehab [29] = "FSB1 Fatal Error", 239c3af2eafSMauro Carvalho Chehab [28] = "FSB0 Fatal Error", 240c3af2eafSMauro Carvalho Chehab [27] = "FBD Channel 3 Fatal Error", 241c3af2eafSMauro Carvalho Chehab [26] = "FBD Channel 2 Fatal Error", 242c3af2eafSMauro Carvalho Chehab [25] = "FBD Channel 1 Fatal Error", 243c3af2eafSMauro Carvalho Chehab [24] = "FBD Channel 0 Fatal Error", 244c3af2eafSMauro Carvalho Chehab [23] = "PCI Express Device 7Fatal Error", 245c3af2eafSMauro Carvalho Chehab [22] = "PCI Express Device 6 Fatal Error", 246c3af2eafSMauro Carvalho Chehab [21] = "PCI Express Device 5 Fatal Error", 247c3af2eafSMauro Carvalho Chehab [20] = "PCI Express Device 4 Fatal Error", 248c3af2eafSMauro Carvalho Chehab [19] = "PCI Express Device 3 Fatal Error", 249c3af2eafSMauro Carvalho Chehab [18] = "PCI Express Device 2 Fatal Error", 250c3af2eafSMauro Carvalho Chehab [17] = "PCI Express Device 1 Fatal Error", 251c3af2eafSMauro Carvalho Chehab [16] = "ESI Fatal Error", 252c3af2eafSMauro Carvalho Chehab [15] = "Internal MCH Non-Fatal Error", 253c3af2eafSMauro Carvalho Chehab [14] = "Intel QuickData Technology Device Non Fatal Error", 254c3af2eafSMauro Carvalho Chehab [13] = "FSB1 Non-Fatal Error", 255c3af2eafSMauro Carvalho Chehab [12] = "FSB 0 Non-Fatal Error", 256c3af2eafSMauro Carvalho Chehab [11] = "FBD Channel 3 Non-Fatal Error", 257c3af2eafSMauro Carvalho Chehab [10] = "FBD Channel 2 Non-Fatal Error", 258c3af2eafSMauro Carvalho Chehab [9] = "FBD Channel 1 Non-Fatal Error", 259c3af2eafSMauro Carvalho Chehab [8] = "FBD Channel 0 Non-Fatal Error", 260c3af2eafSMauro Carvalho Chehab [7] = "PCI Express Device 7 Non-Fatal Error", 261c3af2eafSMauro Carvalho Chehab [6] = "PCI Express Device 6 Non-Fatal Error", 262c3af2eafSMauro Carvalho Chehab [5] = "PCI Express Device 5 Non-Fatal Error", 263c3af2eafSMauro Carvalho Chehab [4] = "PCI Express Device 4 Non-Fatal Error", 264c3af2eafSMauro Carvalho Chehab [3] = "PCI Express Device 3 Non-Fatal Error", 265c3af2eafSMauro Carvalho Chehab [2] = "PCI Express Device 2 Non-Fatal Error", 266c3af2eafSMauro Carvalho Chehab [1] = "PCI Express Device 1 Non-Fatal Error", 267c3af2eafSMauro Carvalho Chehab [0] = "ESI Non-Fatal Error", 268c3af2eafSMauro Carvalho Chehab }; 2695de6e07eSMauro Carvalho Chehab #define ferr_global_lo_is_fatal(errno) ((errno < 16) ? 0 : 1) 270fcaf780bSMauro Carvalho Chehab 271fcaf780bSMauro Carvalho Chehab /* Device name and register DID (Device ID) */ 272fcaf780bSMauro Carvalho Chehab struct i7300_dev_info { 273fcaf780bSMauro Carvalho Chehab const char *ctl_name; /* name for this device */ 274fcaf780bSMauro Carvalho Chehab u16 fsb_mapping_errors; /* DID for the branchmap,control */ 275fcaf780bSMauro Carvalho Chehab }; 276fcaf780bSMauro Carvalho Chehab 277fcaf780bSMauro Carvalho Chehab /* Table of devices attributes supported by this driver */ 278fcaf780bSMauro Carvalho Chehab static const struct i7300_dev_info i7300_devs[] = { 279fcaf780bSMauro Carvalho Chehab { 280fcaf780bSMauro Carvalho Chehab .ctl_name = "I7300", 281fcaf780bSMauro Carvalho Chehab .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, 282fcaf780bSMauro Carvalho Chehab }, 283fcaf780bSMauro Carvalho Chehab }; 284fcaf780bSMauro Carvalho Chehab 285fcaf780bSMauro Carvalho Chehab struct i7300_dimm_info { 286fcaf780bSMauro Carvalho Chehab int megabytes; /* size, 0 means not present */ 287fcaf780bSMauro Carvalho Chehab }; 288fcaf780bSMauro Carvalho Chehab 289fcaf780bSMauro Carvalho Chehab /* driver private data structure */ 290fcaf780bSMauro Carvalho Chehab struct i7300_pvt { 2913e57eef6SMauro Carvalho Chehab struct pci_dev *pci_dev_16_0_fsb_ctlr; /* 16.0 */ 2923e57eef6SMauro Carvalho Chehab struct pci_dev *pci_dev_16_1_fsb_addr_map; /* 16.1 */ 2933e57eef6SMauro Carvalho Chehab struct pci_dev *pci_dev_16_2_fsb_err_regs; /* 16.2 */ 2943e57eef6SMauro Carvalho Chehab struct pci_dev *pci_dev_2x_0_fbd_branch[MAX_BRANCHES]; /* 21.0 and 22.0 */ 295fcaf780bSMauro Carvalho Chehab 296fcaf780bSMauro Carvalho Chehab u16 tolm; /* top of low memory */ 297fcaf780bSMauro Carvalho Chehab u64 ambase; /* AMB BAR */ 298fcaf780bSMauro Carvalho Chehab 299bb81a216SMauro Carvalho Chehab u32 mc_settings; /* Report several settings */ 300bb81a216SMauro Carvalho Chehab u32 mc_settings_a; 301bb81a216SMauro Carvalho Chehab 302bb81a216SMauro Carvalho Chehab u16 mir[MAX_MIR]; /* Memory Interleave Reg*/ 303fcaf780bSMauro Carvalho Chehab 304fcaf780bSMauro Carvalho Chehab u16 mtr[MAX_SLOTS][MAX_BRANCHES]; /* Memory Technlogy Reg */ 305fcaf780bSMauro Carvalho Chehab u16 ambpresent[MAX_CHANNELS]; /* AMB present regs */ 306fcaf780bSMauro Carvalho Chehab 307fcaf780bSMauro Carvalho Chehab /* DIMM information matrix, allocating architecture maximums */ 308fcaf780bSMauro Carvalho Chehab struct i7300_dimm_info dimm_info[MAX_SLOTS][MAX_CHANNELS]; 309*85580ea4SMauro Carvalho Chehab 310*85580ea4SMauro Carvalho Chehab /* Temporary buffer for use when preparing error messages */ 311*85580ea4SMauro Carvalho Chehab char *tmp_prt_buffer; 312fcaf780bSMauro Carvalho Chehab }; 313fcaf780bSMauro Carvalho Chehab 314fcaf780bSMauro Carvalho Chehab /* FIXME: Why do we need to have this static? */ 315fcaf780bSMauro Carvalho Chehab static struct edac_pci_ctl_info *i7300_pci; 316fcaf780bSMauro Carvalho Chehab 3175de6e07eSMauro Carvalho Chehab /******************************************** 3185de6e07eSMauro Carvalho Chehab * i7300 Functions related to error detection 3195de6e07eSMauro Carvalho Chehab ********************************************/ 320fcaf780bSMauro Carvalho Chehab 3215de6e07eSMauro Carvalho Chehab const char *get_err_from_table(const char *table[], int size, int pos) 322fcaf780bSMauro Carvalho Chehab { 3235de6e07eSMauro Carvalho Chehab if (pos >= size) 3245de6e07eSMauro Carvalho Chehab return "Reserved"; 3255de6e07eSMauro Carvalho Chehab 3265de6e07eSMauro Carvalho Chehab return table[pos]; 327fcaf780bSMauro Carvalho Chehab } 3285de6e07eSMauro Carvalho Chehab 3295de6e07eSMauro Carvalho Chehab #define GET_ERR_FROM_TABLE(table, pos) \ 3305de6e07eSMauro Carvalho Chehab get_err_from_table(table, ARRAY_SIZE(table), pos) 331fcaf780bSMauro Carvalho Chehab 332fcaf780bSMauro Carvalho Chehab /* 3335de6e07eSMauro Carvalho Chehab * i7300_process_error_global Retrieve the hardware error information from 3345de6e07eSMauro Carvalho Chehab * the hardware and cache it in the 'info' 3355de6e07eSMauro Carvalho Chehab * structure 3365de6e07eSMauro Carvalho Chehab */ 337f4277422SMauro Carvalho Chehab static void i7300_process_error_global(struct mem_ctl_info *mci) 3385de6e07eSMauro Carvalho Chehab { 339fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 3405de6e07eSMauro Carvalho Chehab u32 errnum, value; 3415de6e07eSMauro Carvalho Chehab unsigned long errors; 3425de6e07eSMauro Carvalho Chehab const char *specific; 3435de6e07eSMauro Carvalho Chehab bool is_fatal; 344fcaf780bSMauro Carvalho Chehab 345fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 346fcaf780bSMauro Carvalho Chehab 347fcaf780bSMauro Carvalho Chehab /* read in the 1st FATAL error register */ 3485de6e07eSMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 3495de6e07eSMauro Carvalho Chehab FERR_GLOBAL_HI, &value); 3505de6e07eSMauro Carvalho Chehab if (unlikely(value)) { 3515de6e07eSMauro Carvalho Chehab errors = value; 3525de6e07eSMauro Carvalho Chehab errnum = find_first_bit(&errors, 3535de6e07eSMauro Carvalho Chehab ARRAY_SIZE(ferr_global_hi_name)); 3545de6e07eSMauro Carvalho Chehab specific = GET_ERR_FROM_TABLE(ferr_global_hi_name, errnum); 3555de6e07eSMauro Carvalho Chehab is_fatal = ferr_global_hi_is_fatal(errnum); 35686002324SMauro Carvalho Chehab 35786002324SMauro Carvalho Chehab /* Clear the error bit */ 35886002324SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 35986002324SMauro Carvalho Chehab FERR_GLOBAL_HI, value); 36086002324SMauro Carvalho Chehab 3615de6e07eSMauro Carvalho Chehab goto error_global; 362fcaf780bSMauro Carvalho Chehab } 363fcaf780bSMauro Carvalho Chehab 3645de6e07eSMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 3655de6e07eSMauro Carvalho Chehab FERR_GLOBAL_LO, &value); 3665de6e07eSMauro Carvalho Chehab if (unlikely(value)) { 3675de6e07eSMauro Carvalho Chehab errors = value; 3685de6e07eSMauro Carvalho Chehab errnum = find_first_bit(&errors, 3695de6e07eSMauro Carvalho Chehab ARRAY_SIZE(ferr_global_lo_name)); 3705de6e07eSMauro Carvalho Chehab specific = GET_ERR_FROM_TABLE(ferr_global_lo_name, errnum); 3715de6e07eSMauro Carvalho Chehab is_fatal = ferr_global_lo_is_fatal(errnum); 37286002324SMauro Carvalho Chehab 37386002324SMauro Carvalho Chehab /* Clear the error bit */ 37486002324SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 37586002324SMauro Carvalho Chehab FERR_GLOBAL_LO, value); 37686002324SMauro Carvalho Chehab 3775de6e07eSMauro Carvalho Chehab goto error_global; 378fcaf780bSMauro Carvalho Chehab } 379fcaf780bSMauro Carvalho Chehab return; 380fcaf780bSMauro Carvalho Chehab 3815de6e07eSMauro Carvalho Chehab error_global: 3825de6e07eSMauro Carvalho Chehab i7300_mc_printk(mci, KERN_EMERG, "%s misc error: %s\n", 3835de6e07eSMauro Carvalho Chehab is_fatal ? "Fatal" : "NOT fatal", specific); 384fcaf780bSMauro Carvalho Chehab } 385fcaf780bSMauro Carvalho Chehab 386fcaf780bSMauro Carvalho Chehab /* 38757021918SMauro Carvalho Chehab * i7300_process_fbd_error Retrieve the hardware error information from 38857021918SMauro Carvalho Chehab * the hardware and cache it in the 'info' 38957021918SMauro Carvalho Chehab * structure 39057021918SMauro Carvalho Chehab */ 391f4277422SMauro Carvalho Chehab static void i7300_process_fbd_error(struct mem_ctl_info *mci) 39257021918SMauro Carvalho Chehab { 39357021918SMauro Carvalho Chehab struct i7300_pvt *pvt; 39457021918SMauro Carvalho Chehab u32 errnum, value; 39557021918SMauro Carvalho Chehab int branch; 39657021918SMauro Carvalho Chehab unsigned long errors; 39757021918SMauro Carvalho Chehab const char *specific; 39857021918SMauro Carvalho Chehab bool is_fatal; 39957021918SMauro Carvalho Chehab 40057021918SMauro Carvalho Chehab pvt = mci->pvt_info; 40157021918SMauro Carvalho Chehab 40257021918SMauro Carvalho Chehab /* read in the 1st FATAL error register */ 40357021918SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 40457021918SMauro Carvalho Chehab FERR_FAT_FBD, &value); 40557021918SMauro Carvalho Chehab if (unlikely(value & FERR_FAT_FBD_ERR_MASK)) { 40657021918SMauro Carvalho Chehab errors = value & FERR_FAT_FBD_ERR_MASK ; 40757021918SMauro Carvalho Chehab errnum = find_first_bit(&errors, 40857021918SMauro Carvalho Chehab ARRAY_SIZE(ferr_fat_fbd_name)); 40957021918SMauro Carvalho Chehab specific = GET_ERR_FROM_TABLE(ferr_fat_fbd_name, errnum); 41057021918SMauro Carvalho Chehab is_fatal = 1; 41157021918SMauro Carvalho Chehab 41257021918SMauro Carvalho Chehab branch = (GET_FBD_FAT_IDX(value) == 2) ? 1 : 0; 41357021918SMauro Carvalho Chehab 41457021918SMauro Carvalho Chehab goto error_fbd; 41557021918SMauro Carvalho Chehab } 41657021918SMauro Carvalho Chehab 41757021918SMauro Carvalho Chehab /* read in the 1st NON-FATAL error register */ 41857021918SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 41957021918SMauro Carvalho Chehab FERR_NF_FBD, &value); 42057021918SMauro Carvalho Chehab if (unlikely(value & FERR_NF_FBD_ERR_MASK)) { 42157021918SMauro Carvalho Chehab errors = value & FERR_NF_FBD_ERR_MASK; 42257021918SMauro Carvalho Chehab errnum = find_first_bit(&errors, 42357021918SMauro Carvalho Chehab ARRAY_SIZE(ferr_nf_fbd_name)); 42457021918SMauro Carvalho Chehab specific = GET_ERR_FROM_TABLE(ferr_nf_fbd_name, errnum); 42557021918SMauro Carvalho Chehab is_fatal = 0; 42657021918SMauro Carvalho Chehab 42757021918SMauro Carvalho Chehab /* Clear the error bit */ 42857021918SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 42957021918SMauro Carvalho Chehab FERR_GLOBAL_LO, value); 43057021918SMauro Carvalho Chehab 43157021918SMauro Carvalho Chehab goto error_fbd; 43257021918SMauro Carvalho Chehab } 43357021918SMauro Carvalho Chehab return; 43457021918SMauro Carvalho Chehab 43557021918SMauro Carvalho Chehab error_fbd: 43657021918SMauro Carvalho Chehab i7300_mc_printk(mci, KERN_EMERG, "%s FBD error on branch %d: %s\n", 43757021918SMauro Carvalho Chehab is_fatal ? "Fatal" : "NOT fatal", branch, specific); 43857021918SMauro Carvalho Chehab } 43957021918SMauro Carvalho Chehab 44057021918SMauro Carvalho Chehab /* 441f4277422SMauro Carvalho Chehab * i7300_check_error Retrieve the hardware error information from 4425de6e07eSMauro Carvalho Chehab * the hardware and cache it in the 'info' 4435de6e07eSMauro Carvalho Chehab * structure 444fcaf780bSMauro Carvalho Chehab */ 445f4277422SMauro Carvalho Chehab static void i7300_check_error(struct mem_ctl_info *mci) 4465de6e07eSMauro Carvalho Chehab { 447f4277422SMauro Carvalho Chehab i7300_process_error_global(mci); 448f4277422SMauro Carvalho Chehab i7300_process_fbd_error(mci); 4495de6e07eSMauro Carvalho Chehab }; 450fcaf780bSMauro Carvalho Chehab 451fcaf780bSMauro Carvalho Chehab /* 452fcaf780bSMauro Carvalho Chehab * i7300_clear_error Retrieve any error from the hardware 453fcaf780bSMauro Carvalho Chehab * but do NOT process that error. 454fcaf780bSMauro Carvalho Chehab * Used for 'clearing' out of previous errors 455fcaf780bSMauro Carvalho Chehab * Called by the Core module. 456fcaf780bSMauro Carvalho Chehab */ 457fcaf780bSMauro Carvalho Chehab static void i7300_clear_error(struct mem_ctl_info *mci) 458fcaf780bSMauro Carvalho Chehab { 459e4327605SMauro Carvalho Chehab struct i7300_pvt *pvt = mci->pvt_info; 460e4327605SMauro Carvalho Chehab u32 value; 461e4327605SMauro Carvalho Chehab /* 462e4327605SMauro Carvalho Chehab * All error values are RWC - we need to read and write 1 to the 463e4327605SMauro Carvalho Chehab * bit that we want to cleanup 464e4327605SMauro Carvalho Chehab */ 465fcaf780bSMauro Carvalho Chehab 466e4327605SMauro Carvalho Chehab /* Clear global error registers */ 467e4327605SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 468e4327605SMauro Carvalho Chehab FERR_GLOBAL_HI, &value); 469e4327605SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 470e4327605SMauro Carvalho Chehab FERR_GLOBAL_HI, value); 471e4327605SMauro Carvalho Chehab 472e4327605SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 473e4327605SMauro Carvalho Chehab FERR_GLOBAL_LO, &value); 474e4327605SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 475e4327605SMauro Carvalho Chehab FERR_GLOBAL_LO, value); 476e4327605SMauro Carvalho Chehab 477e4327605SMauro Carvalho Chehab /* Clear FBD error registers */ 478e4327605SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 479e4327605SMauro Carvalho Chehab FERR_FAT_FBD, &value); 480e4327605SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 481e4327605SMauro Carvalho Chehab FERR_FAT_FBD, value); 482e4327605SMauro Carvalho Chehab 483e4327605SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 484e4327605SMauro Carvalho Chehab FERR_NF_FBD, &value); 485e4327605SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 486e4327605SMauro Carvalho Chehab FERR_NF_FBD, value); 487fcaf780bSMauro Carvalho Chehab } 488fcaf780bSMauro Carvalho Chehab 489fcaf780bSMauro Carvalho Chehab /* 490fcaf780bSMauro Carvalho Chehab * i7300_enable_error_reporting 491fcaf780bSMauro Carvalho Chehab * Turn on the memory reporting features of the hardware 492fcaf780bSMauro Carvalho Chehab */ 493fcaf780bSMauro Carvalho Chehab static void i7300_enable_error_reporting(struct mem_ctl_info *mci) 494fcaf780bSMauro Carvalho Chehab { 49557021918SMauro Carvalho Chehab struct i7300_pvt *pvt = mci->pvt_info; 49657021918SMauro Carvalho Chehab u32 fbd_error_mask; 49757021918SMauro Carvalho Chehab 49857021918SMauro Carvalho Chehab /* Read the FBD Error Mask Register */ 49957021918SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 50057021918SMauro Carvalho Chehab EMASK_FBD, &fbd_error_mask); 50157021918SMauro Carvalho Chehab 50257021918SMauro Carvalho Chehab /* Enable with a '0' */ 50357021918SMauro Carvalho Chehab fbd_error_mask &= ~(EMASK_FBD_ERR_MASK); 50457021918SMauro Carvalho Chehab 50557021918SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 50657021918SMauro Carvalho Chehab EMASK_FBD, fbd_error_mask); 507fcaf780bSMauro Carvalho Chehab } 5085de6e07eSMauro Carvalho Chehab 5095de6e07eSMauro Carvalho Chehab /************************************************ 5105de6e07eSMauro Carvalho Chehab * i7300 Functions related to memory enumberation 5115de6e07eSMauro Carvalho Chehab ************************************************/ 512fcaf780bSMauro Carvalho Chehab 513fcaf780bSMauro Carvalho Chehab /* 514fcaf780bSMauro Carvalho Chehab * determine_mtr(pvt, csrow, channel) 515fcaf780bSMauro Carvalho Chehab * 516fcaf780bSMauro Carvalho Chehab * return the proper MTR register as determine by the csrow and desired channel 517fcaf780bSMauro Carvalho Chehab */ 518fcaf780bSMauro Carvalho Chehab static int decode_mtr(struct i7300_pvt *pvt, 519fcaf780bSMauro Carvalho Chehab int slot, int ch, int branch, 520fcaf780bSMauro Carvalho Chehab struct i7300_dimm_info *dinfo, 521fcaf780bSMauro Carvalho Chehab struct csrow_info *p_csrow) 522fcaf780bSMauro Carvalho Chehab { 523fcaf780bSMauro Carvalho Chehab int mtr, ans, addrBits, channel; 524fcaf780bSMauro Carvalho Chehab 525fcaf780bSMauro Carvalho Chehab channel = to_channel(ch, branch); 526fcaf780bSMauro Carvalho Chehab 527fcaf780bSMauro Carvalho Chehab mtr = pvt->mtr[slot][branch]; 528fcaf780bSMauro Carvalho Chehab ans = MTR_DIMMS_PRESENT(mtr) ? 1 : 0; 529fcaf780bSMauro Carvalho Chehab 530fcaf780bSMauro Carvalho Chehab debugf2("\tMTR%d CH%d: DIMMs are %s (mtr)\n", 531fcaf780bSMauro Carvalho Chehab slot, channel, 532fcaf780bSMauro Carvalho Chehab ans ? "Present" : "NOT Present"); 533fcaf780bSMauro Carvalho Chehab 534fcaf780bSMauro Carvalho Chehab /* Determine if there is a DIMM present in this DIMM slot */ 535fcaf780bSMauro Carvalho Chehab 536fcaf780bSMauro Carvalho Chehab #if 0 537fcaf780bSMauro Carvalho Chehab if (!amb_present || !ans) 538fcaf780bSMauro Carvalho Chehab return 0; 539fcaf780bSMauro Carvalho Chehab #else 540fcaf780bSMauro Carvalho Chehab if (!ans) 541fcaf780bSMauro Carvalho Chehab return 0; 542fcaf780bSMauro Carvalho Chehab #endif 543fcaf780bSMauro Carvalho Chehab 544fcaf780bSMauro Carvalho Chehab /* Start with the number of bits for a Bank 545fcaf780bSMauro Carvalho Chehab * on the DRAM */ 546fcaf780bSMauro Carvalho Chehab addrBits = MTR_DRAM_BANKS_ADDR_BITS; 547fcaf780bSMauro Carvalho Chehab /* Add thenumber of ROW bits */ 548fcaf780bSMauro Carvalho Chehab addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr); 549fcaf780bSMauro Carvalho Chehab /* add the number of COLUMN bits */ 550fcaf780bSMauro Carvalho Chehab addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr); 551fcaf780bSMauro Carvalho Chehab /* add the number of RANK bits */ 552fcaf780bSMauro Carvalho Chehab addrBits += MTR_DIMM_RANKS(mtr); 553fcaf780bSMauro Carvalho Chehab 554fcaf780bSMauro Carvalho Chehab addrBits += 6; /* add 64 bits per DIMM */ 555fcaf780bSMauro Carvalho Chehab addrBits -= 20; /* divide by 2^^20 */ 556fcaf780bSMauro Carvalho Chehab addrBits -= 3; /* 8 bits per bytes */ 557fcaf780bSMauro Carvalho Chehab 558fcaf780bSMauro Carvalho Chehab dinfo->megabytes = 1 << addrBits; 559fcaf780bSMauro Carvalho Chehab 560fcaf780bSMauro Carvalho Chehab debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr)); 561fcaf780bSMauro Carvalho Chehab 562fcaf780bSMauro Carvalho Chehab debugf2("\t\tELECTRICAL THROTTLING is %s\n", 563fcaf780bSMauro Carvalho Chehab MTR_DIMMS_ETHROTTLE(mtr) ? "enabled" : "disabled"); 564fcaf780bSMauro Carvalho Chehab 565fcaf780bSMauro Carvalho Chehab debugf2("\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr)); 566fcaf780bSMauro Carvalho Chehab debugf2("\t\tNUMRANK: %s\n", MTR_DIMM_RANKS(mtr) ? "double" : "single"); 567fcaf780bSMauro Carvalho Chehab debugf2("\t\tNUMROW: %s\n", numrow_toString[MTR_DIMM_ROWS(mtr)]); 568fcaf780bSMauro Carvalho Chehab debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]); 569fcaf780bSMauro Carvalho Chehab debugf2("\t\tSIZE: %d MB\n", dinfo->megabytes); 570fcaf780bSMauro Carvalho Chehab 571fcaf780bSMauro Carvalho Chehab p_csrow->grain = 8; 572fcaf780bSMauro Carvalho Chehab p_csrow->nr_pages = dinfo->megabytes << 8; 573fcaf780bSMauro Carvalho Chehab p_csrow->mtype = MEM_FB_DDR2; 574116389edSMauro Carvalho Chehab 575116389edSMauro Carvalho Chehab /* 57615154c57SMauro Carvalho Chehab * The type of error detection actually depends of the 577116389edSMauro Carvalho Chehab * mode of operation. When it is just one single memory chip, at 578116389edSMauro Carvalho Chehab * socket 0, channel 0, it uses 8-byte-over-32-byte SECDED+ code. 57915154c57SMauro Carvalho Chehab * In normal or mirrored mode, it uses Lockstep mode, 580116389edSMauro Carvalho Chehab * with the possibility of using an extended algorithm for x8 memories 581116389edSMauro Carvalho Chehab * See datasheet Sections 7.3.6 to 7.3.8 582116389edSMauro Carvalho Chehab */ 58315154c57SMauro Carvalho Chehab 58415154c57SMauro Carvalho Chehab if (IS_SINGLE_MODE(pvt->mc_settings_a)) { 58515154c57SMauro Carvalho Chehab p_csrow->edac_mode = EDAC_SECDED; 5863b330f67SMauro Carvalho Chehab debugf2("\t\tECC code is 8-byte-over-32-byte SECDED+ code\n"); 58715154c57SMauro Carvalho Chehab } else { 5883b330f67SMauro Carvalho Chehab debugf2("\t\tECC code is on Lockstep mode\n"); 58928c2ce7cSMauro Carvalho Chehab if (MTR_DRAM_WIDTH(mtr) == 8) 590fcaf780bSMauro Carvalho Chehab p_csrow->edac_mode = EDAC_S8ECD8ED; 59115154c57SMauro Carvalho Chehab else 59215154c57SMauro Carvalho Chehab p_csrow->edac_mode = EDAC_S4ECD4ED; 59315154c57SMauro Carvalho Chehab } 594fcaf780bSMauro Carvalho Chehab 595fcaf780bSMauro Carvalho Chehab /* ask what device type on this row */ 59628c2ce7cSMauro Carvalho Chehab if (MTR_DRAM_WIDTH(mtr) == 8) { 5973b330f67SMauro Carvalho Chehab debugf2("\t\tScrub algorithm for x8 is on %s mode\n", 598d7de2bdbSMauro Carvalho Chehab IS_SCRBALGO_ENHANCED(pvt->mc_settings) ? 599d7de2bdbSMauro Carvalho Chehab "enhanced" : "normal"); 600d7de2bdbSMauro Carvalho Chehab 601fcaf780bSMauro Carvalho Chehab p_csrow->dtype = DEV_X8; 602d7de2bdbSMauro Carvalho Chehab } else 603fcaf780bSMauro Carvalho Chehab p_csrow->dtype = DEV_X4; 604fcaf780bSMauro Carvalho Chehab 605fcaf780bSMauro Carvalho Chehab return mtr; 606fcaf780bSMauro Carvalho Chehab } 607fcaf780bSMauro Carvalho Chehab 608fcaf780bSMauro Carvalho Chehab /* 609fcaf780bSMauro Carvalho Chehab * print_dimm_size 610fcaf780bSMauro Carvalho Chehab * 611fcaf780bSMauro Carvalho Chehab * also will output a DIMM matrix map, if debug is enabled, for viewing 612fcaf780bSMauro Carvalho Chehab * how the DIMMs are populated 613fcaf780bSMauro Carvalho Chehab */ 614fcaf780bSMauro Carvalho Chehab static void print_dimm_size(struct i7300_pvt *pvt) 615fcaf780bSMauro Carvalho Chehab { 616fcaf780bSMauro Carvalho Chehab struct i7300_dimm_info *dinfo; 617*85580ea4SMauro Carvalho Chehab char *p; 618fcaf780bSMauro Carvalho Chehab int space, n; 619fcaf780bSMauro Carvalho Chehab int channel, slot; 620fcaf780bSMauro Carvalho Chehab 621fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 622*85580ea4SMauro Carvalho Chehab p = pvt->tmp_prt_buffer; 623fcaf780bSMauro Carvalho Chehab 624fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, " "); 625fcaf780bSMauro Carvalho Chehab p += n; 626fcaf780bSMauro Carvalho Chehab space -= n; 627fcaf780bSMauro Carvalho Chehab for (channel = 0; channel < MAX_CHANNELS; channel++) { 628fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "channel %d | ", channel); 629fcaf780bSMauro Carvalho Chehab p += n; 630fcaf780bSMauro Carvalho Chehab space -= n; 631fcaf780bSMauro Carvalho Chehab } 632*85580ea4SMauro Carvalho Chehab debugf2("%s\n", pvt->tmp_prt_buffer); 633*85580ea4SMauro Carvalho Chehab p = pvt->tmp_prt_buffer; 634fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 635fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "-------------------------------" 636fcaf780bSMauro Carvalho Chehab "------------------------------"); 637fcaf780bSMauro Carvalho Chehab p += n; 638fcaf780bSMauro Carvalho Chehab space -= n; 639*85580ea4SMauro Carvalho Chehab debugf2("%s\n", pvt->tmp_prt_buffer); 640*85580ea4SMauro Carvalho Chehab p = pvt->tmp_prt_buffer; 641fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 642fcaf780bSMauro Carvalho Chehab 643fcaf780bSMauro Carvalho Chehab for (slot = 0; slot < MAX_SLOTS; slot++) { 644fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "csrow/SLOT %d ", slot); 645fcaf780bSMauro Carvalho Chehab p += n; 646fcaf780bSMauro Carvalho Chehab space -= n; 647fcaf780bSMauro Carvalho Chehab 648fcaf780bSMauro Carvalho Chehab for (channel = 0; channel < MAX_CHANNELS; channel++) { 649fcaf780bSMauro Carvalho Chehab dinfo = &pvt->dimm_info[slot][channel]; 650fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "%4d MB | ", dinfo->megabytes); 651fcaf780bSMauro Carvalho Chehab p += n; 652fcaf780bSMauro Carvalho Chehab space -= n; 653fcaf780bSMauro Carvalho Chehab } 654fcaf780bSMauro Carvalho Chehab 655*85580ea4SMauro Carvalho Chehab debugf2("%s\n", pvt->tmp_prt_buffer); 656*85580ea4SMauro Carvalho Chehab p = pvt->tmp_prt_buffer; 657fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 658fcaf780bSMauro Carvalho Chehab } 659fcaf780bSMauro Carvalho Chehab 660fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "-------------------------------" 661fcaf780bSMauro Carvalho Chehab "------------------------------"); 662fcaf780bSMauro Carvalho Chehab p += n; 663fcaf780bSMauro Carvalho Chehab space -= n; 664*85580ea4SMauro Carvalho Chehab debugf2("%s\n", pvt->tmp_prt_buffer); 665*85580ea4SMauro Carvalho Chehab p = pvt->tmp_prt_buffer; 666fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 667fcaf780bSMauro Carvalho Chehab } 668fcaf780bSMauro Carvalho Chehab 669fcaf780bSMauro Carvalho Chehab /* 670fcaf780bSMauro Carvalho Chehab * i7300_init_csrows Initialize the 'csrows' table within 671fcaf780bSMauro Carvalho Chehab * the mci control structure with the 672fcaf780bSMauro Carvalho Chehab * addressing of memory. 673fcaf780bSMauro Carvalho Chehab * 674fcaf780bSMauro Carvalho Chehab * return: 675fcaf780bSMauro Carvalho Chehab * 0 success 676fcaf780bSMauro Carvalho Chehab * 1 no actual memory found on this MC 677fcaf780bSMauro Carvalho Chehab */ 678fcaf780bSMauro Carvalho Chehab static int i7300_init_csrows(struct mem_ctl_info *mci) 679fcaf780bSMauro Carvalho Chehab { 680fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 681fcaf780bSMauro Carvalho Chehab struct i7300_dimm_info *dinfo; 682fcaf780bSMauro Carvalho Chehab struct csrow_info *p_csrow; 683fcaf780bSMauro Carvalho Chehab int empty; 684fcaf780bSMauro Carvalho Chehab int mtr; 685fcaf780bSMauro Carvalho Chehab int ch, branch, slot, channel; 686fcaf780bSMauro Carvalho Chehab 687fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 688fcaf780bSMauro Carvalho Chehab 689fcaf780bSMauro Carvalho Chehab empty = 1; /* Assume NO memory */ 690fcaf780bSMauro Carvalho Chehab 691fcaf780bSMauro Carvalho Chehab debugf2("Memory Technology Registers:\n"); 692fcaf780bSMauro Carvalho Chehab 693fcaf780bSMauro Carvalho Chehab /* Get the AMB present registers for the four channels */ 694fcaf780bSMauro Carvalho Chehab for (branch = 0; branch < MAX_BRANCHES; branch++) { 695fcaf780bSMauro Carvalho Chehab /* Read and dump branch 0's MTRs */ 696fcaf780bSMauro Carvalho Chehab channel = to_channel(0, branch); 6973e57eef6SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch], AMBPRESENT_0, 698fcaf780bSMauro Carvalho Chehab &pvt->ambpresent[channel]); 699fcaf780bSMauro Carvalho Chehab debugf2("\t\tAMB-present CH%d = 0x%x:\n", 700fcaf780bSMauro Carvalho Chehab channel, pvt->ambpresent[channel]); 701fcaf780bSMauro Carvalho Chehab 702fcaf780bSMauro Carvalho Chehab channel = to_channel(1, branch); 7033e57eef6SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch], AMBPRESENT_1, 704fcaf780bSMauro Carvalho Chehab &pvt->ambpresent[channel]); 705fcaf780bSMauro Carvalho Chehab debugf2("\t\tAMB-present CH%d = 0x%x:\n", 706fcaf780bSMauro Carvalho Chehab channel, pvt->ambpresent[channel]); 707fcaf780bSMauro Carvalho Chehab } 708fcaf780bSMauro Carvalho Chehab 709fcaf780bSMauro Carvalho Chehab /* Get the set of MTR[0-7] regs by each branch */ 710fcaf780bSMauro Carvalho Chehab for (slot = 0; slot < MAX_SLOTS; slot++) { 711fcaf780bSMauro Carvalho Chehab int where = mtr_regs[slot]; 712fcaf780bSMauro Carvalho Chehab for (branch = 0; branch < MAX_BRANCHES; branch++) { 7133e57eef6SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch], 714fcaf780bSMauro Carvalho Chehab where, 715fcaf780bSMauro Carvalho Chehab &pvt->mtr[slot][branch]); 716fcaf780bSMauro Carvalho Chehab for (ch = 0; ch < MAX_BRANCHES; ch++) { 717fcaf780bSMauro Carvalho Chehab int channel = to_channel(ch, branch); 718fcaf780bSMauro Carvalho Chehab 719fcaf780bSMauro Carvalho Chehab dinfo = &pvt->dimm_info[slot][channel]; 720fcaf780bSMauro Carvalho Chehab p_csrow = &mci->csrows[slot]; 721fcaf780bSMauro Carvalho Chehab 722fcaf780bSMauro Carvalho Chehab mtr = decode_mtr(pvt, slot, ch, branch, 723fcaf780bSMauro Carvalho Chehab dinfo, p_csrow); 724fcaf780bSMauro Carvalho Chehab /* if no DIMMS on this row, continue */ 725fcaf780bSMauro Carvalho Chehab if (!MTR_DIMMS_PRESENT(mtr)) 726fcaf780bSMauro Carvalho Chehab continue; 727fcaf780bSMauro Carvalho Chehab 728fcaf780bSMauro Carvalho Chehab p_csrow->csrow_idx = slot; 729fcaf780bSMauro Carvalho Chehab 730fcaf780bSMauro Carvalho Chehab /* FAKE OUT VALUES, FIXME */ 731fcaf780bSMauro Carvalho Chehab p_csrow->first_page = 0 + slot * 20; 732fcaf780bSMauro Carvalho Chehab p_csrow->last_page = 9 + slot * 20; 733fcaf780bSMauro Carvalho Chehab p_csrow->page_mask = 0xfff; 734fcaf780bSMauro Carvalho Chehab 735fcaf780bSMauro Carvalho Chehab empty = 0; 736fcaf780bSMauro Carvalho Chehab } 737fcaf780bSMauro Carvalho Chehab } 738fcaf780bSMauro Carvalho Chehab } 739fcaf780bSMauro Carvalho Chehab 740fcaf780bSMauro Carvalho Chehab return empty; 741fcaf780bSMauro Carvalho Chehab } 742fcaf780bSMauro Carvalho Chehab 743fcaf780bSMauro Carvalho Chehab static void decode_mir(int mir_no, u16 mir[MAX_MIR]) 744fcaf780bSMauro Carvalho Chehab { 745fcaf780bSMauro Carvalho Chehab if (mir[mir_no] & 3) 746fcaf780bSMauro Carvalho Chehab debugf2("MIR%d: limit= 0x%x Branch(es) that participate: %s %s\n", 747fcaf780bSMauro Carvalho Chehab mir_no, 748fcaf780bSMauro Carvalho Chehab (mir[mir_no] >> 4) & 0xfff, 749fcaf780bSMauro Carvalho Chehab (mir[mir_no] & 1) ? "B0" : "", 750fcaf780bSMauro Carvalho Chehab (mir[mir_no] & 2) ? "B1": ""); 751fcaf780bSMauro Carvalho Chehab } 752fcaf780bSMauro Carvalho Chehab 753fcaf780bSMauro Carvalho Chehab /* 754fcaf780bSMauro Carvalho Chehab * i7300_get_mc_regs read in the necessary registers and 755fcaf780bSMauro Carvalho Chehab * cache locally 756fcaf780bSMauro Carvalho Chehab * 757fcaf780bSMauro Carvalho Chehab * Fills in the private data members 758fcaf780bSMauro Carvalho Chehab */ 759fcaf780bSMauro Carvalho Chehab static int i7300_get_mc_regs(struct mem_ctl_info *mci) 760fcaf780bSMauro Carvalho Chehab { 761fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 762fcaf780bSMauro Carvalho Chehab u32 actual_tolm; 763fcaf780bSMauro Carvalho Chehab int i, rc; 764fcaf780bSMauro Carvalho Chehab 765fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 766fcaf780bSMauro Carvalho Chehab 7673e57eef6SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_0_fsb_ctlr, AMBASE, 768fcaf780bSMauro Carvalho Chehab (u32 *) &pvt->ambase); 769fcaf780bSMauro Carvalho Chehab 770fcaf780bSMauro Carvalho Chehab debugf2("AMBASE= 0x%lx\n", (long unsigned int)pvt->ambase); 771fcaf780bSMauro Carvalho Chehab 772fcaf780bSMauro Carvalho Chehab /* Get the Branch Map regs */ 7733e57eef6SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, TOLM, &pvt->tolm); 774fcaf780bSMauro Carvalho Chehab pvt->tolm >>= 12; 775fcaf780bSMauro Carvalho Chehab debugf2("TOLM (number of 256M regions) =%u (0x%x)\n", pvt->tolm, 776fcaf780bSMauro Carvalho Chehab pvt->tolm); 777fcaf780bSMauro Carvalho Chehab 778fcaf780bSMauro Carvalho Chehab actual_tolm = (u32) ((1000l * pvt->tolm) >> (30 - 28)); 779fcaf780bSMauro Carvalho Chehab debugf2("Actual TOLM byte addr=%u.%03u GB (0x%x)\n", 780fcaf780bSMauro Carvalho Chehab actual_tolm/1000, actual_tolm % 1000, pvt->tolm << 28); 781fcaf780bSMauro Carvalho Chehab 782af3d8831SMauro Carvalho Chehab /* Get memory controller settings */ 7833e57eef6SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, MC_SETTINGS, 784af3d8831SMauro Carvalho Chehab &pvt->mc_settings); 785bb81a216SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, MC_SETTINGS_A, 786bb81a216SMauro Carvalho Chehab &pvt->mc_settings_a); 787d7de2bdbSMauro Carvalho Chehab 788bb81a216SMauro Carvalho Chehab if (IS_SINGLE_MODE(pvt->mc_settings_a)) 789bb81a216SMauro Carvalho Chehab debugf0("Memory controller operating on single mode\n"); 790bb81a216SMauro Carvalho Chehab else 791af3d8831SMauro Carvalho Chehab debugf0("Memory controller operating on %s mode\n", 792d7de2bdbSMauro Carvalho Chehab IS_MIRRORED(pvt->mc_settings) ? "mirrored" : "non-mirrored"); 793bb81a216SMauro Carvalho Chehab 794af3d8831SMauro Carvalho Chehab debugf0("Error detection is %s\n", 795d7de2bdbSMauro Carvalho Chehab IS_ECC_ENABLED(pvt->mc_settings) ? "enabled" : "disabled"); 796d7de2bdbSMauro Carvalho Chehab debugf0("Retry is %s\n", 797d7de2bdbSMauro Carvalho Chehab IS_RETRY_ENABLED(pvt->mc_settings) ? "enabled" : "disabled"); 798af3d8831SMauro Carvalho Chehab 799af3d8831SMauro Carvalho Chehab /* Get Memory Interleave Range registers */ 8003e57eef6SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR0, &pvt->mir[0]); 8013e57eef6SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR1, &pvt->mir[1]); 8023e57eef6SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR2, &pvt->mir[2]); 803fcaf780bSMauro Carvalho Chehab 804fcaf780bSMauro Carvalho Chehab /* Decode the MIR regs */ 805fcaf780bSMauro Carvalho Chehab for (i = 0; i < MAX_MIR; i++) 806fcaf780bSMauro Carvalho Chehab decode_mir(i, pvt->mir); 807fcaf780bSMauro Carvalho Chehab 808fcaf780bSMauro Carvalho Chehab rc = i7300_init_csrows(mci); 809fcaf780bSMauro Carvalho Chehab if (rc < 0) 810fcaf780bSMauro Carvalho Chehab return rc; 811fcaf780bSMauro Carvalho Chehab 812fcaf780bSMauro Carvalho Chehab /* Go and determine the size of each DIMM and place in an 813fcaf780bSMauro Carvalho Chehab * orderly matrix */ 814fcaf780bSMauro Carvalho Chehab print_dimm_size(pvt); 815fcaf780bSMauro Carvalho Chehab 816fcaf780bSMauro Carvalho Chehab return 0; 817fcaf780bSMauro Carvalho Chehab } 818fcaf780bSMauro Carvalho Chehab 8195de6e07eSMauro Carvalho Chehab /************************************************* 8205de6e07eSMauro Carvalho Chehab * i7300 Functions related to device probe/release 8215de6e07eSMauro Carvalho Chehab *************************************************/ 8225de6e07eSMauro Carvalho Chehab 823fcaf780bSMauro Carvalho Chehab /* 824fcaf780bSMauro Carvalho Chehab * i7300_put_devices 'put' all the devices that we have 825fcaf780bSMauro Carvalho Chehab * reserved via 'get' 826fcaf780bSMauro Carvalho Chehab */ 827fcaf780bSMauro Carvalho Chehab static void i7300_put_devices(struct mem_ctl_info *mci) 828fcaf780bSMauro Carvalho Chehab { 829fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 830fcaf780bSMauro Carvalho Chehab int branch; 831fcaf780bSMauro Carvalho Chehab 832fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 833fcaf780bSMauro Carvalho Chehab 834fcaf780bSMauro Carvalho Chehab /* Decrement usage count for devices */ 835fcaf780bSMauro Carvalho Chehab for (branch = 0; branch < MAX_CH_PER_BRANCH; branch++) 8363e57eef6SMauro Carvalho Chehab pci_dev_put(pvt->pci_dev_2x_0_fbd_branch[branch]); 8373e57eef6SMauro Carvalho Chehab pci_dev_put(pvt->pci_dev_16_2_fsb_err_regs); 8383e57eef6SMauro Carvalho Chehab pci_dev_put(pvt->pci_dev_16_1_fsb_addr_map); 839fcaf780bSMauro Carvalho Chehab } 840fcaf780bSMauro Carvalho Chehab 841fcaf780bSMauro Carvalho Chehab /* 842fcaf780bSMauro Carvalho Chehab * i7300_get_devices Find and perform 'get' operation on the MCH's 843fcaf780bSMauro Carvalho Chehab * device/functions we want to reference for this driver 844fcaf780bSMauro Carvalho Chehab * 845fcaf780bSMauro Carvalho Chehab * Need to 'get' device 16 func 1 and func 2 846fcaf780bSMauro Carvalho Chehab */ 847fcaf780bSMauro Carvalho Chehab static int i7300_get_devices(struct mem_ctl_info *mci, int dev_idx) 848fcaf780bSMauro Carvalho Chehab { 849fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 850fcaf780bSMauro Carvalho Chehab struct pci_dev *pdev; 851fcaf780bSMauro Carvalho Chehab 852fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 853fcaf780bSMauro Carvalho Chehab 854fcaf780bSMauro Carvalho Chehab /* Attempt to 'get' the MCH register we want */ 855fcaf780bSMauro Carvalho Chehab pdev = NULL; 8563e57eef6SMauro Carvalho Chehab while (!pvt->pci_dev_16_1_fsb_addr_map || !pvt->pci_dev_16_2_fsb_err_regs) { 857fcaf780bSMauro Carvalho Chehab pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 858fcaf780bSMauro Carvalho Chehab PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, pdev); 859fcaf780bSMauro Carvalho Chehab if (!pdev) { 860fcaf780bSMauro Carvalho Chehab /* End of list, leave */ 861fcaf780bSMauro Carvalho Chehab i7300_printk(KERN_ERR, 862fcaf780bSMauro Carvalho Chehab "'system address,Process Bus' " 863fcaf780bSMauro Carvalho Chehab "device not found:" 864fcaf780bSMauro Carvalho Chehab "vendor 0x%x device 0x%x ERR funcs " 865fcaf780bSMauro Carvalho Chehab "(broken BIOS?)\n", 866fcaf780bSMauro Carvalho Chehab PCI_VENDOR_ID_INTEL, 867fcaf780bSMauro Carvalho Chehab PCI_DEVICE_ID_INTEL_I7300_MCH_ERR); 868fcaf780bSMauro Carvalho Chehab goto error; 869fcaf780bSMauro Carvalho Chehab } 870fcaf780bSMauro Carvalho Chehab 871fcaf780bSMauro Carvalho Chehab /* Store device 16 funcs 1 and 2 */ 872fcaf780bSMauro Carvalho Chehab switch (PCI_FUNC(pdev->devfn)) { 873fcaf780bSMauro Carvalho Chehab case 1: 8743e57eef6SMauro Carvalho Chehab pvt->pci_dev_16_1_fsb_addr_map = pdev; 875fcaf780bSMauro Carvalho Chehab break; 876fcaf780bSMauro Carvalho Chehab case 2: 8773e57eef6SMauro Carvalho Chehab pvt->pci_dev_16_2_fsb_err_regs = pdev; 878fcaf780bSMauro Carvalho Chehab break; 879fcaf780bSMauro Carvalho Chehab } 880fcaf780bSMauro Carvalho Chehab } 881fcaf780bSMauro Carvalho Chehab 882fcaf780bSMauro Carvalho Chehab debugf1("System Address, processor bus- PCI Bus ID: %s %x:%x\n", 8833e57eef6SMauro Carvalho Chehab pci_name(pvt->pci_dev_16_0_fsb_ctlr), 8843e57eef6SMauro Carvalho Chehab pvt->pci_dev_16_0_fsb_ctlr->vendor, pvt->pci_dev_16_0_fsb_ctlr->device); 885fcaf780bSMauro Carvalho Chehab debugf1("Branchmap, control and errors - PCI Bus ID: %s %x:%x\n", 8863e57eef6SMauro Carvalho Chehab pci_name(pvt->pci_dev_16_1_fsb_addr_map), 8873e57eef6SMauro Carvalho Chehab pvt->pci_dev_16_1_fsb_addr_map->vendor, pvt->pci_dev_16_1_fsb_addr_map->device); 888fcaf780bSMauro Carvalho Chehab debugf1("FSB Error Regs - PCI Bus ID: %s %x:%x\n", 8893e57eef6SMauro Carvalho Chehab pci_name(pvt->pci_dev_16_2_fsb_err_regs), 8903e57eef6SMauro Carvalho Chehab pvt->pci_dev_16_2_fsb_err_regs->vendor, pvt->pci_dev_16_2_fsb_err_regs->device); 891fcaf780bSMauro Carvalho Chehab 8923e57eef6SMauro Carvalho Chehab pvt->pci_dev_2x_0_fbd_branch[0] = pci_get_device(PCI_VENDOR_ID_INTEL, 893fcaf780bSMauro Carvalho Chehab PCI_DEVICE_ID_INTEL_I7300_MCH_FB0, 894fcaf780bSMauro Carvalho Chehab NULL); 8953e57eef6SMauro Carvalho Chehab if (!pvt->pci_dev_2x_0_fbd_branch[0]) { 896fcaf780bSMauro Carvalho Chehab i7300_printk(KERN_ERR, 897fcaf780bSMauro Carvalho Chehab "MC: 'BRANCH 0' device not found:" 898fcaf780bSMauro Carvalho Chehab "vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n", 899fcaf780bSMauro Carvalho Chehab PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_FB0); 900fcaf780bSMauro Carvalho Chehab goto error; 901fcaf780bSMauro Carvalho Chehab } 902fcaf780bSMauro Carvalho Chehab 9033e57eef6SMauro Carvalho Chehab pvt->pci_dev_2x_0_fbd_branch[1] = pci_get_device(PCI_VENDOR_ID_INTEL, 904fcaf780bSMauro Carvalho Chehab PCI_DEVICE_ID_INTEL_I7300_MCH_FB1, 905fcaf780bSMauro Carvalho Chehab NULL); 9063e57eef6SMauro Carvalho Chehab if (!pvt->pci_dev_2x_0_fbd_branch[1]) { 907fcaf780bSMauro Carvalho Chehab i7300_printk(KERN_ERR, 908fcaf780bSMauro Carvalho Chehab "MC: 'BRANCH 1' device not found:" 909fcaf780bSMauro Carvalho Chehab "vendor 0x%x device 0x%x Func 0 " 910fcaf780bSMauro Carvalho Chehab "(broken BIOS?)\n", 911fcaf780bSMauro Carvalho Chehab PCI_VENDOR_ID_INTEL, 912fcaf780bSMauro Carvalho Chehab PCI_DEVICE_ID_INTEL_I7300_MCH_FB1); 913fcaf780bSMauro Carvalho Chehab goto error; 914fcaf780bSMauro Carvalho Chehab } 915fcaf780bSMauro Carvalho Chehab 916fcaf780bSMauro Carvalho Chehab return 0; 917fcaf780bSMauro Carvalho Chehab 918fcaf780bSMauro Carvalho Chehab error: 919fcaf780bSMauro Carvalho Chehab i7300_put_devices(mci); 920fcaf780bSMauro Carvalho Chehab return -ENODEV; 921fcaf780bSMauro Carvalho Chehab } 922fcaf780bSMauro Carvalho Chehab 923fcaf780bSMauro Carvalho Chehab /* 924fcaf780bSMauro Carvalho Chehab * i7300_probe1 Probe for ONE instance of device to see if it is 925fcaf780bSMauro Carvalho Chehab * present. 926fcaf780bSMauro Carvalho Chehab * return: 927fcaf780bSMauro Carvalho Chehab * 0 for FOUND a device 928fcaf780bSMauro Carvalho Chehab * < 0 for error code 929fcaf780bSMauro Carvalho Chehab */ 930fcaf780bSMauro Carvalho Chehab static int i7300_probe1(struct pci_dev *pdev, int dev_idx) 931fcaf780bSMauro Carvalho Chehab { 932fcaf780bSMauro Carvalho Chehab struct mem_ctl_info *mci; 933fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 934fcaf780bSMauro Carvalho Chehab int num_channels; 935fcaf780bSMauro Carvalho Chehab int num_dimms_per_channel; 936fcaf780bSMauro Carvalho Chehab int num_csrows; 937fcaf780bSMauro Carvalho Chehab 938fcaf780bSMauro Carvalho Chehab if (dev_idx >= ARRAY_SIZE(i7300_devs)) 939fcaf780bSMauro Carvalho Chehab return -EINVAL; 940fcaf780bSMauro Carvalho Chehab 941fcaf780bSMauro Carvalho Chehab debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n", 942fcaf780bSMauro Carvalho Chehab __func__, 943fcaf780bSMauro Carvalho Chehab pdev->bus->number, 944fcaf780bSMauro Carvalho Chehab PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); 945fcaf780bSMauro Carvalho Chehab 946fcaf780bSMauro Carvalho Chehab /* We only are looking for func 0 of the set */ 947fcaf780bSMauro Carvalho Chehab if (PCI_FUNC(pdev->devfn) != 0) 948fcaf780bSMauro Carvalho Chehab return -ENODEV; 949fcaf780bSMauro Carvalho Chehab 950fcaf780bSMauro Carvalho Chehab /* As we don't have a motherboard identification routine to determine 951fcaf780bSMauro Carvalho Chehab * actual number of slots/dimms per channel, we thus utilize the 952fcaf780bSMauro Carvalho Chehab * resource as specified by the chipset. Thus, we might have 953fcaf780bSMauro Carvalho Chehab * have more DIMMs per channel than actually on the mobo, but this 954fcaf780bSMauro Carvalho Chehab * allows the driver to support upto the chipset max, without 955fcaf780bSMauro Carvalho Chehab * some fancy mobo determination. 956fcaf780bSMauro Carvalho Chehab */ 957fcaf780bSMauro Carvalho Chehab num_dimms_per_channel = MAX_SLOTS; 958fcaf780bSMauro Carvalho Chehab num_channels = MAX_CHANNELS; 959fcaf780bSMauro Carvalho Chehab num_csrows = MAX_SLOTS * MAX_CHANNELS; 960fcaf780bSMauro Carvalho Chehab 961fcaf780bSMauro Carvalho Chehab debugf0("MC: %s(): Number of - Channels= %d DIMMS= %d CSROWS= %d\n", 962fcaf780bSMauro Carvalho Chehab __func__, num_channels, num_dimms_per_channel, num_csrows); 963fcaf780bSMauro Carvalho Chehab 964fcaf780bSMauro Carvalho Chehab /* allocate a new MC control structure */ 965fcaf780bSMauro Carvalho Chehab mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); 966fcaf780bSMauro Carvalho Chehab 967fcaf780bSMauro Carvalho Chehab if (mci == NULL) 968fcaf780bSMauro Carvalho Chehab return -ENOMEM; 969fcaf780bSMauro Carvalho Chehab 970fcaf780bSMauro Carvalho Chehab debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); 971fcaf780bSMauro Carvalho Chehab 972fcaf780bSMauro Carvalho Chehab mci->dev = &pdev->dev; /* record ptr to the generic device */ 973fcaf780bSMauro Carvalho Chehab 974fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 9753e57eef6SMauro Carvalho Chehab pvt->pci_dev_16_0_fsb_ctlr = pdev; /* Record this device in our private */ 976fcaf780bSMauro Carvalho Chehab 977*85580ea4SMauro Carvalho Chehab pvt->tmp_prt_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); 978*85580ea4SMauro Carvalho Chehab if (!pvt->tmp_prt_buffer) { 979*85580ea4SMauro Carvalho Chehab edac_mc_free(mci); 980*85580ea4SMauro Carvalho Chehab return -ENOMEM; 981*85580ea4SMauro Carvalho Chehab } 982*85580ea4SMauro Carvalho Chehab 983fcaf780bSMauro Carvalho Chehab /* 'get' the pci devices we want to reserve for our use */ 984fcaf780bSMauro Carvalho Chehab if (i7300_get_devices(mci, dev_idx)) 985fcaf780bSMauro Carvalho Chehab goto fail0; 986fcaf780bSMauro Carvalho Chehab 987fcaf780bSMauro Carvalho Chehab mci->mc_idx = 0; 988fcaf780bSMauro Carvalho Chehab mci->mtype_cap = MEM_FLAG_FB_DDR2; 989fcaf780bSMauro Carvalho Chehab mci->edac_ctl_cap = EDAC_FLAG_NONE; 990fcaf780bSMauro Carvalho Chehab mci->edac_cap = EDAC_FLAG_NONE; 991fcaf780bSMauro Carvalho Chehab mci->mod_name = "i7300_edac.c"; 992fcaf780bSMauro Carvalho Chehab mci->mod_ver = I7300_REVISION; 993fcaf780bSMauro Carvalho Chehab mci->ctl_name = i7300_devs[dev_idx].ctl_name; 994fcaf780bSMauro Carvalho Chehab mci->dev_name = pci_name(pdev); 995fcaf780bSMauro Carvalho Chehab mci->ctl_page_to_phys = NULL; 996fcaf780bSMauro Carvalho Chehab 997fcaf780bSMauro Carvalho Chehab /* Set the function pointer to an actual operation function */ 998fcaf780bSMauro Carvalho Chehab mci->edac_check = i7300_check_error; 999fcaf780bSMauro Carvalho Chehab 1000fcaf780bSMauro Carvalho Chehab /* initialize the MC control structure 'csrows' table 1001fcaf780bSMauro Carvalho Chehab * with the mapping and control information */ 1002fcaf780bSMauro Carvalho Chehab if (i7300_get_mc_regs(mci)) { 1003fcaf780bSMauro Carvalho Chehab debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n" 1004fcaf780bSMauro Carvalho Chehab " because i7300_init_csrows() returned nonzero " 1005fcaf780bSMauro Carvalho Chehab "value\n"); 1006fcaf780bSMauro Carvalho Chehab mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */ 1007fcaf780bSMauro Carvalho Chehab } else { 1008fcaf780bSMauro Carvalho Chehab debugf1("MC: Enable error reporting now\n"); 1009fcaf780bSMauro Carvalho Chehab i7300_enable_error_reporting(mci); 1010fcaf780bSMauro Carvalho Chehab } 1011fcaf780bSMauro Carvalho Chehab 1012fcaf780bSMauro Carvalho Chehab /* add this new MC control structure to EDAC's list of MCs */ 1013fcaf780bSMauro Carvalho Chehab if (edac_mc_add_mc(mci)) { 1014fcaf780bSMauro Carvalho Chehab debugf0("MC: " __FILE__ 1015fcaf780bSMauro Carvalho Chehab ": %s(): failed edac_mc_add_mc()\n", __func__); 1016fcaf780bSMauro Carvalho Chehab /* FIXME: perhaps some code should go here that disables error 1017fcaf780bSMauro Carvalho Chehab * reporting if we just enabled it 1018fcaf780bSMauro Carvalho Chehab */ 1019fcaf780bSMauro Carvalho Chehab goto fail1; 1020fcaf780bSMauro Carvalho Chehab } 1021fcaf780bSMauro Carvalho Chehab 1022fcaf780bSMauro Carvalho Chehab i7300_clear_error(mci); 1023fcaf780bSMauro Carvalho Chehab 1024fcaf780bSMauro Carvalho Chehab /* allocating generic PCI control info */ 1025fcaf780bSMauro Carvalho Chehab i7300_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); 1026fcaf780bSMauro Carvalho Chehab if (!i7300_pci) { 1027fcaf780bSMauro Carvalho Chehab printk(KERN_WARNING 1028fcaf780bSMauro Carvalho Chehab "%s(): Unable to create PCI control\n", 1029fcaf780bSMauro Carvalho Chehab __func__); 1030fcaf780bSMauro Carvalho Chehab printk(KERN_WARNING 1031fcaf780bSMauro Carvalho Chehab "%s(): PCI error report via EDAC not setup\n", 1032fcaf780bSMauro Carvalho Chehab __func__); 1033fcaf780bSMauro Carvalho Chehab } 1034fcaf780bSMauro Carvalho Chehab 1035fcaf780bSMauro Carvalho Chehab return 0; 1036fcaf780bSMauro Carvalho Chehab 1037fcaf780bSMauro Carvalho Chehab /* Error exit unwinding stack */ 1038fcaf780bSMauro Carvalho Chehab fail1: 1039fcaf780bSMauro Carvalho Chehab 1040fcaf780bSMauro Carvalho Chehab i7300_put_devices(mci); 1041fcaf780bSMauro Carvalho Chehab 1042fcaf780bSMauro Carvalho Chehab fail0: 1043*85580ea4SMauro Carvalho Chehab kfree(pvt->tmp_prt_buffer); 1044fcaf780bSMauro Carvalho Chehab edac_mc_free(mci); 1045fcaf780bSMauro Carvalho Chehab return -ENODEV; 1046fcaf780bSMauro Carvalho Chehab } 1047fcaf780bSMauro Carvalho Chehab 1048fcaf780bSMauro Carvalho Chehab /* 1049fcaf780bSMauro Carvalho Chehab * i7300_init_one constructor for one instance of device 1050fcaf780bSMauro Carvalho Chehab * 1051fcaf780bSMauro Carvalho Chehab * returns: 1052fcaf780bSMauro Carvalho Chehab * negative on error 1053fcaf780bSMauro Carvalho Chehab * count (>= 0) 1054fcaf780bSMauro Carvalho Chehab */ 1055fcaf780bSMauro Carvalho Chehab static int __devinit i7300_init_one(struct pci_dev *pdev, 1056fcaf780bSMauro Carvalho Chehab const struct pci_device_id *id) 1057fcaf780bSMauro Carvalho Chehab { 1058fcaf780bSMauro Carvalho Chehab int rc; 1059fcaf780bSMauro Carvalho Chehab 1060fcaf780bSMauro Carvalho Chehab debugf0("MC: " __FILE__ ": %s()\n", __func__); 1061fcaf780bSMauro Carvalho Chehab 1062fcaf780bSMauro Carvalho Chehab /* wake up device */ 1063fcaf780bSMauro Carvalho Chehab rc = pci_enable_device(pdev); 1064fcaf780bSMauro Carvalho Chehab if (rc == -EIO) 1065fcaf780bSMauro Carvalho Chehab return rc; 1066fcaf780bSMauro Carvalho Chehab 1067fcaf780bSMauro Carvalho Chehab /* now probe and enable the device */ 1068fcaf780bSMauro Carvalho Chehab return i7300_probe1(pdev, id->driver_data); 1069fcaf780bSMauro Carvalho Chehab } 1070fcaf780bSMauro Carvalho Chehab 1071fcaf780bSMauro Carvalho Chehab /* 1072fcaf780bSMauro Carvalho Chehab * i7300_remove_one destructor for one instance of device 1073fcaf780bSMauro Carvalho Chehab * 1074fcaf780bSMauro Carvalho Chehab */ 1075fcaf780bSMauro Carvalho Chehab static void __devexit i7300_remove_one(struct pci_dev *pdev) 1076fcaf780bSMauro Carvalho Chehab { 1077fcaf780bSMauro Carvalho Chehab struct mem_ctl_info *mci; 1078*85580ea4SMauro Carvalho Chehab char *tmp; 1079fcaf780bSMauro Carvalho Chehab 1080fcaf780bSMauro Carvalho Chehab debugf0(__FILE__ ": %s()\n", __func__); 1081fcaf780bSMauro Carvalho Chehab 1082fcaf780bSMauro Carvalho Chehab if (i7300_pci) 1083fcaf780bSMauro Carvalho Chehab edac_pci_release_generic_ctl(i7300_pci); 1084fcaf780bSMauro Carvalho Chehab 1085fcaf780bSMauro Carvalho Chehab mci = edac_mc_del_mc(&pdev->dev); 1086fcaf780bSMauro Carvalho Chehab if (!mci) 1087fcaf780bSMauro Carvalho Chehab return; 1088fcaf780bSMauro Carvalho Chehab 1089*85580ea4SMauro Carvalho Chehab tmp = ((struct i7300_pvt *)mci->pvt_info)->tmp_prt_buffer; 1090*85580ea4SMauro Carvalho Chehab 1091fcaf780bSMauro Carvalho Chehab /* retrieve references to resources, and free those resources */ 1092fcaf780bSMauro Carvalho Chehab i7300_put_devices(mci); 1093fcaf780bSMauro Carvalho Chehab 1094*85580ea4SMauro Carvalho Chehab kfree(tmp); 1095fcaf780bSMauro Carvalho Chehab edac_mc_free(mci); 1096fcaf780bSMauro Carvalho Chehab } 1097fcaf780bSMauro Carvalho Chehab 1098fcaf780bSMauro Carvalho Chehab /* 1099fcaf780bSMauro Carvalho Chehab * pci_device_id table for which devices we are looking for 1100fcaf780bSMauro Carvalho Chehab * 1101fcaf780bSMauro Carvalho Chehab * The "E500P" device is the first device supported. 1102fcaf780bSMauro Carvalho Chehab */ 1103fcaf780bSMauro Carvalho Chehab static const struct pci_device_id i7300_pci_tbl[] __devinitdata = { 1104fcaf780bSMauro Carvalho Chehab {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_ERR)}, 1105fcaf780bSMauro Carvalho Chehab {0,} /* 0 terminated list. */ 1106fcaf780bSMauro Carvalho Chehab }; 1107fcaf780bSMauro Carvalho Chehab 1108fcaf780bSMauro Carvalho Chehab MODULE_DEVICE_TABLE(pci, i7300_pci_tbl); 1109fcaf780bSMauro Carvalho Chehab 1110fcaf780bSMauro Carvalho Chehab /* 1111fcaf780bSMauro Carvalho Chehab * i7300_driver pci_driver structure for this module 1112fcaf780bSMauro Carvalho Chehab * 1113fcaf780bSMauro Carvalho Chehab */ 1114fcaf780bSMauro Carvalho Chehab static struct pci_driver i7300_driver = { 1115fcaf780bSMauro Carvalho Chehab .name = "i7300_edac", 1116fcaf780bSMauro Carvalho Chehab .probe = i7300_init_one, 1117fcaf780bSMauro Carvalho Chehab .remove = __devexit_p(i7300_remove_one), 1118fcaf780bSMauro Carvalho Chehab .id_table = i7300_pci_tbl, 1119fcaf780bSMauro Carvalho Chehab }; 1120fcaf780bSMauro Carvalho Chehab 1121fcaf780bSMauro Carvalho Chehab /* 1122fcaf780bSMauro Carvalho Chehab * i7300_init Module entry function 1123fcaf780bSMauro Carvalho Chehab * Try to initialize this module for its devices 1124fcaf780bSMauro Carvalho Chehab */ 1125fcaf780bSMauro Carvalho Chehab static int __init i7300_init(void) 1126fcaf780bSMauro Carvalho Chehab { 1127fcaf780bSMauro Carvalho Chehab int pci_rc; 1128fcaf780bSMauro Carvalho Chehab 1129fcaf780bSMauro Carvalho Chehab debugf2("MC: " __FILE__ ": %s()\n", __func__); 1130fcaf780bSMauro Carvalho Chehab 1131fcaf780bSMauro Carvalho Chehab /* Ensure that the OPSTATE is set correctly for POLL or NMI */ 1132fcaf780bSMauro Carvalho Chehab opstate_init(); 1133fcaf780bSMauro Carvalho Chehab 1134fcaf780bSMauro Carvalho Chehab pci_rc = pci_register_driver(&i7300_driver); 1135fcaf780bSMauro Carvalho Chehab 1136fcaf780bSMauro Carvalho Chehab return (pci_rc < 0) ? pci_rc : 0; 1137fcaf780bSMauro Carvalho Chehab } 1138fcaf780bSMauro Carvalho Chehab 1139fcaf780bSMauro Carvalho Chehab /* 1140fcaf780bSMauro Carvalho Chehab * i7300_exit() Module exit function 1141fcaf780bSMauro Carvalho Chehab * Unregister the driver 1142fcaf780bSMauro Carvalho Chehab */ 1143fcaf780bSMauro Carvalho Chehab static void __exit i7300_exit(void) 1144fcaf780bSMauro Carvalho Chehab { 1145fcaf780bSMauro Carvalho Chehab debugf2("MC: " __FILE__ ": %s()\n", __func__); 1146fcaf780bSMauro Carvalho Chehab pci_unregister_driver(&i7300_driver); 1147fcaf780bSMauro Carvalho Chehab } 1148fcaf780bSMauro Carvalho Chehab 1149fcaf780bSMauro Carvalho Chehab module_init(i7300_init); 1150fcaf780bSMauro Carvalho Chehab module_exit(i7300_exit); 1151fcaf780bSMauro Carvalho Chehab 1152fcaf780bSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 1153fcaf780bSMauro Carvalho Chehab MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); 1154fcaf780bSMauro Carvalho Chehab MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); 1155fcaf780bSMauro Carvalho Chehab MODULE_DESCRIPTION("MC Driver for Intel I7300 memory controllers - " 1156fcaf780bSMauro Carvalho Chehab I7300_REVISION); 1157fcaf780bSMauro Carvalho Chehab 1158fcaf780bSMauro Carvalho Chehab module_param(edac_op_state, int, 0444); 1159fcaf780bSMauro Carvalho Chehab MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); 1160