cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cell_edac.c (7908B)


      1/*
      2 * Cell MIC driver for ECC counting
      3 *
      4 * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
      5 *                <benh@kernel.crashing.org>
      6 *
      7 * This file may be distributed under the terms of the
      8 * GNU General Public License.
      9 */
     10#undef DEBUG
     11
     12#include <linux/edac.h>
     13#include <linux/module.h>
     14#include <linux/init.h>
     15#include <linux/platform_device.h>
     16#include <linux/stop_machine.h>
     17#include <linux/io.h>
     18#include <linux/of_address.h>
     19#include <asm/machdep.h>
     20#include <asm/cell-regs.h>
     21
     22#include "edac_module.h"
     23
     24struct cell_edac_priv
     25{
     26	struct cbe_mic_tm_regs __iomem	*regs;
     27	int				node;
     28	int				chanmask;
     29#ifdef DEBUG
     30	u64				prev_fir;
     31#endif
     32};
     33
     34static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar)
     35{
     36	struct cell_edac_priv		*priv = mci->pvt_info;
     37	struct csrow_info		*csrow = mci->csrows[0];
     38	unsigned long			address, pfn, offset, syndrome;
     39
     40	dev_dbg(mci->pdev, "ECC CE err on node %d, channel %d, ar = 0x%016llx\n",
     41		priv->node, chan, ar);
     42
     43	/* Address decoding is likely a bit bogus, to dbl check */
     44	address = (ar & 0xffffffffe0000000ul) >> 29;
     45	if (priv->chanmask == 0x3)
     46		address = (address << 1) | chan;
     47	pfn = address >> PAGE_SHIFT;
     48	offset = address & ~PAGE_MASK;
     49	syndrome = (ar & 0x000000001fe00000ul) >> 21;
     50
     51	/* TODO: Decoding of the error address */
     52	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1,
     53			     csrow->first_page + pfn, offset, syndrome,
     54			     0, chan, -1, "", "");
     55}
     56
     57static void cell_edac_count_ue(struct mem_ctl_info *mci, int chan, u64 ar)
     58{
     59	struct cell_edac_priv		*priv = mci->pvt_info;
     60	struct csrow_info		*csrow = mci->csrows[0];
     61	unsigned long			address, pfn, offset;
     62
     63	dev_dbg(mci->pdev, "ECC UE err on node %d, channel %d, ar = 0x%016llx\n",
     64		priv->node, chan, ar);
     65
     66	/* Address decoding is likely a bit bogus, to dbl check */
     67	address = (ar & 0xffffffffe0000000ul) >> 29;
     68	if (priv->chanmask == 0x3)
     69		address = (address << 1) | chan;
     70	pfn = address >> PAGE_SHIFT;
     71	offset = address & ~PAGE_MASK;
     72
     73	/* TODO: Decoding of the error address */
     74	edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1,
     75			     csrow->first_page + pfn, offset, 0,
     76			     0, chan, -1, "", "");
     77}
     78
     79static void cell_edac_check(struct mem_ctl_info *mci)
     80{
     81	struct cell_edac_priv		*priv = mci->pvt_info;
     82	u64				fir, addreg, clear = 0;
     83
     84	fir = in_be64(&priv->regs->mic_fir);
     85#ifdef DEBUG
     86	if (fir != priv->prev_fir) {
     87		dev_dbg(mci->pdev, "fir change : 0x%016lx\n", fir);
     88		priv->prev_fir = fir;
     89	}
     90#endif
     91	if ((priv->chanmask & 0x1) && (fir & CBE_MIC_FIR_ECC_SINGLE_0_ERR)) {
     92		addreg = in_be64(&priv->regs->mic_df_ecc_address_0);
     93		clear |= CBE_MIC_FIR_ECC_SINGLE_0_RESET;
     94		cell_edac_count_ce(mci, 0, addreg);
     95	}
     96	if ((priv->chanmask & 0x2) && (fir & CBE_MIC_FIR_ECC_SINGLE_1_ERR)) {
     97		addreg = in_be64(&priv->regs->mic_df_ecc_address_1);
     98		clear |= CBE_MIC_FIR_ECC_SINGLE_1_RESET;
     99		cell_edac_count_ce(mci, 1, addreg);
    100	}
    101	if ((priv->chanmask & 0x1) && (fir & CBE_MIC_FIR_ECC_MULTI_0_ERR)) {
    102		addreg = in_be64(&priv->regs->mic_df_ecc_address_0);
    103		clear |= CBE_MIC_FIR_ECC_MULTI_0_RESET;
    104		cell_edac_count_ue(mci, 0, addreg);
    105	}
    106	if ((priv->chanmask & 0x2) && (fir & CBE_MIC_FIR_ECC_MULTI_1_ERR)) {
    107		addreg = in_be64(&priv->regs->mic_df_ecc_address_1);
    108		clear |= CBE_MIC_FIR_ECC_MULTI_1_RESET;
    109		cell_edac_count_ue(mci, 1, addreg);
    110	}
    111
    112	/* The procedure for clearing FIR bits is a bit ... weird */
    113	if (clear) {
    114		fir &= ~(CBE_MIC_FIR_ECC_ERR_MASK | CBE_MIC_FIR_ECC_SET_MASK);
    115		fir |= CBE_MIC_FIR_ECC_RESET_MASK;
    116		fir &= ~clear;
    117		out_be64(&priv->regs->mic_fir, fir);
    118		(void)in_be64(&priv->regs->mic_fir);
    119
    120		mb();	/* sync up */
    121#ifdef DEBUG
    122		fir = in_be64(&priv->regs->mic_fir);
    123		dev_dbg(mci->pdev, "fir clear  : 0x%016lx\n", fir);
    124#endif
    125	}
    126}
    127
    128static void cell_edac_init_csrows(struct mem_ctl_info *mci)
    129{
    130	struct csrow_info		*csrow = mci->csrows[0];
    131	struct dimm_info		*dimm;
    132	struct cell_edac_priv		*priv = mci->pvt_info;
    133	struct device_node		*np;
    134	int				j;
    135	u32				nr_pages;
    136
    137	for_each_node_by_name(np, "memory") {
    138		struct resource r;
    139
    140		/* We "know" that the Cell firmware only creates one entry
    141		 * in the "memory" nodes. If that changes, this code will
    142		 * need to be adapted.
    143		 */
    144		if (of_address_to_resource(np, 0, &r))
    145			continue;
    146		if (of_node_to_nid(np) != priv->node)
    147			continue;
    148		csrow->first_page = r.start >> PAGE_SHIFT;
    149		nr_pages = resource_size(&r) >> PAGE_SHIFT;
    150		csrow->last_page = csrow->first_page + nr_pages - 1;
    151
    152		for (j = 0; j < csrow->nr_channels; j++) {
    153			dimm = csrow->channels[j]->dimm;
    154			dimm->mtype = MEM_XDR;
    155			dimm->edac_mode = EDAC_SECDED;
    156			dimm->nr_pages = nr_pages / csrow->nr_channels;
    157		}
    158		dev_dbg(mci->pdev,
    159			"Initialized on node %d, chanmask=0x%x,"
    160			" first_page=0x%lx, nr_pages=0x%x\n",
    161			priv->node, priv->chanmask,
    162			csrow->first_page, nr_pages);
    163		break;
    164	}
    165	of_node_put(np);
    166}
    167
    168static int cell_edac_probe(struct platform_device *pdev)
    169{
    170	struct cbe_mic_tm_regs __iomem	*regs;
    171	struct mem_ctl_info		*mci;
    172	struct edac_mc_layer		layers[2];
    173	struct cell_edac_priv		*priv;
    174	u64				reg;
    175	int				rc, chanmask, num_chans;
    176
    177	regs = cbe_get_cpu_mic_tm_regs(cbe_node_to_cpu(pdev->id));
    178	if (regs == NULL)
    179		return -ENODEV;
    180
    181	edac_op_state = EDAC_OPSTATE_POLL;
    182
    183	/* Get channel population */
    184	reg = in_be64(&regs->mic_mnt_cfg);
    185	dev_dbg(&pdev->dev, "MIC_MNT_CFG = 0x%016llx\n", reg);
    186	chanmask = 0;
    187	if (reg & CBE_MIC_MNT_CFG_CHAN_0_POP)
    188		chanmask |= 0x1;
    189	if (reg & CBE_MIC_MNT_CFG_CHAN_1_POP)
    190		chanmask |= 0x2;
    191	if (chanmask == 0) {
    192		dev_warn(&pdev->dev,
    193			 "Yuck ! No channel populated ? Aborting !\n");
    194		return -ENODEV;
    195	}
    196	dev_dbg(&pdev->dev, "Initial FIR = 0x%016llx\n",
    197		in_be64(&regs->mic_fir));
    198
    199	/* Allocate & init EDAC MC data structure */
    200	num_chans = chanmask == 3 ? 2 : 1;
    201
    202	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
    203	layers[0].size = 1;
    204	layers[0].is_virt_csrow = true;
    205	layers[1].type = EDAC_MC_LAYER_CHANNEL;
    206	layers[1].size = num_chans;
    207	layers[1].is_virt_csrow = false;
    208	mci = edac_mc_alloc(pdev->id, ARRAY_SIZE(layers), layers,
    209			    sizeof(struct cell_edac_priv));
    210	if (mci == NULL)
    211		return -ENOMEM;
    212	priv = mci->pvt_info;
    213	priv->regs = regs;
    214	priv->node = pdev->id;
    215	priv->chanmask = chanmask;
    216	mci->pdev = &pdev->dev;
    217	mci->mtype_cap = MEM_FLAG_XDR;
    218	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
    219	mci->edac_cap = EDAC_FLAG_EC | EDAC_FLAG_SECDED;
    220	mci->mod_name = "cell_edac";
    221	mci->ctl_name = "MIC";
    222	mci->dev_name = dev_name(&pdev->dev);
    223	mci->edac_check = cell_edac_check;
    224	cell_edac_init_csrows(mci);
    225
    226	/* Register with EDAC core */
    227	rc = edac_mc_add_mc(mci);
    228	if (rc) {
    229		dev_err(&pdev->dev, "failed to register with EDAC core\n");
    230		edac_mc_free(mci);
    231		return rc;
    232	}
    233
    234	return 0;
    235}
    236
    237static int cell_edac_remove(struct platform_device *pdev)
    238{
    239	struct mem_ctl_info *mci = edac_mc_del_mc(&pdev->dev);
    240	if (mci)
    241		edac_mc_free(mci);
    242	return 0;
    243}
    244
    245static struct platform_driver cell_edac_driver = {
    246	.driver		= {
    247		.name	= "cbe-mic",
    248	},
    249	.probe		= cell_edac_probe,
    250	.remove		= cell_edac_remove,
    251};
    252
    253static int __init cell_edac_init(void)
    254{
    255	/* Sanity check registers data structure */
    256	BUILD_BUG_ON(offsetof(struct cbe_mic_tm_regs,
    257			      mic_df_ecc_address_0) != 0xf8);
    258	BUILD_BUG_ON(offsetof(struct cbe_mic_tm_regs,
    259			      mic_df_ecc_address_1) != 0x1b8);
    260	BUILD_BUG_ON(offsetof(struct cbe_mic_tm_regs,
    261			      mic_df_config) != 0x218);
    262	BUILD_BUG_ON(offsetof(struct cbe_mic_tm_regs,
    263			      mic_fir) != 0x230);
    264	BUILD_BUG_ON(offsetof(struct cbe_mic_tm_regs,
    265			      mic_mnt_cfg) != 0x210);
    266	BUILD_BUG_ON(offsetof(struct cbe_mic_tm_regs,
    267			      mic_exc) != 0x208);
    268
    269	return platform_driver_register(&cell_edac_driver);
    270}
    271
    272static void __exit cell_edac_exit(void)
    273{
    274	platform_driver_unregister(&cell_edac_driver);
    275}
    276
    277module_init(cell_edac_init);
    278module_exit(cell_edac_exit);
    279
    280MODULE_LICENSE("GPL");
    281MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
    282MODULE_DESCRIPTION("ECC counting for Cell MIC");