linux/drivers/edac/i5400_edac.c

/*
 * Intel 5400 class Memory Controllers kernel module (Seaburg)
 *
 * This file may be distributed under the terms of the
 * GNU General Public License.
 *
 * Copyright (c) 2008 by:
 *	 Ben Woodard <[email protected]>
 *	 Mauro Carvalho Chehab
 *
 * Red Hat Inc. https://www.redhat.com
 *
 * Forked and adapted from the i5000_edac driver which was
 * written by Douglas Thompson Linux Networx <[email protected]>
 *
 * This module is based on the following document:
 *
 * Intel 5400 Chipset Memory Controller Hub (MCH) - Datasheet
 * 	http://developer.intel.com/design/chipsets/datashts/313070.htm
 *
 * This Memory Controller manages DDR2 FB-DIMMs. It has 2 branches, each with
 * 2 channels operating in lockstep no-mirror mode. Each channel can have up to
 * 4 dimm's, each with up to 8GB.
 *
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
#include <linux/edac.h>
#include <linux/mmzone.h>

#include "edac_module.h"

/*
 * Alter this version for the I5400 module when modifications are made
 */
#define I5400_REVISION

#define EDAC_MOD_STR

#define i5400_printk(level, fmt, arg...)

#define i5400_mc_printk(mci, level, fmt, arg...)

/* Limits for i5400 */
#define MAX_BRANCHES
#define CHANNELS_PER_BRANCH
#define DIMMS_PER_CHANNEL
#define MAX_CHANNELS

/* Device 16,
 * Function 0: System Address
 * Function 1: Memory Branch Map, Control, Errors Register
 * Function 2: FSB Error Registers
 *
 * All 3 functions of Device 16 (0,1,2) share the SAME DID and
 * uses PCI_DEVICE_ID_INTEL_5400_ERR for device 16 (0,1,2),
 * PCI_DEVICE_ID_INTEL_5400_FBD0 and PCI_DEVICE_ID_INTEL_5400_FBD1
 * for device 21 (0,1).
 */

	/* OFFSETS for Function 0 */
#define AMBASE
#define MAXCH
#define MAXDIMMPERCH

	/* OFFSETS for Function 1 */
#define TOLM
#define REDMEMB
#define REC_ECC_LOCATOR_ODD(x)
#define MIR0
#define MIR1
#define AMIR0
#define AMIR1

	/* Fatal error registers */
#define FERR_FAT_FBD
#define FERR_FAT_FBDCHAN

#define NERR_FAT_FBD
#define FERR_NF_FBD

	/* Non-fatal error register */
#define NERR_NF_FBD

	/* Enable error mask */
#define EMASK_FBD

#define ERR0_FBD
#define ERR1_FBD
#define ERR2_FBD
#define MCERR_FBD

	/* No OFFSETS for Device 16 Function 2 */

/*
 * Device 21,
 * Function 0: Memory Map Branch 0
 *
 * Device 22,
 * Function 0: Memory Map Branch 1
 */

	/* OFFSETS for Function 0 */
#define AMBPRESENT_0
#define AMBPRESENT_1
#define MTR0
#define MTR1
#define MTR2
#define MTR3

	/* OFFSETS for Function 1 */
#define NRECFGLOG
#define RECFGLOG
#define NRECMEMA
#define NRECMEMB
#define NRECFB_DIMMA
#define NRECFB_DIMMB
#define NRECFB_DIMMC
#define NRECFB_DIMMD
#define NRECFB_DIMME
#define NRECFB_DIMMF
#define REDMEMA
#define RECMEMA
#define RECMEMB
#define RECFB_DIMMA
#define RECFB_DIMMB
#define RECFB_DIMMC
#define RECFB_DIMMD
#define RECFB_DIMME
#define RECFB_DIMMF

/*
 * Error indicator bits and masks
 * Error masks are according with Table 5-17 of i5400 datasheet
 */

enum error_mask {};

/*
 * Names to translate bit error into something useful
 */
static const char *error_name[] =;

/* Fatal errors */
#define ERROR_FAT_MASK

/* Correctable errors */
#define ERROR_NF_CORRECTABLE
#define ERROR_NF_DIMM_SPARE
#define ERROR_NF_SPD_PROTOCOL
#define ERROR_NF_NORTH_CRC

/* Recoverable errors */
#define ERROR_NF_RECOVERABLE

/* uncorrectable errors */
#define ERROR_NF_UNCORRECTABLE

