linux/drivers/edac/igen6_edac.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Driver for Intel client SoC with integrated memory controller using IBECC
 *
 * Copyright (C) 2020 Intel Corporation
 *
 * The In-Band ECC (IBECC) IP provides ECC protection to all or specific
 * regions of the physical memory space. It's used for memory controllers
 * that don't support the out-of-band ECC which often needs an additional
 * storage device to each channel for storing ECC data.
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/irq_work.h>
#include <linux/llist.h>
#include <linux/genalloc.h>
#include <linux/edac.h>
#include <linux/bits.h>
#include <linux/io.h>
#include <asm/mach_traps.h>
#include <asm/nmi.h>
#include <asm/mce.h>

#include "edac_mc.h"
#include "edac_module.h"

#define IGEN6_REVISION

#define EDAC_MOD_STR
#define IGEN6_NMI_NAME

/* Debug macros */
#define igen6_printk(level, fmt, arg...)

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

#define GET_BITFIELD(v, lo, hi)

#define NUM_IMC
#define NUM_CHANNELS
#define NUM_DIMMS

#define _4GB

/* Size of physical memory */
#define TOM_OFFSET
/* Top of low usable DRAM */
#define TOLUD_OFFSET
/* Capability register C */
#define CAPID_C_OFFSET
#define CAPID_C_IBECC

/* Capability register E */
#define CAPID_E_OFFSET
#define CAPID_E_IBECC
#define CAPID_E_IBECC_BIT18

/* Error Status */
#define ERRSTS_OFFSET
#define ERRSTS_CE
#define ERRSTS_UE

/* Error Command */
#define ERRCMD_OFFSET
#define ERRCMD_CE
#define ERRCMD_UE

/* IBECC MMIO base address */
#define IBECC_BASE
#define IBECC_ACTIVATE_OFFSET
#define IBECC_ACTIVATE_EN

/* IBECC error log */
#define ECC_ERROR_LOG_OFFSET
#define ECC_ERROR_LOG_CE
#define ECC_ERROR_LOG_UE
#define ECC_ERROR_LOG_ADDR_SHIFT
#define ECC_ERROR_LOG_ADDR(v)
#define ECC_ERROR_LOG_ADDR45(v)
#define ECC_ERROR_LOG_SYND(v)

/* Host MMIO base address */
#define MCHBAR_OFFSET
#define MCHBAR_EN
#define MCHBAR_BASE(v)
#define MCHBAR_SIZE

/* Parameters for the channel decode stage */
#define IMC_BASE
#define MAD_INTER_CHANNEL_OFFSET
#define MAD_INTER_CHANNEL_DDR_TYPE(v)
#define MAD_INTER_CHANNEL_ECHM(v)
#define MAD_INTER_CHANNEL_CH_L_MAP(v)
#define MAD_INTER_CHANNEL_CH_S_SIZE(v)

/* Parameters for DRAM decode stage */
#define MAD_INTRA_CH0_OFFSET
#define MAD_INTRA_CH_DIMM_L_MAP(v)

/* DIMM characteristics */
#define MAD_DIMM_CH0_OFFSET
#define MAD_DIMM_CH_DIMM_L_SIZE(v)
#define MAD_DIMM_CH_DLW(v)
#define MAD_DIMM_CH_DIMM_S_SIZE(v)
#define MAD_DIMM_CH_DSW(v)

/* Hash for memory controller selection */
#define MAD_MC_HASH_OFFSET
#define MAC_MC_HASH_LSB(v)

/* Hash for channel selection */
#define CHANNEL_HASH_OFFSET
/* Hash for enhanced channel selection */
#define CHANNEL_EHASH_OFFSET
#define CHANNEL_HASH_MASK(v)
#define CHANNEL_HASH_LSB_MASK_BIT(v)
#define CHANNEL_HASH_MODE(v)

/* Parameters for memory slice decode stage */
#define MEM_SLICE_HASH_MASK(v)
#define MEM_SLICE_HASH_LSB_MASK_BIT(v)

static struct res_config {} *res_cfg;

struct igen6_imc {};

