112237550SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2fcaf780bSMauro Carvalho Chehab /* 3fcaf780bSMauro Carvalho Chehab * Intel 7300 class Memory Controllers kernel module (Clarksboro) 4fcaf780bSMauro Carvalho Chehab * 5fcaf780bSMauro Carvalho Chehab * Copyright (c) 2010 by: 637e59f87SMauro Carvalho Chehab * Mauro Carvalho Chehab 7fcaf780bSMauro Carvalho Chehab * 87d4c1ea2SAlexander A. Klimov * Red Hat Inc. https://www.redhat.com 9fcaf780bSMauro Carvalho Chehab * 10fcaf780bSMauro Carvalho Chehab * Intel 7300 Chipset Memory Controller Hub (MCH) - Datasheet 11fcaf780bSMauro Carvalho Chehab * http://www.intel.com/Assets/PDF/datasheet/318082.pdf 12fcaf780bSMauro Carvalho Chehab * 13fcaf780bSMauro Carvalho Chehab * TODO: The chipset allow checking for PCI Express errors also. Currently, 14fcaf780bSMauro Carvalho Chehab * the driver covers only memory error errors 15fcaf780bSMauro Carvalho Chehab * 16fcaf780bSMauro Carvalho Chehab * This driver uses "csrows" EDAC attribute to represent DIMM slot# 17fcaf780bSMauro Carvalho Chehab */ 18fcaf780bSMauro Carvalho Chehab 19fcaf780bSMauro Carvalho Chehab #include <linux/module.h> 20fcaf780bSMauro Carvalho Chehab #include <linux/init.h> 21fcaf780bSMauro Carvalho Chehab #include <linux/pci.h> 22fcaf780bSMauro Carvalho Chehab #include <linux/pci_ids.h> 23fcaf780bSMauro Carvalho Chehab #include <linux/slab.h> 24fcaf780bSMauro Carvalho Chehab #include <linux/edac.h> 25fcaf780bSMauro Carvalho Chehab #include <linux/mmzone.h> 26fcaf780bSMauro Carvalho Chehab 2778d88e8aSMauro Carvalho Chehab #include "edac_module.h" 28fcaf780bSMauro Carvalho Chehab 29fcaf780bSMauro Carvalho Chehab /* 30fcaf780bSMauro Carvalho Chehab * Alter this version for the I7300 module when modifications are made 31fcaf780bSMauro Carvalho Chehab */ 32152ba394SMichal Marek #define I7300_REVISION " Ver: 1.0.0" 33fcaf780bSMauro Carvalho Chehab 34fcaf780bSMauro Carvalho Chehab #define EDAC_MOD_STR "i7300_edac" 35fcaf780bSMauro Carvalho Chehab 36fcaf780bSMauro Carvalho Chehab #define i7300_printk(level, fmt, arg...) \ 37fcaf780bSMauro Carvalho Chehab edac_printk(level, "i7300", fmt, ##arg) 38fcaf780bSMauro Carvalho Chehab 39fcaf780bSMauro Carvalho Chehab #define i7300_mc_printk(mci, level, fmt, arg...) \ 40fcaf780bSMauro Carvalho Chehab edac_mc_chipset_printk(mci, level, "i7300", fmt, ##arg) 41fcaf780bSMauro Carvalho Chehab 42b4552aceSMauro Carvalho Chehab /*********************************************** 43b4552aceSMauro Carvalho Chehab * i7300 Limit constants Structs and static vars 44b4552aceSMauro Carvalho Chehab ***********************************************/ 45b4552aceSMauro Carvalho Chehab 46fcaf780bSMauro Carvalho Chehab /* 47fcaf780bSMauro Carvalho Chehab * Memory topology is organized as: 48fcaf780bSMauro Carvalho Chehab * Branch 0 - 2 channels: channels 0 and 1 (FDB0 PCI dev 21.0) 49fcaf780bSMauro Carvalho Chehab * Branch 1 - 2 channels: channels 2 and 3 (FDB1 PCI dev 22.0) 50fcaf780bSMauro Carvalho Chehab * Each channel can have to 8 DIMM sets (called as SLOTS) 51fcaf780bSMauro Carvalho Chehab * Slots should generally be filled in pairs 52fcaf780bSMauro Carvalho Chehab * Except on Single Channel mode of operation 53fcaf780bSMauro Carvalho Chehab * just slot 0/channel0 filled on this mode 54fcaf780bSMauro Carvalho Chehab * On normal operation mode, the two channels on a branch should be 55c3af2eafSMauro Carvalho Chehab * filled together for the same SLOT# 56fcaf780bSMauro Carvalho Chehab * When in mirrored mode, Branch 1 replicate memory at Branch 0, so, the four 57fcaf780bSMauro Carvalho Chehab * channels on both branches should be filled 58fcaf780bSMauro Carvalho Chehab */ 59fcaf780bSMauro Carvalho Chehab 60fcaf780bSMauro Carvalho Chehab /* Limits for i7300 */ 61fcaf780bSMauro Carvalho Chehab #define MAX_SLOTS 8 62fcaf780bSMauro Carvalho Chehab #define MAX_BRANCHES 2 63fcaf780bSMauro Carvalho Chehab #define MAX_CH_PER_BRANCH 2 64fcaf780bSMauro Carvalho Chehab #define MAX_CHANNELS (MAX_CH_PER_BRANCH * MAX_BRANCHES) 65fcaf780bSMauro Carvalho Chehab #define MAX_MIR 3 66fcaf780bSMauro Carvalho Chehab 67fcaf780bSMauro Carvalho Chehab #define to_channel(ch, branch) ((((branch)) << 1) | (ch)) 68fcaf780bSMauro Carvalho Chehab 69fcaf780bSMauro Carvalho Chehab #define to_csrow(slot, ch, branch) \ 70fcaf780bSMauro Carvalho Chehab (to_channel(ch, branch) | ((slot) << 2)) 71fcaf780bSMauro Carvalho Chehab 72b4552aceSMauro Carvalho Chehab /* Device name and register DID (Device ID) */ 73b4552aceSMauro Carvalho Chehab struct i7300_dev_info { 74b4552aceSMauro Carvalho Chehab const char *ctl_name; /* name for this device */ 75b4552aceSMauro Carvalho Chehab u16 fsb_mapping_errors; /* DID for the branchmap,control */ 76b4552aceSMauro Carvalho Chehab }; 77fcaf780bSMauro Carvalho Chehab 78b4552aceSMauro Carvalho Chehab /* Table of devices attributes supported by this driver */ 79b4552aceSMauro Carvalho Chehab static const struct i7300_dev_info i7300_devs[] = { 80b4552aceSMauro Carvalho Chehab { 81b4552aceSMauro Carvalho Chehab .ctl_name = "I7300", 82b4552aceSMauro Carvalho Chehab .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, 83b4552aceSMauro Carvalho Chehab }, 84b4552aceSMauro Carvalho Chehab }; 85b4552aceSMauro Carvalho Chehab 86b4552aceSMauro Carvalho Chehab struct i7300_dimm_info { 87b4552aceSMauro Carvalho Chehab int megabytes; /* size, 0 means not present */ 88b4552aceSMauro Carvalho Chehab }; 89b4552aceSMauro Carvalho Chehab 90b4552aceSMauro Carvalho Chehab /* driver private data structure */ 91b4552aceSMauro Carvalho Chehab struct i7300_pvt { 92b4552aceSMauro Carvalho Chehab struct pci_dev *pci_dev_16_0_fsb_ctlr; /* 16.0 */ 93b4552aceSMauro Carvalho Chehab struct pci_dev *pci_dev_16_1_fsb_addr_map; /* 16.1 */ 94b4552aceSMauro Carvalho Chehab struct pci_dev *pci_dev_16_2_fsb_err_regs; /* 16.2 */ 95b4552aceSMauro Carvalho Chehab struct pci_dev *pci_dev_2x_0_fbd_branch[MAX_BRANCHES]; /* 21.0 and 22.0 */ 96b4552aceSMauro Carvalho Chehab 97b4552aceSMauro Carvalho Chehab u16 tolm; /* top of low memory */ 98b4552aceSMauro Carvalho Chehab u64 ambase; /* AMB BAR */ 99b4552aceSMauro Carvalho Chehab 100b4552aceSMauro Carvalho Chehab u32 mc_settings; /* Report several settings */ 101b4552aceSMauro Carvalho Chehab u32 mc_settings_a; 102b4552aceSMauro Carvalho Chehab 103b4552aceSMauro Carvalho Chehab u16 mir[MAX_MIR]; /* Memory Interleave Reg*/ 104b4552aceSMauro Carvalho Chehab 105b4552aceSMauro Carvalho Chehab u16 mtr[MAX_SLOTS][MAX_BRANCHES]; /* Memory Technlogy Reg */ 106b4552aceSMauro Carvalho Chehab u16 ambpresent[MAX_CHANNELS]; /* AMB present regs */ 107b4552aceSMauro Carvalho Chehab 108b4552aceSMauro Carvalho Chehab /* DIMM information matrix, allocating architecture maximums */ 109b4552aceSMauro Carvalho Chehab struct i7300_dimm_info dimm_info[MAX_SLOTS][MAX_CHANNELS]; 110b4552aceSMauro Carvalho Chehab 111b4552aceSMauro Carvalho Chehab /* Temporary buffer for use when preparing error messages */ 112b4552aceSMauro Carvalho Chehab char *tmp_prt_buffer; 113b4552aceSMauro Carvalho Chehab }; 114b4552aceSMauro Carvalho Chehab 115b4552aceSMauro Carvalho Chehab /* FIXME: Why do we need to have this static? */ 116b4552aceSMauro Carvalho Chehab static struct edac_pci_ctl_info *i7300_pci; 117b4552aceSMauro Carvalho Chehab 118b4552aceSMauro Carvalho Chehab /*************************************************** 119b4552aceSMauro Carvalho Chehab * i7300 Register definitions for memory enumeration 120b4552aceSMauro Carvalho Chehab ***************************************************/ 121b4552aceSMauro Carvalho Chehab 122b4552aceSMauro Carvalho Chehab /* 123c3af2eafSMauro Carvalho Chehab * Device 16, 124c3af2eafSMauro Carvalho Chehab * Function 0: System Address (not documented) 125c3af2eafSMauro Carvalho Chehab * Function 1: Memory Branch Map, Control, Errors Register 126c3af2eafSMauro Carvalho Chehab */ 127c3af2eafSMauro Carvalho Chehab 128fcaf780bSMauro Carvalho Chehab /* OFFSETS for Function 0 */ 129fcaf780bSMauro Carvalho Chehab #define AMBASE 0x48 /* AMB Mem Mapped Reg Region Base */ 130fcaf780bSMauro Carvalho Chehab #define MAXCH 0x56 /* Max Channel Number */ 131fcaf780bSMauro Carvalho Chehab #define MAXDIMMPERCH 0x57 /* Max DIMM PER Channel Number */ 132fcaf780bSMauro Carvalho Chehab 133fcaf780bSMauro Carvalho Chehab /* OFFSETS for Function 1 */ 134af3d8831SMauro Carvalho Chehab #define MC_SETTINGS 0x40 135d7de2bdbSMauro Carvalho Chehab #define IS_MIRRORED(mc) ((mc) & (1 << 16)) 136d7de2bdbSMauro Carvalho Chehab #define IS_ECC_ENABLED(mc) ((mc) & (1 << 5)) 137d7de2bdbSMauro Carvalho Chehab #define IS_RETRY_ENABLED(mc) ((mc) & (1 << 31)) 138d7de2bdbSMauro Carvalho Chehab #define IS_SCRBALGO_ENHANCED(mc) ((mc) & (1 << 8)) 139d7de2bdbSMauro Carvalho Chehab 140bb81a216SMauro Carvalho Chehab #define MC_SETTINGS_A 0x58 141bb81a216SMauro Carvalho Chehab #define IS_SINGLE_MODE(mca) ((mca) & (1 << 14)) 142d7de2bdbSMauro Carvalho Chehab 143fcaf780bSMauro Carvalho Chehab #define TOLM 0x6C 144fcaf780bSMauro Carvalho Chehab 145fcaf780bSMauro Carvalho Chehab #define MIR0 0x80 146fcaf780bSMauro Carvalho Chehab #define MIR1 0x84 147fcaf780bSMauro Carvalho Chehab #define MIR2 0x88 148fcaf780bSMauro Carvalho Chehab 149fcaf780bSMauro Carvalho Chehab /* 150fcaf780bSMauro Carvalho Chehab * Note: Other Intel EDAC drivers use AMBPRESENT to identify if the available 151fcaf780bSMauro Carvalho Chehab * memory. From datasheet item 7.3.1 (FB-DIMM technology & organization), it 152fcaf780bSMauro Carvalho Chehab * seems that we cannot use this information directly for the same usage. 153fcaf780bSMauro Carvalho Chehab * Each memory slot may have up to 2 AMB interfaces, one for income and another 154fcaf780bSMauro Carvalho Chehab * for outcome interface to the next slot. 155fcaf780bSMauro Carvalho Chehab * For now, the driver just stores the AMB present registers, but rely only at 156fcaf780bSMauro Carvalho Chehab * the MTR info to detect memory. 157fcaf780bSMauro Carvalho Chehab * Datasheet is also not clear about how to map each AMBPRESENT registers to 158fcaf780bSMauro Carvalho Chehab * one of the 4 available channels. 159fcaf780bSMauro Carvalho Chehab */ 160fcaf780bSMauro Carvalho Chehab #define AMBPRESENT_0 0x64 161fcaf780bSMauro Carvalho Chehab #define AMBPRESENT_1 0x66 162fcaf780bSMauro Carvalho Chehab 16342b16b3fSJesper Juhl static const u16 mtr_regs[MAX_SLOTS] = { 164fcaf780bSMauro Carvalho Chehab 0x80, 0x84, 0x88, 0x8c, 165fcaf780bSMauro Carvalho Chehab 0x82, 0x86, 0x8a, 0x8e 166fcaf780bSMauro Carvalho Chehab }; 167fcaf780bSMauro Carvalho Chehab 168b4552aceSMauro Carvalho Chehab /* 169b4552aceSMauro Carvalho Chehab * Defines to extract the vaious fields from the 170fcaf780bSMauro Carvalho Chehab * MTRx - Memory Technology Registers 171fcaf780bSMauro Carvalho Chehab */ 172fcaf780bSMauro Carvalho Chehab #define MTR_DIMMS_PRESENT(mtr) ((mtr) & (1 << 8)) 173fcaf780bSMauro Carvalho Chehab #define MTR_DIMMS_ETHROTTLE(mtr) ((mtr) & (1 << 7)) 174fcaf780bSMauro Carvalho Chehab #define MTR_DRAM_WIDTH(mtr) (((mtr) & (1 << 6)) ? 8 : 4) 175fcaf780bSMauro Carvalho Chehab #define MTR_DRAM_BANKS(mtr) (((mtr) & (1 << 5)) ? 8 : 4) 176fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_RANKS(mtr) (((mtr) & (1 << 4)) ? 1 : 0) 177fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_ROWS(mtr) (((mtr) >> 2) & 0x3) 178fcaf780bSMauro Carvalho Chehab #define MTR_DRAM_BANKS_ADDR_BITS 2 179fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_ROWS_ADDR_BITS(mtr) (MTR_DIMM_ROWS(mtr) + 13) 180fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_COLS(mtr) ((mtr) & 0x3) 181fcaf780bSMauro Carvalho Chehab #define MTR_DIMM_COLS_ADDR_BITS(mtr) (MTR_DIMM_COLS(mtr) + 10) 182fcaf780bSMauro Carvalho Chehab 183c3af2eafSMauro Carvalho Chehab /************************************************ 184c3af2eafSMauro Carvalho Chehab * i7300 Register definitions for error detection 185c3af2eafSMauro Carvalho Chehab ************************************************/ 18657021918SMauro Carvalho Chehab 18757021918SMauro Carvalho Chehab /* 18857021918SMauro Carvalho Chehab * Device 16.1: FBD Error Registers 18957021918SMauro Carvalho Chehab */ 19057021918SMauro Carvalho Chehab #define FERR_FAT_FBD 0x98 19157021918SMauro Carvalho Chehab static const char *ferr_fat_fbd_name[] = { 19257021918SMauro Carvalho Chehab [22] = "Non-Redundant Fast Reset Timeout", 19357021918SMauro Carvalho Chehab [2] = ">Tmid Thermal event with intelligent throttling disabled", 19457021918SMauro Carvalho Chehab [1] = "Memory or FBD configuration CRC read error", 19557021918SMauro Carvalho Chehab [0] = "Memory Write error on non-redundant retry or " 19657021918SMauro Carvalho Chehab "FBD configuration Write error on retry", 19757021918SMauro Carvalho Chehab }; 1987e06b7a3SJean Delvare #define GET_FBD_FAT_IDX(fbderr) (((fbderr) >> 28) & 3) 1997e06b7a3SJean Delvare #define FERR_FAT_FBD_ERR_MASK ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 22)) 20057021918SMauro Carvalho Chehab 20157021918SMauro Carvalho Chehab #define FERR_NF_FBD 0xa0 20257021918SMauro Carvalho Chehab static const char *ferr_nf_fbd_name[] = { 20357021918SMauro Carvalho Chehab [24] = "DIMM-Spare Copy Completed", 20457021918SMauro Carvalho Chehab [23] = "DIMM-Spare Copy Initiated", 20557021918SMauro Carvalho Chehab [22] = "Redundant Fast Reset Timeout", 20657021918SMauro Carvalho Chehab [21] = "Memory Write error on redundant retry", 20757021918SMauro Carvalho Chehab [18] = "SPD protocol Error", 20857021918SMauro Carvalho Chehab [17] = "FBD Northbound parity error on FBD Sync Status", 20957021918SMauro Carvalho Chehab [16] = "Correctable Patrol Data ECC", 21057021918SMauro Carvalho Chehab [15] = "Correctable Resilver- or Spare-Copy Data ECC", 21157021918SMauro Carvalho Chehab [14] = "Correctable Mirrored Demand Data ECC", 21257021918SMauro Carvalho Chehab [13] = "Correctable Non-Mirrored Demand Data ECC", 21357021918SMauro Carvalho Chehab [11] = "Memory or FBD configuration CRC read error", 21457021918SMauro Carvalho Chehab [10] = "FBD Configuration Write error on first attempt", 21557021918SMauro Carvalho Chehab [9] = "Memory Write error on first attempt", 21657021918SMauro Carvalho Chehab [8] = "Non-Aliased Uncorrectable Patrol Data ECC", 21757021918SMauro Carvalho Chehab [7] = "Non-Aliased Uncorrectable Resilver- or Spare-Copy Data ECC", 21857021918SMauro Carvalho Chehab [6] = "Non-Aliased Uncorrectable Mirrored Demand Data ECC", 21957021918SMauro Carvalho Chehab [5] = "Non-Aliased Uncorrectable Non-Mirrored Demand Data ECC", 22057021918SMauro Carvalho Chehab [4] = "Aliased Uncorrectable Patrol Data ECC", 22157021918SMauro Carvalho Chehab [3] = "Aliased Uncorrectable Resilver- or Spare-Copy Data ECC", 22257021918SMauro Carvalho Chehab [2] = "Aliased Uncorrectable Mirrored Demand Data ECC", 22357021918SMauro Carvalho Chehab [1] = "Aliased Uncorrectable Non-Mirrored Demand Data ECC", 22457021918SMauro Carvalho Chehab [0] = "Uncorrectable Data ECC on Replay", 22557021918SMauro Carvalho Chehab }; 2267e06b7a3SJean Delvare #define GET_FBD_NF_IDX(fbderr) (((fbderr) >> 28) & 3) 22757021918SMauro Carvalho Chehab #define FERR_NF_FBD_ERR_MASK ((1 << 24) | (1 << 23) | (1 << 22) | (1 << 21) |\ 22857021918SMauro Carvalho Chehab (1 << 18) | (1 << 17) | (1 << 16) | (1 << 15) |\ 22957021918SMauro Carvalho Chehab (1 << 14) | (1 << 13) | (1 << 11) | (1 << 10) |\ 23057021918SMauro Carvalho Chehab (1 << 9) | (1 << 8) | (1 << 7) | (1 << 6) |\ 23157021918SMauro Carvalho Chehab (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) |\ 23257021918SMauro Carvalho Chehab (1 << 1) | (1 << 0)) 23357021918SMauro Carvalho Chehab 23457021918SMauro Carvalho Chehab #define EMASK_FBD 0xa8 23557021918SMauro Carvalho Chehab #define EMASK_FBD_ERR_MASK ((1 << 27) | (1 << 26) | (1 << 25) | (1 << 24) |\ 23657021918SMauro Carvalho Chehab (1 << 22) | (1 << 21) | (1 << 20) | (1 << 19) |\ 23757021918SMauro Carvalho Chehab (1 << 18) | (1 << 17) | (1 << 16) | (1 << 14) |\ 23857021918SMauro Carvalho Chehab (1 << 13) | (1 << 12) | (1 << 11) | (1 << 10) |\ 23957021918SMauro Carvalho Chehab (1 << 9) | (1 << 8) | (1 << 7) | (1 << 6) |\ 24057021918SMauro Carvalho Chehab (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) |\ 24157021918SMauro Carvalho Chehab (1 << 1) | (1 << 0)) 24257021918SMauro Carvalho Chehab 243c3af2eafSMauro Carvalho Chehab /* 244c3af2eafSMauro Carvalho Chehab * Device 16.2: Global Error Registers 245c3af2eafSMauro Carvalho Chehab */ 246c3af2eafSMauro Carvalho Chehab 2475de6e07eSMauro Carvalho Chehab #define FERR_GLOBAL_HI 0x48 2485de6e07eSMauro Carvalho Chehab static const char *ferr_global_hi_name[] = { 2495de6e07eSMauro Carvalho Chehab [3] = "FSB 3 Fatal Error", 2505de6e07eSMauro Carvalho Chehab [2] = "FSB 2 Fatal Error", 2515de6e07eSMauro Carvalho Chehab [1] = "FSB 1 Fatal Error", 2525de6e07eSMauro Carvalho Chehab [0] = "FSB 0 Fatal Error", 2535de6e07eSMauro Carvalho Chehab }; 2545de6e07eSMauro Carvalho Chehab #define ferr_global_hi_is_fatal(errno) 1 2555de6e07eSMauro Carvalho Chehab 256c3af2eafSMauro Carvalho Chehab #define FERR_GLOBAL_LO 0x40 2575de6e07eSMauro Carvalho Chehab static const char *ferr_global_lo_name[] = { 258c3af2eafSMauro Carvalho Chehab [31] = "Internal MCH Fatal Error", 259c3af2eafSMauro Carvalho Chehab [30] = "Intel QuickData Technology Device Fatal Error", 260c3af2eafSMauro Carvalho Chehab [29] = "FSB1 Fatal Error", 261c3af2eafSMauro Carvalho Chehab [28] = "FSB0 Fatal Error", 262c3af2eafSMauro Carvalho Chehab [27] = "FBD Channel 3 Fatal Error", 263c3af2eafSMauro Carvalho Chehab [26] = "FBD Channel 2 Fatal Error", 264c3af2eafSMauro Carvalho Chehab [25] = "FBD Channel 1 Fatal Error", 265c3af2eafSMauro Carvalho Chehab [24] = "FBD Channel 0 Fatal Error", 266c3af2eafSMauro Carvalho Chehab [23] = "PCI Express Device 7Fatal Error", 267c3af2eafSMauro Carvalho Chehab [22] = "PCI Express Device 6 Fatal Error", 268c3af2eafSMauro Carvalho Chehab [21] = "PCI Express Device 5 Fatal Error", 269c3af2eafSMauro Carvalho Chehab [20] = "PCI Express Device 4 Fatal Error", 270c3af2eafSMauro Carvalho Chehab [19] = "PCI Express Device 3 Fatal Error", 271c3af2eafSMauro Carvalho Chehab [18] = "PCI Express Device 2 Fatal Error", 272c3af2eafSMauro Carvalho Chehab [17] = "PCI Express Device 1 Fatal Error", 273c3af2eafSMauro Carvalho Chehab [16] = "ESI Fatal Error", 274c3af2eafSMauro Carvalho Chehab [15] = "Internal MCH Non-Fatal Error", 275c3af2eafSMauro Carvalho Chehab [14] = "Intel QuickData Technology Device Non Fatal Error", 276c3af2eafSMauro Carvalho Chehab [13] = "FSB1 Non-Fatal Error", 277c3af2eafSMauro Carvalho Chehab [12] = "FSB 0 Non-Fatal Error", 278c3af2eafSMauro Carvalho Chehab [11] = "FBD Channel 3 Non-Fatal Error", 279c3af2eafSMauro Carvalho Chehab [10] = "FBD Channel 2 Non-Fatal Error", 280c3af2eafSMauro Carvalho Chehab [9] = "FBD Channel 1 Non-Fatal Error", 281c3af2eafSMauro Carvalho Chehab [8] = "FBD Channel 0 Non-Fatal Error", 282c3af2eafSMauro Carvalho Chehab [7] = "PCI Express Device 7 Non-Fatal Error", 283c3af2eafSMauro Carvalho Chehab [6] = "PCI Express Device 6 Non-Fatal Error", 284c3af2eafSMauro Carvalho Chehab [5] = "PCI Express Device 5 Non-Fatal Error", 285c3af2eafSMauro Carvalho Chehab [4] = "PCI Express Device 4 Non-Fatal Error", 286c3af2eafSMauro Carvalho Chehab [3] = "PCI Express Device 3 Non-Fatal Error", 287c3af2eafSMauro Carvalho Chehab [2] = "PCI Express Device 2 Non-Fatal Error", 288c3af2eafSMauro Carvalho Chehab [1] = "PCI Express Device 1 Non-Fatal Error", 289c3af2eafSMauro Carvalho Chehab [0] = "ESI Non-Fatal Error", 290c3af2eafSMauro Carvalho Chehab }; 2915de6e07eSMauro Carvalho Chehab #define ferr_global_lo_is_fatal(errno) ((errno < 16) ? 0 : 1) 292fcaf780bSMauro Carvalho Chehab 2938199d8ccSMauro Carvalho Chehab #define NRECMEMA 0xbe 2948199d8ccSMauro Carvalho Chehab #define NRECMEMA_BANK(v) (((v) >> 12) & 7) 2958199d8ccSMauro Carvalho Chehab #define NRECMEMA_RANK(v) (((v) >> 8) & 15) 2968199d8ccSMauro Carvalho Chehab 2978199d8ccSMauro Carvalho Chehab #define NRECMEMB 0xc0 2988199d8ccSMauro Carvalho Chehab #define NRECMEMB_IS_WR(v) ((v) & (1 << 31)) 2998199d8ccSMauro Carvalho Chehab #define NRECMEMB_CAS(v) (((v) >> 16) & 0x1fff) 3008199d8ccSMauro Carvalho Chehab #define NRECMEMB_RAS(v) ((v) & 0xffff) 3018199d8ccSMauro Carvalho Chehab 30232f94726SMauro Carvalho Chehab #define REDMEMA 0xdc 30332f94726SMauro Carvalho Chehab 30437b69cf9SMauro Carvalho Chehab #define REDMEMB 0x7c 30537b69cf9SMauro Carvalho Chehab 30632f94726SMauro Carvalho Chehab #define RECMEMA 0xe0 30732f94726SMauro Carvalho Chehab #define RECMEMA_BANK(v) (((v) >> 12) & 7) 30832f94726SMauro Carvalho Chehab #define RECMEMA_RANK(v) (((v) >> 8) & 15) 30932f94726SMauro Carvalho Chehab 31032f94726SMauro Carvalho Chehab #define RECMEMB 0xe4 31132f94726SMauro Carvalho Chehab #define RECMEMB_IS_WR(v) ((v) & (1 << 31)) 31232f94726SMauro Carvalho Chehab #define RECMEMB_CAS(v) (((v) >> 16) & 0x1fff) 31332f94726SMauro Carvalho Chehab #define RECMEMB_RAS(v) ((v) & 0xffff) 31432f94726SMauro Carvalho Chehab 3155de6e07eSMauro Carvalho Chehab /******************************************** 3165de6e07eSMauro Carvalho Chehab * i7300 Functions related to error detection 3175de6e07eSMauro Carvalho Chehab ********************************************/ 318fcaf780bSMauro Carvalho Chehab 319d091a6ebSMauro Carvalho Chehab /** 320d091a6ebSMauro Carvalho Chehab * get_err_from_table() - Gets the error message from a table 321d091a6ebSMauro Carvalho Chehab * @table: table name (array of char *) 322d091a6ebSMauro Carvalho Chehab * @size: number of elements at the table 323d091a6ebSMauro Carvalho Chehab * @pos: position of the element to be returned 324d091a6ebSMauro Carvalho Chehab * 325d091a6ebSMauro Carvalho Chehab * This is a small routine that gets the pos-th element of a table. If the 326d091a6ebSMauro Carvalho Chehab * element doesn't exist (or it is empty), it returns "reserved". 327d091a6ebSMauro Carvalho Chehab * Instead of calling it directly, the better is to call via the macro 328d091a6ebSMauro Carvalho Chehab * GET_ERR_FROM_TABLE(), that automatically checks the table size via 329d091a6ebSMauro Carvalho Chehab * ARRAY_SIZE() macro 330d091a6ebSMauro Carvalho Chehab */ 331d091a6ebSMauro Carvalho Chehab static const char *get_err_from_table(const char *table[], int size, int pos) 332fcaf780bSMauro Carvalho Chehab { 333d091a6ebSMauro Carvalho Chehab if (unlikely(pos >= size)) 334d091a6ebSMauro Carvalho Chehab return "Reserved"; 335d091a6ebSMauro Carvalho Chehab 336d091a6ebSMauro Carvalho Chehab if (unlikely(!table[pos])) 3375de6e07eSMauro Carvalho Chehab return "Reserved"; 3385de6e07eSMauro Carvalho Chehab 3395de6e07eSMauro Carvalho Chehab return table[pos]; 340fcaf780bSMauro Carvalho Chehab } 3415de6e07eSMauro Carvalho Chehab 3425de6e07eSMauro Carvalho Chehab #define GET_ERR_FROM_TABLE(table, pos) \ 3435de6e07eSMauro Carvalho Chehab get_err_from_table(table, ARRAY_SIZE(table), pos) 344fcaf780bSMauro Carvalho Chehab 345d091a6ebSMauro Carvalho Chehab /** 346d091a6ebSMauro Carvalho Chehab * i7300_process_error_global() - Retrieve the hardware error information from 347d091a6ebSMauro Carvalho Chehab * the hardware global error registers and 348d091a6ebSMauro Carvalho Chehab * sends it to dmesg 349d091a6ebSMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer 3505de6e07eSMauro Carvalho Chehab */ 351f4277422SMauro Carvalho Chehab static void i7300_process_error_global(struct mem_ctl_info *mci) 3525de6e07eSMauro Carvalho Chehab { 353fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 3545f032119SMauro Carvalho Chehab u32 errnum, error_reg; 3555de6e07eSMauro Carvalho Chehab unsigned long errors; 3565de6e07eSMauro Carvalho Chehab const char *specific; 3575de6e07eSMauro Carvalho Chehab bool is_fatal; 358fcaf780bSMauro Carvalho Chehab 359fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 360fcaf780bSMauro Carvalho Chehab 361fcaf780bSMauro Carvalho Chehab /* read in the 1st FATAL error register */ 3625de6e07eSMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 3635f032119SMauro Carvalho Chehab FERR_GLOBAL_HI, &error_reg); 3645f032119SMauro Carvalho Chehab if (unlikely(error_reg)) { 3655f032119SMauro Carvalho Chehab errors = error_reg; 3665de6e07eSMauro Carvalho Chehab errnum = find_first_bit(&errors, 3675de6e07eSMauro Carvalho Chehab ARRAY_SIZE(ferr_global_hi_name)); 3685de6e07eSMauro Carvalho Chehab specific = GET_ERR_FROM_TABLE(ferr_global_hi_name, errnum); 3695de6e07eSMauro Carvalho Chehab is_fatal = ferr_global_hi_is_fatal(errnum); 37086002324SMauro Carvalho Chehab 37186002324SMauro Carvalho Chehab /* Clear the error bit */ 37286002324SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 3735f032119SMauro Carvalho Chehab FERR_GLOBAL_HI, error_reg); 37486002324SMauro Carvalho Chehab 3755de6e07eSMauro Carvalho Chehab goto error_global; 376fcaf780bSMauro Carvalho Chehab } 377fcaf780bSMauro Carvalho Chehab 3785de6e07eSMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 3795f032119SMauro Carvalho Chehab FERR_GLOBAL_LO, &error_reg); 3805f032119SMauro Carvalho Chehab if (unlikely(error_reg)) { 3815f032119SMauro Carvalho Chehab errors = error_reg; 3825de6e07eSMauro Carvalho Chehab errnum = find_first_bit(&errors, 3835de6e07eSMauro Carvalho Chehab ARRAY_SIZE(ferr_global_lo_name)); 3845de6e07eSMauro Carvalho Chehab specific = GET_ERR_FROM_TABLE(ferr_global_lo_name, errnum); 3855de6e07eSMauro Carvalho Chehab is_fatal = ferr_global_lo_is_fatal(errnum); 38686002324SMauro Carvalho Chehab 38786002324SMauro Carvalho Chehab /* Clear the error bit */ 38886002324SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 3895f032119SMauro Carvalho Chehab FERR_GLOBAL_LO, error_reg); 39086002324SMauro Carvalho Chehab 3915de6e07eSMauro Carvalho Chehab goto error_global; 392fcaf780bSMauro Carvalho Chehab } 393fcaf780bSMauro Carvalho Chehab return; 394fcaf780bSMauro Carvalho Chehab 3955de6e07eSMauro Carvalho Chehab error_global: 3965de6e07eSMauro Carvalho Chehab i7300_mc_printk(mci, KERN_EMERG, "%s misc error: %s\n", 3975de6e07eSMauro Carvalho Chehab is_fatal ? "Fatal" : "NOT fatal", specific); 398fcaf780bSMauro Carvalho Chehab } 399fcaf780bSMauro Carvalho Chehab 400d091a6ebSMauro Carvalho Chehab /** 401d091a6ebSMauro Carvalho Chehab * i7300_process_fbd_error() - Retrieve the hardware error information from 402d091a6ebSMauro Carvalho Chehab * the FBD error registers and sends it via 403d091a6ebSMauro Carvalho Chehab * EDAC error API calls 404d091a6ebSMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer 40557021918SMauro Carvalho Chehab */ 406f4277422SMauro Carvalho Chehab static void i7300_process_fbd_error(struct mem_ctl_info *mci) 40757021918SMauro Carvalho Chehab { 40857021918SMauro Carvalho Chehab struct i7300_pvt *pvt; 4095f032119SMauro Carvalho Chehab u32 errnum, value, error_reg; 4108199d8ccSMauro Carvalho Chehab u16 val16; 41137b69cf9SMauro Carvalho Chehab unsigned branch, channel, bank, rank, cas, ras; 41232f94726SMauro Carvalho Chehab u32 syndrome; 41332f94726SMauro Carvalho Chehab 41457021918SMauro Carvalho Chehab unsigned long errors; 41557021918SMauro Carvalho Chehab const char *specific; 41632f94726SMauro Carvalho Chehab bool is_wr; 41757021918SMauro Carvalho Chehab 41857021918SMauro Carvalho Chehab pvt = mci->pvt_info; 41957021918SMauro Carvalho Chehab 42057021918SMauro Carvalho Chehab /* read in the 1st FATAL error register */ 42157021918SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 4225f032119SMauro Carvalho Chehab FERR_FAT_FBD, &error_reg); 4235f032119SMauro Carvalho Chehab if (unlikely(error_reg & FERR_FAT_FBD_ERR_MASK)) { 4245f032119SMauro Carvalho Chehab errors = error_reg & FERR_FAT_FBD_ERR_MASK ; 42557021918SMauro Carvalho Chehab errnum = find_first_bit(&errors, 42657021918SMauro Carvalho Chehab ARRAY_SIZE(ferr_fat_fbd_name)); 42757021918SMauro Carvalho Chehab specific = GET_ERR_FROM_TABLE(ferr_fat_fbd_name, errnum); 4285f032119SMauro Carvalho Chehab branch = (GET_FBD_FAT_IDX(error_reg) == 2) ? 1 : 0; 42957021918SMauro Carvalho Chehab 4308199d8ccSMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, 4318199d8ccSMauro Carvalho Chehab NRECMEMA, &val16); 4328199d8ccSMauro Carvalho Chehab bank = NRECMEMA_BANK(val16); 4338199d8ccSMauro Carvalho Chehab rank = NRECMEMA_RANK(val16); 43457021918SMauro Carvalho Chehab 4358199d8ccSMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 4368199d8ccSMauro Carvalho Chehab NRECMEMB, &value); 4378199d8ccSMauro Carvalho Chehab is_wr = NRECMEMB_IS_WR(value); 4388199d8ccSMauro Carvalho Chehab cas = NRECMEMB_CAS(value); 4398199d8ccSMauro Carvalho Chehab ras = NRECMEMB_RAS(value); 4408199d8ccSMauro Carvalho Chehab 4415f032119SMauro Carvalho Chehab /* Clean the error register */ 4425f032119SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 4435f032119SMauro Carvalho Chehab FERR_FAT_FBD, error_reg); 4445f032119SMauro Carvalho Chehab 4458199d8ccSMauro Carvalho Chehab snprintf(pvt->tmp_prt_buffer, PAGE_SIZE, 44670e2a837SMauro Carvalho Chehab "Bank=%d RAS=%d CAS=%d Err=0x%lx (%s))", 44770e2a837SMauro Carvalho Chehab bank, ras, cas, errors, specific); 4488199d8ccSMauro Carvalho Chehab 4499eb07a7fSMauro Carvalho Chehab edac_mc_handle_error(HW_EVENT_ERR_FATAL, mci, 1, 0, 0, 0, 45070e2a837SMauro Carvalho Chehab branch, -1, rank, 45170e2a837SMauro Carvalho Chehab is_wr ? "Write error" : "Read error", 45203f7eae8SMauro Carvalho Chehab pvt->tmp_prt_buffer); 45370e2a837SMauro Carvalho Chehab 45457021918SMauro Carvalho Chehab } 45557021918SMauro Carvalho Chehab 45657021918SMauro Carvalho Chehab /* read in the 1st NON-FATAL error register */ 45757021918SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 4585f032119SMauro Carvalho Chehab FERR_NF_FBD, &error_reg); 4595f032119SMauro Carvalho Chehab if (unlikely(error_reg & FERR_NF_FBD_ERR_MASK)) { 4605f032119SMauro Carvalho Chehab errors = error_reg & FERR_NF_FBD_ERR_MASK; 46157021918SMauro Carvalho Chehab errnum = find_first_bit(&errors, 46257021918SMauro Carvalho Chehab ARRAY_SIZE(ferr_nf_fbd_name)); 46357021918SMauro Carvalho Chehab specific = GET_ERR_FROM_TABLE(ferr_nf_fbd_name, errnum); 4647e06b7a3SJean Delvare branch = (GET_FBD_NF_IDX(error_reg) == 2) ? 1 : 0; 46557021918SMauro Carvalho Chehab 46632f94726SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 46732f94726SMauro Carvalho Chehab REDMEMA, &syndrome); 46832f94726SMauro Carvalho Chehab 46932f94726SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, 47032f94726SMauro Carvalho Chehab RECMEMA, &val16); 47132f94726SMauro Carvalho Chehab bank = RECMEMA_BANK(val16); 47232f94726SMauro Carvalho Chehab rank = RECMEMA_RANK(val16); 47332f94726SMauro Carvalho Chehab 47432f94726SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 47532f94726SMauro Carvalho Chehab RECMEMB, &value); 47632f94726SMauro Carvalho Chehab is_wr = RECMEMB_IS_WR(value); 47732f94726SMauro Carvalho Chehab cas = RECMEMB_CAS(value); 47832f94726SMauro Carvalho Chehab ras = RECMEMB_RAS(value); 47932f94726SMauro Carvalho Chehab 48037b69cf9SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 48137b69cf9SMauro Carvalho Chehab REDMEMB, &value); 48237b69cf9SMauro Carvalho Chehab channel = (branch << 1); 48358fb24cbSBorislav Petkov 48458fb24cbSBorislav Petkov /* Second channel ? */ 48558fb24cbSBorislav Petkov channel += !!(value & BIT(17)); 48637b69cf9SMauro Carvalho Chehab 4875f032119SMauro Carvalho Chehab /* Clear the error bit */ 4885f032119SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 4895f032119SMauro Carvalho Chehab FERR_NF_FBD, error_reg); 4905f032119SMauro Carvalho Chehab 49132f94726SMauro Carvalho Chehab /* Form out message */ 49232f94726SMauro Carvalho Chehab snprintf(pvt->tmp_prt_buffer, PAGE_SIZE, 49370e2a837SMauro Carvalho Chehab "DRAM-Bank=%d RAS=%d CAS=%d, Err=0x%lx (%s))", 49470e2a837SMauro Carvalho Chehab bank, ras, cas, errors, specific); 49532f94726SMauro Carvalho Chehab 4969eb07a7fSMauro Carvalho Chehab edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 0, 0, 49770e2a837SMauro Carvalho Chehab syndrome, 49870e2a837SMauro Carvalho Chehab branch >> 1, channel % 2, rank, 49970e2a837SMauro Carvalho Chehab is_wr ? "Write error" : "Read error", 50003f7eae8SMauro Carvalho Chehab pvt->tmp_prt_buffer); 50157021918SMauro Carvalho Chehab } 50257021918SMauro Carvalho Chehab return; 50357021918SMauro Carvalho Chehab } 50457021918SMauro Carvalho Chehab 505d091a6ebSMauro Carvalho Chehab /** 506d091a6ebSMauro Carvalho Chehab * i7300_check_error() - Calls the error checking subroutines 507d091a6ebSMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer 508fcaf780bSMauro Carvalho Chehab */ 509f4277422SMauro Carvalho Chehab static void i7300_check_error(struct mem_ctl_info *mci) 5105de6e07eSMauro Carvalho Chehab { 511f4277422SMauro Carvalho Chehab i7300_process_error_global(mci); 512f4277422SMauro Carvalho Chehab i7300_process_fbd_error(mci); 5135de6e07eSMauro Carvalho Chehab }; 514fcaf780bSMauro Carvalho Chehab 515d091a6ebSMauro Carvalho Chehab /** 516d091a6ebSMauro Carvalho Chehab * i7300_clear_error() - Clears the error registers 517d091a6ebSMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer 518fcaf780bSMauro Carvalho Chehab */ 519fcaf780bSMauro Carvalho Chehab static void i7300_clear_error(struct mem_ctl_info *mci) 520fcaf780bSMauro Carvalho Chehab { 521e4327605SMauro Carvalho Chehab struct i7300_pvt *pvt = mci->pvt_info; 522e4327605SMauro Carvalho Chehab u32 value; 523e4327605SMauro Carvalho Chehab /* 524e4327605SMauro Carvalho Chehab * All error values are RWC - we need to read and write 1 to the 525e4327605SMauro Carvalho Chehab * bit that we want to cleanup 526e4327605SMauro Carvalho Chehab */ 527fcaf780bSMauro Carvalho Chehab 528e4327605SMauro Carvalho Chehab /* Clear global error registers */ 529e4327605SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 530e4327605SMauro Carvalho Chehab FERR_GLOBAL_HI, &value); 531e4327605SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 532e4327605SMauro Carvalho Chehab FERR_GLOBAL_HI, value); 533e4327605SMauro Carvalho Chehab 534e4327605SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 535e4327605SMauro Carvalho Chehab FERR_GLOBAL_LO, &value); 536e4327605SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_2_fsb_err_regs, 537e4327605SMauro Carvalho Chehab FERR_GLOBAL_LO, value); 538e4327605SMauro Carvalho Chehab 539e4327605SMauro Carvalho Chehab /* Clear FBD error registers */ 540e4327605SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 541e4327605SMauro Carvalho Chehab FERR_FAT_FBD, &value); 542e4327605SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 543e4327605SMauro Carvalho Chehab FERR_FAT_FBD, value); 544e4327605SMauro Carvalho Chehab 545e4327605SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 546e4327605SMauro Carvalho Chehab FERR_NF_FBD, &value); 547e4327605SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 548e4327605SMauro Carvalho Chehab FERR_NF_FBD, value); 549fcaf780bSMauro Carvalho Chehab } 550fcaf780bSMauro Carvalho Chehab 551d091a6ebSMauro Carvalho Chehab /** 552d091a6ebSMauro Carvalho Chehab * i7300_enable_error_reporting() - Enable the memory reporting logic at the 553d091a6ebSMauro Carvalho Chehab * hardware 554d091a6ebSMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer 555fcaf780bSMauro Carvalho Chehab */ 556fcaf780bSMauro Carvalho Chehab static void i7300_enable_error_reporting(struct mem_ctl_info *mci) 557fcaf780bSMauro Carvalho Chehab { 55857021918SMauro Carvalho Chehab struct i7300_pvt *pvt = mci->pvt_info; 55957021918SMauro Carvalho Chehab u32 fbd_error_mask; 56057021918SMauro Carvalho Chehab 56157021918SMauro Carvalho Chehab /* Read the FBD Error Mask Register */ 56257021918SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 56357021918SMauro Carvalho Chehab EMASK_FBD, &fbd_error_mask); 56457021918SMauro Carvalho Chehab 56557021918SMauro Carvalho Chehab /* Enable with a '0' */ 56657021918SMauro Carvalho Chehab fbd_error_mask &= ~(EMASK_FBD_ERR_MASK); 56757021918SMauro Carvalho Chehab 56857021918SMauro Carvalho Chehab pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map, 56957021918SMauro Carvalho Chehab EMASK_FBD, fbd_error_mask); 570fcaf780bSMauro Carvalho Chehab } 5715de6e07eSMauro Carvalho Chehab 5725de6e07eSMauro Carvalho Chehab /************************************************ 5735de6e07eSMauro Carvalho Chehab * i7300 Functions related to memory enumberation 5745de6e07eSMauro Carvalho Chehab ************************************************/ 575fcaf780bSMauro Carvalho Chehab 576d091a6ebSMauro Carvalho Chehab /** 577d091a6ebSMauro Carvalho Chehab * decode_mtr() - Decodes the MTR descriptor, filling the edac structs 578d091a6ebSMauro Carvalho Chehab * @pvt: pointer to the private data struct used by i7300 driver 579d091a6ebSMauro Carvalho Chehab * @slot: DIMM slot (0 to 7) 580d091a6ebSMauro Carvalho Chehab * @ch: Channel number within the branch (0 or 1) 581d091a6ebSMauro Carvalho Chehab * @branch: Branch number (0 or 1) 582d091a6ebSMauro Carvalho Chehab * @dinfo: Pointer to DIMM info where dimm size is stored 5839f95c8d5SMauro Carvalho Chehab * @dimm: Pointer to the struct dimm_info that corresponds to that element 584fcaf780bSMauro Carvalho Chehab */ 585fcaf780bSMauro Carvalho Chehab static int decode_mtr(struct i7300_pvt *pvt, 586fcaf780bSMauro Carvalho Chehab int slot, int ch, int branch, 587fcaf780bSMauro Carvalho Chehab struct i7300_dimm_info *dinfo, 588a895bf8bSMauro Carvalho Chehab struct dimm_info *dimm) 589fcaf780bSMauro Carvalho Chehab { 590fcaf780bSMauro Carvalho Chehab int mtr, ans, addrBits, channel; 591fcaf780bSMauro Carvalho Chehab 592fcaf780bSMauro Carvalho Chehab channel = to_channel(ch, branch); 593fcaf780bSMauro Carvalho Chehab 594fcaf780bSMauro Carvalho Chehab mtr = pvt->mtr[slot][branch]; 595fcaf780bSMauro Carvalho Chehab ans = MTR_DIMMS_PRESENT(mtr) ? 1 : 0; 596fcaf780bSMauro Carvalho Chehab 597956b9ba1SJoe Perches edac_dbg(2, "\tMTR%d CH%d: DIMMs are %sPresent (mtr)\n", 598956b9ba1SJoe Perches slot, channel, ans ? "" : "NOT "); 599fcaf780bSMauro Carvalho Chehab 600fcaf780bSMauro Carvalho Chehab /* Determine if there is a DIMM present in this DIMM slot */ 601fcaf780bSMauro Carvalho Chehab if (!ans) 602fcaf780bSMauro Carvalho Chehab return 0; 603fcaf780bSMauro Carvalho Chehab 604fcaf780bSMauro Carvalho Chehab /* Start with the number of bits for a Bank 605fcaf780bSMauro Carvalho Chehab * on the DRAM */ 606fcaf780bSMauro Carvalho Chehab addrBits = MTR_DRAM_BANKS_ADDR_BITS; 607fcaf780bSMauro Carvalho Chehab /* Add thenumber of ROW bits */ 608fcaf780bSMauro Carvalho Chehab addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr); 609fcaf780bSMauro Carvalho Chehab /* add the number of COLUMN bits */ 610fcaf780bSMauro Carvalho Chehab addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr); 611fcaf780bSMauro Carvalho Chehab /* add the number of RANK bits */ 612fcaf780bSMauro Carvalho Chehab addrBits += MTR_DIMM_RANKS(mtr); 613fcaf780bSMauro Carvalho Chehab 614fcaf780bSMauro Carvalho Chehab addrBits += 6; /* add 64 bits per DIMM */ 615fcaf780bSMauro Carvalho Chehab addrBits -= 20; /* divide by 2^^20 */ 616fcaf780bSMauro Carvalho Chehab addrBits -= 3; /* 8 bits per bytes */ 617fcaf780bSMauro Carvalho Chehab 618fcaf780bSMauro Carvalho Chehab dinfo->megabytes = 1 << addrBits; 619fcaf780bSMauro Carvalho Chehab 620956b9ba1SJoe Perches edac_dbg(2, "\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr)); 621fcaf780bSMauro Carvalho Chehab 622956b9ba1SJoe Perches edac_dbg(2, "\t\tELECTRICAL THROTTLING is %s\n", 623fcaf780bSMauro Carvalho Chehab MTR_DIMMS_ETHROTTLE(mtr) ? "enabled" : "disabled"); 624fcaf780bSMauro Carvalho Chehab 625956b9ba1SJoe Perches edac_dbg(2, "\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr)); 626956b9ba1SJoe Perches edac_dbg(2, "\t\tNUMRANK: %s\n", 627956b9ba1SJoe Perches MTR_DIMM_RANKS(mtr) ? "double" : "single"); 628956b9ba1SJoe Perches edac_dbg(2, "\t\tNUMROW: %s\n", 6297e881856SJoe Perches MTR_DIMM_ROWS(mtr) == 0 ? "8,192 - 13 rows" : 6307e881856SJoe Perches MTR_DIMM_ROWS(mtr) == 1 ? "16,384 - 14 rows" : 6317e881856SJoe Perches MTR_DIMM_ROWS(mtr) == 2 ? "32,768 - 15 rows" : 6327e881856SJoe Perches "65,536 - 16 rows"); 633956b9ba1SJoe Perches edac_dbg(2, "\t\tNUMCOL: %s\n", 6347e881856SJoe Perches MTR_DIMM_COLS(mtr) == 0 ? "1,024 - 10 columns" : 6357e881856SJoe Perches MTR_DIMM_COLS(mtr) == 1 ? "2,048 - 11 columns" : 6367e881856SJoe Perches MTR_DIMM_COLS(mtr) == 2 ? "4,096 - 12 columns" : 6377e881856SJoe Perches "reserved"); 638956b9ba1SJoe Perches edac_dbg(2, "\t\tSIZE: %d MB\n", dinfo->megabytes); 639fcaf780bSMauro Carvalho Chehab 640116389edSMauro Carvalho Chehab /* 64115154c57SMauro Carvalho Chehab * The type of error detection actually depends of the 642116389edSMauro Carvalho Chehab * mode of operation. When it is just one single memory chip, at 643116389edSMauro Carvalho Chehab * socket 0, channel 0, it uses 8-byte-over-32-byte SECDED+ code. 64415154c57SMauro Carvalho Chehab * In normal or mirrored mode, it uses Lockstep mode, 645116389edSMauro Carvalho Chehab * with the possibility of using an extended algorithm for x8 memories 646116389edSMauro Carvalho Chehab * See datasheet Sections 7.3.6 to 7.3.8 647116389edSMauro Carvalho Chehab */ 64815154c57SMauro Carvalho Chehab 649a895bf8bSMauro Carvalho Chehab dimm->nr_pages = MiB_TO_PAGES(dinfo->megabytes); 650084a4fccSMauro Carvalho Chehab dimm->grain = 8; 651084a4fccSMauro Carvalho Chehab dimm->mtype = MEM_FB_DDR2; 65215154c57SMauro Carvalho Chehab if (IS_SINGLE_MODE(pvt->mc_settings_a)) { 653084a4fccSMauro Carvalho Chehab dimm->edac_mode = EDAC_SECDED; 654956b9ba1SJoe Perches edac_dbg(2, "\t\tECC code is 8-byte-over-32-byte SECDED+ code\n"); 65515154c57SMauro Carvalho Chehab } else { 656956b9ba1SJoe Perches edac_dbg(2, "\t\tECC code is on Lockstep mode\n"); 65728c2ce7cSMauro Carvalho Chehab if (MTR_DRAM_WIDTH(mtr) == 8) 658084a4fccSMauro Carvalho Chehab dimm->edac_mode = EDAC_S8ECD8ED; 65915154c57SMauro Carvalho Chehab else 660084a4fccSMauro Carvalho Chehab dimm->edac_mode = EDAC_S4ECD4ED; 66115154c57SMauro Carvalho Chehab } 662fcaf780bSMauro Carvalho Chehab 663fcaf780bSMauro Carvalho Chehab /* ask what device type on this row */ 66428c2ce7cSMauro Carvalho Chehab if (MTR_DRAM_WIDTH(mtr) == 8) { 665956b9ba1SJoe Perches edac_dbg(2, "\t\tScrub algorithm for x8 is on %s mode\n", 666d7de2bdbSMauro Carvalho Chehab IS_SCRBALGO_ENHANCED(pvt->mc_settings) ? 667d7de2bdbSMauro Carvalho Chehab "enhanced" : "normal"); 668d7de2bdbSMauro Carvalho Chehab 669084a4fccSMauro Carvalho Chehab dimm->dtype = DEV_X8; 670d7de2bdbSMauro Carvalho Chehab } else 671084a4fccSMauro Carvalho Chehab dimm->dtype = DEV_X4; 672fcaf780bSMauro Carvalho Chehab 673fcaf780bSMauro Carvalho Chehab return mtr; 674fcaf780bSMauro Carvalho Chehab } 675fcaf780bSMauro Carvalho Chehab 676d091a6ebSMauro Carvalho Chehab /** 677d091a6ebSMauro Carvalho Chehab * print_dimm_size() - Prints dump of the memory organization 678d091a6ebSMauro Carvalho Chehab * @pvt: pointer to the private data struct used by i7300 driver 679fcaf780bSMauro Carvalho Chehab * 680d091a6ebSMauro Carvalho Chehab * Useful for debug. If debug is disabled, this routine do nothing 681fcaf780bSMauro Carvalho Chehab */ 682fcaf780bSMauro Carvalho Chehab static void print_dimm_size(struct i7300_pvt *pvt) 683fcaf780bSMauro Carvalho Chehab { 684d091a6ebSMauro Carvalho Chehab #ifdef CONFIG_EDAC_DEBUG 685fcaf780bSMauro Carvalho Chehab struct i7300_dimm_info *dinfo; 68685580ea4SMauro Carvalho Chehab char *p; 687fcaf780bSMauro Carvalho Chehab int space, n; 688fcaf780bSMauro Carvalho Chehab int channel, slot; 689fcaf780bSMauro Carvalho Chehab 690fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 69185580ea4SMauro Carvalho Chehab p = pvt->tmp_prt_buffer; 692fcaf780bSMauro Carvalho Chehab 693fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, " "); 694fcaf780bSMauro Carvalho Chehab p += n; 695fcaf780bSMauro Carvalho Chehab space -= n; 696fcaf780bSMauro Carvalho Chehab for (channel = 0; channel < MAX_CHANNELS; channel++) { 697fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "channel %d | ", channel); 698fcaf780bSMauro Carvalho Chehab p += n; 699fcaf780bSMauro Carvalho Chehab space -= n; 700fcaf780bSMauro Carvalho Chehab } 701956b9ba1SJoe Perches edac_dbg(2, "%s\n", pvt->tmp_prt_buffer); 70285580ea4SMauro Carvalho Chehab p = pvt->tmp_prt_buffer; 703fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 704fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "-------------------------------" 705fcaf780bSMauro Carvalho Chehab "------------------------------"); 706fcaf780bSMauro Carvalho Chehab p += n; 707fcaf780bSMauro Carvalho Chehab space -= n; 708956b9ba1SJoe Perches edac_dbg(2, "%s\n", pvt->tmp_prt_buffer); 70985580ea4SMauro Carvalho Chehab p = pvt->tmp_prt_buffer; 710fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 711fcaf780bSMauro Carvalho Chehab 712fcaf780bSMauro Carvalho Chehab for (slot = 0; slot < MAX_SLOTS; slot++) { 713fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "csrow/SLOT %d ", slot); 714fcaf780bSMauro Carvalho Chehab p += n; 715fcaf780bSMauro Carvalho Chehab space -= n; 716fcaf780bSMauro Carvalho Chehab 717fcaf780bSMauro Carvalho Chehab for (channel = 0; channel < MAX_CHANNELS; channel++) { 718fcaf780bSMauro Carvalho Chehab dinfo = &pvt->dimm_info[slot][channel]; 719fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "%4d MB | ", dinfo->megabytes); 720fcaf780bSMauro Carvalho Chehab p += n; 721fcaf780bSMauro Carvalho Chehab space -= n; 722fcaf780bSMauro Carvalho Chehab } 723fcaf780bSMauro Carvalho Chehab 724956b9ba1SJoe Perches edac_dbg(2, "%s\n", pvt->tmp_prt_buffer); 72585580ea4SMauro Carvalho Chehab p = pvt->tmp_prt_buffer; 726fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 727fcaf780bSMauro Carvalho Chehab } 728fcaf780bSMauro Carvalho Chehab 729fcaf780bSMauro Carvalho Chehab n = snprintf(p, space, "-------------------------------" 730fcaf780bSMauro Carvalho Chehab "------------------------------"); 731fcaf780bSMauro Carvalho Chehab p += n; 732fcaf780bSMauro Carvalho Chehab space -= n; 733956b9ba1SJoe Perches edac_dbg(2, "%s\n", pvt->tmp_prt_buffer); 73485580ea4SMauro Carvalho Chehab p = pvt->tmp_prt_buffer; 735fcaf780bSMauro Carvalho Chehab space = PAGE_SIZE; 736d091a6ebSMauro Carvalho Chehab #endif 737fcaf780bSMauro Carvalho Chehab } 738fcaf780bSMauro Carvalho Chehab 739d091a6ebSMauro Carvalho Chehab /** 740d091a6ebSMauro Carvalho Chehab * i7300_init_csrows() - Initialize the 'csrows' table within 741fcaf780bSMauro Carvalho Chehab * the mci control structure with the 742fcaf780bSMauro Carvalho Chehab * addressing of memory. 743d091a6ebSMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer 744fcaf780bSMauro Carvalho Chehab */ 745fcaf780bSMauro Carvalho Chehab static int i7300_init_csrows(struct mem_ctl_info *mci) 746fcaf780bSMauro Carvalho Chehab { 747fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 748fcaf780bSMauro Carvalho Chehab struct i7300_dimm_info *dinfo; 749d091a6ebSMauro Carvalho Chehab int rc = -ENODEV; 750fcaf780bSMauro Carvalho Chehab int mtr; 75133ad4126SMauro Carvalho Chehab int ch, branch, slot, channel, max_channel, max_branch; 752084a4fccSMauro Carvalho Chehab struct dimm_info *dimm; 753fcaf780bSMauro Carvalho Chehab 754fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 755fcaf780bSMauro Carvalho Chehab 756956b9ba1SJoe Perches edac_dbg(2, "Memory Technology Registers:\n"); 757fcaf780bSMauro Carvalho Chehab 75833ad4126SMauro Carvalho Chehab if (IS_SINGLE_MODE(pvt->mc_settings_a)) { 75933ad4126SMauro Carvalho Chehab max_branch = 1; 76033ad4126SMauro Carvalho Chehab max_channel = 1; 76133ad4126SMauro Carvalho Chehab } else { 76233ad4126SMauro Carvalho Chehab max_branch = MAX_BRANCHES; 76333ad4126SMauro Carvalho Chehab max_channel = MAX_CH_PER_BRANCH; 76433ad4126SMauro Carvalho Chehab } 76533ad4126SMauro Carvalho Chehab 766fcaf780bSMauro Carvalho Chehab /* Get the AMB present registers for the four channels */ 76733ad4126SMauro Carvalho Chehab for (branch = 0; branch < max_branch; branch++) { 768fcaf780bSMauro Carvalho Chehab /* Read and dump branch 0's MTRs */ 769fcaf780bSMauro Carvalho Chehab channel = to_channel(0, branch); 7709c6f6b65SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch], 7719c6f6b65SMauro Carvalho Chehab AMBPRESENT_0, 772fcaf780bSMauro Carvalho Chehab &pvt->ambpresent[channel]); 773956b9ba1SJoe Perches edac_dbg(2, "\t\tAMB-present CH%d = 0x%x:\n", 774fcaf780bSMauro Carvalho Chehab channel, pvt->ambpresent[channel]); 775fcaf780bSMauro Carvalho Chehab 77633ad4126SMauro Carvalho Chehab if (max_channel == 1) 77733ad4126SMauro Carvalho Chehab continue; 77833ad4126SMauro Carvalho Chehab 779fcaf780bSMauro Carvalho Chehab channel = to_channel(1, branch); 7809c6f6b65SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch], 7819c6f6b65SMauro Carvalho Chehab AMBPRESENT_1, 782fcaf780bSMauro Carvalho Chehab &pvt->ambpresent[channel]); 783956b9ba1SJoe Perches edac_dbg(2, "\t\tAMB-present CH%d = 0x%x:\n", 784fcaf780bSMauro Carvalho Chehab channel, pvt->ambpresent[channel]); 785fcaf780bSMauro Carvalho Chehab } 786fcaf780bSMauro Carvalho Chehab 787fcaf780bSMauro Carvalho Chehab /* Get the set of MTR[0-7] regs by each branch */ 788fcaf780bSMauro Carvalho Chehab for (slot = 0; slot < MAX_SLOTS; slot++) { 789fcaf780bSMauro Carvalho Chehab int where = mtr_regs[slot]; 79033ad4126SMauro Carvalho Chehab for (branch = 0; branch < max_branch; branch++) { 7913e57eef6SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch], 792fcaf780bSMauro Carvalho Chehab where, 793fcaf780bSMauro Carvalho Chehab &pvt->mtr[slot][branch]); 79433ad4126SMauro Carvalho Chehab for (ch = 0; ch < max_channel; ch++) { 795fcaf780bSMauro Carvalho Chehab int channel = to_channel(ch, branch); 796fcaf780bSMauro Carvalho Chehab 797bc9ad9e4SRobert Richter dimm = edac_get_dimm(mci, branch, ch, slot); 798fcaf780bSMauro Carvalho Chehab 79970e2a837SMauro Carvalho Chehab dinfo = &pvt->dimm_info[slot][channel]; 800084a4fccSMauro Carvalho Chehab 801fcaf780bSMauro Carvalho Chehab mtr = decode_mtr(pvt, slot, ch, branch, 802a895bf8bSMauro Carvalho Chehab dinfo, dimm); 803a895bf8bSMauro Carvalho Chehab 804fcaf780bSMauro Carvalho Chehab /* if no DIMMS on this row, continue */ 805fcaf780bSMauro Carvalho Chehab if (!MTR_DIMMS_PRESENT(mtr)) 806fcaf780bSMauro Carvalho Chehab continue; 807fcaf780bSMauro Carvalho Chehab 808d091a6ebSMauro Carvalho Chehab rc = 0; 809a895bf8bSMauro Carvalho Chehab 810fcaf780bSMauro Carvalho Chehab } 811fcaf780bSMauro Carvalho Chehab } 812fcaf780bSMauro Carvalho Chehab } 813fcaf780bSMauro Carvalho Chehab 814d091a6ebSMauro Carvalho Chehab return rc; 815fcaf780bSMauro Carvalho Chehab } 816fcaf780bSMauro Carvalho Chehab 817d091a6ebSMauro Carvalho Chehab /** 818d091a6ebSMauro Carvalho Chehab * decode_mir() - Decodes Memory Interleave Register (MIR) info 81948356e0dSMauro Carvalho Chehab * @mir_no: number of the MIR register to decode 820d091a6ebSMauro Carvalho Chehab * @mir: array with the MIR data cached on the driver 821d091a6ebSMauro Carvalho Chehab */ 822fcaf780bSMauro Carvalho Chehab static void decode_mir(int mir_no, u16 mir[MAX_MIR]) 823fcaf780bSMauro Carvalho Chehab { 824fcaf780bSMauro Carvalho Chehab if (mir[mir_no] & 3) 825956b9ba1SJoe Perches edac_dbg(2, "MIR%d: limit= 0x%x Branch(es) that participate: %s %s\n", 826fcaf780bSMauro Carvalho Chehab mir_no, 827fcaf780bSMauro Carvalho Chehab (mir[mir_no] >> 4) & 0xfff, 828fcaf780bSMauro Carvalho Chehab (mir[mir_no] & 1) ? "B0" : "", 829fcaf780bSMauro Carvalho Chehab (mir[mir_no] & 2) ? "B1" : ""); 830fcaf780bSMauro Carvalho Chehab } 831fcaf780bSMauro Carvalho Chehab 832d091a6ebSMauro Carvalho Chehab /** 833d091a6ebSMauro Carvalho Chehab * i7300_get_mc_regs() - Get the contents of the MC enumeration registers 834d091a6ebSMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer 835fcaf780bSMauro Carvalho Chehab * 836d091a6ebSMauro Carvalho Chehab * Data read is cached internally for its usage when needed 837fcaf780bSMauro Carvalho Chehab */ 838fcaf780bSMauro Carvalho Chehab static int i7300_get_mc_regs(struct mem_ctl_info *mci) 839fcaf780bSMauro Carvalho Chehab { 840fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 841fcaf780bSMauro Carvalho Chehab u32 actual_tolm; 842fcaf780bSMauro Carvalho Chehab int i, rc; 843fcaf780bSMauro Carvalho Chehab 844fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 845fcaf780bSMauro Carvalho Chehab 8463e57eef6SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_0_fsb_ctlr, AMBASE, 847fcaf780bSMauro Carvalho Chehab (u32 *) &pvt->ambase); 848fcaf780bSMauro Carvalho Chehab 849956b9ba1SJoe Perches edac_dbg(2, "AMBASE= 0x%lx\n", (long unsigned int)pvt->ambase); 850fcaf780bSMauro Carvalho Chehab 851fcaf780bSMauro Carvalho Chehab /* Get the Branch Map regs */ 8523e57eef6SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, TOLM, &pvt->tolm); 853fcaf780bSMauro Carvalho Chehab pvt->tolm >>= 12; 854956b9ba1SJoe Perches edac_dbg(2, "TOLM (number of 256M regions) =%u (0x%x)\n", 855956b9ba1SJoe Perches pvt->tolm, pvt->tolm); 856fcaf780bSMauro Carvalho Chehab 857fcaf780bSMauro Carvalho Chehab actual_tolm = (u32) ((1000l * pvt->tolm) >> (30 - 28)); 858956b9ba1SJoe Perches edac_dbg(2, "Actual TOLM byte addr=%u.%03u GB (0x%x)\n", 859fcaf780bSMauro Carvalho Chehab actual_tolm/1000, actual_tolm % 1000, pvt->tolm << 28); 860fcaf780bSMauro Carvalho Chehab 861af3d8831SMauro Carvalho Chehab /* Get memory controller settings */ 8623e57eef6SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, MC_SETTINGS, 863af3d8831SMauro Carvalho Chehab &pvt->mc_settings); 864bb81a216SMauro Carvalho Chehab pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, MC_SETTINGS_A, 865bb81a216SMauro Carvalho Chehab &pvt->mc_settings_a); 866d7de2bdbSMauro Carvalho Chehab 867bb81a216SMauro Carvalho Chehab if (IS_SINGLE_MODE(pvt->mc_settings_a)) 868956b9ba1SJoe Perches edac_dbg(0, "Memory controller operating on single mode\n"); 869bb81a216SMauro Carvalho Chehab else 870956b9ba1SJoe Perches edac_dbg(0, "Memory controller operating on %smirrored mode\n", 871956b9ba1SJoe Perches IS_MIRRORED(pvt->mc_settings) ? "" : "non-"); 872bb81a216SMauro Carvalho Chehab 873956b9ba1SJoe Perches edac_dbg(0, "Error detection is %s\n", 874d7de2bdbSMauro Carvalho Chehab IS_ECC_ENABLED(pvt->mc_settings) ? "enabled" : "disabled"); 875956b9ba1SJoe Perches edac_dbg(0, "Retry is %s\n", 876d7de2bdbSMauro Carvalho Chehab IS_RETRY_ENABLED(pvt->mc_settings) ? "enabled" : "disabled"); 877af3d8831SMauro Carvalho Chehab 878af3d8831SMauro Carvalho Chehab /* Get Memory Interleave Range registers */ 8799c6f6b65SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR0, 8809c6f6b65SMauro Carvalho Chehab &pvt->mir[0]); 8819c6f6b65SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR1, 8829c6f6b65SMauro Carvalho Chehab &pvt->mir[1]); 8839c6f6b65SMauro Carvalho Chehab pci_read_config_word(pvt->pci_dev_16_1_fsb_addr_map, MIR2, 8849c6f6b65SMauro Carvalho Chehab &pvt->mir[2]); 885fcaf780bSMauro Carvalho Chehab 886fcaf780bSMauro Carvalho Chehab /* Decode the MIR regs */ 887fcaf780bSMauro Carvalho Chehab for (i = 0; i < MAX_MIR; i++) 888fcaf780bSMauro Carvalho Chehab decode_mir(i, pvt->mir); 889fcaf780bSMauro Carvalho Chehab 890fcaf780bSMauro Carvalho Chehab rc = i7300_init_csrows(mci); 891fcaf780bSMauro Carvalho Chehab if (rc < 0) 892fcaf780bSMauro Carvalho Chehab return rc; 893fcaf780bSMauro Carvalho Chehab 894fcaf780bSMauro Carvalho Chehab /* Go and determine the size of each DIMM and place in an 895fcaf780bSMauro Carvalho Chehab * orderly matrix */ 896fcaf780bSMauro Carvalho Chehab print_dimm_size(pvt); 897fcaf780bSMauro Carvalho Chehab 898fcaf780bSMauro Carvalho Chehab return 0; 899fcaf780bSMauro Carvalho Chehab } 900fcaf780bSMauro Carvalho Chehab 9015de6e07eSMauro Carvalho Chehab /************************************************* 9025de6e07eSMauro Carvalho Chehab * i7300 Functions related to device probe/release 9035de6e07eSMauro Carvalho Chehab *************************************************/ 9045de6e07eSMauro Carvalho Chehab 905d091a6ebSMauro Carvalho Chehab /** 906d091a6ebSMauro Carvalho Chehab * i7300_put_devices() - Release the PCI devices 907d091a6ebSMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer 908fcaf780bSMauro Carvalho Chehab */ 909fcaf780bSMauro Carvalho Chehab static void i7300_put_devices(struct mem_ctl_info *mci) 910fcaf780bSMauro Carvalho Chehab { 911fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 912fcaf780bSMauro Carvalho Chehab int branch; 913fcaf780bSMauro Carvalho Chehab 914fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 915fcaf780bSMauro Carvalho Chehab 916fcaf780bSMauro Carvalho Chehab /* Decrement usage count for devices */ 917fcaf780bSMauro Carvalho Chehab for (branch = 0; branch < MAX_CH_PER_BRANCH; branch++) 9183e57eef6SMauro Carvalho Chehab pci_dev_put(pvt->pci_dev_2x_0_fbd_branch[branch]); 9193e57eef6SMauro Carvalho Chehab pci_dev_put(pvt->pci_dev_16_2_fsb_err_regs); 9203e57eef6SMauro Carvalho Chehab pci_dev_put(pvt->pci_dev_16_1_fsb_addr_map); 921fcaf780bSMauro Carvalho Chehab } 922fcaf780bSMauro Carvalho Chehab 923d091a6ebSMauro Carvalho Chehab /** 924d091a6ebSMauro Carvalho Chehab * i7300_get_devices() - Find and perform 'get' operation on the MCH's 925fcaf780bSMauro Carvalho Chehab * device/functions we want to reference for this driver 926d091a6ebSMauro Carvalho Chehab * @mci: struct mem_ctl_info pointer 927fcaf780bSMauro Carvalho Chehab * 928d091a6ebSMauro Carvalho Chehab * Access and prepare the several devices for usage: 929d091a6ebSMauro Carvalho Chehab * I7300 devices used by this driver: 930d091a6ebSMauro Carvalho Chehab * Device 16, functions 0,1 and 2: PCI_DEVICE_ID_INTEL_I7300_MCH_ERR 931d091a6ebSMauro Carvalho Chehab * Device 21 function 0: PCI_DEVICE_ID_INTEL_I7300_MCH_FB0 932d091a6ebSMauro Carvalho Chehab * Device 22 function 0: PCI_DEVICE_ID_INTEL_I7300_MCH_FB1 933fcaf780bSMauro Carvalho Chehab */ 9349b3c6e85SGreg Kroah-Hartman static int i7300_get_devices(struct mem_ctl_info *mci) 935fcaf780bSMauro Carvalho Chehab { 936fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 937fcaf780bSMauro Carvalho Chehab struct pci_dev *pdev; 938fcaf780bSMauro Carvalho Chehab 939fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 940fcaf780bSMauro Carvalho Chehab 941fcaf780bSMauro Carvalho Chehab /* Attempt to 'get' the MCH register we want */ 942fcaf780bSMauro Carvalho Chehab pdev = NULL; 94375135da0SJean Delvare while ((pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 94475135da0SJean Delvare PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, 94575135da0SJean Delvare pdev))) { 946fcaf780bSMauro Carvalho Chehab /* Store device 16 funcs 1 and 2 */ 947fcaf780bSMauro Carvalho Chehab switch (PCI_FUNC(pdev->devfn)) { 948fcaf780bSMauro Carvalho Chehab case 1: 94975135da0SJean Delvare if (!pvt->pci_dev_16_1_fsb_addr_map) 95075135da0SJean Delvare pvt->pci_dev_16_1_fsb_addr_map = 95175135da0SJean Delvare pci_dev_get(pdev); 952fcaf780bSMauro Carvalho Chehab break; 953fcaf780bSMauro Carvalho Chehab case 2: 95475135da0SJean Delvare if (!pvt->pci_dev_16_2_fsb_err_regs) 95575135da0SJean Delvare pvt->pci_dev_16_2_fsb_err_regs = 95675135da0SJean Delvare pci_dev_get(pdev); 957fcaf780bSMauro Carvalho Chehab break; 958fcaf780bSMauro Carvalho Chehab } 959fcaf780bSMauro Carvalho Chehab } 960fcaf780bSMauro Carvalho Chehab 96175135da0SJean Delvare if (!pvt->pci_dev_16_1_fsb_addr_map || 96275135da0SJean Delvare !pvt->pci_dev_16_2_fsb_err_regs) { 96375135da0SJean Delvare /* At least one device was not found */ 96475135da0SJean Delvare i7300_printk(KERN_ERR, 96575135da0SJean Delvare "'system address,Process Bus' device not found:" 96675135da0SJean Delvare "vendor 0x%x device 0x%x ERR funcs (broken BIOS?)\n", 96775135da0SJean Delvare PCI_VENDOR_ID_INTEL, 96875135da0SJean Delvare PCI_DEVICE_ID_INTEL_I7300_MCH_ERR); 96975135da0SJean Delvare goto error; 97075135da0SJean Delvare } 97175135da0SJean Delvare 972956b9ba1SJoe Perches edac_dbg(1, "System Address, processor bus- PCI Bus ID: %s %x:%x\n", 9733e57eef6SMauro Carvalho Chehab pci_name(pvt->pci_dev_16_0_fsb_ctlr), 9749c6f6b65SMauro Carvalho Chehab pvt->pci_dev_16_0_fsb_ctlr->vendor, 9759c6f6b65SMauro Carvalho Chehab pvt->pci_dev_16_0_fsb_ctlr->device); 976956b9ba1SJoe Perches edac_dbg(1, "Branchmap, control and errors - PCI Bus ID: %s %x:%x\n", 9773e57eef6SMauro Carvalho Chehab pci_name(pvt->pci_dev_16_1_fsb_addr_map), 9789c6f6b65SMauro Carvalho Chehab pvt->pci_dev_16_1_fsb_addr_map->vendor, 9799c6f6b65SMauro Carvalho Chehab pvt->pci_dev_16_1_fsb_addr_map->device); 980956b9ba1SJoe Perches edac_dbg(1, "FSB Error Regs - PCI Bus ID: %s %x:%x\n", 9813e57eef6SMauro Carvalho Chehab pci_name(pvt->pci_dev_16_2_fsb_err_regs), 9829c6f6b65SMauro Carvalho Chehab pvt->pci_dev_16_2_fsb_err_regs->vendor, 9839c6f6b65SMauro Carvalho Chehab pvt->pci_dev_16_2_fsb_err_regs->device); 984fcaf780bSMauro Carvalho Chehab 9853e57eef6SMauro Carvalho Chehab pvt->pci_dev_2x_0_fbd_branch[0] = pci_get_device(PCI_VENDOR_ID_INTEL, 986fcaf780bSMauro Carvalho Chehab PCI_DEVICE_ID_INTEL_I7300_MCH_FB0, 987fcaf780bSMauro Carvalho Chehab NULL); 9883e57eef6SMauro Carvalho Chehab if (!pvt->pci_dev_2x_0_fbd_branch[0]) { 989fcaf780bSMauro Carvalho Chehab i7300_printk(KERN_ERR, 990fcaf780bSMauro Carvalho Chehab "MC: 'BRANCH 0' device not found:" 991fcaf780bSMauro Carvalho Chehab "vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n", 992fcaf780bSMauro Carvalho Chehab PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_FB0); 993fcaf780bSMauro Carvalho Chehab goto error; 994fcaf780bSMauro Carvalho Chehab } 995fcaf780bSMauro Carvalho Chehab 9963e57eef6SMauro Carvalho Chehab pvt->pci_dev_2x_0_fbd_branch[1] = pci_get_device(PCI_VENDOR_ID_INTEL, 997fcaf780bSMauro Carvalho Chehab PCI_DEVICE_ID_INTEL_I7300_MCH_FB1, 998fcaf780bSMauro Carvalho Chehab NULL); 9993e57eef6SMauro Carvalho Chehab if (!pvt->pci_dev_2x_0_fbd_branch[1]) { 1000fcaf780bSMauro Carvalho Chehab i7300_printk(KERN_ERR, 1001fcaf780bSMauro Carvalho Chehab "MC: 'BRANCH 1' device not found:" 1002fcaf780bSMauro Carvalho Chehab "vendor 0x%x device 0x%x Func 0 " 1003fcaf780bSMauro Carvalho Chehab "(broken BIOS?)\n", 1004fcaf780bSMauro Carvalho Chehab PCI_VENDOR_ID_INTEL, 1005fcaf780bSMauro Carvalho Chehab PCI_DEVICE_ID_INTEL_I7300_MCH_FB1); 1006fcaf780bSMauro Carvalho Chehab goto error; 1007fcaf780bSMauro Carvalho Chehab } 1008fcaf780bSMauro Carvalho Chehab 1009fcaf780bSMauro Carvalho Chehab return 0; 1010fcaf780bSMauro Carvalho Chehab 1011fcaf780bSMauro Carvalho Chehab error: 1012fcaf780bSMauro Carvalho Chehab i7300_put_devices(mci); 1013fcaf780bSMauro Carvalho Chehab return -ENODEV; 1014fcaf780bSMauro Carvalho Chehab } 1015fcaf780bSMauro Carvalho Chehab 1016d091a6ebSMauro Carvalho Chehab /** 1017d091a6ebSMauro Carvalho Chehab * i7300_init_one() - Probe for one instance of the device 1018d091a6ebSMauro Carvalho Chehab * @pdev: struct pci_dev pointer 1019d091a6ebSMauro Carvalho Chehab * @id: struct pci_device_id pointer - currently unused 1020fcaf780bSMauro Carvalho Chehab */ 10219b3c6e85SGreg Kroah-Hartman static int i7300_init_one(struct pci_dev *pdev, const struct pci_device_id *id) 1022fcaf780bSMauro Carvalho Chehab { 1023fcaf780bSMauro Carvalho Chehab struct mem_ctl_info *mci; 102470e2a837SMauro Carvalho Chehab struct edac_mc_layer layers[3]; 1025fcaf780bSMauro Carvalho Chehab struct i7300_pvt *pvt; 1026d091a6ebSMauro Carvalho Chehab int rc; 1027fcaf780bSMauro Carvalho Chehab 1028d091a6ebSMauro Carvalho Chehab /* wake up device */ 1029d091a6ebSMauro Carvalho Chehab rc = pci_enable_device(pdev); 1030d091a6ebSMauro Carvalho Chehab if (rc == -EIO) 1031d091a6ebSMauro Carvalho Chehab return rc; 1032fcaf780bSMauro Carvalho Chehab 1033956b9ba1SJoe Perches edac_dbg(0, "MC: pdev bus %u dev=0x%x fn=0x%x\n", 1034fcaf780bSMauro Carvalho Chehab pdev->bus->number, 1035fcaf780bSMauro Carvalho Chehab PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); 1036fcaf780bSMauro Carvalho Chehab 1037fcaf780bSMauro Carvalho Chehab /* We only are looking for func 0 of the set */ 1038fcaf780bSMauro Carvalho Chehab if (PCI_FUNC(pdev->devfn) != 0) 1039fcaf780bSMauro Carvalho Chehab return -ENODEV; 1040fcaf780bSMauro Carvalho Chehab 1041fcaf780bSMauro Carvalho Chehab /* allocate a new MC control structure */ 104270e2a837SMauro Carvalho Chehab layers[0].type = EDAC_MC_LAYER_BRANCH; 104370e2a837SMauro Carvalho Chehab layers[0].size = MAX_BRANCHES; 104470e2a837SMauro Carvalho Chehab layers[0].is_virt_csrow = false; 104570e2a837SMauro Carvalho Chehab layers[1].type = EDAC_MC_LAYER_CHANNEL; 104670e2a837SMauro Carvalho Chehab layers[1].size = MAX_CH_PER_BRANCH; 104770e2a837SMauro Carvalho Chehab layers[1].is_virt_csrow = true; 104870e2a837SMauro Carvalho Chehab layers[2].type = EDAC_MC_LAYER_SLOT; 104970e2a837SMauro Carvalho Chehab layers[2].size = MAX_SLOTS; 105070e2a837SMauro Carvalho Chehab layers[2].is_virt_csrow = true; 1051ca0907b9SMauro Carvalho Chehab mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt)); 1052fcaf780bSMauro Carvalho Chehab if (mci == NULL) 1053fcaf780bSMauro Carvalho Chehab return -ENOMEM; 1054fcaf780bSMauro Carvalho Chehab 1055956b9ba1SJoe Perches edac_dbg(0, "MC: mci = %p\n", mci); 1056fcaf780bSMauro Carvalho Chehab 1057fd687502SMauro Carvalho Chehab mci->pdev = &pdev->dev; /* record ptr to the generic device */ 1058fcaf780bSMauro Carvalho Chehab 1059fcaf780bSMauro Carvalho Chehab pvt = mci->pvt_info; 10603e57eef6SMauro Carvalho Chehab pvt->pci_dev_16_0_fsb_ctlr = pdev; /* Record this device in our private */ 1061fcaf780bSMauro Carvalho Chehab 106285580ea4SMauro Carvalho Chehab pvt->tmp_prt_buffer = kmalloc(PAGE_SIZE, GFP_KERNEL); 106385580ea4SMauro Carvalho Chehab if (!pvt->tmp_prt_buffer) { 106485580ea4SMauro Carvalho Chehab edac_mc_free(mci); 106585580ea4SMauro Carvalho Chehab return -ENOMEM; 106685580ea4SMauro Carvalho Chehab } 106785580ea4SMauro Carvalho Chehab 1068fcaf780bSMauro Carvalho Chehab /* 'get' the pci devices we want to reserve for our use */ 1069d091a6ebSMauro Carvalho Chehab if (i7300_get_devices(mci)) 1070fcaf780bSMauro Carvalho Chehab goto fail0; 1071fcaf780bSMauro Carvalho Chehab 1072fcaf780bSMauro Carvalho Chehab mci->mc_idx = 0; 1073fcaf780bSMauro Carvalho Chehab mci->mtype_cap = MEM_FLAG_FB_DDR2; 1074fcaf780bSMauro Carvalho Chehab mci->edac_ctl_cap = EDAC_FLAG_NONE; 1075fcaf780bSMauro Carvalho Chehab mci->edac_cap = EDAC_FLAG_NONE; 1076fcaf780bSMauro Carvalho Chehab mci->mod_name = "i7300_edac.c"; 1077d091a6ebSMauro Carvalho Chehab mci->ctl_name = i7300_devs[0].ctl_name; 1078fcaf780bSMauro Carvalho Chehab mci->dev_name = pci_name(pdev); 1079fcaf780bSMauro Carvalho Chehab mci->ctl_page_to_phys = NULL; 1080fcaf780bSMauro Carvalho Chehab 1081fcaf780bSMauro Carvalho Chehab /* Set the function pointer to an actual operation function */ 1082fcaf780bSMauro Carvalho Chehab mci->edac_check = i7300_check_error; 1083fcaf780bSMauro Carvalho Chehab 1084fcaf780bSMauro Carvalho Chehab /* initialize the MC control structure 'csrows' table 1085fcaf780bSMauro Carvalho Chehab * with the mapping and control information */ 1086fcaf780bSMauro Carvalho Chehab if (i7300_get_mc_regs(mci)) { 1087956b9ba1SJoe Perches edac_dbg(0, "MC: Setting mci->edac_cap to EDAC_FLAG_NONE because i7300_init_csrows() returned nonzero value\n"); 1088fcaf780bSMauro Carvalho Chehab mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */ 1089fcaf780bSMauro Carvalho Chehab } else { 1090956b9ba1SJoe Perches edac_dbg(1, "MC: Enable error reporting now\n"); 1091fcaf780bSMauro Carvalho Chehab i7300_enable_error_reporting(mci); 1092fcaf780bSMauro Carvalho Chehab } 1093fcaf780bSMauro Carvalho Chehab 1094fcaf780bSMauro Carvalho Chehab /* add this new MC control structure to EDAC's list of MCs */ 1095fcaf780bSMauro Carvalho Chehab if (edac_mc_add_mc(mci)) { 1096956b9ba1SJoe Perches edac_dbg(0, "MC: failed edac_mc_add_mc()\n"); 1097fcaf780bSMauro Carvalho Chehab /* FIXME: perhaps some code should go here that disables error 1098fcaf780bSMauro Carvalho Chehab * reporting if we just enabled it 1099fcaf780bSMauro Carvalho Chehab */ 1100fcaf780bSMauro Carvalho Chehab goto fail1; 1101fcaf780bSMauro Carvalho Chehab } 1102fcaf780bSMauro Carvalho Chehab 1103fcaf780bSMauro Carvalho Chehab i7300_clear_error(mci); 1104fcaf780bSMauro Carvalho Chehab 1105fcaf780bSMauro Carvalho Chehab /* allocating generic PCI control info */ 1106fcaf780bSMauro Carvalho Chehab i7300_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); 1107fcaf780bSMauro Carvalho Chehab if (!i7300_pci) { 1108fcaf780bSMauro Carvalho Chehab printk(KERN_WARNING 1109fcaf780bSMauro Carvalho Chehab "%s(): Unable to create PCI control\n", 1110fcaf780bSMauro Carvalho Chehab __func__); 1111fcaf780bSMauro Carvalho Chehab printk(KERN_WARNING 1112fcaf780bSMauro Carvalho Chehab "%s(): PCI error report via EDAC not setup\n", 1113fcaf780bSMauro Carvalho Chehab __func__); 1114fcaf780bSMauro Carvalho Chehab } 1115fcaf780bSMauro Carvalho Chehab 1116fcaf780bSMauro Carvalho Chehab return 0; 1117fcaf780bSMauro Carvalho Chehab 1118fcaf780bSMauro Carvalho Chehab /* Error exit unwinding stack */ 1119fcaf780bSMauro Carvalho Chehab fail1: 1120fcaf780bSMauro Carvalho Chehab 1121fcaf780bSMauro Carvalho Chehab i7300_put_devices(mci); 1122fcaf780bSMauro Carvalho Chehab 1123fcaf780bSMauro Carvalho Chehab fail0: 112485580ea4SMauro Carvalho Chehab kfree(pvt->tmp_prt_buffer); 1125fcaf780bSMauro Carvalho Chehab edac_mc_free(mci); 1126fcaf780bSMauro Carvalho Chehab return -ENODEV; 1127fcaf780bSMauro Carvalho Chehab } 1128fcaf780bSMauro Carvalho Chehab 1129d091a6ebSMauro Carvalho Chehab /** 1130d091a6ebSMauro Carvalho Chehab * i7300_remove_one() - Remove the driver 1131d091a6ebSMauro Carvalho Chehab * @pdev: struct pci_dev pointer 1132fcaf780bSMauro Carvalho Chehab */ 11339b3c6e85SGreg Kroah-Hartman static void i7300_remove_one(struct pci_dev *pdev) 1134fcaf780bSMauro Carvalho Chehab { 1135fcaf780bSMauro Carvalho Chehab struct mem_ctl_info *mci; 113685580ea4SMauro Carvalho Chehab char *tmp; 1137fcaf780bSMauro Carvalho Chehab 1138956b9ba1SJoe Perches edac_dbg(0, "\n"); 1139fcaf780bSMauro Carvalho Chehab 1140fcaf780bSMauro Carvalho Chehab if (i7300_pci) 1141fcaf780bSMauro Carvalho Chehab edac_pci_release_generic_ctl(i7300_pci); 1142fcaf780bSMauro Carvalho Chehab 1143fcaf780bSMauro Carvalho Chehab mci = edac_mc_del_mc(&pdev->dev); 1144fcaf780bSMauro Carvalho Chehab if (!mci) 1145fcaf780bSMauro Carvalho Chehab return; 1146fcaf780bSMauro Carvalho Chehab 114785580ea4SMauro Carvalho Chehab tmp = ((struct i7300_pvt *)mci->pvt_info)->tmp_prt_buffer; 114885580ea4SMauro Carvalho Chehab 1149fcaf780bSMauro Carvalho Chehab /* retrieve references to resources, and free those resources */ 1150fcaf780bSMauro Carvalho Chehab i7300_put_devices(mci); 1151fcaf780bSMauro Carvalho Chehab 115285580ea4SMauro Carvalho Chehab kfree(tmp); 1153fcaf780bSMauro Carvalho Chehab edac_mc_free(mci); 1154fcaf780bSMauro Carvalho Chehab } 1155fcaf780bSMauro Carvalho Chehab 1156fcaf780bSMauro Carvalho Chehab /* 1157d091a6ebSMauro Carvalho Chehab * pci_device_id: table for which devices we are looking for 1158fcaf780bSMauro Carvalho Chehab * 1159d091a6ebSMauro Carvalho Chehab * Has only 8086:360c PCI ID 1160fcaf780bSMauro Carvalho Chehab */ 1161ba935f40SJingoo Han static const struct pci_device_id i7300_pci_tbl[] = { 1162fcaf780bSMauro Carvalho Chehab {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_ERR)}, 1163fcaf780bSMauro Carvalho Chehab {0,} /* 0 terminated list. */ 1164fcaf780bSMauro Carvalho Chehab }; 1165fcaf780bSMauro Carvalho Chehab 1166fcaf780bSMauro Carvalho Chehab MODULE_DEVICE_TABLE(pci, i7300_pci_tbl); 1167fcaf780bSMauro Carvalho Chehab 1168fcaf780bSMauro Carvalho Chehab /* 1169d091a6ebSMauro Carvalho Chehab * i7300_driver: pci_driver structure for this module 1170fcaf780bSMauro Carvalho Chehab */ 1171fcaf780bSMauro Carvalho Chehab static struct pci_driver i7300_driver = { 1172fcaf780bSMauro Carvalho Chehab .name = "i7300_edac", 1173fcaf780bSMauro Carvalho Chehab .probe = i7300_init_one, 11749b3c6e85SGreg Kroah-Hartman .remove = i7300_remove_one, 1175fcaf780bSMauro Carvalho Chehab .id_table = i7300_pci_tbl, 1176fcaf780bSMauro Carvalho Chehab }; 1177fcaf780bSMauro Carvalho Chehab 1178d091a6ebSMauro Carvalho Chehab /** 1179d091a6ebSMauro Carvalho Chehab * i7300_init() - Registers the driver 1180fcaf780bSMauro Carvalho Chehab */ 1181fcaf780bSMauro Carvalho Chehab static int __init i7300_init(void) 1182fcaf780bSMauro Carvalho Chehab { 1183fcaf780bSMauro Carvalho Chehab int pci_rc; 1184fcaf780bSMauro Carvalho Chehab 1185956b9ba1SJoe Perches edac_dbg(2, "\n"); 1186fcaf780bSMauro Carvalho Chehab 1187fcaf780bSMauro Carvalho Chehab /* Ensure that the OPSTATE is set correctly for POLL or NMI */ 1188fcaf780bSMauro Carvalho Chehab opstate_init(); 1189fcaf780bSMauro Carvalho Chehab 1190fcaf780bSMauro Carvalho Chehab pci_rc = pci_register_driver(&i7300_driver); 1191fcaf780bSMauro Carvalho Chehab 1192fcaf780bSMauro Carvalho Chehab return (pci_rc < 0) ? pci_rc : 0; 1193fcaf780bSMauro Carvalho Chehab } 1194fcaf780bSMauro Carvalho Chehab 1195d091a6ebSMauro Carvalho Chehab /** 1196*d3923513SColin Ian King * i7300_exit() - Unregisters the driver 1197fcaf780bSMauro Carvalho Chehab */ 1198fcaf780bSMauro Carvalho Chehab static void __exit i7300_exit(void) 1199fcaf780bSMauro Carvalho Chehab { 1200956b9ba1SJoe Perches edac_dbg(2, "\n"); 1201fcaf780bSMauro Carvalho Chehab pci_unregister_driver(&i7300_driver); 1202fcaf780bSMauro Carvalho Chehab } 1203fcaf780bSMauro Carvalho Chehab 1204fcaf780bSMauro Carvalho Chehab module_init(i7300_init); 1205fcaf780bSMauro Carvalho Chehab module_exit(i7300_exit); 1206fcaf780bSMauro Carvalho Chehab 1207fcaf780bSMauro Carvalho Chehab MODULE_LICENSE("GPL"); 120837e59f87SMauro Carvalho Chehab MODULE_AUTHOR("Mauro Carvalho Chehab"); 12097d4c1ea2SAlexander A. Klimov MODULE_AUTHOR("Red Hat Inc. (https://www.redhat.com)"); 1210fcaf780bSMauro Carvalho Chehab MODULE_DESCRIPTION("MC Driver for Intel I7300 memory controllers - " 1211fcaf780bSMauro Carvalho Chehab I7300_REVISION); 1212fcaf780bSMauro Carvalho Chehab 1213fcaf780bSMauro Carvalho Chehab module_param(edac_op_state, int, 0444); 1214fcaf780bSMauro Carvalho Chehab MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); 1215