/* mask to all non-fatal errors */
#define ERROR_NF_MASK

/*
 * Define error masks for the several registers
 */

/* Enable all fatal and non fatal errors */
#define ENABLE_EMASK_ALL

/* mask for fatal error registers */
#define FERR_FAT_MASK

/* masks for non-fatal error register */
static inline int to_nf_mask(unsigned int mask)
{
	return (mask & EMASK_M29) | (mask >> 3);
};

static inline int from_nf_ferr(unsigned int mask)
{
	return (mask & EMASK_M29) |		/* Bit 28 */
	       (mask & ((1 << 28) - 1) << 3);	/* Bits 0 to 27 */
};

#define FERR_NF_MASK
#define FERR_NF_CORRECTABLE
#define FERR_NF_DIMM_SPARE
#define FERR_NF_SPD_PROTOCOL
#define FERR_NF_NORTH_CRC
#define FERR_NF_RECOVERABLE
#define FERR_NF_UNCORRECTABLE

/*
 * Defines to extract the various fields from the
 *	MTRx - Memory Technology Registers
 */
#define MTR_DIMMS_PRESENT(mtr)
#define MTR_DIMMS_ETHROTTLE(mtr)
#define MTR_DRAM_WIDTH(mtr)
#define MTR_DRAM_BANKS(mtr)
#define MTR_DRAM_BANKS_ADDR_BITS(mtr)
#define MTR_DIMM_RANK(mtr)
#define MTR_DIMM_RANK_ADDR_BITS(mtr)
#define MTR_DIMM_ROWS(mtr)
#define MTR_DIMM_ROWS_ADDR_BITS(mtr)
#define MTR_DIMM_COLS(mtr)
#define MTR_DIMM_COLS_ADDR_BITS(mtr)

/* This applies to FERR_NF_FB-DIMM as well as FERR_FAT_FB-DIMM */
static inline int extract_fbdchan_indx(u32 x)
{}

/* Device name and register DID (Device ID) */
struct i5400_dev_info {};

/* Table of devices attributes supported by this driver */
static const struct i5400_dev_info i5400_devs[] =;

struct i5400_dimm_info {};

/* driver private data structure */
struct i5400_pvt {};

/* I5400 MCH error information retrieved from Hardware */
struct i5400_error_info {};

/* note that nrec_rdwr changed from NRECMEMA to NRECMEMB between the 5000 and
   5400 better to use an inline function than a macro in this case */
static inline int nrec_bank(struct i5400_error_info *info)
{}
static inline int nrec_rank(struct i5400_error_info *info)
{}
static inline int nrec_buf_id(struct i5400_error_info *info)
{}
static inline int nrec_rdwr(struct i5400_error_info *info)
{}
/* This applies to both NREC and REC string so it can be used with nrec_rdwr
   and rec_rdwr */
static inline const char *rdwr_str(int rdwr)
{}
static inline int nrec_cas(struct i5400_error_info *info)
{}
static inline int nrec_ras(struct i5400_error_info *info)
{}
static inline int rec_bank(struct i5400_error_info *info)
{}
static inline int rec_rank(struct i5400_error_info *info)
{}
static inline int rec_rdwr(struct i5400_error_info *info)
{}
static inline int rec_cas(struct i5400_error_info *info)
{}
static inline int rec_ras(struct i5400_error_info *info)
{}

static struct edac_pci_ctl_info *i5400_pci;

/*
 *	i5400_get_error_info	Retrieve the hardware error information from
 *				the hardware and cache it in the 'info'
 *				structure
 */
static void i5400_get_error_info(struct mem_ctl_info *mci,
				 struct i5400_error_info *info)
{}

/*
 * i5400_proccess_non_recoverable_info(struct mem_ctl_info *mci,
 * 					struct i5400_error_info *info,
 * 					int handle_errors);
 *
 *	handle the Intel FATAL and unrecoverable errors, if any
 */
static void i5400_proccess_non_recoverable_info(struct mem_ctl_info *mci,
				    struct i5400_error_info *info,
				    unsigned long allErrors)
{}

/*
 * i5400_process_fatal_error_info(struct mem_ctl_info *mci,
 * 				struct i5400_error_info *info,
 * 				int handle_errors);
 *
 *	handle the Intel NON-FATAL errors, if any
 */
static void i5400_process_nonfatal_error_info(struct mem_ctl_info *mci,
					struct i5400_error_info *info)
{}