static struct igen6_pvt {} *igen6_pvt;

/* The top of low usable DRAM */
static u32 igen6_tolud;
/* The size of physical memory */
static u64 igen6_tom;

struct decoded_addr {};

struct ecclog_node {};

/*
 * In the NMI handler, the driver uses the lock-less memory allocator
 * to allocate memory to store the IBECC error logs and links the logs
 * to the lock-less list. Delay printk() and the work of error reporting
 * to EDAC core in a worker.
 */
#define ECCLOG_POOL_SIZE
static LLIST_HEAD(ecclog_llist);
static struct gen_pool *ecclog_pool;
static char ecclog_buf[ECCLOG_POOL_SIZE];
static struct irq_work ecclog_irq_work;
static struct work_struct ecclog_work;

/* Compute die IDs for Elkhart Lake with IBECC */
#define DID_EHL_SKU5
#define DID_EHL_SKU6
#define DID_EHL_SKU7
#define DID_EHL_SKU8
#define DID_EHL_SKU9
#define DID_EHL_SKU10
#define DID_EHL_SKU11
#define DID_EHL_SKU12
#define DID_EHL_SKU13
#define DID_EHL_SKU14
#define DID_EHL_SKU15

/* Compute die IDs for ICL-NNPI with IBECC */
#define DID_ICL_SKU8
#define DID_ICL_SKU10
#define DID_ICL_SKU11
#define DID_ICL_SKU12

/* Compute die IDs for Tiger Lake with IBECC */
#define DID_TGL_SKU

/* Compute die IDs for Alder Lake with IBECC */
#define DID_ADL_SKU1
#define DID_ADL_SKU2
#define DID_ADL_SKU3
#define DID_ADL_SKU4

/* Compute die IDs for Alder Lake-N with IBECC */
#define DID_ADL_N_SKU1
#define DID_ADL_N_SKU2
#define DID_ADL_N_SKU3
#define DID_ADL_N_SKU4
#define DID_ADL_N_SKU5
#define DID_ADL_N_SKU6
#define DID_ADL_N_SKU7
#define DID_ADL_N_SKU8
#define DID_ADL_N_SKU9
#define DID_ADL_N_SKU10
#define DID_ADL_N_SKU11
#define DID_ADL_N_SKU12

/* Compute die IDs for Raptor Lake-P with IBECC */
#define DID_RPL_P_SKU1
#define DID_RPL_P_SKU2
#define DID_RPL_P_SKU3
#define DID_RPL_P_SKU4
#define DID_RPL_P_SKU5

/* Compute die IDs for Meteor Lake-PS with IBECC */
#define DID_MTL_PS_SKU1
#define DID_MTL_PS_SKU2
#define DID_MTL_PS_SKU3
#define DID_MTL_PS_SKU4

/* Compute die IDs for Meteor Lake-P with IBECC */
#define DID_MTL_P_SKU1
#define DID_MTL_P_SKU2
#define DID_MTL_P_SKU3

/* Compute die IDs for Arrow Lake-UH with IBECC */
#define DID_ARL_UH_SKU1
#define DID_ARL_UH_SKU2
#define DID_ARL_UH_SKU3

static int get_mchbar(struct pci_dev *pdev, u64 *mchbar)
{}

static bool ehl_ibecc_available(struct pci_dev *pdev)
{}

static u64 ehl_err_addr_to_sys_addr(u64 eaddr, int mc)
{}

static u64 ehl_err_addr_to_imc_addr(u64 eaddr, int mc)
{}

static bool icl_ibecc_available(struct pci_dev *pdev)
{}

static bool tgl_ibecc_available(struct pci_dev *pdev)
{}

static bool mtl_p_ibecc_available(struct pci_dev *pdev)
{}

static bool mtl_ps_ibecc_available(struct pci_dev *pdev)
{}

static u64 mem_addr_to_sys_addr(u64 maddr)
{}

static u64 mem_slice_hash(u64 addr, u64 mask, u64 hash_init, int intlv_bit)
{}

static u64 tgl_err_addr_to_mem_addr(u64 eaddr, int mc)
{}

