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