/*
 *	i5400_process_error_info	Process the error info that is
 *	in the 'info' structure, previously retrieved from hardware
 */
static void i5400_process_error_info(struct mem_ctl_info *mci,
				struct i5400_error_info *info)
{}

/*
 *	i5400_clear_error	Retrieve any error from the hardware
 *				but do NOT process that error.
 *				Used for 'clearing' out of previous errors
 *				Called by the Core module.
 */
static void i5400_clear_error(struct mem_ctl_info *mci)
{}

/*
 *	i5400_check_error	Retrieve and process errors reported by the
 *				hardware. Called by the Core module.
 */
static void i5400_check_error(struct mem_ctl_info *mci)
{}

/*
 *	i5400_put_devices	'put' all the devices that we have
 *				reserved via 'get'
 */
static void i5400_put_devices(struct mem_ctl_info *mci)
{}

/*
 *	i5400_get_devices	Find and perform 'get' operation on the MCH's
 *			device/functions we want to reference for this driver
 *
 *			Need to 'get' device 16 func 1 and func 2
 */
static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx)
{}

/*
 *	determine_amb_present
 *
 *		the information is contained in DIMMS_PER_CHANNEL different
 *		registers determining which of the DIMMS_PER_CHANNEL requires
 *              knowing which channel is in question
 *
 *	2 branches, each with 2 channels
 *		b0_ambpresent0 for channel '0'
 *		b0_ambpresent1 for channel '1'
 *		b1_ambpresent0 for channel '2'
 *		b1_ambpresent1 for channel '3'
 */
static int determine_amb_present_reg(struct i5400_pvt *pvt, int channel)
{}

/*
 * determine_mtr(pvt, dimm, channel)
 *
 * return the proper MTR register as determine by the dimm and desired channel
 */
static int determine_mtr(struct i5400_pvt *pvt, int dimm, int channel)
{}

/*
 */
static void decode_mtr(int slot_row, u16 mtr)
{}

static void handle_channel(struct i5400_pvt *pvt, int dimm, int channel,
			struct i5400_dimm_info *dinfo)
{}

/*
 *	calculate_dimm_size
 *
 *	also will output a DIMM matrix map, if debug is enabled, for viewing
 *	how the DIMMs are populated
 */
static void calculate_dimm_size(struct i5400_pvt *pvt)
{}

/*
 *	i5400_get_mc_regs	read in the necessary registers and
 *				cache locally
 *
 *			Fills in the private data members
 */
static void i5400_get_mc_regs(struct mem_ctl_info *mci)
{}

/*
 *	i5400_init_dimms	Initialize the 'dimms' table within
 *				the mci control	structure with the
 *				addressing of memory.
 *
 *	return:
 *		0	success
 *		1	no actual memory found on this MC
 */
static int i5400_init_dimms(struct mem_ctl_info *mci)
{}

/*
 *	i5400_enable_error_reporting
 *			Turn on the memory reporting features of the hardware
 */
static void i5400_enable_error_reporting(struct mem_ctl_info *mci)
{}

/*
 *	i5400_probe1	Probe for ONE instance of device to see if it is
 *			present.
 *	return:
 *		0 for FOUND a device
 *		< 0 for error code
 */
static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
{}

/*
 *	i5400_init_one	constructor for one instance of device
 *
 * 	returns:
 *		negative on error
 *		count (>= 0)
 */
static int i5400_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{}

/*
 *	i5400_remove_one	destructor for one instance of device
 *
 */
static void i5400_remove_one(struct pci_dev *pdev)
{}

/*
 *	pci_device_id	table for which devices we are looking for
 *
 *	The "E500P" device is the first device supported.
 */
static const struct pci_device_id i5400_pci_tbl[] =;

MODULE_DEVICE_TABLE(pci, i5400_pci_tbl);

/*
 *	i5400_driver	pci_driver structure for this module
 *
 */
static struct pci_driver i5400_driver =;

/*
 *	i5400_init		Module entry function
 *			Try to initialize this module for its devices
 */
static int __init i5400_init(void)
{}

/*
 *	i5400_exit()	Module exit function
 *			Unregister the driver
 */
static void __exit i5400_exit(void)
{}

module_init();
module_exit(i5400_exit);

MODULE_LICENSE();
MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_AUTHOR();
MODULE_DESCRIPTION();

module_param(edac_op_state, int, 0444);
MODULE_PARM_DESC();