static u64 tgl_err_addr_to_sys_addr(u64 eaddr, int mc)
{}

static u64 tgl_err_addr_to_imc_addr(u64 eaddr, int mc)
{}

static u64 adl_err_addr_to_sys_addr(u64 eaddr, int mc)
{}

static u64 adl_err_addr_to_imc_addr(u64 eaddr, int mc)
{}

static u64 rpl_p_err_addr(u64 ecclog)
{}

static struct res_config ehl_cfg =;

static struct res_config icl_cfg =;

static struct res_config tgl_cfg =;

static struct res_config adl_cfg =;

static struct res_config adl_n_cfg =;

static struct res_config rpl_p_cfg =;

static struct res_config mtl_ps_cfg =;

static struct res_config mtl_p_cfg =;

static const struct pci_device_id igen6_pci_tbl[] =;
MODULE_DEVICE_TABLE(pci, igen6_pci_tbl);

static enum dev_type get_width(int dimm_l, u32 mad_dimm)
{}

static enum mem_type get_memory_type(u32 mad_inter)
{}

static int decode_chan_idx(u64 addr, u64 mask, int intlv_bit)
{}

static u64 decode_channel_addr(u64 addr, int intlv_bit)
{}

static void decode_addr(u64 addr, u32 hash, u64 s_size, int l_map,
			int *idx, u64 *sub_addr)
{}

static int igen6_decode(struct decoded_addr *res)
{}

static void igen6_output_error(struct decoded_addr *res,
			       struct mem_ctl_info *mci, u64 ecclog)
{}

static struct gen_pool *ecclog_gen_pool_create(void)
{}

static int ecclog_gen_pool_add(int mc, u64 ecclog)
{}

/*
 * Either the memory-mapped I/O status register ECC_ERROR_LOG or the PCI
 * configuration space status register ERRSTS can indicate whether a
 * correctable error or an uncorrectable error occurred. We only use the
 * ECC_ERROR_LOG register to check error type, but need to clear both
 * registers to enable future error events.
 */
static u64 ecclog_read_and_clear(struct igen6_imc *imc)
{}

static void errsts_clear(struct igen6_imc *imc)
{}

static int errcmd_enable_error_reporting(bool enable)
{}

static int ecclog_handler(void)
{}

static void ecclog_work_cb(struct work_struct *work)
{}

static void ecclog_irq_work_cb(struct irq_work *irq_work)
{}

static int ecclog_nmi_handler(unsigned int cmd, struct pt_regs *regs)
{}

static int ecclog_mce_handler(struct notifier_block *nb, unsigned long val,
			      void *data)
{}

static struct notifier_block ecclog_mce_dec =;

static bool igen6_check_ecc(struct igen6_imc *imc)
{}

static int igen6_get_dimm_config(struct mem_ctl_info *mci)
{}

#ifdef CONFIG_EDAC_DEBUG
/* Top of upper usable DRAM */
static u64 igen6_touud;
#define TOUUD_OFFSET

static void igen6_reg_dump(struct igen6_imc *imc)
{}

static struct dentry *igen6_test;

static int debugfs_u64_set(void *data, u64 val)
{}
DEFINE_SIMPLE_ATTRIBUTE();

static void igen6_debug_setup(void)
{}

static void igen6_debug_teardown(void)
{}
#else
static void igen6_reg_dump(struct igen6_imc *imc) {}
static void igen6_debug_setup(void) {}
static void igen6_debug_teardown(void) {}
#endif

static int igen6_pci_setup(struct pci_dev *pdev, u64 *mchbar)
{}

static int igen6_register_mci(int mc, u64 mchbar, struct pci_dev *pdev)
{}

static void igen6_unregister_mcis(void)
{}

static int igen6_mem_slice_setup(u64 mchbar)
{}

static int register_err_handler(void)
{}

static void unregister_err_handler(void)
{}

static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{}

static void igen6_remove(struct pci_dev *pdev)
{}

static struct pci_driver igen6_driver =;

static int __init igen6_init(void)
{}

static void __exit igen6_exit(void)
{}

module_init();
module_exit(igen6_exit);

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