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 */ 34152ba394SMichal Marek #define I7300_REVISION " Ver: 1.0.0" 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 44b4552aceSMauro Carvalho Chehab /*********************************************** 45b4552aceSMauro Carvalho Chehab * i7300 Limit constants Structs and static vars 46b4552aceSMauro Carvalho Chehab ***********************************************/ 47b4552aceSMauro Carvalho Chehab 48fcaf780bSMauro Carvalho Chehab /* 49fcaf780bSMauro Carvalho Chehab * Memory topology is organized as: 50fcaf780bSMauro Carvalho Chehab * Branch 0 - 2 channels: channels 0 and 1 (FDB0 PCI dev 21.0) 51fcaf780bSMauro Carvalho Chehab * Branch 1 - 2 channels: channels 2 and 3 (FDB1 PCI dev 22.0) 52fcaf780bSMauro Carvalho Chehab * Each channel can have to 8 DIMM sets (called as SLOTS) 53fcaf780bSMauro Carvalho Chehab * Slots should generally be filled in pairs 54fcaf780bSMauro Carvalho Chehab * Except on Single Channel mode of operation 55fcaf780bSMauro Carvalho Chehab * just slot 0/channel0 filled on this mode 56fcaf780bSMauro Carvalho Chehab * On normal operation mode, the two channels on a branch should be 57c3af2eafSMauro Carvalho Chehab * filled together for the same SLOT# 58fcaf780bSMauro Carvalho Chehab * When in mirrored mode, Branch 1 replicate memory at Branch 0, so, the four 59fcaf780bSMauro Carvalho Chehab * channels on both branches should be filled 60fcaf780bSMauro Carvalho Chehab */ 61fcaf780bSMauro Carvalho Chehab 62fcaf780bSMauro Carvalho Chehab /* Limits for i7300 */ 63fcaf780bSMauro Carvalho Chehab #define MAX_SLOTS 8 64fcaf780bSMauro Carvalho Chehab #define MAX_BRANCHES 2 65fcaf780bSMauro Carvalho Chehab #define MAX_CH_PER_BRANCH 2 66fcaf780bSMauro Carvalho Chehab #define MAX_CHANNELS (MAX_CH_PER_BRANCH * MAX_BRANCHES) 67fcaf780bSMauro Carvalho Chehab #define MAX_MIR 3 68fcaf780bSMauro Carvalho Chehab 69fcaf780bSMauro Carvalho Chehab #define to_channel(ch, branch) ((((branch)) << 1) | (ch)) 70fcaf780bSMauro Carvalho Chehab 71fcaf780bSMauro Carvalho Chehab #define to_csrow(slot, ch, branch) \ 72fcaf780bSMauro Carvalho Chehab (to_channel(ch, branch) | ((slot) << 2)) 73fcaf780bSMauro Carvalho Chehab 74b4552aceSMauro Carvalho Chehab /* Device name and register DID (Device ID) */ 75b4552aceSMauro Carvalho Chehab struct i7300_dev_info { 76b4552aceSMauro Carvalho Chehab const char *ctl_name; /* name for this device */ 77b4552aceSMauro Carvalho Chehab u16 fsb_mapping_errors; /* DID for the branchmap,control */ 78b4552aceSMauro Carvalho Chehab }; 79fcaf780bSMauro Carvalho Chehab 80b4552aceSMauro Carvalho Chehab /* Table of devices attributes supported by this driver */ 81b4552aceSMauro Carvalho Chehab static const struct i7300_dev_info i7300_devs[] = { 82b4552aceSMauro Carvalho Chehab { 83b4552aceSMauro Carvalho Chehab .ctl_name = "I7300", 84b4552aceSMauro Carvalho Chehab .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, 85b4552aceSMauro Carvalho Chehab }, 86b4552aceSMauro Carvalho Chehab }; 87b4552aceSMauro Carvalho Chehab 88b4552aceSMauro Carvalho Chehab struct i7300_dimm_info { 89b4552aceSMauro Carvalho Chehab int megabytes; /* size, 0 means not present */ 90b4552aceSMauro Carvalho Chehab }; 91b4552aceSMauro Carvalho Chehab 92b4552aceSMauro Carvalho Chehab /* driver private data structure */ 93b4552aceSMauro Carvalho Chehab struct i7300_pvt { 94b4552aceSMauro Carvalho Chehab struct pci_dev *pci_dev_16_0_fsb_ctlr; /* 16.0 */ 95b4552aceSMauro Carvalho Chehab struct pci_dev *pci_dev_16_1_fsb_addr_map; /* 16.1 */ 96b4552aceSMauro Carvalho Chehab struct pci_dev *pci_dev_16_2_fsb_err_regs; /* 16.2 */ 97b4552aceSMauro Carvalho Chehab struct pci_dev *pci_dev_2x_0_fbd_branch[MAX_BRANCHES]; /* 21.0 and 22.0 */ 98b4552aceSMauro Carvalho Chehab 99b4552aceSMauro Carvalho Chehab u16 tolm; /* top of low memory */ 100b4552aceSMauro Carvalho Chehab u64 ambase; /* AMB BAR */ 101b4552aceSMauro Carvalho Chehab 102b4552aceSMauro Carvalho Chehab u32 mc_settings; /* Report several settings */ 103b4552aceSMauro Carvalho Chehab u32 mc_settings_a; 104b4552aceSMauro Carvalho Chehab 105b4552aceSMauro Carvalho Chehab u16 mir[MAX_MIR]; /* Memory Interleave Reg*/ 106b4552aceSMauro Carvalho Chehab 107b4552aceSMauro Carvalho Chehab u16 mtr[MAX_SLOTS][MAX_BRANCHES]; /* Memory Technlogy Reg */ 108b4552aceSMauro Carvalho Chehab u16 ambpresent[MAX_CHANNELS]; /* AMB present regs */ 109b4552aceSMauro Carvalho Chehab 110b4552aceSMauro Carvalho Chehab /* DIMM information matrix, allocating architecture maximums */ 111b4552aceSMauro Carvalho Chehab struct i7300_dimm_info dimm_info[MAX_SLOTS][MAX_CHANNELS]; 112b4552aceSMauro Carvalho Chehab 113b4552aceSMauro Carvalho Chehab /* Temporary buffer for use when preparing error messages */ 114b4552aceSMauro Carvalho Chehab char *tmp_prt_buffer; 115b4552aceSMauro Carvalho Chehab }; 116b4552aceSMauro Carvalho Chehab 117b4552aceSMauro Carvalho Chehab /* FIXME: Why do we need to have this static? */ 118b4552aceSMauro Carvalho Chehab static struct edac_pci_ctl_info *i7300_pci; 119b4552aceSMauro Carvalho Chehab 120b4552aceSMauro Carvalho Chehab /*************************************************** 121b4552aceSMauro Carvalho Chehab * i7300 Register definitions for memory enumeration 122b4552aceSMauro Carvalho Chehab ***************************************************/ 123b4552aceSMauro Carvalho Chehab 124b4552aceSMauro Carvalho Chehab /* 125c3af2eafSMauro Carvalho Chehab * Device 16, 126c3af2eafSMauro Carvalho Chehab * Function 0: System Address (not documented) 127c3af2eafSMauro Carvalho Chehab * Function 1: Memory Branch Map, Control, Errors Register 128c3af2eafSMauro Carvalho Chehab */ 129c3af2eafSMauro Carvalho Chehab 130fcaf780bSMauro Carvalho Chehab /* OFFSETS for Function 0 */ 131fcaf780bSMauro Carvalho Chehab #define AMBASE 0x48 /* AMB Mem Mapped Reg Region Base */ 132fcaf780bSMauro Carvalho Chehab #define MAXCH 0x56 /* Max Channel Number */ 133fcaf780bSMauro Carvalho Chehab #define MAXDIMMPERCH 0x57 /* Max DIMM PER Channel Number */ 134fcaf780bSMauro Carvalho Chehab 135fcaf780bSMauro Carvalho Chehab /* OFFSETS for Function 1 */ 136af3d8831SMauro Carvalho Chehab #define MC_SETTINGS 0x40 137d7de2bdbSMauro Carvalho Chehab #define IS_MIRRORED(mc) ((mc) & (1 << 16)) 138d7de2bdbSMauro Carvalho Chehab #define IS_ECC_ENABLED(mc) ((mc) & (1 << 5)) 139d7de2bdbSMauro Carvalho Chehab #define IS_RETRY_ENABLED(mc) ((mc) & (1 << 31)) 140d7de2bdbSMauro Carvalho Chehab #define IS_SCRBALGO_ENHANCED(mc) ((mc) & (1 << 8)) 141d7de2bdbSMauro Carvalho Chehab 142bb81a216SMauro Carvalho Chehab #define MC_SETTINGS_A 0x58 143bb81a216SMauro Carvalho Chehab #define IS_SINGLE_MODE(mca) ((mca) & (1 << 14)) 144d7de2bdbSMauro Carvalho Chehab 145fcaf780bSMauro Carvalho Chehab #define TOLM 0x6C 146fcaf780bSMauro Carvalho Chehab 147fcaf780bSMauro Carvalho Chehab #define MIR0 0x80 148fcaf780bSMauro Carvalho Chehab #define MIR1 0x84 149fcaf780bSMauro Carvalho Chehab #define MIR2 0x88 150fcaf780bSMauro Carvalho Chehab 151fcaf780bSMauro Carvalho Chehab /* 152fcaf780bSMauro Carvalho Chehab * Note: Other Intel EDAC drivers use AMBPRESENT to identify if the available 153fcaf780bSMauro Carvalho Chehab * memory. From datasheet item 7.3.1 (FB-DIMM technology & organization), it 154fcaf780bSMauro Carvalho Chehab * seems that we cannot use this information directly for the same usage. 155fcaf780bSMauro Carvalho Chehab * Each memory slot may have up to 2 AMB interfaces, one for income and another 156fcaf780bSMauro Carvalho Chehab * for outcome interface to the next slot. 157fcaf780bSMauro Carvalho Chehab * For now, the driver just stores the AMB present registers, but rely only at 158fcaf780bSMauro Carvalho Chehab * the MTR info to detect memory. 159fcaf780bSMauro Carvalho Chehab * Datasheet is also not clear about how to map each AMBPRESENT registers to 160fcaf780bSMauro Carvalho Chehab * one of the 4 available channels. 161fcaf780bSMauro Carvalho Chehab */ 162fcaf780bSMauro Carvalho Chehab #define AMBPRESENT_0 0x64 163fcaf780bSMauro Carvalho Chehab #define AMBPRESENT_1 0x66 164fcaf780bSMauro Carvalho Chehab 16542b16b3fSJesper Juhl static const u16 mtr_regs[MAX_SLOTS] = { 166fcaf780bSMauro Carvalho Chehab 0x80, 0x84, 0x88, 0x8c, 167fcaf780bSMauro Carvalho Chehab 0x82, 0x86, 0x8a, 0x8e 168fcaf780bSMauro Carvalho Chehab }; 169fcaf780bSMauro Carvalho Chehab 170b4552aceSMauro Carvalho Chehab /* 171b4552aceSMauro Carvalho Chehab * Defines to extract the vaious fields from the 172fcaf780bSMauro Carvalho Chehab * MTRx - Memory Technology Registers 173fcaf780bSMauro Carvalho Chehab */ 174fcaf780bSMauro Carvalho Chehab #define MTR_DIMMS_PRESENT(mtr) ((mtr) & (1 << 8)) 175fcaf780bSMauro Carvalho Chehab #define MTR_DIMMS_ETHROTTLE(mtr) ((mtr) & (1 << 7)) 176fcaf780bSMauro Carvalho Chehab #define MTR_DRAM_WIDTH(mtr) (((mtr) & (1 << 6)) ? 8 : 4) 177fcaf780bSMauro Carvalho Chehab #define MTR_DRAM_BANKS(mtr) (((mtr) & (1 << 5)) ? 8 : 4) 178fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_RANKS(mtr) (((mtr) & (1 << 4)) ? 1 : 0) 179fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_ROWS(mtr) (((mtr) >> 2) & 0x3) 180fcaf780bSMauro Carvalho Chehab #define MTR_DRAM_BANKS_ADDR_BITS 2 181fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_ROWS_ADDR_BITS(mtr) (MTR_DIMM_ROWS(mtr) + 13) 182fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_COLS(mtr) ((mtr) & 0x3) 183fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_COLS_ADDR_BITS(mtr) (MTR_DIMM_COLS(mtr) + 10) 184fcaf780bSMauro Carvalho Chehab 185fcaf780bSMauro Carvalho Chehab #ifdef CONFIG_EDAC_DEBUG 186fcaf780bSMauro Carvalho Chehab /* MTR NUMROW */ 187fcaf780bSMauro Carvalho Chehab static const char *numrow_toString[] = { 188fcaf780bSMauro Carvalho Chehab "8,192 - 13 rows", 189fcaf780bSMauro Carvalho Chehab "16,384 - 14 rows", 190fcaf780bSMauro Carvalho Chehab "32,768 - 15 rows", 191fcaf780bSMauro Carvalho Chehab "65,536 - 16 rows" 192fcaf780bSMauro Carvalho Chehab }; 193fcaf780bSMauro Carvalho Chehab 194fcaf780bSMauro Carvalho Chehab /* MTR NUMCOL */ 195fcaf780bSMauro Carvalho Chehab static const char *numcol_toString[] = { 196fcaf780bSMauro Carvalho Chehab "1,024 - 10 columns", 197fcaf780bSMauro Carvalho Chehab "2,048 - 11 columns", 198fcaf780bSMauro Carvalho Chehab "4,096 - 12 columns", 199fcaf780bSMauro Carvalho Chehab "reserved" 200fcaf780bSMauro Carvalho Chehab }; 201fcaf780bSMauro Carvalho Chehab #endif 202fcaf780bSMauro Carvalho Chehab 203c3af2eafSMauro Carvalho Chehab /************************************************ 204c3af2eafSMauro Carvalho Chehab * i7300 Register definitions for error detection 205c3af2eafSMauro Carvalho Chehab ************************************************/ 20657021918SMauro Carvalho Chehab 20757021918SMauro Carvalho Chehab /* 20857021918SMauro Carvalho Chehab * Device 16.1: FBD Error Registers 20957021918SMauro Carvalho Chehab */ 21057021918SMauro Carvalho Chehab #define FERR_FAT_FBD 0x98 21157021918SMauro Carvalho Chehab static const char *ferr_fat_fbd_name[] = { 21257021918SMauro Carvalho Chehab [22] = "Non-Redundant Fast Reset Timeout", 21357021918SMauro Carvalho Chehab [2] = ">Tmid Thermal event with intelligent throttling disabled", 21457021918SMauro Carvalho Chehab [1] = "Memory or FBD configuration CRC read error", 21557021918SMauro Carvalho Chehab [0] = "Memory Write error on non-redundant retry or " 21657021918SMauro Carvalho Chehab "FBD configuration Write error on retry", 21757021918SMauro Carvalho Chehab }; 21857021918SMauro Carvalho Chehab #define GET_FBD_FAT_IDX(fbderr) (fbderr & (3 << 28)) 21957021918SMauro Carvalho Chehab #define FERR_FAT_FBD_ERR_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)) 22057021918SMauro Carvalho Chehab 22157021918SMauro Carvalho Chehab #define FERR_NF_FBD 0xa0 22257021918SMauro Carvalho Chehab static const char *ferr_nf_fbd_name[] = { 22357021918SMauro Carvalho Chehab [24] = "DIMM-Spare Copy Completed", 22457021918SMauro Carvalho Chehab [23] = "DIMM-Spare Copy Initiated", 22557021918SMauro Carvalho Chehab [22] = "Redundant Fast Reset Timeout", 22657021918SMauro Carvalho Chehab [21] = "Memory Write error on redundant retry", 22757021918SMauro Carvalho Chehab [18] = "SPD protocol Error", 22857021918SMauro Carvalho Chehab [17] = "FBD Northbound parity error on FBD Sync Status", 22957021918SMauro Carvalho Chehab [16] = "Correctable Patrol Data ECC", 23057021918SMauro Carvalho Chehab [15] = "Correctable Resilver- or Spare-Copy Data ECC", 23157021918SMauro Carvalho Chehab [14] = "Correctable Mirrored Demand Data ECC", 23257021918SMauro Carvalho Chehab [13] = "Correctable Non-Mirrored Demand Data ECC", 23357021918SMauro Carvalho Chehab [11] = "Memory or FBD configuration CRC read error", 23457021918SMauro Carvalho Chehab [10] = "FBD Configuration Write error on first attempt", 23557021918SMauro Carvalho Chehab [9] = "Memory Write error on first attempt", 23657021918SMauro Carvalho Chehab [8] = "Non-Aliased Uncorrectable Patrol Data ECC", 23757021918SMauro Carvalho Chehab [7] = "Non-Aliased Uncorrectable Resilver- or Spare-Copy Data ECC", 23857021918SMauro Carvalho Chehab [6] = "Non-Aliased Uncorrectable Mirrored Demand Data ECC", 23957021918SMauro Carvalho Chehab [5] = "Non-Aliased Uncorrectable Non-Mirrored Demand Data ECC", 24057021918SMauro Carvalho Chehab [4] = "Aliased Uncorrectable Patrol Data ECC", 24157021918SMauro Carvalho Chehab [3] = "Aliased Uncorrectable Resilver- or Spare-Copy Data ECC", 24257021918SMauro Carvalho Chehab [2] = "Aliased Uncorrectable Mirrored Demand Data ECC", 24357021918SMauro Carvalho Chehab [1] = "Aliased Uncorrectable Non-Mirrored Demand Data ECC", 24457021918SMauro Carvalho Chehab [0] = "Uncorrectable Data ECC on Replay", 24557021918SMauro Carvalho Chehab }; 24657021918SMauro Carvalho Chehab #define GET_FBD_NF_IDX(fbderr) (fbderr & (3 << 28)) 24757021918SMauro Carvalho Chehab #define FERR_NF_FBD_ERR_MASK ((1 << 24) | (1 << 23) | (1 << 22) | (1 << 21) |\ 24857021918SMauro Carvalho Chehab (1 << 18) | (1 << 17) | (1 << 16) | (1 << 15) |\ 24957021918SMauro Carvalho Chehab (1 << 14) | (1 << 13) | (1 << 11) | (1 << 10) |\ 25057021918SMauro Carvalho Chehab (1 << 9) | (1 << 8) | (1 << 7) | (1 << 6) |\ 25157021918SMauro Carvalho Chehab (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) |\ 25257021918SMauro Carvalho Chehab (1 << 1) | (1 << 0)) 25357021918SMauro Carvalho Chehab 25457021918SMauro Carvalho Chehab #define EMASK_FBD 0xa8 25557021918SMauro Carvalho Chehab #define EMASK_FBD_ERR_MASK ((1 << 27) | (1 << 26) | (1 << 25) | (1 << 24) |\ 25657021918SMauro Carvalho Chehab (1 << 22) | (1 << 21) | (1 << 20) | (1 << 19) |\ 25757021918SMauro Carvalho Chehab (1 << 18) | (1 << 17) | (1 << 16) | (1 << 14) |\ 25857021918SMauro Carvalho Chehab (1 << 13) | (1 << 12) | (1 << 11) | (1 << 10) |\ 25957021918SMauro Carvalho Chehab (1 << 9) | (1 << 8) | (1 << 7) | (1 << 6) |\ 26057021918SMauro Carvalho Chehab (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) |\ 26157021918SMauro Carvalho Chehab (1 << 1) | (1 << 0)) 26257021918SMauro Carvalho Chehab 263c3af2eafSMauro Carvalho Chehab /* 264c3af2eafSMauro Carvalho Chehab * Device 16.2: Global Error Registers 265c3af2eafSMauro Carvalho Chehab */ 266c3af2eafSMauro Carvalho Chehab 2675de6e07eSMauro Carvalho Chehab #define FERR_GLOBAL_HI 0x48 2685de6e07eSMauro Carvalho Chehab static const char *ferr_global_hi_name[] = { 2695de6e07eSMauro Carvalho Chehab [3] = "FSB 3 Fatal Error", 2705de6e07eSMauro Carvalho Chehab [2] = "FSB 2 Fatal Error", 2715de6e07eSMauro Carvalho Chehab [1] = "FSB 1 Fatal Error", 2725de6e07eSMauro Carvalho Chehab [0] = "FSB 0 Fatal Error", 2735de6e07eSMauro Carvalho Chehab }; 2745de6e07eSMauro Carvalho Chehab #define ferr_global_hi_is_fatal(errno) 1 2755de6e07eSMauro Carvalho Chehab 276c3af2eafSMauro Carvalho Chehab #define FERR_GLOBAL_LO 0x40 2775de6e07eSMauro Carvalho Chehab static const char *ferr_global_lo_name[] = { 278c3af2eafSMauro Carvalho Chehab [31] = "Internal MCH Fatal Error", 279c3af2eafSMauro Carvalho Chehab [30] = "Intel QuickData Technology Device Fatal Error", 280c3af2eafSMauro Carvalho Chehab [29] = "FSB1 Fatal Error", 281c3af2eafSMauro Carvalho Chehab [28] = "FSB0 Fatal Error", 282c3af2eafSMauro Carvalho Chehab [27] = "FBD Channel 3 Fatal Error", 283c3af2eafSMauro Carvalho Chehab [26] = "FBD Channel 2 Fatal Error", 284c3af2eafSMauro Carvalho Chehab [25] = "FBD Channel 1 Fatal Error", 285c3af2eafSMauro Carvalho Chehab [24] = "FBD Channel 0 Fatal Error", 286c3af2eafSMauro Carvalho Chehab [23] = "PCI Express Device 7Fatal Error", 287c3af2eafSMauro Carvalho Chehab [22] = "PCI Express Device 6 Fatal Error", 288c3af2eafSMauro Carvalho Chehab [21] = "PCI Express Device 5 Fatal Error", 289c3af2eafSMauro Carvalho Chehab [20] = "PCI Express Device 4 Fatal Error", 290c3af2eafSMauro Carvalho Chehab [19] = "PCI Express Device 3 Fatal Error", 291c3af2eafSMauro Carvalho Chehab [18] = "PCI Express Device 2 Fatal Error", 292c3af2eafSMauro Carvalho Chehab [17] = "PCI Express Device 1 Fatal Error", 293c3af2eafSMauro Carvalho Chehab [16] = "ESI Fatal Error", 294c3af2eafSMauro Carvalho Chehab [15] = "Internal MCH Non-Fatal Error", 295c3af2eafSMauro Carvalho Chehab [14] = "Intel QuickData Technology Device Non Fatal Error", 296c3af2eafSMauro Carvalho Chehab [13] = "FSB1 Non-Fatal Error", 297c3af2eafSMauro Carvalho Chehab [12] = "FSB 0 Non-Fatal Error", 298c3af2eafSMauro Carvalho Chehab [11] = "FBD Channel 3 Non-Fatal Error", 299c3af2eafSMauro Carvalho Chehab [10] = "FBD Channel 2 Non-Fatal Error", 300c3af2eafSMauro Carvalho Chehab [9] = "FBD Channel 1 Non-Fatal Error", 301c3af2eafSMauro Carvalho Chehab [8] = "FBD Channel 0 Non-Fatal Error", 302c3af2eafSMauro Carvalho Chehab [7] = "PCI Express Device 7 Non-Fatal Error", 303c3af2eafSMauro Carvalho Chehab [6] = "PCI Express Device 6 Non-Fatal Error", 304c3af2eafSMauro Carvalho Chehab [5] = "PCI Express Device 5 Non-Fatal Error", 305c3af2eafSMauro Carvalho Chehab [4] = "PCI Express Device 4 Non-Fatal Error", 306c3af2eafSMauro Carvalho Chehab [3] = "PCI Express Device 3 Non-Fatal Error", 307c3af2eafSMauro Carvalho Chehab [2] = "PCI Express Device 2 Non-Fatal Error", 308c3af2eafSMauro Carvalho Chehab [1] = "PCI Express Device 1 Non-Fatal Error", 309c3af2eafSMauro Carvalho Chehab [0] = "ESI Non-Fatal Error", 310c3af2eafSMauro Carvalho Chehab }; 3115de6e07eSMauro Carvalho Chehab #define ferr_global_lo_is_fatal(errno) ((errno < 16) ? 0 : 1) 312fcaf780bSMauro Carvalho Chehab 3138199d8ccSMauro Carvalho Chehab #define NRECMEMA 0xbe 3148199d8ccSMauro Carvalho Chehab #define NRECMEMA_BANK(v) (((v) >> 12) & 7) 3158199d8ccSMauro Carvalho Chehab #define NRECMEMA_RANK(v) (((v) >> 8) & 15) 3168199d8ccSMauro Carvalho Chehab 3178199d8ccSMauro Carvalho Chehab #define NRECMEMB 0xc0 3188199d8ccSMauro Carvalho Chehab #define NRECMEMB_IS_WR(v) ((v) & (1 << 31)) 3198199d8ccSMauro Carvalho Chehab #define NRECMEMB_CAS(v) (((v) >> 16) & 0x1fff) 3208199d8ccSMauro Carvalho Chehab #define NRECMEMB_RAS(v) ((v) & 0xffff) 3218199d8ccSMauro Carvalho Chehab 32232f94726SMauro Carvalho Chehab #define REDMEMA 0xdc 32332f94726SMauro Carvalho Chehab 32437b69cf9SMauro Carvalho Chehab #define REDMEMB 0x7c 32537b69cf9SMauro Carvalho Chehab #define IS_SECOND_CH(v) ((v) * (1 << 17)) 32637b69cf9SMauro Carvalho Chehab 32732f94726SMauro Carvalho Chehab #define RECMEMA 0xe0 32832f94726SMauro Carvalho Chehab #define RECMEMA_BANK(v) (((v) >> 12) & 7) 32932f94726SMauro Carvalho Chehab #define RECMEMA_RANK(v) (((v) >> 8) & 15) 33032f94726SMauro Carvalho Chehab 33132f94726SMauro Carvalho Chehab #define RECMEMB 0xe4 33232f94726SMauro Carvalho Chehab #define RECMEMB_IS_WR(v) ((v) & (1 << 31)) 33332f94726SMauro Carvalho Chehab #define RECMEMB_CAS(v) (((v) >> 16) & 0x1fff) 33432f94726SMauro Carvalho Chehab #define RECMEMB_RAS(v) ((v) & 0xffff) 33532f94726SMauro Carvalho Chehab 3365de6e07eSMauro Carvalho Chehab /******************************************** 3375de6e07eSMauro Carvalho Chehab * i7300 Functions related to error detection 3385de6e07eSMauro Carvalho Chehab ********************************************/ 339fcaf780bSMauro Carvalho Chehab 340d091a6ebSMauro Carvalho Chehab /** 341d091a6ebSMauro Carvalho Chehab * get_err_from_table() - Gets the error message from a table 342d091a6ebSMauro Carvalho Chehab * @table: table name (array of char *) 343d091a6ebSMauro Carvalho Chehab * @size: number of elements at the table 344d091a6ebSMauro Carvalho Chehab * @pos: position of the element to be returned 345d091a6ebSMauro Carvalho Chehab * 346d091a6ebSMauro Carvalho Chehab * This is a small routine that gets the pos-th element of a table. If the 347d091a6ebSMauro Carvalho Chehab * element doesn't exist (or it is empty), it returns "reserved". 348d091a6ebSMauro Carvalho Chehab * Instead of calling it directly, the better is to call via the macro 349d091a6ebSMauro Carvalho Chehab * GET_ERR_FROM_TABLE(), that automatically checks the table size via 350d091a6ebSMauro Carvalho Chehab * ARRAY_SIZE() macro 351d091a6ebSMauro Carvalho Chehab */ 352d091a6ebSMauro Carvalho Chehab static const char *get_err_from_table(const char *table[], int size, int pos) 353fcaf780bSMauro Carvalho Chehab { 354d091a6ebSMauro Carvalho Chehab if (unlikely(pos >= size)) 355d091a6ebSMauro Carvalho Chehab return "Reserved"; 356d091a6ebSMauro Carvalho Chehab 357d091a6ebSMauro Carvalho Chehab if (unlikely(!table[pos])) 3585de6e07eSMauro Carvalho Chehab return "Reserved"; 3595de6e07eSMauro Carvalho Chehab 3605de6e07eSMauro Carvalho Chehab return table[pos]; 361fcaf780bSMauro Carvalho Chehab } 3625de6e07eSMauro Carvalho Chehab 3635de6e07eSMauro Carvalho Chehab #define GET_ERR_FROM_TABLE(table, pos) \ 3645de6e07eSMauro Carvalho Chehab get_err_from_table(table, ARRAY_SIZE(table), pos) 365fcaf780bSMauro Carvalho Chehab 366d091a6ebSMauro Carvalho Chehab /** 367d091a6ebSMauro Carvalho Chehab * i7300_process_error_global() - Retrieve the hardware error information from 368d091a6ebSMauro Carvalho Chehab * the hardware global error registers and 369d091a6ebSMauro Carvalho Chehab * sends it to dmesg 370d091a6ebSMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer 3715de6e07eSMauro Carvalho Chehab */ 372f4277422SMauro Carvalho Chehab static void i7300_process_error_global(struct mem_ctl_info *mci) 3735de6e07eSMauro Carvalho Chehab { 374fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 375*5f032119SMauro Carvalho Chehab u32 errnum, error_reg; 3765de6e07eSMauro Carvalho Chehab unsigned long errors; 3775de6e07eSMauro Carvalho Chehab const char *specific; 3785de6e07eSMauro Carvalho Chehab bool is_fatal; 379fcaf780bSMauro Carvalho Chehab 380fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 381fcaf780bSMauro Carvalho Chehab 382fcaf780bSMauro Carvalho Chehab /* read in the 1st FATAL error register */ 3835de6e07eSMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 384*5f032119SMauro Carvalho Chehab FERR_GLOBAL_HI, &error_reg); 385*5f032119SMauro Carvalho Chehab if (unlikely(error_reg)) { 386*5f032119SMauro Carvalho Chehab errors = error_reg; 3875de6e07eSMauro Carvalho Chehab errnum = find_first_bit(&errors, 3885de6e07eSMauro Carvalho Chehab ARRAY_SIZE(ferr_global_hi_name)); 3895de6e07eSMauro Carvalho Chehab specific = GET_ERR_FROM_TABLE(ferr_global_hi_name, errnum); 3905de6e07eSMauro Carvalho Chehab is_fatal = ferr_global_hi_is_fatal(errnum); 39186002324SMauro Carvalho Chehab 39286002324SMauro Carvalho Chehab /* Clear the error bit */ 39386002324SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 394*5f032119SMauro Carvalho Chehab FERR_GLOBAL_HI, error_reg); 39586002324SMauro Carvalho Chehab 3965de6e07eSMauro Carvalho Chehab goto error_global; 397fcaf780bSMauro Carvalho Chehab } 398fcaf780bSMauro Carvalho Chehab 3995de6e07eSMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 400*5f032119SMauro Carvalho Chehab FERR_GLOBAL_LO, &error_reg); 401*5f032119SMauro Carvalho Chehab if (unlikely(error_reg)) { 402*5f032119SMauro Carvalho Chehab errors = error_reg; 4035de6e07eSMauro Carvalho Chehab errnum = find_first_bit(&errors, 4045de6e07eSMauro Carvalho Chehab ARRAY_SIZE(ferr_global_lo_name)); 4055de6e07eSMauro Carvalho Chehab specific = GET_ERR_FROM_TABLE(ferr_global_lo_name, errnum); 4065de6e07eSMauro Carvalho Chehab is_fatal = ferr_global_lo_is_fatal(errnum); 40786002324SMauro Carvalho Chehab 40886002324SMauro Carvalho Chehab /* Clear the error bit */ 40986002324SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 410*5f032119SMauro Carvalho Chehab FERR_GLOBAL_LO, error_reg); 41186002324SMauro Carvalho Chehab 4125de6e07eSMauro Carvalho Chehab goto error_global; 413fcaf780bSMauro Carvalho Chehab } 414fcaf780bSMauro Carvalho Chehab return; 415fcaf780bSMauro Carvalho Chehab 4165de6e07eSMauro Carvalho Chehab error_global: 4175de6e07eSMauro Carvalho Chehab i7300_mc_printk(mci, KERN_EMERG, "%s misc error: %s\n", 4185de6e07eSMauro Carvalho Chehab is_fatal ? "Fatal" : "NOT fatal", specific); 419fcaf780bSMauro Carvalho Chehab } 420fcaf780bSMauro Carvalho Chehab 421d091a6ebSMauro Carvalho Chehab /** 422d091a6ebSMauro Carvalho Chehab * i7300_process_fbd_error() - Retrieve the hardware error information from 423d091a6ebSMauro Carvalho Chehab * the FBD error registers and sends it via 424d091a6ebSMauro Carvalho Chehab * EDAC error API calls 425d091a6ebSMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer 42657021918SMauro Carvalho Chehab */ 427f4277422SMauro Carvalho Chehab static void i7300_process_fbd_error(struct mem_ctl_info *mci) 42857021918SMauro Carvalho Chehab { 42957021918SMauro Carvalho Chehab struct i7300_pvt *pvt; 430*5f032119SMauro Carvalho Chehab u32 errnum, value, error_reg; 4318199d8ccSMauro Carvalho Chehab u16 val16; 43237b69cf9SMauro Carvalho Chehab unsigned branch, channel, bank, rank, cas, ras; 43332f94726SMauro Carvalho Chehab u32 syndrome; 43432f94726SMauro Carvalho Chehab 43557021918SMauro Carvalho Chehab unsigned long errors; 43657021918SMauro Carvalho Chehab const char *specific; 43732f94726SMauro Carvalho Chehab bool is_wr; 43857021918SMauro Carvalho Chehab 43957021918SMauro Carvalho Chehab pvt = mci->pvt_info; 44057021918SMauro Carvalho Chehab 44157021918SMauro Carvalho Chehab /* read in the 1st FATAL error register */ 44257021918SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 443*5f032119SMauro Carvalho Chehab FERR_FAT_FBD, &error_reg); 444*5f032119SMauro Carvalho Chehab if (unlikely(error_reg & FERR_FAT_FBD_ERR_MASK)) { 445*5f032119SMauro Carvalho Chehab errors = error_reg & FERR_FAT_FBD_ERR_MASK ; 44657021918SMauro Carvalho Chehab errnum = find_first_bit(&errors, 44757021918SMauro Carvalho Chehab ARRAY_SIZE(ferr_fat_fbd_name)); 44857021918SMauro Carvalho Chehab specific = GET_ERR_FROM_TABLE(ferr_fat_fbd_name, errnum); 449*5f032119SMauro Carvalho Chehab branch = (GET_FBD_FAT_IDX(error_reg) == 2) ? 1 : 0; 45057021918SMauro Carvalho Chehab 4518199d8ccSMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, 4528199d8ccSMauro Carvalho Chehab NRECMEMA, &val16); 4538199d8ccSMauro Carvalho Chehab bank = NRECMEMA_BANK(val16); 4548199d8ccSMauro Carvalho Chehab rank = NRECMEMA_RANK(val16); 45557021918SMauro Carvalho Chehab 4568199d8ccSMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 4578199d8ccSMauro Carvalho Chehab NRECMEMB, &value); 4588199d8ccSMauro Carvalho Chehab is_wr = NRECMEMB_IS_WR(value); 4598199d8ccSMauro Carvalho Chehab cas = NRECMEMB_CAS(value); 4608199d8ccSMauro Carvalho Chehab ras = NRECMEMB_RAS(value); 4618199d8ccSMauro Carvalho Chehab 462*5f032119SMauro Carvalho Chehab /* Clean the error register */ 463*5f032119SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 464*5f032119SMauro Carvalho Chehab FERR_FAT_FBD, error_reg); 465*5f032119SMauro Carvalho Chehab 4668199d8ccSMauro Carvalho Chehab snprintf(pvt->tmp_prt_buffer, PAGE_SIZE, 4678199d8ccSMauro Carvalho Chehab "FATAL (Branch=%d DRAM-Bank=%d %s " 4688199d8ccSMauro Carvalho Chehab "RAS=%d CAS=%d Err=0x%lx (%s))", 46932f94726SMauro Carvalho Chehab branch, bank, 4708199d8ccSMauro Carvalho Chehab is_wr ? "RDWR" : "RD", 4718199d8ccSMauro Carvalho Chehab ras, cas, 4728199d8ccSMauro Carvalho Chehab errors, specific); 4738199d8ccSMauro Carvalho Chehab 4748199d8ccSMauro Carvalho Chehab /* Call the helper to output message */ 4758199d8ccSMauro Carvalho Chehab edac_mc_handle_fbd_ue(mci, rank, branch << 1, 4768199d8ccSMauro Carvalho Chehab (branch << 1) + 1, 4778199d8ccSMauro Carvalho Chehab pvt->tmp_prt_buffer); 47857021918SMauro Carvalho Chehab } 47957021918SMauro Carvalho Chehab 48057021918SMauro Carvalho Chehab /* read in the 1st NON-FATAL error register */ 48157021918SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 482*5f032119SMauro Carvalho Chehab FERR_NF_FBD, &error_reg); 483*5f032119SMauro Carvalho Chehab if (unlikely(error_reg & FERR_NF_FBD_ERR_MASK)) { 484*5f032119SMauro Carvalho Chehab errors = error_reg & FERR_NF_FBD_ERR_MASK; 48557021918SMauro Carvalho Chehab errnum = find_first_bit(&errors, 48657021918SMauro Carvalho Chehab ARRAY_SIZE(ferr_nf_fbd_name)); 48757021918SMauro Carvalho Chehab specific = GET_ERR_FROM_TABLE(ferr_nf_fbd_name, errnum); 488*5f032119SMauro Carvalho Chehab branch = (GET_FBD_FAT_IDX(error_reg) == 2) ? 1 : 0; 48957021918SMauro Carvalho Chehab 49032f94726SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 49132f94726SMauro Carvalho Chehab REDMEMA, &syndrome); 49232f94726SMauro Carvalho Chehab 49332f94726SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, 49432f94726SMauro Carvalho Chehab RECMEMA, &val16); 49532f94726SMauro Carvalho Chehab bank = RECMEMA_BANK(val16); 49632f94726SMauro Carvalho Chehab rank = RECMEMA_RANK(val16); 49732f94726SMauro Carvalho Chehab 49832f94726SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 49932f94726SMauro Carvalho Chehab RECMEMB, &value); 50032f94726SMauro Carvalho Chehab is_wr = RECMEMB_IS_WR(value); 50132f94726SMauro Carvalho Chehab cas = RECMEMB_CAS(value); 50232f94726SMauro Carvalho Chehab ras = RECMEMB_RAS(value); 50332f94726SMauro Carvalho Chehab 50437b69cf9SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 50537b69cf9SMauro Carvalho Chehab REDMEMB, &value); 50637b69cf9SMauro Carvalho Chehab channel = (branch << 1); 50737b69cf9SMauro Carvalho Chehab if (IS_SECOND_CH(value)) 50837b69cf9SMauro Carvalho Chehab channel++; 50937b69cf9SMauro Carvalho Chehab 510*5f032119SMauro Carvalho Chehab /* Clear the error bit */ 511*5f032119SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 512*5f032119SMauro Carvalho Chehab FERR_NF_FBD, error_reg); 513*5f032119SMauro Carvalho Chehab 51432f94726SMauro Carvalho Chehab /* Form out message */ 51532f94726SMauro Carvalho Chehab snprintf(pvt->tmp_prt_buffer, PAGE_SIZE, 51637b69cf9SMauro Carvalho Chehab "Corrected error (Branch=%d, Channel %d), " 51732f94726SMauro Carvalho Chehab " DRAM-Bank=%d %s " 51832f94726SMauro Carvalho Chehab "RAS=%d CAS=%d, CE Err=0x%lx, Syndrome=0x%08x(%s))", 51937b69cf9SMauro Carvalho Chehab branch, channel, 52032f94726SMauro Carvalho Chehab bank, 52132f94726SMauro Carvalho Chehab is_wr ? "RDWR" : "RD", 52232f94726SMauro Carvalho Chehab ras, cas, 52332f94726SMauro Carvalho Chehab errors, syndrome, specific); 52432f94726SMauro Carvalho Chehab 52532f94726SMauro Carvalho Chehab /* 52632f94726SMauro Carvalho Chehab * Call the helper to output message 52732f94726SMauro Carvalho Chehab * NOTE: Errors are reported per-branch, and not per-channel 52832f94726SMauro Carvalho Chehab * Currently, we don't know how to identify the right 52932f94726SMauro Carvalho Chehab * channel. 53032f94726SMauro Carvalho Chehab */ 53137b69cf9SMauro Carvalho Chehab edac_mc_handle_fbd_ce(mci, rank, channel, 53232f94726SMauro Carvalho Chehab pvt->tmp_prt_buffer); 53357021918SMauro Carvalho Chehab } 53457021918SMauro Carvalho Chehab return; 53557021918SMauro Carvalho Chehab } 53657021918SMauro Carvalho Chehab 537d091a6ebSMauro Carvalho Chehab /** 538d091a6ebSMauro Carvalho Chehab * i7300_check_error() - Calls the error checking subroutines 539d091a6ebSMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer 540fcaf780bSMauro Carvalho Chehab */ 541f4277422SMauro Carvalho Chehab static void i7300_check_error(struct mem_ctl_info *mci) 5425de6e07eSMauro Carvalho Chehab { 543f4277422SMauro Carvalho Chehab i7300_process_error_global(mci); 544f4277422SMauro Carvalho Chehab i7300_process_fbd_error(mci); 5455de6e07eSMauro Carvalho Chehab }; 546fcaf780bSMauro Carvalho Chehab 547d091a6ebSMauro Carvalho Chehab /** 548d091a6ebSMauro Carvalho Chehab * i7300_clear_error() - Clears the error registers 549d091a6ebSMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer 550fcaf780bSMauro Carvalho Chehab */ 551fcaf780bSMauro Carvalho Chehab static void i7300_clear_error(struct mem_ctl_info *mci) 552fcaf780bSMauro Carvalho Chehab { 553e4327605SMauro Carvalho Chehab struct i7300_pvt *pvt = mci->pvt_info; 554e4327605SMauro Carvalho Chehab u32 value; 555e4327605SMauro Carvalho Chehab /* 556e4327605SMauro Carvalho Chehab * All error values are RWC - we need to read and write 1 to the 557e4327605SMauro Carvalho Chehab * bit that we want to cleanup 558e4327605SMauro Carvalho Chehab */ 559fcaf780bSMauro Carvalho Chehab 560e4327605SMauro Carvalho Chehab /* Clear global error registers */ 561e4327605SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 562e4327605SMauro Carvalho Chehab FERR_GLOBAL_HI, &value); 563e4327605SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 564e4327605SMauro Carvalho Chehab FERR_GLOBAL_HI, value); 565e4327605SMauro Carvalho Chehab 566e4327605SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 567e4327605SMauro Carvalho Chehab FERR_GLOBAL_LO, &value); 568e4327605SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 569e4327605SMauro Carvalho Chehab FERR_GLOBAL_LO, value); 570e4327605SMauro Carvalho Chehab 571e4327605SMauro Carvalho Chehab /* Clear FBD error registers */ 572e4327605SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 573e4327605SMauro Carvalho Chehab FERR_FAT_FBD, &value); 574e4327605SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 575e4327605SMauro Carvalho Chehab FERR_FAT_FBD, value); 576e4327605SMauro Carvalho Chehab 577e4327605SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 578e4327605SMauro Carvalho Chehab FERR_NF_FBD, &value); 579e4327605SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 580e4327605SMauro Carvalho Chehab FERR_NF_FBD, value); 581fcaf780bSMauro Carvalho Chehab } 582fcaf780bSMauro Carvalho Chehab 583d091a6ebSMauro Carvalho Chehab /** 584d091a6ebSMauro Carvalho Chehab * i7300_enable_error_reporting() - Enable the memory reporting logic at the 585d091a6ebSMauro Carvalho Chehab * hardware 586d091a6ebSMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer 587fcaf780bSMauro Carvalho Chehab */ 588fcaf780bSMauro Carvalho Chehab static void i7300_enable_error_reporting(struct mem_ctl_info *mci) 589fcaf780bSMauro Carvalho Chehab { 59057021918SMauro Carvalho Chehab struct i7300_pvt *pvt = mci->pvt_info; 59157021918SMauro Carvalho Chehab u32 fbd_error_mask; 59257021918SMauro Carvalho Chehab 59357021918SMauro Carvalho Chehab /* Read the FBD Error Mask Register */ 59457021918SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 59557021918SMauro Carvalho Chehab EMASK_FBD, &fbd_error_mask); 59657021918SMauro Carvalho Chehab 59757021918SMauro Carvalho Chehab /* Enable with a '0' */ 59857021918SMauro Carvalho Chehab fbd_error_mask &= ~(EMASK_FBD_ERR_MASK); 59957021918SMauro Carvalho Chehab 60057021918SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 60157021918SMauro Carvalho Chehab EMASK_FBD, fbd_error_mask); 602fcaf780bSMauro Carvalho Chehab } 6035de6e07eSMauro Carvalho Chehab 6045de6e07eSMauro Carvalho Chehab /************************************************ 6055de6e07eSMauro Carvalho Chehab * i7300 Functions related to memory enumberation 6065de6e07eSMauro Carvalho Chehab ************************************************/ 607fcaf780bSMauro Carvalho Chehab 608d091a6ebSMauro Carvalho Chehab /** 609d091a6ebSMauro Carvalho Chehab * decode_mtr() - Decodes the MTR descriptor, filling the edac structs 610d091a6ebSMauro Carvalho Chehab * @pvt: pointer to the private data struct used by i7300 driver 611d091a6ebSMauro Carvalho Chehab * @slot: DIMM slot (0 to 7) 612d091a6ebSMauro Carvalho Chehab * @ch: Channel number within the branch (0 or 1) 613d091a6ebSMauro Carvalho Chehab * @branch: Branch number (0 or 1) 614d091a6ebSMauro Carvalho Chehab * @dinfo: Pointer to DIMM info where dimm size is stored 615d091a6ebSMauro Carvalho Chehab * @p_csrow: Pointer to the struct csrow_info that corresponds to that element 616fcaf780bSMauro Carvalho Chehab */ 617fcaf780bSMauro Carvalho Chehab static int decode_mtr(struct i7300_pvt *pvt, 618fcaf780bSMauro Carvalho Chehab int slot, int ch, int branch, 619fcaf780bSMauro Carvalho Chehab struct i7300_dimm_info *dinfo, 6201aa4a7b6SMauro Carvalho Chehab struct csrow_info *p_csrow, 621e6649cc6SMauro Carvalho Chehab u32 *nr_pages) 622fcaf780bSMauro Carvalho Chehab { 623fcaf780bSMauro Carvalho Chehab int mtr, ans, addrBits, channel; 624fcaf780bSMauro Carvalho Chehab 625fcaf780bSMauro Carvalho Chehab channel = to_channel(ch, branch); 626fcaf780bSMauro Carvalho Chehab 627fcaf780bSMauro Carvalho Chehab mtr = pvt->mtr[slot][branch]; 628fcaf780bSMauro Carvalho Chehab ans = MTR_DIMMS_PRESENT(mtr) ? 1 : 0; 629fcaf780bSMauro Carvalho Chehab 630fcaf780bSMauro Carvalho Chehab debugf2("\tMTR%d CH%d: DIMMs are %s (mtr)\n", 631fcaf780bSMauro Carvalho Chehab slot, channel, 632fcaf780bSMauro Carvalho Chehab ans ? "Present" : "NOT Present"); 633fcaf780bSMauro Carvalho Chehab 634fcaf780bSMauro Carvalho Chehab /* Determine if there is a DIMM present in this DIMM slot */ 635fcaf780bSMauro Carvalho Chehab if (!ans) 636fcaf780bSMauro Carvalho Chehab return 0; 637fcaf780bSMauro Carvalho Chehab 638fcaf780bSMauro Carvalho Chehab /* Start with the number of bits for a Bank 639fcaf780bSMauro Carvalho Chehab * on the DRAM */ 640fcaf780bSMauro Carvalho Chehab addrBits = MTR_DRAM_BANKS_ADDR_BITS; 641fcaf780bSMauro Carvalho Chehab /* Add thenumber of ROW bits */ 642fcaf780bSMauro Carvalho Chehab addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr); 643fcaf780bSMauro Carvalho Chehab /* add the number of COLUMN bits */ 644fcaf780bSMauro Carvalho Chehab addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr); 645fcaf780bSMauro Carvalho Chehab /* add the number of RANK bits */ 646fcaf780bSMauro Carvalho Chehab addrBits += MTR_DIMM_RANKS(mtr); 647fcaf780bSMauro Carvalho Chehab 648fcaf780bSMauro Carvalho Chehab addrBits += 6; /* add 64 bits per DIMM */ 649fcaf780bSMauro Carvalho Chehab addrBits -= 20; /* divide by 2^^20 */ 650fcaf780bSMauro Carvalho Chehab addrBits -= 3; /* 8 bits per bytes */ 651fcaf780bSMauro Carvalho Chehab 652fcaf780bSMauro Carvalho Chehab dinfo->megabytes = 1 << addrBits; 653e6649cc6SMauro Carvalho Chehab *nr_pages = dinfo->megabytes << 8; 654fcaf780bSMauro Carvalho Chehab 655fcaf780bSMauro Carvalho Chehab debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr)); 656fcaf780bSMauro Carvalho Chehab 657fcaf780bSMauro Carvalho Chehab debugf2("\t\tELECTRICAL THROTTLING is %s\n", 658fcaf780bSMauro Carvalho Chehab MTR_DIMMS_ETHROTTLE(mtr) ? "enabled" : "disabled"); 659fcaf780bSMauro Carvalho Chehab 660fcaf780bSMauro Carvalho Chehab debugf2("\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr)); 661fcaf780bSMauro Carvalho Chehab debugf2("\t\tNUMRANK: %s\n", MTR_DIMM_RANKS(mtr) ? "double" : "single"); 662fcaf780bSMauro Carvalho Chehab debugf2("\t\tNUMROW: %s\n", numrow_toString[MTR_DIMM_ROWS(mtr)]); 663fcaf780bSMauro Carvalho Chehab debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]); 664fcaf780bSMauro Carvalho Chehab debugf2("\t\tSIZE: %d MB\n", dinfo->megabytes); 665fcaf780bSMauro Carvalho Chehab 666fcaf780bSMauro Carvalho Chehab p_csrow->grain = 8; 667fcaf780bSMauro Carvalho Chehab p_csrow->mtype = MEM_FB_DDR2; 6681aa4a7b6SMauro Carvalho Chehab p_csrow->csrow_idx = slot; 6691aa4a7b6SMauro Carvalho Chehab p_csrow->page_mask = 0; 670116389edSMauro Carvalho Chehab 671116389edSMauro Carvalho Chehab /* 67215154c57SMauro Carvalho Chehab * The type of error detection actually depends of the 673116389edSMauro Carvalho Chehab * mode of operation. When it is just one single memory chip, at 674116389edSMauro Carvalho Chehab * socket 0, channel 0, it uses 8-byte-over-32-byte SECDED+ code. 67515154c57SMauro Carvalho Chehab * In normal or mirrored mode, it uses Lockstep mode, 676116389edSMauro Carvalho Chehab * with the possibility of using an extended algorithm for x8 memories 677116389edSMauro Carvalho Chehab * See datasheet Sections 7.3.6 to 7.3.8 678116389edSMauro Carvalho Chehab */ 67915154c57SMauro Carvalho Chehab 68015154c57SMauro Carvalho Chehab if (IS_SINGLE_MODE(pvt->mc_settings_a)) { 68115154c57SMauro Carvalho Chehab p_csrow->edac_mode = EDAC_SECDED; 6823b330f67SMauro Carvalho Chehab debugf2("\t\tECC code is 8-byte-over-32-byte SECDED+ code\n"); 68315154c57SMauro Carvalho Chehab } else { 6843b330f67SMauro Carvalho Chehab debugf2("\t\tECC code is on Lockstep mode\n"); 68528c2ce7cSMauro Carvalho Chehab if (MTR_DRAM_WIDTH(mtr) == 8) 686fcaf780bSMauro Carvalho Chehab p_csrow->edac_mode = EDAC_S8ECD8ED; 68715154c57SMauro Carvalho Chehab else 68815154c57SMauro Carvalho Chehab p_csrow->edac_mode = EDAC_S4ECD4ED; 68915154c57SMauro Carvalho Chehab } 690fcaf780bSMauro Carvalho Chehab 691fcaf780bSMauro Carvalho Chehab /* ask what device type on this row */ 69228c2ce7cSMauro Carvalho Chehab if (MTR_DRAM_WIDTH(mtr) == 8) { 6933b330f67SMauro Carvalho Chehab debugf2("\t\tScrub algorithm for x8 is on %s mode\n", 694d7de2bdbSMauro Carvalho Chehab IS_SCRBALGO_ENHANCED(pvt->mc_settings) ? 695d7de2bdbSMauro Carvalho Chehab "enhanced" : "normal"); 696d7de2bdbSMauro Carvalho Chehab 697fcaf780bSMauro Carvalho Chehab p_csrow->dtype = DEV_X8; 698d7de2bdbSMauro Carvalho Chehab } else 699fcaf780bSMauro Carvalho Chehab p_csrow->dtype = DEV_X4; 700fcaf780bSMauro Carvalho Chehab 701fcaf780bSMauro Carvalho Chehab return mtr; 702fcaf780bSMauro Carvalho Chehab } 703fcaf780bSMauro Carvalho Chehab 704d091a6ebSMauro Carvalho Chehab /** 705d091a6ebSMauro Carvalho Chehab * print_dimm_size() - Prints dump of the memory organization 706d091a6ebSMauro Carvalho Chehab * @pvt: pointer to the private data struct used by i7300 driver 707fcaf780bSMauro Carvalho Chehab * 708d091a6ebSMauro Carvalho Chehab * Useful for debug. If debug is disabled, this routine do nothing 709fcaf780bSMauro Carvalho Chehab */ 710fcaf780bSMauro Carvalho Chehab static void print_dimm_size(struct i7300_pvt *pvt) 711fcaf780bSMauro Carvalho Chehab { 712d091a6ebSMauro Carvalho Chehab #ifdef CONFIG_EDAC_DEBUG 713fcaf780bSMauro Carvalho Chehab struct i7300_dimm_info *dinfo; 71485580ea4SMauro Carvalho Chehab char *p; 715fcaf780bSMauro Carvalho Chehab int space, n; 716fcaf780bSMauro Carvalho Chehab int channel, slot; 717fcaf780bSMauro Carvalho Chehab 718fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 71985580ea4SMauro Carvalho Chehab p = pvt->tmp_prt_buffer; 720fcaf780bSMauro Carvalho Chehab 721fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, " "); 722fcaf780bSMauro Carvalho Chehab p += n; 723fcaf780bSMauro Carvalho Chehab space -= n; 724fcaf780bSMauro Carvalho Chehab for (channel = 0; channel < MAX_CHANNELS; channel++) { 725fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "channel %d | ", channel); 726fcaf780bSMauro Carvalho Chehab p += n; 727fcaf780bSMauro Carvalho Chehab space -= n; 728fcaf780bSMauro Carvalho Chehab } 72985580ea4SMauro Carvalho Chehab debugf2("%s\n", pvt->tmp_prt_buffer); 73085580ea4SMauro Carvalho Chehab p = pvt->tmp_prt_buffer; 731fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 732fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "-------------------------------" 733fcaf780bSMauro Carvalho Chehab "------------------------------"); 734fcaf780bSMauro Carvalho Chehab p += n; 735fcaf780bSMauro Carvalho Chehab space -= n; 73685580ea4SMauro Carvalho Chehab debugf2("%s\n", pvt->tmp_prt_buffer); 73785580ea4SMauro Carvalho Chehab p = pvt->tmp_prt_buffer; 738fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 739fcaf780bSMauro Carvalho Chehab 740fcaf780bSMauro Carvalho Chehab for (slot = 0; slot < MAX_SLOTS; slot++) { 741fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "csrow/SLOT %d ", slot); 742fcaf780bSMauro Carvalho Chehab p += n; 743fcaf780bSMauro Carvalho Chehab space -= n; 744fcaf780bSMauro Carvalho Chehab 745fcaf780bSMauro Carvalho Chehab for (channel = 0; channel < MAX_CHANNELS; channel++) { 746fcaf780bSMauro Carvalho Chehab dinfo = &pvt->dimm_info[slot][channel]; 747fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "%4d MB | ", dinfo->megabytes); 748fcaf780bSMauro Carvalho Chehab p += n; 749fcaf780bSMauro Carvalho Chehab space -= n; 750fcaf780bSMauro Carvalho Chehab } 751fcaf780bSMauro Carvalho Chehab 75285580ea4SMauro Carvalho Chehab debugf2("%s\n", pvt->tmp_prt_buffer); 75385580ea4SMauro Carvalho Chehab p = pvt->tmp_prt_buffer; 754fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 755fcaf780bSMauro Carvalho Chehab } 756fcaf780bSMauro Carvalho Chehab 757fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "-------------------------------" 758fcaf780bSMauro Carvalho Chehab "------------------------------"); 759fcaf780bSMauro Carvalho Chehab p += n; 760fcaf780bSMauro Carvalho Chehab space -= n; 76185580ea4SMauro Carvalho Chehab debugf2("%s\n", pvt->tmp_prt_buffer); 76285580ea4SMauro Carvalho Chehab p = pvt->tmp_prt_buffer; 763fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 764d091a6ebSMauro Carvalho Chehab #endif 765fcaf780bSMauro Carvalho Chehab } 766fcaf780bSMauro Carvalho Chehab 767d091a6ebSMauro Carvalho Chehab /** 768d091a6ebSMauro Carvalho Chehab * i7300_init_csrows() - Initialize the 'csrows' table within 769fcaf780bSMauro Carvalho Chehab * the mci control structure with the 770fcaf780bSMauro Carvalho Chehab * addressing of memory. 771d091a6ebSMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer 772fcaf780bSMauro Carvalho Chehab */ 773fcaf780bSMauro Carvalho Chehab static int i7300_init_csrows(struct mem_ctl_info *mci) 774fcaf780bSMauro Carvalho Chehab { 775fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 776fcaf780bSMauro Carvalho Chehab struct i7300_dimm_info *dinfo; 777fcaf780bSMauro Carvalho Chehab struct csrow_info *p_csrow; 778d091a6ebSMauro Carvalho Chehab int rc = -ENODEV; 779fcaf780bSMauro Carvalho Chehab int mtr; 780fcaf780bSMauro Carvalho Chehab int ch, branch, slot, channel; 781e6649cc6SMauro Carvalho Chehab u32 last_page = 0, nr_pages; 782fcaf780bSMauro Carvalho Chehab 783fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 784fcaf780bSMauro Carvalho Chehab 785fcaf780bSMauro Carvalho Chehab debugf2("Memory Technology Registers:\n"); 786fcaf780bSMauro Carvalho Chehab 787fcaf780bSMauro Carvalho Chehab /* Get the AMB present registers for the four channels */ 788fcaf780bSMauro Carvalho Chehab for (branch = 0; branch < MAX_BRANCHES; branch++) { 789fcaf780bSMauro Carvalho Chehab /* Read and dump branch 0's MTRs */ 790fcaf780bSMauro Carvalho Chehab channel = to_channel(0, branch); 7919c6f6b65SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch], 7929c6f6b65SMauro Carvalho Chehab AMBPRESENT_0, 793fcaf780bSMauro Carvalho Chehab &pvt->ambpresent[channel]); 794fcaf780bSMauro Carvalho Chehab debugf2("\t\tAMB-present CH%d = 0x%x:\n", 795fcaf780bSMauro Carvalho Chehab channel, pvt->ambpresent[channel]); 796fcaf780bSMauro Carvalho Chehab 797fcaf780bSMauro Carvalho Chehab channel = to_channel(1, branch); 7989c6f6b65SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch], 7999c6f6b65SMauro Carvalho Chehab AMBPRESENT_1, 800fcaf780bSMauro Carvalho Chehab &pvt->ambpresent[channel]); 801fcaf780bSMauro Carvalho Chehab debugf2("\t\tAMB-present CH%d = 0x%x:\n", 802fcaf780bSMauro Carvalho Chehab channel, pvt->ambpresent[channel]); 803fcaf780bSMauro Carvalho Chehab } 804fcaf780bSMauro Carvalho Chehab 805fcaf780bSMauro Carvalho Chehab /* Get the set of MTR[0-7] regs by each branch */ 806fcaf780bSMauro Carvalho Chehab for (slot = 0; slot < MAX_SLOTS; slot++) { 807fcaf780bSMauro Carvalho Chehab int where = mtr_regs[slot]; 808fcaf780bSMauro Carvalho Chehab for (branch = 0; branch < MAX_BRANCHES; branch++) { 8093e57eef6SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch], 810fcaf780bSMauro Carvalho Chehab where, 811fcaf780bSMauro Carvalho Chehab &pvt->mtr[slot][branch]); 812fcaf780bSMauro Carvalho Chehab for (ch = 0; ch < MAX_BRANCHES; ch++) { 813fcaf780bSMauro Carvalho Chehab int channel = to_channel(ch, branch); 814fcaf780bSMauro Carvalho Chehab 815fcaf780bSMauro Carvalho Chehab dinfo = &pvt->dimm_info[slot][channel]; 816fcaf780bSMauro Carvalho Chehab p_csrow = &mci->csrows[slot]; 817fcaf780bSMauro Carvalho Chehab 818fcaf780bSMauro Carvalho Chehab mtr = decode_mtr(pvt, slot, ch, branch, 819e6649cc6SMauro Carvalho Chehab dinfo, p_csrow, &nr_pages); 820fcaf780bSMauro Carvalho Chehab /* if no DIMMS on this row, continue */ 821fcaf780bSMauro Carvalho Chehab if (!MTR_DIMMS_PRESENT(mtr)) 822fcaf780bSMauro Carvalho Chehab continue; 823fcaf780bSMauro Carvalho Chehab 824e6649cc6SMauro Carvalho Chehab /* Update per_csrow memory count */ 825e6649cc6SMauro Carvalho Chehab p_csrow->nr_pages += nr_pages; 826e6649cc6SMauro Carvalho Chehab p_csrow->first_page = last_page; 827e6649cc6SMauro Carvalho Chehab last_page += nr_pages; 828e6649cc6SMauro Carvalho Chehab p_csrow->last_page = last_page; 829e6649cc6SMauro Carvalho Chehab 830d091a6ebSMauro Carvalho Chehab rc = 0; 831fcaf780bSMauro Carvalho Chehab } 832fcaf780bSMauro Carvalho Chehab } 833fcaf780bSMauro Carvalho Chehab } 834fcaf780bSMauro Carvalho Chehab 835d091a6ebSMauro Carvalho Chehab return rc; 836fcaf780bSMauro Carvalho Chehab } 837fcaf780bSMauro Carvalho Chehab 838d091a6ebSMauro Carvalho Chehab /** 839d091a6ebSMauro Carvalho Chehab * decode_mir() - Decodes Memory Interleave Register (MIR) info 840d091a6ebSMauro Carvalho Chehab * @int mir_no: number of the MIR register to decode 841d091a6ebSMauro Carvalho Chehab * @mir: array with the MIR data cached on the driver 842d091a6ebSMauro Carvalho Chehab */ 843fcaf780bSMauro Carvalho Chehab static void decode_mir(int mir_no, u16 mir[MAX_MIR]) 844fcaf780bSMauro Carvalho Chehab { 845fcaf780bSMauro Carvalho Chehab if (mir[mir_no] & 3) 8469c6f6b65SMauro Carvalho Chehab debugf2("MIR%d: limit= 0x%x Branch(es) that participate:" 8479c6f6b65SMauro Carvalho Chehab " %s %s\n", 848fcaf780bSMauro Carvalho Chehab mir_no, 849fcaf780bSMauro Carvalho Chehab (mir[mir_no] >> 4) & 0xfff, 850fcaf780bSMauro Carvalho Chehab (mir[mir_no] & 1) ? "B0" : "", 851fcaf780bSMauro Carvalho Chehab (mir[mir_no] & 2) ? "B1" : ""); 852fcaf780bSMauro Carvalho Chehab } 853fcaf780bSMauro Carvalho Chehab 854d091a6ebSMauro Carvalho Chehab /** 855d091a6ebSMauro Carvalho Chehab * i7300_get_mc_regs() - Get the contents of the MC enumeration registers 856d091a6ebSMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer 857fcaf780bSMauro Carvalho Chehab * 858d091a6ebSMauro Carvalho Chehab * Data read is cached internally for its usage when needed 859fcaf780bSMauro Carvalho Chehab */ 860fcaf780bSMauro Carvalho Chehab static int i7300_get_mc_regs(struct mem_ctl_info *mci) 861fcaf780bSMauro Carvalho Chehab { 862fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 863fcaf780bSMauro Carvalho Chehab u32 actual_tolm; 864fcaf780bSMauro Carvalho Chehab int i, rc; 865fcaf780bSMauro Carvalho Chehab 866fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 867fcaf780bSMauro Carvalho Chehab 8683e57eef6SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_0_fsb_ctlr, AMBASE, 869fcaf780bSMauro Carvalho Chehab (u32 *) &pvt->ambase); 870fcaf780bSMauro Carvalho Chehab 871fcaf780bSMauro Carvalho Chehab debugf2("AMBASE= 0x%lx\n", (long unsigned int)pvt->ambase); 872fcaf780bSMauro Carvalho Chehab 873fcaf780bSMauro Carvalho Chehab /* Get the Branch Map regs */ 8743e57eef6SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, TOLM, &pvt->tolm); 875fcaf780bSMauro Carvalho Chehab pvt->tolm >>= 12; 876fcaf780bSMauro Carvalho Chehab debugf2("TOLM (number of 256M regions) =%u (0x%x)\n", pvt->tolm, 877fcaf780bSMauro Carvalho Chehab pvt->tolm); 878fcaf780bSMauro Carvalho Chehab 879fcaf780bSMauro Carvalho Chehab actual_tolm = (u32) ((1000l * pvt->tolm) >> (30 - 28)); 880fcaf780bSMauro Carvalho Chehab debugf2("Actual TOLM byte addr=%u.%03u GB (0x%x)\n", 881fcaf780bSMauro Carvalho Chehab actual_tolm/1000, actual_tolm % 1000, pvt->tolm << 28); 882fcaf780bSMauro Carvalho Chehab 883af3d8831SMauro Carvalho Chehab /* Get memory controller settings */ 8843e57eef6SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, MC_SETTINGS, 885af3d8831SMauro Carvalho Chehab &pvt->mc_settings); 886bb81a216SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, MC_SETTINGS_A, 887bb81a216SMauro Carvalho Chehab &pvt->mc_settings_a); 888d7de2bdbSMauro Carvalho Chehab 889bb81a216SMauro Carvalho Chehab if (IS_SINGLE_MODE(pvt->mc_settings_a)) 890bb81a216SMauro Carvalho Chehab debugf0("Memory controller operating on single mode\n"); 891bb81a216SMauro Carvalho Chehab else 892af3d8831SMauro Carvalho Chehab debugf0("Memory controller operating on %s mode\n", 893d7de2bdbSMauro Carvalho Chehab IS_MIRRORED(pvt->mc_settings) ? "mirrored" : "non-mirrored"); 894bb81a216SMauro Carvalho Chehab 895af3d8831SMauro Carvalho Chehab debugf0("Error detection is %s\n", 896d7de2bdbSMauro Carvalho Chehab IS_ECC_ENABLED(pvt->mc_settings) ? "enabled" : "disabled"); 897d7de2bdbSMauro Carvalho Chehab debugf0("Retry is %s\n", 898d7de2bdbSMauro Carvalho Chehab IS_RETRY_ENABLED(pvt->mc_settings) ? "enabled" : "disabled"); 899af3d8831SMauro Carvalho Chehab 900af3d8831SMauro Carvalho Chehab /* Get Memory Interleave Range registers */ 9019c6f6b65SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR0, 9029c6f6b65SMauro Carvalho Chehab &pvt->mir[0]); 9039c6f6b65SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR1, 9049c6f6b65SMauro Carvalho Chehab &pvt->mir[1]); 9059c6f6b65SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR2, 9069c6f6b65SMauro Carvalho Chehab &pvt->mir[2]); 907fcaf780bSMauro Carvalho Chehab 908fcaf780bSMauro Carvalho Chehab /* Decode the MIR regs */ 909fcaf780bSMauro Carvalho Chehab for (i = 0; i < MAX_MIR; i++) 910fcaf780bSMauro Carvalho Chehab decode_mir(i, pvt->mir); 911fcaf780bSMauro Carvalho Chehab 912fcaf780bSMauro Carvalho Chehab rc = i7300_init_csrows(mci); 913fcaf780bSMauro Carvalho Chehab if (rc < 0) 914fcaf780bSMauro Carvalho Chehab return rc; 915fcaf780bSMauro Carvalho Chehab 916fcaf780bSMauro Carvalho Chehab /* Go and determine the size of each DIMM and place in an 917fcaf780bSMauro Carvalho Chehab * orderly matrix */ 918fcaf780bSMauro Carvalho Chehab print_dimm_size(pvt); 919fcaf780bSMauro Carvalho Chehab 920fcaf780bSMauro Carvalho Chehab return 0; 921fcaf780bSMauro Carvalho Chehab } 922fcaf780bSMauro Carvalho Chehab 9235de6e07eSMauro Carvalho Chehab /************************************************* 9245de6e07eSMauro Carvalho Chehab * i7300 Functions related to device probe/release 9255de6e07eSMauro Carvalho Chehab *************************************************/ 9265de6e07eSMauro Carvalho Chehab 927d091a6ebSMauro Carvalho Chehab /** 928d091a6ebSMauro Carvalho Chehab * i7300_put_devices() - Release the PCI devices 929d091a6ebSMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer 930fcaf780bSMauro Carvalho Chehab */ 931fcaf780bSMauro Carvalho Chehab static void i7300_put_devices(struct mem_ctl_info *mci) 932fcaf780bSMauro Carvalho Chehab { 933fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 934fcaf780bSMauro Carvalho Chehab int branch; 935fcaf780bSMauro Carvalho Chehab 936fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 937fcaf780bSMauro Carvalho Chehab 938fcaf780bSMauro Carvalho Chehab /* Decrement usage count for devices */ 939fcaf780bSMauro Carvalho Chehab for (branch = 0; branch < MAX_CH_PER_BRANCH; branch++) 9403e57eef6SMauro Carvalho Chehab pci_dev_put(pvt->pci_dev_2x_0_fbd_branch[branch]); 9413e57eef6SMauro Carvalho Chehab pci_dev_put(pvt->pci_dev_16_2_fsb_err_regs); 9423e57eef6SMauro Carvalho Chehab pci_dev_put(pvt->pci_dev_16_1_fsb_addr_map); 943fcaf780bSMauro Carvalho Chehab } 944fcaf780bSMauro Carvalho Chehab 945d091a6ebSMauro Carvalho Chehab /** 946d091a6ebSMauro Carvalho Chehab * i7300_get_devices() - Find and perform 'get' operation on the MCH's 947fcaf780bSMauro Carvalho Chehab * device/functions we want to reference for this driver 948d091a6ebSMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer 949fcaf780bSMauro Carvalho Chehab * 950d091a6ebSMauro Carvalho Chehab * Access and prepare the several devices for usage: 951d091a6ebSMauro Carvalho Chehab * I7300 devices used by this driver: 952d091a6ebSMauro Carvalho Chehab * Device 16, functions 0,1 and 2: PCI_DEVICE_ID_INTEL_I7300_MCH_ERR 953d091a6ebSMauro Carvalho Chehab * Device 21 function 0: PCI_DEVICE_ID_INTEL_I7300_MCH_FB0 954d091a6ebSMauro Carvalho Chehab * Device 22 function 0: PCI_DEVICE_ID_INTEL_I7300_MCH_FB1 955fcaf780bSMauro Carvalho Chehab */ 956d091a6ebSMauro Carvalho Chehab static int __devinit i7300_get_devices(struct mem_ctl_info *mci) 957fcaf780bSMauro Carvalho Chehab { 958fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 959fcaf780bSMauro Carvalho Chehab struct pci_dev *pdev; 960fcaf780bSMauro Carvalho Chehab 961fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 962fcaf780bSMauro Carvalho Chehab 963fcaf780bSMauro Carvalho Chehab /* Attempt to 'get' the MCH register we want */ 964fcaf780bSMauro Carvalho Chehab pdev = NULL; 9659c6f6b65SMauro Carvalho Chehab while (!pvt->pci_dev_16_1_fsb_addr_map || 9669c6f6b65SMauro Carvalho Chehab !pvt->pci_dev_16_2_fsb_err_regs) { 967fcaf780bSMauro Carvalho Chehab pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 968fcaf780bSMauro Carvalho Chehab PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, pdev); 969fcaf780bSMauro Carvalho Chehab if (!pdev) { 970fcaf780bSMauro Carvalho Chehab /* End of list, leave */ 971fcaf780bSMauro Carvalho Chehab i7300_printk(KERN_ERR, 972fcaf780bSMauro Carvalho Chehab "'system address,Process Bus' " 973fcaf780bSMauro Carvalho Chehab "device not found:" 974fcaf780bSMauro Carvalho Chehab "vendor 0x%x device 0x%x ERR funcs " 975fcaf780bSMauro Carvalho Chehab "(broken BIOS?)\n", 976fcaf780bSMauro Carvalho Chehab PCI_VENDOR_ID_INTEL, 977fcaf780bSMauro Carvalho Chehab PCI_DEVICE_ID_INTEL_I7300_MCH_ERR); 978fcaf780bSMauro Carvalho Chehab goto error; 979fcaf780bSMauro Carvalho Chehab } 980fcaf780bSMauro Carvalho Chehab 981fcaf780bSMauro Carvalho Chehab /* Store device 16 funcs 1 and 2 */ 982fcaf780bSMauro Carvalho Chehab switch (PCI_FUNC(pdev->devfn)) { 983fcaf780bSMauro Carvalho Chehab case 1: 9843e57eef6SMauro Carvalho Chehab pvt->pci_dev_16_1_fsb_addr_map = pdev; 985fcaf780bSMauro Carvalho Chehab break; 986fcaf780bSMauro Carvalho Chehab case 2: 9873e57eef6SMauro Carvalho Chehab pvt->pci_dev_16_2_fsb_err_regs = pdev; 988fcaf780bSMauro Carvalho Chehab break; 989fcaf780bSMauro Carvalho Chehab } 990fcaf780bSMauro Carvalho Chehab } 991fcaf780bSMauro Carvalho Chehab 992fcaf780bSMauro Carvalho Chehab debugf1("System Address, processor bus- PCI Bus ID: %s %x:%x\n", 9933e57eef6SMauro Carvalho Chehab pci_name(pvt->pci_dev_16_0_fsb_ctlr), 9949c6f6b65SMauro Carvalho Chehab pvt->pci_dev_16_0_fsb_ctlr->vendor, 9959c6f6b65SMauro Carvalho Chehab pvt->pci_dev_16_0_fsb_ctlr->device); 996fcaf780bSMauro Carvalho Chehab debugf1("Branchmap, control and errors - PCI Bus ID: %s %x:%x\n", 9973e57eef6SMauro Carvalho Chehab pci_name(pvt->pci_dev_16_1_fsb_addr_map), 9989c6f6b65SMauro Carvalho Chehab pvt->pci_dev_16_1_fsb_addr_map->vendor, 9999c6f6b65SMauro Carvalho Chehab pvt->pci_dev_16_1_fsb_addr_map->device); 1000fcaf780bSMauro Carvalho Chehab debugf1("FSB Error Regs - PCI Bus ID: %s %x:%x\n", 10013e57eef6SMauro Carvalho Chehab pci_name(pvt->pci_dev_16_2_fsb_err_regs), 10029c6f6b65SMauro Carvalho Chehab pvt->pci_dev_16_2_fsb_err_regs->vendor, 10039c6f6b65SMauro Carvalho Chehab pvt->pci_dev_16_2_fsb_err_regs->device); 1004fcaf780bSMauro Carvalho Chehab 10053e57eef6SMauro Carvalho Chehab pvt->pci_dev_2x_0_fbd_branch[0] = pci_get_device(PCI_VENDOR_ID_INTEL, 1006fcaf780bSMauro Carvalho Chehab PCI_DEVICE_ID_INTEL_I7300_MCH_FB0, 1007fcaf780bSMauro Carvalho Chehab NULL); 10083e57eef6SMauro Carvalho Chehab if (!pvt->pci_dev_2x_0_fbd_branch[0]) { 1009fcaf780bSMauro Carvalho Chehab i7300_printk(KERN_ERR, 1010fcaf780bSMauro Carvalho Chehab "MC: 'BRANCH 0' device not found:" 1011fcaf780bSMauro Carvalho Chehab "vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n", 1012fcaf780bSMauro Carvalho Chehab PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_FB0); 1013fcaf780bSMauro Carvalho Chehab goto error; 1014fcaf780bSMauro Carvalho Chehab } 1015fcaf780bSMauro Carvalho Chehab 10163e57eef6SMauro Carvalho Chehab pvt->pci_dev_2x_0_fbd_branch[1] = pci_get_device(PCI_VENDOR_ID_INTEL, 1017fcaf780bSMauro Carvalho Chehab PCI_DEVICE_ID_INTEL_I7300_MCH_FB1, 1018fcaf780bSMauro Carvalho Chehab NULL); 10193e57eef6SMauro Carvalho Chehab if (!pvt->pci_dev_2x_0_fbd_branch[1]) { 1020fcaf780bSMauro Carvalho Chehab i7300_printk(KERN_ERR, 1021fcaf780bSMauro Carvalho Chehab "MC: 'BRANCH 1' device not found:" 1022fcaf780bSMauro Carvalho Chehab "vendor 0x%x device 0x%x Func 0 " 1023fcaf780bSMauro Carvalho Chehab "(broken BIOS?)\n", 1024fcaf780bSMauro Carvalho Chehab PCI_VENDOR_ID_INTEL, 1025fcaf780bSMauro Carvalho Chehab PCI_DEVICE_ID_INTEL_I7300_MCH_FB1); 1026fcaf780bSMauro Carvalho Chehab goto error; 1027fcaf780bSMauro Carvalho Chehab } 1028fcaf780bSMauro Carvalho Chehab 1029fcaf780bSMauro Carvalho Chehab return 0; 1030fcaf780bSMauro Carvalho Chehab 1031fcaf780bSMauro Carvalho Chehab error: 1032fcaf780bSMauro Carvalho Chehab i7300_put_devices(mci); 1033fcaf780bSMauro Carvalho Chehab return -ENODEV; 1034fcaf780bSMauro Carvalho Chehab } 1035fcaf780bSMauro Carvalho Chehab 1036d091a6ebSMauro Carvalho Chehab /** 1037d091a6ebSMauro Carvalho Chehab * i7300_init_one() - Probe for one instance of the device 1038d091a6ebSMauro Carvalho Chehab * @pdev: struct pci_dev pointer 1039d091a6ebSMauro Carvalho Chehab * @id: struct pci_device_id pointer - currently unused 1040fcaf780bSMauro Carvalho Chehab */ 1041d091a6ebSMauro Carvalho Chehab static int __devinit i7300_init_one(struct pci_dev *pdev, 1042d091a6ebSMauro Carvalho Chehab const struct pci_device_id *id) 1043fcaf780bSMauro Carvalho Chehab { 1044fcaf780bSMauro Carvalho Chehab struct mem_ctl_info *mci; 1045fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 1046fcaf780bSMauro Carvalho Chehab int num_channels; 1047fcaf780bSMauro Carvalho Chehab int num_dimms_per_channel; 1048fcaf780bSMauro Carvalho Chehab int num_csrows; 1049d091a6ebSMauro Carvalho Chehab int rc; 1050fcaf780bSMauro Carvalho Chehab 1051d091a6ebSMauro Carvalho Chehab /* wake up device */ 1052d091a6ebSMauro Carvalho Chehab rc = pci_enable_device(pdev); 1053d091a6ebSMauro Carvalho Chehab if (rc == -EIO) 1054d091a6ebSMauro Carvalho Chehab return rc; 1055fcaf780bSMauro Carvalho Chehab 1056fcaf780bSMauro Carvalho Chehab debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n", 1057fcaf780bSMauro Carvalho Chehab __func__, 1058fcaf780bSMauro Carvalho Chehab pdev->bus->number, 1059fcaf780bSMauro Carvalho Chehab PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); 1060fcaf780bSMauro Carvalho Chehab 1061fcaf780bSMauro Carvalho Chehab /* We only are looking for func 0 of the set */ 1062fcaf780bSMauro Carvalho Chehab if (PCI_FUNC(pdev->devfn) != 0) 1063fcaf780bSMauro Carvalho Chehab return -ENODEV; 1064fcaf780bSMauro Carvalho Chehab 1065fcaf780bSMauro Carvalho Chehab /* As we don't have a motherboard identification routine to determine 1066fcaf780bSMauro Carvalho Chehab * actual number of slots/dimms per channel, we thus utilize the 1067fcaf780bSMauro Carvalho Chehab * resource as specified by the chipset. Thus, we might have 1068fcaf780bSMauro Carvalho Chehab * have more DIMMs per channel than actually on the mobo, but this 1069fcaf780bSMauro Carvalho Chehab * allows the driver to support up to the chipset max, without 1070fcaf780bSMauro Carvalho Chehab * some fancy mobo determination. 1071fcaf780bSMauro Carvalho Chehab */ 1072fcaf780bSMauro Carvalho Chehab num_dimms_per_channel = MAX_SLOTS; 1073fcaf780bSMauro Carvalho Chehab num_channels = MAX_CHANNELS; 1074fcaf780bSMauro Carvalho Chehab num_csrows = MAX_SLOTS * MAX_CHANNELS; 1075fcaf780bSMauro Carvalho Chehab 1076fcaf780bSMauro Carvalho Chehab debugf0("MC: %s(): Number of - Channels= %d DIMMS= %d CSROWS= %d\n", 1077fcaf780bSMauro Carvalho Chehab __func__, num_channels, num_dimms_per_channel, num_csrows); 1078fcaf780bSMauro Carvalho Chehab 1079fcaf780bSMauro Carvalho Chehab /* allocate a new MC control structure */ 1080fcaf780bSMauro Carvalho Chehab mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); 1081fcaf780bSMauro Carvalho Chehab 1082fcaf780bSMauro Carvalho Chehab if (mci == NULL) 1083fcaf780bSMauro Carvalho Chehab return -ENOMEM; 1084fcaf780bSMauro Carvalho Chehab 1085fcaf780bSMauro Carvalho Chehab debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); 1086fcaf780bSMauro Carvalho Chehab 1087fcaf780bSMauro Carvalho Chehab mci->dev = &pdev->dev; /* record ptr to the generic device */ 1088fcaf780bSMauro Carvalho Chehab 1089fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 10903e57eef6SMauro Carvalho Chehab pvt->pci_dev_16_0_fsb_ctlr = pdev; /* Record this device in our private */ 1091fcaf780bSMauro Carvalho Chehab 109285580ea4SMauro Carvalho Chehab pvt->tmp_prt_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); 109385580ea4SMauro Carvalho Chehab if (!pvt->tmp_prt_buffer) { 109485580ea4SMauro Carvalho Chehab edac_mc_free(mci); 109585580ea4SMauro Carvalho Chehab return -ENOMEM; 109685580ea4SMauro Carvalho Chehab } 109785580ea4SMauro Carvalho Chehab 1098fcaf780bSMauro Carvalho Chehab /* 'get' the pci devices we want to reserve for our use */ 1099d091a6ebSMauro Carvalho Chehab if (i7300_get_devices(mci)) 1100fcaf780bSMauro Carvalho Chehab goto fail0; 1101fcaf780bSMauro Carvalho Chehab 1102fcaf780bSMauro Carvalho Chehab mci->mc_idx = 0; 1103fcaf780bSMauro Carvalho Chehab mci->mtype_cap = MEM_FLAG_FB_DDR2; 1104fcaf780bSMauro Carvalho Chehab mci->edac_ctl_cap = EDAC_FLAG_NONE; 1105fcaf780bSMauro Carvalho Chehab mci->edac_cap = EDAC_FLAG_NONE; 1106fcaf780bSMauro Carvalho Chehab mci->mod_name = "i7300_edac.c"; 1107fcaf780bSMauro Carvalho Chehab mci->mod_ver = I7300_REVISION; 1108d091a6ebSMauro Carvalho Chehab mci->ctl_name = i7300_devs[0].ctl_name; 1109fcaf780bSMauro Carvalho Chehab mci->dev_name = pci_name(pdev); 1110fcaf780bSMauro Carvalho Chehab mci->ctl_page_to_phys = NULL; 1111fcaf780bSMauro Carvalho Chehab 1112fcaf780bSMauro Carvalho Chehab /* Set the function pointer to an actual operation function */ 1113fcaf780bSMauro Carvalho Chehab mci->edac_check = i7300_check_error; 1114fcaf780bSMauro Carvalho Chehab 1115fcaf780bSMauro Carvalho Chehab /* initialize the MC control structure 'csrows' table 1116fcaf780bSMauro Carvalho Chehab * with the mapping and control information */ 1117fcaf780bSMauro Carvalho Chehab if (i7300_get_mc_regs(mci)) { 1118fcaf780bSMauro Carvalho Chehab debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n" 1119fcaf780bSMauro Carvalho Chehab " because i7300_init_csrows() returned nonzero " 1120fcaf780bSMauro Carvalho Chehab "value\n"); 1121fcaf780bSMauro Carvalho Chehab mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */ 1122fcaf780bSMauro Carvalho Chehab } else { 1123fcaf780bSMauro Carvalho Chehab debugf1("MC: Enable error reporting now\n"); 1124fcaf780bSMauro Carvalho Chehab i7300_enable_error_reporting(mci); 1125fcaf780bSMauro Carvalho Chehab } 1126fcaf780bSMauro Carvalho Chehab 1127fcaf780bSMauro Carvalho Chehab /* add this new MC control structure to EDAC's list of MCs */ 1128fcaf780bSMauro Carvalho Chehab if (edac_mc_add_mc(mci)) { 1129fcaf780bSMauro Carvalho Chehab debugf0("MC: " __FILE__ 1130fcaf780bSMauro Carvalho Chehab ": %s(): failed edac_mc_add_mc()\n", __func__); 1131fcaf780bSMauro Carvalho Chehab /* FIXME: perhaps some code should go here that disables error 1132fcaf780bSMauro Carvalho Chehab * reporting if we just enabled it 1133fcaf780bSMauro Carvalho Chehab */ 1134fcaf780bSMauro Carvalho Chehab goto fail1; 1135fcaf780bSMauro Carvalho Chehab } 1136fcaf780bSMauro Carvalho Chehab 1137fcaf780bSMauro Carvalho Chehab i7300_clear_error(mci); 1138fcaf780bSMauro Carvalho Chehab 1139fcaf780bSMauro Carvalho Chehab /* allocating generic PCI control info */ 1140fcaf780bSMauro Carvalho Chehab i7300_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); 1141fcaf780bSMauro Carvalho Chehab if (!i7300_pci) { 1142fcaf780bSMauro Carvalho Chehab printk(KERN_WARNING 1143fcaf780bSMauro Carvalho Chehab "%s(): Unable to create PCI control\n", 1144fcaf780bSMauro Carvalho Chehab __func__); 1145fcaf780bSMauro Carvalho Chehab printk(KERN_WARNING 1146fcaf780bSMauro Carvalho Chehab "%s(): PCI error report via EDAC not setup\n", 1147fcaf780bSMauro Carvalho Chehab __func__); 1148fcaf780bSMauro Carvalho Chehab } 1149fcaf780bSMauro Carvalho Chehab 1150fcaf780bSMauro Carvalho Chehab return 0; 1151fcaf780bSMauro Carvalho Chehab 1152fcaf780bSMauro Carvalho Chehab /* Error exit unwinding stack */ 1153fcaf780bSMauro Carvalho Chehab fail1: 1154fcaf780bSMauro Carvalho Chehab 1155fcaf780bSMauro Carvalho Chehab i7300_put_devices(mci); 1156fcaf780bSMauro Carvalho Chehab 1157fcaf780bSMauro Carvalho Chehab fail0: 115885580ea4SMauro Carvalho Chehab kfree(pvt->tmp_prt_buffer); 1159fcaf780bSMauro Carvalho Chehab edac_mc_free(mci); 1160fcaf780bSMauro Carvalho Chehab return -ENODEV; 1161fcaf780bSMauro Carvalho Chehab } 1162fcaf780bSMauro Carvalho Chehab 1163d091a6ebSMauro Carvalho Chehab /** 1164d091a6ebSMauro Carvalho Chehab * i7300_remove_one() - Remove the driver 1165d091a6ebSMauro Carvalho Chehab * @pdev: struct pci_dev pointer 1166fcaf780bSMauro Carvalho Chehab */ 1167fcaf780bSMauro Carvalho Chehab static void __devexit i7300_remove_one(struct pci_dev *pdev) 1168fcaf780bSMauro Carvalho Chehab { 1169fcaf780bSMauro Carvalho Chehab struct mem_ctl_info *mci; 117085580ea4SMauro Carvalho Chehab char *tmp; 1171fcaf780bSMauro Carvalho Chehab 1172fcaf780bSMauro Carvalho Chehab debugf0(__FILE__ ": %s()\n", __func__); 1173fcaf780bSMauro Carvalho Chehab 1174fcaf780bSMauro Carvalho Chehab if (i7300_pci) 1175fcaf780bSMauro Carvalho Chehab edac_pci_release_generic_ctl(i7300_pci); 1176fcaf780bSMauro Carvalho Chehab 1177fcaf780bSMauro Carvalho Chehab mci = edac_mc_del_mc(&pdev->dev); 1178fcaf780bSMauro Carvalho Chehab if (!mci) 1179fcaf780bSMauro Carvalho Chehab return; 1180fcaf780bSMauro Carvalho Chehab 118185580ea4SMauro Carvalho Chehab tmp = ((struct i7300_pvt *)mci->pvt_info)->tmp_prt_buffer; 118285580ea4SMauro Carvalho Chehab 1183fcaf780bSMauro Carvalho Chehab /* retrieve references to resources, and free those resources */ 1184fcaf780bSMauro Carvalho Chehab i7300_put_devices(mci); 1185fcaf780bSMauro Carvalho Chehab 118685580ea4SMauro Carvalho Chehab kfree(tmp); 1187fcaf780bSMauro Carvalho Chehab edac_mc_free(mci); 1188fcaf780bSMauro Carvalho Chehab } 1189fcaf780bSMauro Carvalho Chehab 1190fcaf780bSMauro Carvalho Chehab /* 1191d091a6ebSMauro Carvalho Chehab * pci_device_id: table for which devices we are looking for 1192fcaf780bSMauro Carvalho Chehab * 1193d091a6ebSMauro Carvalho Chehab * Has only 8086:360c PCI ID 1194fcaf780bSMauro Carvalho Chehab */ 1195fcaf780bSMauro Carvalho Chehab static const struct pci_device_id i7300_pci_tbl[] __devinitdata = { 1196fcaf780bSMauro Carvalho Chehab {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_ERR)}, 1197fcaf780bSMauro Carvalho Chehab {0,} /* 0 terminated list. */ 1198fcaf780bSMauro Carvalho Chehab }; 1199fcaf780bSMauro Carvalho Chehab 1200fcaf780bSMauro Carvalho Chehab MODULE_DEVICE_TABLE(pci, i7300_pci_tbl); 1201fcaf780bSMauro Carvalho Chehab 1202fcaf780bSMauro Carvalho Chehab /* 1203d091a6ebSMauro Carvalho Chehab * i7300_driver: pci_driver structure for this module 1204fcaf780bSMauro Carvalho Chehab */ 1205fcaf780bSMauro Carvalho Chehab static struct pci_driver i7300_driver = { 1206fcaf780bSMauro Carvalho Chehab .name = "i7300_edac", 1207fcaf780bSMauro Carvalho Chehab .probe = i7300_init_one, 1208fcaf780bSMauro Carvalho Chehab .remove = __devexit_p(i7300_remove_one), 1209fcaf780bSMauro Carvalho Chehab .id_table = i7300_pci_tbl, 1210fcaf780bSMauro Carvalho Chehab }; 1211fcaf780bSMauro Carvalho Chehab 1212d091a6ebSMauro Carvalho Chehab /** 1213d091a6ebSMauro Carvalho Chehab * i7300_init() - Registers the driver 1214fcaf780bSMauro Carvalho Chehab */ 1215fcaf780bSMauro Carvalho Chehab static int __init i7300_init(void) 1216fcaf780bSMauro Carvalho Chehab { 1217fcaf780bSMauro Carvalho Chehab int pci_rc; 1218fcaf780bSMauro Carvalho Chehab 1219fcaf780bSMauro Carvalho Chehab debugf2("MC: " __FILE__ ": %s()\n", __func__); 1220fcaf780bSMauro Carvalho Chehab 1221fcaf780bSMauro Carvalho Chehab /* Ensure that the OPSTATE is set correctly for POLL or NMI */ 1222fcaf780bSMauro Carvalho Chehab opstate_init(); 1223fcaf780bSMauro Carvalho Chehab 1224fcaf780bSMauro Carvalho Chehab pci_rc = pci_register_driver(&i7300_driver); 1225fcaf780bSMauro Carvalho Chehab 1226fcaf780bSMauro Carvalho Chehab return (pci_rc < 0) ? pci_rc : 0; 1227fcaf780bSMauro Carvalho Chehab } 1228fcaf780bSMauro Carvalho Chehab 1229d091a6ebSMauro Carvalho Chehab /** 1230d091a6ebSMauro Carvalho Chehab * i7300_init() - Unregisters the driver 1231fcaf780bSMauro Carvalho Chehab */ 1232fcaf780bSMauro Carvalho Chehab static void __exit i7300_exit(void) 1233fcaf780bSMauro Carvalho Chehab { 1234fcaf780bSMauro Carvalho Chehab debugf2("MC: " __FILE__ ": %s()\n", __func__); 1235fcaf780bSMauro Carvalho Chehab pci_unregister_driver(&i7300_driver); 1236fcaf780bSMauro Carvalho Chehab } 1237fcaf780bSMauro Carvalho Chehab 1238fcaf780bSMauro Carvalho Chehab module_init(i7300_init); 1239fcaf780bSMauro Carvalho Chehab module_exit(i7300_exit); 1240fcaf780bSMauro Carvalho Chehab 1241fcaf780bSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 1242fcaf780bSMauro Carvalho Chehab MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); 1243fcaf780bSMauro Carvalho Chehab MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); 1244fcaf780bSMauro Carvalho Chehab MODULE_DESCRIPTION("MC Driver for Intel I7300 memory controllers - " 1245fcaf780bSMauro Carvalho Chehab I7300_REVISION); 1246fcaf780bSMauro Carvalho Chehab 1247fcaf780bSMauro Carvalho Chehab module_param(edac_op_state, int, 0444); 1248fcaf780bSMauro Carvalho Chehab MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); 1249