12a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* 22a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * cpc925_edac.c, EDAC driver for IBM CPC925 Bridge and Memory Controller. 32a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * 42a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Copyright (c) 2008 Wind River Systems, Inc. 52a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * 62a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Authors: Cao Qingtao <qingtao.cao@windriver.com> 72a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * 82a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * This program is free software; you can redistribute it and/or modify 92a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * it under the terms of the GNU General Public License version 2 as 102a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * published by the Free Software Foundation. 112a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * 122a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * This program is distributed in the hope that it will be useful, 132a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * but WITHOUT ANY WARRANTY; without even the implied warranty of 142a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 152a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * See the GNU General Public License for more details. 162a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * 172a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * You should have received a copy of the GNU General Public License 182a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * along with this program; if not, write to the Free Software 192a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 202a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao */ 212a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 222a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#include <linux/module.h> 232a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#include <linux/init.h> 242a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#include <linux/io.h> 252a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#include <linux/edac.h> 262a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#include <linux/of.h> 272a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#include <linux/platform_device.h> 285a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h> 292a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 302a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#include "edac_core.h" 312a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#include "edac_module.h" 322a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 33152ba3942276c2a240703669ae4a3099e0a79451Michal Marek#define CPC925_EDAC_REVISION " Ver: 1.0.0" 342a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define CPC925_EDAC_MOD_STR "cpc925_edac" 352a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 362a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define cpc925_printk(level, fmt, arg...) \ 372a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao edac_printk(level, "CPC925", fmt, ##arg) 382a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 392a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define cpc925_mc_printk(mci, level, fmt, arg...) \ 402a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao edac_mc_chipset_printk(mci, level, "CPC925", fmt, ##arg) 412a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 422a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* 432a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * CPC925 registers are of 32 bits with bit0 defined at the 442a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * most significant bit and bit31 at that of least significant. 452a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao */ 462a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define CPC925_BITS_PER_REG 32 472a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define CPC925_BIT(nr) (1UL << (CPC925_BITS_PER_REG - 1 - nr)) 482a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 492a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* 502a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * EDAC device names for the error detections of 512a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * CPU Interface and Hypertransport Link. 522a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao */ 532a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define CPC925_CPU_ERR_DEV "cpu" 542a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define CPC925_HT_LINK_DEV "htlink" 552a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 562a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* Suppose DDR Refresh cycle is 15.6 microsecond */ 572a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define CPC925_REF_FREQ 0xFA69 582a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define CPC925_SCRUB_BLOCK_SIZE 64 /* bytes */ 592a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define CPC925_NR_CSROWS 8 602a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 612a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* 622a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * All registers and bits definitions are taken from 632a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * "CPC925 Bridge and Memory Controller User Manual, SA14-2761-02". 642a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao */ 652a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 662a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* 672a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * CPU and Memory Controller Registers 682a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao */ 692a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/************************************************************ 702a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Processor Interface Exception Mask Register (APIMASK) 712a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ************************************************************/ 722a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define REG_APIMASK_OFFSET 0x30070 732a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaoenum apimask_bits { 742a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIMASK_DART = CPC925_BIT(0), /* DART Exception */ 752a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIMASK_ADI0 = CPC925_BIT(1), /* Handshake Error on PI0_ADI */ 762a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIMASK_ADI1 = CPC925_BIT(2), /* Handshake Error on PI1_ADI */ 772a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIMASK_STAT = CPC925_BIT(3), /* Status Exception */ 782a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIMASK_DERR = CPC925_BIT(4), /* Data Error Exception */ 792a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIMASK_ADRS0 = CPC925_BIT(5), /* Addressing Exception on PI0 */ 802a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIMASK_ADRS1 = CPC925_BIT(6), /* Addressing Exception on PI1 */ 812a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* BIT(7) Reserved */ 822a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIMASK_ECC_UE_H = CPC925_BIT(8), /* UECC upper */ 832a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIMASK_ECC_CE_H = CPC925_BIT(9), /* CECC upper */ 842a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIMASK_ECC_UE_L = CPC925_BIT(10), /* UECC lower */ 852a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIMASK_ECC_CE_L = CPC925_BIT(11), /* CECC lower */ 862a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 872a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao CPU_MASK_ENABLE = (APIMASK_DART | APIMASK_ADI0 | APIMASK_ADI1 | 882a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIMASK_STAT | APIMASK_DERR | APIMASK_ADRS0 | 892a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIMASK_ADRS1), 902a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ECC_MASK_ENABLE = (APIMASK_ECC_UE_H | APIMASK_ECC_CE_H | 912a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIMASK_ECC_UE_L | APIMASK_ECC_CE_L), 922a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao}; 93ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov#define APIMASK_ADI(n) CPC925_BIT(((n)+1)) 942a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 952a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/************************************************************ 962a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Processor Interface Exception Register (APIEXCP) 972a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ************************************************************/ 982a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define REG_APIEXCP_OFFSET 0x30060 992a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaoenum apiexcp_bits { 1002a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIEXCP_DART = CPC925_BIT(0), /* DART Exception */ 1012a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIEXCP_ADI0 = CPC925_BIT(1), /* Handshake Error on PI0_ADI */ 1022a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIEXCP_ADI1 = CPC925_BIT(2), /* Handshake Error on PI1_ADI */ 1032a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIEXCP_STAT = CPC925_BIT(3), /* Status Exception */ 1042a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIEXCP_DERR = CPC925_BIT(4), /* Data Error Exception */ 1052a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIEXCP_ADRS0 = CPC925_BIT(5), /* Addressing Exception on PI0 */ 1062a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIEXCP_ADRS1 = CPC925_BIT(6), /* Addressing Exception on PI1 */ 1072a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* BIT(7) Reserved */ 1082a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIEXCP_ECC_UE_H = CPC925_BIT(8), /* UECC upper */ 1092a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIEXCP_ECC_CE_H = CPC925_BIT(9), /* CECC upper */ 1102a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIEXCP_ECC_UE_L = CPC925_BIT(10), /* UECC lower */ 1112a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIEXCP_ECC_CE_L = CPC925_BIT(11), /* CECC lower */ 1122a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 1132a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao CPU_EXCP_DETECTED = (APIEXCP_DART | APIEXCP_ADI0 | APIEXCP_ADI1 | 1142a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIEXCP_STAT | APIEXCP_DERR | APIEXCP_ADRS0 | 1152a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao APIEXCP_ADRS1), 1162a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao UECC_EXCP_DETECTED = (APIEXCP_ECC_UE_H | APIEXCP_ECC_UE_L), 1172a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao CECC_EXCP_DETECTED = (APIEXCP_ECC_CE_H | APIEXCP_ECC_CE_L), 1182a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ECC_EXCP_DETECTED = (UECC_EXCP_DETECTED | CECC_EXCP_DETECTED), 1192a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao}; 1202a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 1212a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/************************************************************ 1222a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Memory Bus Configuration Register (MBCR) 1232a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao************************************************************/ 1242a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define REG_MBCR_OFFSET 0x2190 1252a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MBCR_64BITCFG_SHIFT 23 1262a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MBCR_64BITCFG_MASK (1UL << MBCR_64BITCFG_SHIFT) 1272a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MBCR_64BITBUS_SHIFT 22 1282a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MBCR_64BITBUS_MASK (1UL << MBCR_64BITBUS_SHIFT) 1292a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 1302a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/************************************************************ 1312a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Memory Bank Mode Register (MBMR) 1322a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao************************************************************/ 1332a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define REG_MBMR_OFFSET 0x21C0 1342a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MBMR_MODE_MAX_VALUE 0xF 1352a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MBMR_MODE_SHIFT 25 1362a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MBMR_MODE_MASK (MBMR_MODE_MAX_VALUE << MBMR_MODE_SHIFT) 1372a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MBMR_BBA_SHIFT 24 1382a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MBMR_BBA_MASK (1UL << MBMR_BBA_SHIFT) 1392a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 1402a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/************************************************************ 1412a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Memory Bank Boundary Address Register (MBBAR) 1422a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ************************************************************/ 1432a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define REG_MBBAR_OFFSET 0x21D0 1442a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MBBAR_BBA_MAX_VALUE 0xFF 1452a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MBBAR_BBA_SHIFT 24 1462a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MBBAR_BBA_MASK (MBBAR_BBA_MAX_VALUE << MBBAR_BBA_SHIFT) 1472a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 1482a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/************************************************************ 1492a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Memory Scrub Control Register (MSCR) 1502a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ************************************************************/ 1512a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define REG_MSCR_OFFSET 0x2400 1522a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MSCR_SCRUB_MOD_MASK 0xC0000000 /* scrub_mod - bit0:1*/ 1532a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MSCR_BACKGR_SCRUB 0x40000000 /* 01 */ 1542a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MSCR_SI_SHIFT 16 /* si - bit8:15*/ 1552a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MSCR_SI_MAX_VALUE 0xFF 1562a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MSCR_SI_MASK (MSCR_SI_MAX_VALUE << MSCR_SI_SHIFT) 1572a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 1582a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/************************************************************ 1592a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Memory Scrub Range Start Register (MSRSR) 1602a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ************************************************************/ 1612a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define REG_MSRSR_OFFSET 0x2410 1622a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 1632a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/************************************************************ 1642a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Memory Scrub Range End Register (MSRER) 1652a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ************************************************************/ 1662a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define REG_MSRER_OFFSET 0x2420 1672a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 1682a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/************************************************************ 1692a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Memory Scrub Pattern Register (MSPR) 1702a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ************************************************************/ 1712a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define REG_MSPR_OFFSET 0x2430 1722a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 1732a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/************************************************************ 1742a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Memory Check Control Register (MCCR) 1752a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ************************************************************/ 1762a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define REG_MCCR_OFFSET 0x2440 1772a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaoenum mccr_bits { 1782a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao MCCR_ECC_EN = CPC925_BIT(0), /* ECC high and low check */ 1792a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao}; 1802a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 1812a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/************************************************************ 1822a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Memory Check Range End Register (MCRER) 1832a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ************************************************************/ 1842a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define REG_MCRER_OFFSET 0x2450 1852a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 1862a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/************************************************************ 1872a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Memory Error Address Register (MEAR) 1882a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ************************************************************/ 1892a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define REG_MEAR_OFFSET 0x2460 1902a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MEAR_BCNT_MAX_VALUE 0x3 1912a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MEAR_BCNT_SHIFT 30 1922a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MEAR_BCNT_MASK (MEAR_BCNT_MAX_VALUE << MEAR_BCNT_SHIFT) 1932a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MEAR_RANK_MAX_VALUE 0x7 1942a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MEAR_RANK_SHIFT 27 1952a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MEAR_RANK_MASK (MEAR_RANK_MAX_VALUE << MEAR_RANK_SHIFT) 1962a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MEAR_COL_MAX_VALUE 0x7FF 1972a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MEAR_COL_SHIFT 16 1982a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MEAR_COL_MASK (MEAR_COL_MAX_VALUE << MEAR_COL_SHIFT) 1992a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MEAR_BANK_MAX_VALUE 0x3 2002a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MEAR_BANK_SHIFT 14 2012a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MEAR_BANK_MASK (MEAR_BANK_MAX_VALUE << MEAR_BANK_SHIFT) 2022a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MEAR_ROW_MASK 0x00003FFF 2032a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 2042a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/************************************************************ 2052a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Memory Error Syndrome Register (MESR) 2062a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ************************************************************/ 2072a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define REG_MESR_OFFSET 0x2470 2082a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MESR_ECC_SYN_H_MASK 0xFF00 2092a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define MESR_ECC_SYN_L_MASK 0x00FF 2102a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 2112a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/************************************************************ 2122a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Memory Mode Control Register (MMCR) 2132a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ************************************************************/ 2142a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define REG_MMCR_OFFSET 0x2500 2152a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaoenum mmcr_bits { 2162a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao MMCR_REG_DIMM_MODE = CPC925_BIT(3), 2172a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao}; 2182a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 2192a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* 2202a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * HyperTransport Link Registers 2212a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao */ 2222a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/************************************************************ 2232a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Error Handling/Enumeration Scratch Pad Register (ERRCTRL) 2242a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ************************************************************/ 2252a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define REG_ERRCTRL_OFFSET 0x70140 2262a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaoenum errctrl_bits { /* nonfatal interrupts for */ 2272a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ERRCTRL_SERR_NF = CPC925_BIT(0), /* system error */ 2282a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ERRCTRL_CRC_NF = CPC925_BIT(1), /* CRC error */ 2292a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ERRCTRL_RSP_NF = CPC925_BIT(2), /* Response error */ 2302a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ERRCTRL_EOC_NF = CPC925_BIT(3), /* End-Of-Chain error */ 2312a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ERRCTRL_OVF_NF = CPC925_BIT(4), /* Overflow error */ 2322a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ERRCTRL_PROT_NF = CPC925_BIT(5), /* Protocol error */ 2332a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 2342a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ERRCTRL_RSP_ERR = CPC925_BIT(6), /* Response error received */ 2352a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ERRCTRL_CHN_FAL = CPC925_BIT(7), /* Sync flooding detected */ 2362a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 2372a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao HT_ERRCTRL_ENABLE = (ERRCTRL_SERR_NF | ERRCTRL_CRC_NF | 2382a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ERRCTRL_RSP_NF | ERRCTRL_EOC_NF | 2392a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ERRCTRL_OVF_NF | ERRCTRL_PROT_NF), 2402a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao HT_ERRCTRL_DETECTED = (ERRCTRL_RSP_ERR | ERRCTRL_CHN_FAL), 2412a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao}; 2422a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 2432a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/************************************************************ 2442a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Link Configuration and Link Control Register (LINKCTRL) 2452a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ************************************************************/ 2462a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define REG_LINKCTRL_OFFSET 0x70110 2472a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaoenum linkctrl_bits { 2482a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao LINKCTRL_CRC_ERR = (CPC925_BIT(22) | CPC925_BIT(23)), 2492a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao LINKCTRL_LINK_FAIL = CPC925_BIT(27), 2502a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 2512a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao HT_LINKCTRL_DETECTED = (LINKCTRL_CRC_ERR | LINKCTRL_LINK_FAIL), 2522a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao}; 2532a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 2542a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/************************************************************ 2552a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Link FreqCap/Error/Freq/Revision ID Register (LINKERR) 2562a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ************************************************************/ 2572a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define REG_LINKERR_OFFSET 0x70120 2582a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaoenum linkerr_bits { 2592a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao LINKERR_EOC_ERR = CPC925_BIT(17), /* End-Of-Chain error */ 2602a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao LINKERR_OVF_ERR = CPC925_BIT(18), /* Receive Buffer Overflow */ 2612a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao LINKERR_PROT_ERR = CPC925_BIT(19), /* Protocol error */ 2622a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 2632a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao HT_LINKERR_DETECTED = (LINKERR_EOC_ERR | LINKERR_OVF_ERR | 2642a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao LINKERR_PROT_ERR), 2652a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao}; 2662a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 2672a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/************************************************************ 2682a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Bridge Control Register (BRGCTRL) 2692a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ************************************************************/ 2702a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#define REG_BRGCTRL_OFFSET 0x70300 2712a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaoenum brgctrl_bits { 2722a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao BRGCTRL_DETSERR = CPC925_BIT(0), /* SERR on Secondary Bus */ 2732a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao BRGCTRL_SECBUSRESET = CPC925_BIT(9), /* Secondary Bus Reset */ 2742a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao}; 2752a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 2762a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* Private structure for edac memory controller */ 2772a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostruct cpc925_mc_pdata { 2782a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao void __iomem *vbase; 2792a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao unsigned long total_mem; 2802a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao const char *name; 2812a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao int edac_idx; 2822a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao}; 2832a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 2842a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* Private structure for common edac device */ 2852a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostruct cpc925_dev_info { 2862a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao void __iomem *vbase; 2872a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao struct platform_device *pdev; 2882a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao char *ctl_name; 2892a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao int edac_idx; 2902a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao struct edac_device_ctl_info *edac_dev; 2912a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao void (*init)(struct cpc925_dev_info *dev_info); 2922a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao void (*exit)(struct cpc925_dev_info *dev_info); 2932a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao void (*check)(struct edac_device_ctl_info *edac_dev); 2942a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao}; 2952a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 2962a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* Get total memory size from Open Firmware DTB */ 2972a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic void get_total_mem(struct cpc925_mc_pdata *pdata) 2982a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 2992a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao struct device_node *np = NULL; 3002a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao const unsigned int *reg, *reg_end; 3012a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao int len, sw, aw; 3022a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao unsigned long start, size; 3032a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 3042a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao np = of_find_node_by_type(NULL, "memory"); 3052a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (!np) 3062a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao return; 3072a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 3082a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao aw = of_n_addr_cells(np); 3092a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao sw = of_n_size_cells(np); 3102a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao reg = (const unsigned int *)of_get_property(np, "reg", &len); 3112a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao reg_end = reg + len/4; 3122a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 3132a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao pdata->total_mem = 0; 3142a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao do { 3152a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao start = of_read_number(reg, aw); 3162a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao reg += aw; 3172a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao size = of_read_number(reg, sw); 3182a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao reg += sw; 319956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches edac_dbg(1, "start 0x%lx, size 0x%lx\n", start, size); 3202a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao pdata->total_mem += size; 3212a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } while (reg < reg_end); 3222a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 3232a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao of_node_put(np); 324956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches edac_dbg(0, "total_mem 0x%lx\n", pdata->total_mem); 3252a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 3262a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 3272a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic void cpc925_init_csrows(struct mem_ctl_info *mci) 3282a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 3292a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao struct cpc925_mc_pdata *pdata = mci->pvt_info; 3302a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao struct csrow_info *csrow; 331084a4fccef39ac7abb039511f32380f28d0b67e6Mauro Carvalho Chehab struct dimm_info *dimm; 332fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab enum dev_type dtype; 333084a4fccef39ac7abb039511f32380f28d0b67e6Mauro Carvalho Chehab int index, j; 334fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab u32 mbmr, mbbar, bba, grain; 335a895bf8b1e1ea4c032a8fa8a09475a2ce09fe77aMauro Carvalho Chehab unsigned long row_size, nr_pages, last_nr_pages = 0; 3362a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 3372a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao get_total_mem(pdata); 3382a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 3392a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao for (index = 0; index < mci->nr_csrows; index++) { 3402a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mbmr = __raw_readl(pdata->vbase + REG_MBMR_OFFSET + 3412a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 0x20 * index); 3422a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mbbar = __raw_readl(pdata->vbase + REG_MBBAR_OFFSET + 3432a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 0x20 + index); 3442a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao bba = (((mbmr & MBMR_BBA_MASK) >> MBMR_BBA_SHIFT) << 8) | 3452a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ((mbbar & MBBAR_BBA_MASK) >> MBBAR_BBA_SHIFT); 3462a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 3472a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (bba == 0) 3482a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao continue; /* not populated */ 3492a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 350de3910eb79ac8c0f29a11224661c0ebaaf813039Mauro Carvalho Chehab csrow = mci->csrows[index]; 3512a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 3522a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao row_size = bba * (1UL << 28); /* 256M */ 3532a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao csrow->first_page = last_nr_pages; 354a895bf8b1e1ea4c032a8fa8a09475a2ce09fe77aMauro Carvalho Chehab nr_pages = row_size >> PAGE_SHIFT; 355a895bf8b1e1ea4c032a8fa8a09475a2ce09fe77aMauro Carvalho Chehab csrow->last_page = csrow->first_page + nr_pages - 1; 3562a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao last_nr_pages = csrow->last_page + 1; 3572a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 358fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab switch (csrow->nr_channels) { 359fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab case 1: /* Single channel */ 360fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab grain = 32; /* four-beat burst of 32 bytes */ 361fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab break; 362fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab case 2: /* Dual channel */ 363fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab default: 364fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab grain = 64; /* four-beat burst of 64 bytes */ 365fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab break; 366fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab } 367fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab switch ((mbmr & MBMR_MODE_MASK) >> MBMR_MODE_SHIFT) { 368fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab case 6: /* 0110, no way to differentiate X8 VS X16 */ 369fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab case 5: /* 0101 */ 370fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab case 8: /* 1000 */ 371fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab dtype = DEV_X16; 372fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab break; 373fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab case 7: /* 0111 */ 374fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab case 9: /* 1001 */ 375fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab dtype = DEV_X8; 376fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab break; 377fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab default: 378fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab dtype = DEV_UNKNOWN; 379fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab break; 380fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab } 381084a4fccef39ac7abb039511f32380f28d0b67e6Mauro Carvalho Chehab for (j = 0; j < csrow->nr_channels; j++) { 382de3910eb79ac8c0f29a11224661c0ebaaf813039Mauro Carvalho Chehab dimm = csrow->channels[j]->dimm; 383a895bf8b1e1ea4c032a8fa8a09475a2ce09fe77aMauro Carvalho Chehab dimm->nr_pages = nr_pages / csrow->nr_channels; 384084a4fccef39ac7abb039511f32380f28d0b67e6Mauro Carvalho Chehab dimm->mtype = MEM_RDDR; 385084a4fccef39ac7abb039511f32380f28d0b67e6Mauro Carvalho Chehab dimm->edac_mode = EDAC_SECDED; 386fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab dimm->grain = grain; 387fd63312dfe70b8279618b4d77dc951b6e309ffa2Mauro Carvalho Chehab dimm->dtype = dtype; 3882a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 3892a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 3902a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 3912a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 3922a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* Enable memory controller ECC detection */ 3932a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic void cpc925_mc_init(struct mem_ctl_info *mci) 3942a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 3952a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao struct cpc925_mc_pdata *pdata = mci->pvt_info; 3962a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u32 apimask; 3972a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u32 mccr; 3982a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 3992a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* Enable various ECC error exceptions */ 4002a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao apimask = __raw_readl(pdata->vbase + REG_APIMASK_OFFSET); 4012a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if ((apimask & ECC_MASK_ENABLE) == 0) { 4022a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao apimask |= ECC_MASK_ENABLE; 4032a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao __raw_writel(apimask, pdata->vbase + REG_APIMASK_OFFSET); 4042a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 4052a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 4062a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* Enable ECC detection */ 4072a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mccr = __raw_readl(pdata->vbase + REG_MCCR_OFFSET); 4082a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if ((mccr & MCCR_ECC_EN) == 0) { 4092a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mccr |= MCCR_ECC_EN; 4102a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao __raw_writel(mccr, pdata->vbase + REG_MCCR_OFFSET); 4112a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 4122a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 4132a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 4142a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* Disable memory controller ECC detection */ 4152a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic void cpc925_mc_exit(struct mem_ctl_info *mci) 4162a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 4172a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* 4182a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * WARNING: 4192a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * We are supposed to clear the ECC error detection bits, 4202a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * and it will be no problem to do so. However, once they 4212a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * are cleared here if we want to re-install CPC925 EDAC 4222a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * module later, setting them up in cpc925_mc_init() will 4232a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * trigger machine check exception. 4242a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Also, it's ok to leave ECC error detection bits enabled, 4252a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * since they are reset to 1 by default or by boot loader. 4262a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao */ 4272a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 4282a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao return; 4292a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 4302a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 4312a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* 4322a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Revert DDR column/row/bank addresses into page frame number and 4332a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * offset in page. 4342a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * 4352a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Suppose memory mode is 0x0111(128-bit mode, identical DIMM pairs), 4362a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * physical address(PA) bits to column address(CA) bits mappings are: 4372a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * CA 0 1 2 3 4 5 6 7 8 9 10 4382a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * PA 59 58 57 56 55 54 53 52 51 50 49 4392a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * 4402a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * physical address(PA) bits to bank address(BA) bits mappings are: 4412a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * BA 0 1 4422a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * PA 43 44 4432a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * 4442a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * physical address(PA) bits to row address(RA) bits mappings are: 4452a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * RA 0 1 2 3 4 5 6 7 8 9 10 11 12 4462a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * PA 36 35 34 48 47 46 45 40 41 42 39 38 37 4472a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao */ 4482a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic void cpc925_mc_get_pfn(struct mem_ctl_info *mci, u32 mear, 4492a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao unsigned long *pfn, unsigned long *offset, int *csrow) 4502a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 4512a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u32 bcnt, rank, col, bank, row; 4522a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u32 c; 4532a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao unsigned long pa; 4542a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao int i; 4552a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 4562a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao bcnt = (mear & MEAR_BCNT_MASK) >> MEAR_BCNT_SHIFT; 4572a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao rank = (mear & MEAR_RANK_MASK) >> MEAR_RANK_SHIFT; 4582a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao col = (mear & MEAR_COL_MASK) >> MEAR_COL_SHIFT; 4592a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao bank = (mear & MEAR_BANK_MASK) >> MEAR_BANK_SHIFT; 4602a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao row = mear & MEAR_ROW_MASK; 4612a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 4622a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao *csrow = rank; 4632a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 4642a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#ifdef CONFIG_EDAC_DEBUG 465de3910eb79ac8c0f29a11224661c0ebaaf813039Mauro Carvalho Chehab if (mci->csrows[rank]->first_page == 0) { 4662a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_printk(mci, KERN_ERR, "ECC occurs in a " 4672a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao "non-populated csrow, broken hardware?\n"); 4682a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao return; 4692a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 4702a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao#endif 4712a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 4722a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* Revert csrow number */ 473de3910eb79ac8c0f29a11224661c0ebaaf813039Mauro Carvalho Chehab pa = mci->csrows[rank]->first_page << PAGE_SHIFT; 4742a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 4752a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* Revert column address */ 4762a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao col += bcnt; 4772a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao for (i = 0; i < 11; i++) { 4782a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao c = col & 0x1; 4792a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao col >>= 1; 4802a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao pa |= c << (14 - i); 4812a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 4822a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 4832a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* Revert bank address */ 4842a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao pa |= bank << 19; 4852a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 4862a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* Revert row address, in 4 steps */ 4872a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao for (i = 0; i < 3; i++) { 4882a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao c = row & 0x1; 4892a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao row >>= 1; 4902a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao pa |= c << (26 - i); 4912a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 4922a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 4932a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao for (i = 0; i < 3; i++) { 4942a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao c = row & 0x1; 4952a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao row >>= 1; 4962a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao pa |= c << (21 + i); 4972a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 4982a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 4992a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao for (i = 0; i < 4; i++) { 5002a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao c = row & 0x1; 5012a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao row >>= 1; 5022a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao pa |= c << (18 - i); 5032a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 5042a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 5052a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao for (i = 0; i < 3; i++) { 5062a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao c = row & 0x1; 5072a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao row >>= 1; 5082a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao pa |= c << (29 - i); 5092a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 5102a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 5112a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao *offset = pa & (PAGE_SIZE - 1); 5122a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao *pfn = pa >> PAGE_SHIFT; 5132a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 514956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches edac_dbg(0, "ECC physical address 0x%lx\n", pa); 5152a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 5162a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 5172a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic int cpc925_mc_find_channel(struct mem_ctl_info *mci, u16 syndrome) 5182a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 5192a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if ((syndrome & MESR_ECC_SYN_H_MASK) == 0) 5202a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao return 0; 5212a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 5222a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if ((syndrome & MESR_ECC_SYN_L_MASK) == 0) 5232a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao return 1; 5242a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 5252a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_printk(mci, KERN_INFO, "Unexpected syndrome value: 0x%x\n", 5262a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao syndrome); 5272a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao return 1; 5282a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 5292a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 5302a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* Check memory controller registers for ECC errors */ 5312a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic void cpc925_mc_check(struct mem_ctl_info *mci) 5322a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 5332a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao struct cpc925_mc_pdata *pdata = mci->pvt_info; 5342a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u32 apiexcp; 5352a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u32 mear; 5362a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u32 mesr; 5372a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u16 syndrome; 5382a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao unsigned long pfn = 0, offset = 0; 5392a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao int csrow = 0, channel = 0; 5402a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 5412a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* APIEXCP is cleared when read */ 5422a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao apiexcp = __raw_readl(pdata->vbase + REG_APIEXCP_OFFSET); 5432a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if ((apiexcp & ECC_EXCP_DETECTED) == 0) 5442a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao return; 5452a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 5462a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mesr = __raw_readl(pdata->vbase + REG_MESR_OFFSET); 5472a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao syndrome = mesr | (MESR_ECC_SYN_H_MASK | MESR_ECC_SYN_L_MASK); 5482a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 5492a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mear = __raw_readl(pdata->vbase + REG_MEAR_OFFSET); 5502a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 5512a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* Revert column/row addresses into page frame number, etc */ 5522a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_get_pfn(mci, mear, &pfn, &offset, &csrow); 5532a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 5542a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (apiexcp & CECC_EXCP_DETECTED) { 5552a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_printk(mci, KERN_INFO, "DRAM CECC Fault\n"); 5562a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao channel = cpc925_mc_find_channel(mci, syndrome); 5579eb07a7fb8a90ee39fa9d5489afc0330cfcfbea7Mauro Carvalho Chehab edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 1, 558df62b1e663904e257fd5b174a9b29e6be6d0e902Mauro Carvalho Chehab pfn, offset, syndrome, 559df62b1e663904e257fd5b174a9b29e6be6d0e902Mauro Carvalho Chehab csrow, channel, -1, 56003f7eae80f4b913929be84e0c883ee98196fd6ffMauro Carvalho Chehab mci->ctl_name, ""); 5612a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 5622a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 5632a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (apiexcp & UECC_EXCP_DETECTED) { 5642a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_printk(mci, KERN_INFO, "DRAM UECC Fault\n"); 565fa19ac4b92bc2b5024af3e868f41f81fa738567aJason Baron edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 1, 566df62b1e663904e257fd5b174a9b29e6be6d0e902Mauro Carvalho Chehab pfn, offset, 0, 567df62b1e663904e257fd5b174a9b29e6be6d0e902Mauro Carvalho Chehab csrow, -1, -1, 56803f7eae80f4b913929be84e0c883ee98196fd6ffMauro Carvalho Chehab mci->ctl_name, ""); 5692a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 5702a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 5712a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_printk(mci, KERN_INFO, "Dump registers:\n"); 5722a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_printk(mci, KERN_INFO, "APIMASK 0x%08x\n", 5732a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao __raw_readl(pdata->vbase + REG_APIMASK_OFFSET)); 5742a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_printk(mci, KERN_INFO, "APIEXCP 0x%08x\n", 5752a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao apiexcp); 5762a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_printk(mci, KERN_INFO, "Mem Scrub Ctrl 0x%08x\n", 5772a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao __raw_readl(pdata->vbase + REG_MSCR_OFFSET)); 5782a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_printk(mci, KERN_INFO, "Mem Scrub Rge Start 0x%08x\n", 5792a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao __raw_readl(pdata->vbase + REG_MSRSR_OFFSET)); 5802a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_printk(mci, KERN_INFO, "Mem Scrub Rge End 0x%08x\n", 5812a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao __raw_readl(pdata->vbase + REG_MSRER_OFFSET)); 5822a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_printk(mci, KERN_INFO, "Mem Scrub Pattern 0x%08x\n", 5832a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao __raw_readl(pdata->vbase + REG_MSPR_OFFSET)); 5842a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_printk(mci, KERN_INFO, "Mem Chk Ctrl 0x%08x\n", 5852a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao __raw_readl(pdata->vbase + REG_MCCR_OFFSET)); 5862a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_printk(mci, KERN_INFO, "Mem Chk Rge End 0x%08x\n", 5872a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao __raw_readl(pdata->vbase + REG_MCRER_OFFSET)); 5882a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_printk(mci, KERN_INFO, "Mem Err Address 0x%08x\n", 5892a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mesr); 5902a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_printk(mci, KERN_INFO, "Mem Err Syndrome 0x%08x\n", 5912a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao syndrome); 5922a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 5932a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 5942a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/******************** CPU err device********************************/ 595ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikovstatic u32 cpc925_cpu_mask_disabled(void) 596ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov{ 597ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov struct device_node *cpus; 598ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov struct device_node *cpunode = NULL; 599ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov static u32 mask = 0; 600ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov 601ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov /* use cached value if available */ 602ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov if (mask != 0) 603ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov return mask; 604ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov 605ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov mask = APIMASK_ADI0 | APIMASK_ADI1; 606ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov 607ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov cpus = of_find_node_by_path("/cpus"); 608ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov if (cpus == NULL) { 609ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov cpc925_printk(KERN_DEBUG, "No /cpus node !\n"); 610ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov return 0; 611ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov } 612ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov 613ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov while ((cpunode = of_get_next_child(cpus, cpunode)) != NULL) { 614ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov const u32 *reg = of_get_property(cpunode, "reg", NULL); 615ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov 616ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov if (strcmp(cpunode->type, "cpu")) { 617ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov cpc925_printk(KERN_ERR, "Not a cpu node in /cpus: %s\n", cpunode->name); 618ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov continue; 619ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov } 620ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov 621ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov if (reg == NULL || *reg > 2) { 622ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov cpc925_printk(KERN_ERR, "Bad reg value at %s\n", cpunode->full_name); 623ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov continue; 624ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov } 625ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov 626ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov mask &= ~APIMASK_ADI(*reg); 627ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov } 628ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov 629ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov if (mask != (APIMASK_ADI0 | APIMASK_ADI1)) { 630ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov /* We assume that each CPU sits on it's own PI and that 631ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov * for present CPUs the reg property equals to the PI 632ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov * interface id */ 633ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov cpc925_printk(KERN_WARNING, 634ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov "Assuming PI id is equal to CPU MPIC id!\n"); 635ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov } 636ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov 637ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov of_node_put(cpunode); 638ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov of_node_put(cpus); 639ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov 640ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov return mask; 641ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov} 642ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov 6432a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* Enable CPU Errors detection */ 6442a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic void cpc925_cpu_init(struct cpc925_dev_info *dev_info) 6452a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 6462a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u32 apimask; 647ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov u32 cpumask; 6482a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 6492a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao apimask = __raw_readl(dev_info->vbase + REG_APIMASK_OFFSET); 650ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov 651ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov cpumask = cpc925_cpu_mask_disabled(); 652ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov if (apimask & cpumask) { 653ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov cpc925_printk(KERN_WARNING, "CPU(s) not present, " 654ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov "but enabled in APIMASK, disabling\n"); 655ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov apimask &= ~cpumask; 6562a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 657ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov 658ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov if ((apimask & CPU_MASK_ENABLE) == 0) 659ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov apimask |= CPU_MASK_ENABLE; 660ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov 661ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov __raw_writel(apimask, dev_info->vbase + REG_APIMASK_OFFSET); 6622a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 6632a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 6642a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* Disable CPU Errors detection */ 6652a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic void cpc925_cpu_exit(struct cpc925_dev_info *dev_info) 6662a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 6672a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* 6682a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * WARNING: 6692a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * We are supposed to clear the CPU error detection bits, 6702a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * and it will be no problem to do so. However, once they 6712a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * are cleared here if we want to re-install CPC925 EDAC 6722a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * module later, setting them up in cpc925_cpu_init() will 6732a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * trigger machine check exception. 6742a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Also, it's ok to leave CPU error detection bits enabled, 6752a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * since they are reset to 1 by default. 6762a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao */ 6772a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 6782a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao return; 6792a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 6802a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 6812a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* Check for CPU Errors */ 6822a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic void cpc925_cpu_check(struct edac_device_ctl_info *edac_dev) 6832a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 6842a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao struct cpc925_dev_info *dev_info = edac_dev->pvt_info; 6852a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u32 apiexcp; 6862a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u32 apimask; 6872a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 6882a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* APIEXCP is cleared when read */ 6892a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao apiexcp = __raw_readl(dev_info->vbase + REG_APIEXCP_OFFSET); 6902a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if ((apiexcp & CPU_EXCP_DETECTED) == 0) 6912a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao return; 6922a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 693ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov if ((apiexcp & ~cpc925_cpu_mask_disabled()) == 0) 694ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov return; 695ce395088832bfd56bd28824b31a6a3685f3fd339Dmitry Eremin-Solenikov 6962a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao apimask = __raw_readl(dev_info->vbase + REG_APIMASK_OFFSET); 6972a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_printk(KERN_INFO, "Processor Interface Fault\n" 6982a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao "Processor Interface register dump:\n"); 6992a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_printk(KERN_INFO, "APIMASK 0x%08x\n", apimask); 7002a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_printk(KERN_INFO, "APIEXCP 0x%08x\n", apiexcp); 7012a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 7022a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name); 7032a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 7042a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 7052a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/******************** HT Link err device****************************/ 7062a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* Enable HyperTransport Link Error detection */ 7072a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic void cpc925_htlink_init(struct cpc925_dev_info *dev_info) 7082a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 7092a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u32 ht_errctrl; 7102a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 7112a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ht_errctrl = __raw_readl(dev_info->vbase + REG_ERRCTRL_OFFSET); 7122a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if ((ht_errctrl & HT_ERRCTRL_ENABLE) == 0) { 7132a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ht_errctrl |= HT_ERRCTRL_ENABLE; 7142a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao __raw_writel(ht_errctrl, dev_info->vbase + REG_ERRCTRL_OFFSET); 7152a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 7162a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 7172a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 7182a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* Disable HyperTransport Link Error detection */ 7192a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic void cpc925_htlink_exit(struct cpc925_dev_info *dev_info) 7202a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 7212a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u32 ht_errctrl; 7222a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 7232a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ht_errctrl = __raw_readl(dev_info->vbase + REG_ERRCTRL_OFFSET); 7242a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ht_errctrl &= ~HT_ERRCTRL_ENABLE; 7252a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao __raw_writel(ht_errctrl, dev_info->vbase + REG_ERRCTRL_OFFSET); 7262a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 7272a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 7282a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* Check for HyperTransport Link errors */ 7292a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic void cpc925_htlink_check(struct edac_device_ctl_info *edac_dev) 7302a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 7312a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao struct cpc925_dev_info *dev_info = edac_dev->pvt_info; 7322a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u32 brgctrl = __raw_readl(dev_info->vbase + REG_BRGCTRL_OFFSET); 7332a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u32 linkctrl = __raw_readl(dev_info->vbase + REG_LINKCTRL_OFFSET); 7342a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u32 errctrl = __raw_readl(dev_info->vbase + REG_ERRCTRL_OFFSET); 7352a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u32 linkerr = __raw_readl(dev_info->vbase + REG_LINKERR_OFFSET); 7362a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 7372a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (!((brgctrl & BRGCTRL_DETSERR) || 7382a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao (linkctrl & HT_LINKCTRL_DETECTED) || 7392a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao (errctrl & HT_ERRCTRL_DETECTED) || 7402a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao (linkerr & HT_LINKERR_DETECTED))) 7412a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao return; 7422a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 7432a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_printk(KERN_INFO, "HT Link Fault\n" 7442a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao "HT register dump:\n"); 7452a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_printk(KERN_INFO, "Bridge Ctrl 0x%08x\n", 7462a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao brgctrl); 7472a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_printk(KERN_INFO, "Link Config Ctrl 0x%08x\n", 7482a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao linkctrl); 7492a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_printk(KERN_INFO, "Error Enum and Ctrl 0x%08x\n", 7502a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao errctrl); 7512a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_printk(KERN_INFO, "Link Error 0x%08x\n", 7522a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao linkerr); 7532a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 7542a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* Clear by write 1 */ 7552a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (brgctrl & BRGCTRL_DETSERR) 7562a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao __raw_writel(BRGCTRL_DETSERR, 7572a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->vbase + REG_BRGCTRL_OFFSET); 7582a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 7592a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (linkctrl & HT_LINKCTRL_DETECTED) 7602a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao __raw_writel(HT_LINKCTRL_DETECTED, 7612a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->vbase + REG_LINKCTRL_OFFSET); 7622a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 7632a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* Initiate Secondary Bus Reset to clear the chain failure */ 7642a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (errctrl & ERRCTRL_CHN_FAL) 7652a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao __raw_writel(BRGCTRL_SECBUSRESET, 7662a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->vbase + REG_BRGCTRL_OFFSET); 7672a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 7682a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (errctrl & ERRCTRL_RSP_ERR) 7692a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao __raw_writel(ERRCTRL_RSP_ERR, 7702a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->vbase + REG_ERRCTRL_OFFSET); 7712a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 7722a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (linkerr & HT_LINKERR_DETECTED) 7732a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao __raw_writel(HT_LINKERR_DETECTED, 7742a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->vbase + REG_LINKERR_OFFSET); 7752a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 7762a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao edac_device_handle_ce(edac_dev, 0, 0, edac_dev->ctl_name); 7772a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 7782a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 7792a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic struct cpc925_dev_info cpc925_devs[] = { 7802a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao { 7812a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao .ctl_name = CPC925_CPU_ERR_DEV, 7822a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao .init = cpc925_cpu_init, 7832a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao .exit = cpc925_cpu_exit, 7842a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao .check = cpc925_cpu_check, 7852a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao }, 7862a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao { 7872a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao .ctl_name = CPC925_HT_LINK_DEV, 7882a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao .init = cpc925_htlink_init, 7892a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao .exit = cpc925_htlink_exit, 7902a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao .check = cpc925_htlink_check, 7912a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao }, 79275a9551f2b3792686df25501f248d1de92d5da0fJingoo Han { } 7932a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao}; 7942a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 7952a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* 7962a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Add CPU Err detection and HyperTransport Link Err detection 7972a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * as common "edac_device", they have no corresponding device 7982a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * nodes in the Open Firmware DTB and we have to add platform 7992a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * devices for them. Also, they will share the MMIO with that 8002a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * of memory controller. 8012a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao */ 8022a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic void cpc925_add_edac_devices(void __iomem *vbase) 8032a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 8042a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao struct cpc925_dev_info *dev_info; 8052a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 8062a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (!vbase) { 8072a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_printk(KERN_ERR, "MMIO not established yet\n"); 8082a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao return; 8092a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 8102a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 8112a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao for (dev_info = &cpc925_devs[0]; dev_info->init; dev_info++) { 8122a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->vbase = vbase; 8132a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->pdev = platform_device_register_simple( 8142a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->ctl_name, 0, NULL, 0); 8152a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (IS_ERR(dev_info->pdev)) { 8162a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_printk(KERN_ERR, 8172a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao "Can't register platform device for %s\n", 8182a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->ctl_name); 8192a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao continue; 8202a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 8212a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 8222a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* 8232a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Don't have to allocate private structure but 8242a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * make use of cpc925_devs[] instead. 8252a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao */ 8262a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->edac_idx = edac_device_alloc_index(); 8272a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->edac_dev = 8282a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao edac_device_alloc_ctl_info(0, dev_info->ctl_name, 8292a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 1, NULL, 0, 0, NULL, 0, dev_info->edac_idx); 8302a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (!dev_info->edac_dev) { 8312a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_printk(KERN_ERR, "No memory for edac device\n"); 8322a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao goto err1; 8332a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 8342a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 8352a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->edac_dev->pvt_info = dev_info; 8362a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->edac_dev->dev = &dev_info->pdev->dev; 8372a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->edac_dev->ctl_name = dev_info->ctl_name; 8382a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->edac_dev->mod_name = CPC925_EDAC_MOD_STR; 8392a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->edac_dev->dev_name = dev_name(&dev_info->pdev->dev); 8402a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 8412a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (edac_op_state == EDAC_OPSTATE_POLL) 8422a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->edac_dev->edac_check = dev_info->check; 8432a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 8442a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (dev_info->init) 8452a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->init(dev_info); 8462a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 8472a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (edac_device_add_device(dev_info->edac_dev) > 0) { 8482a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_printk(KERN_ERR, 8492a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao "Unable to add edac device for %s\n", 8502a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->ctl_name); 8512a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao goto err2; 8522a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 8532a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 854956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches edac_dbg(0, "Successfully added edac device for %s\n", 855956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches dev_info->ctl_name); 8562a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 8572a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao continue; 8582a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 8592a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaoerr2: 8602a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (dev_info->exit) 8612a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->exit(dev_info); 8622a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao edac_device_free_ctl_info(dev_info->edac_dev); 8632a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaoerr1: 8642a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao platform_device_unregister(dev_info->pdev); 8652a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 8662a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 8672a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 8682a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* 8692a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Delete the common "edac_device" for CPU Err Detection 8702a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * and HyperTransport Link Err Detection 8712a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao */ 8722a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic void cpc925_del_edac_devices(void) 8732a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 8742a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao struct cpc925_dev_info *dev_info; 8752a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 8762a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao for (dev_info = &cpc925_devs[0]; dev_info->init; dev_info++) { 8772a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (dev_info->edac_dev) { 8782a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao edac_device_del_device(dev_info->edac_dev->dev); 8792a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao edac_device_free_ctl_info(dev_info->edac_dev); 8802a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao platform_device_unregister(dev_info->pdev); 8812a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 8822a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 8832a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (dev_info->exit) 8842a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dev_info->exit(dev_info); 8852a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 886956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches edac_dbg(0, "Successfully deleted edac device for %s\n", 887956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches dev_info->ctl_name); 8882a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 8892a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 8902a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 89125985edcedea6396277003854657b5f3cb31a628Lucas De Marchi/* Convert current back-ground scrub rate into byte/sec bandwidth */ 892390944439f746824faec51b576f50cb5ef18745bBorislav Petkovstatic int cpc925_get_sdram_scrub_rate(struct mem_ctl_info *mci) 8932a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 8942a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao struct cpc925_mc_pdata *pdata = mci->pvt_info; 895390944439f746824faec51b576f50cb5ef18745bBorislav Petkov int bw; 8962a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u32 mscr; 8972a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u8 si; 8982a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 8992a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mscr = __raw_readl(pdata->vbase + REG_MSCR_OFFSET); 9002a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao si = (mscr & MSCR_SI_MASK) >> MSCR_SI_SHIFT; 9012a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 902956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches edac_dbg(0, "Mem Scrub Ctrl Register 0x%x\n", mscr); 9032a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 9042a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (((mscr & MSCR_SCRUB_MOD_MASK) != MSCR_BACKGR_SCRUB) || 9052a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao (si == 0)) { 9062a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_printk(mci, KERN_INFO, "Scrub mode not enabled\n"); 907390944439f746824faec51b576f50cb5ef18745bBorislav Petkov bw = 0; 9082a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } else 909390944439f746824faec51b576f50cb5ef18745bBorislav Petkov bw = CPC925_SCRUB_BLOCK_SIZE * 0xFA67 / si; 9102a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 911390944439f746824faec51b576f50cb5ef18745bBorislav Petkov return bw; 9122a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 9132a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 9142a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao/* Return 0 for single channel; 1 for dual channel */ 9152a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic int cpc925_mc_get_channels(void __iomem *vbase) 9162a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 9172a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao int dual = 0; 9182a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao u32 mbcr; 9192a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 9202a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mbcr = __raw_readl(vbase + REG_MBCR_OFFSET); 9212a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 9222a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* 9232a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Dual channel only when 128-bit wide physical bus 9242a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * and 128-bit configuration. 9252a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao */ 9262a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (((mbcr & MBCR_64BITCFG_MASK) == 0) && 9272a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ((mbcr & MBCR_64BITBUS_MASK) == 0)) 9282a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao dual = 1; 9292a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 930956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches edac_dbg(0, "%s channel\n", (dual > 0) ? "Dual" : "Single"); 9312a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 9322a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao return dual; 9332a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 9342a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 9359b3c6e85c2cfa731cf67d5a8c49f7d8c60ec0b04Greg Kroah-Hartmanstatic int cpc925_probe(struct platform_device *pdev) 9362a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 9372a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao static int edac_mc_idx; 9382a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao struct mem_ctl_info *mci; 939df62b1e663904e257fd5b174a9b29e6be6d0e902Mauro Carvalho Chehab struct edac_mc_layer layers[2]; 9402a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao void __iomem *vbase; 9412a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao struct cpc925_mc_pdata *pdata; 9422a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao struct resource *r; 9432a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao int res = 0, nr_channels; 9442a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 945956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches edac_dbg(0, "%s platform device found!\n", pdev->name); 9462a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 9472a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (!devres_open_group(&pdev->dev, cpc925_probe, GFP_KERNEL)) { 9482a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao res = -ENOMEM; 9492a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao goto out; 9502a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 9512a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 9522a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 9532a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (!r) { 9542a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_printk(KERN_ERR, "Unable to get resource\n"); 9552a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao res = -ENOENT; 9562a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao goto err1; 9572a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 9582a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 9592a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (!devm_request_mem_region(&pdev->dev, 9602a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao r->start, 96130a61fff3a2b19506c66ea81fecb6a7747af3d47Julia Lawall resource_size(r), 9622a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao pdev->name)) { 9632a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_printk(KERN_ERR, "Unable to request mem region\n"); 9642a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao res = -EBUSY; 9652a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao goto err1; 9662a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 9672a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 96830a61fff3a2b19506c66ea81fecb6a7747af3d47Julia Lawall vbase = devm_ioremap(&pdev->dev, r->start, resource_size(r)); 9692a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (!vbase) { 9702a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_printk(KERN_ERR, "Unable to ioremap device\n"); 9712a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao res = -ENOMEM; 9722a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao goto err2; 9732a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 9742a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 975084a4fccef39ac7abb039511f32380f28d0b67e6Mauro Carvalho Chehab nr_channels = cpc925_mc_get_channels(vbase) + 1; 976df62b1e663904e257fd5b174a9b29e6be6d0e902Mauro Carvalho Chehab 977df62b1e663904e257fd5b174a9b29e6be6d0e902Mauro Carvalho Chehab layers[0].type = EDAC_MC_LAYER_CHIP_SELECT; 978df62b1e663904e257fd5b174a9b29e6be6d0e902Mauro Carvalho Chehab layers[0].size = CPC925_NR_CSROWS; 979df62b1e663904e257fd5b174a9b29e6be6d0e902Mauro Carvalho Chehab layers[0].is_virt_csrow = true; 980df62b1e663904e257fd5b174a9b29e6be6d0e902Mauro Carvalho Chehab layers[1].type = EDAC_MC_LAYER_CHANNEL; 981df62b1e663904e257fd5b174a9b29e6be6d0e902Mauro Carvalho Chehab layers[1].size = nr_channels; 982df62b1e663904e257fd5b174a9b29e6be6d0e902Mauro Carvalho Chehab layers[1].is_virt_csrow = false; 983ca0907b9e413bb1d1f3ea123b663535b74928846Mauro Carvalho Chehab mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers, 984df62b1e663904e257fd5b174a9b29e6be6d0e902Mauro Carvalho Chehab sizeof(struct cpc925_mc_pdata)); 9852a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (!mci) { 9862a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_printk(KERN_ERR, "No memory for mem_ctl_info\n"); 9872a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao res = -ENOMEM; 9882a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao goto err2; 9892a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 9902a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 9912a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao pdata = mci->pvt_info; 9922a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao pdata->vbase = vbase; 9932a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao pdata->edac_idx = edac_mc_idx++; 9942a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao pdata->name = pdev->name; 9952a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 996fd687502dc8037aa5a4b84c570ada971106574eeMauro Carvalho Chehab mci->pdev = &pdev->dev; 9972a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao platform_set_drvdata(pdev, mci); 9982a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mci->dev_name = dev_name(&pdev->dev); 9992a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR; 10002a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; 10012a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mci->edac_cap = EDAC_FLAG_SECDED; 10022a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mci->mod_name = CPC925_EDAC_MOD_STR; 10032a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mci->mod_ver = CPC925_EDAC_REVISION; 10042a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mci->ctl_name = pdev->name; 10052a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10062a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (edac_op_state == EDAC_OPSTATE_POLL) 10072a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mci->edac_check = cpc925_mc_check; 10082a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10092a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mci->ctl_page_to_phys = NULL; 10102a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mci->scrub_mode = SCRUB_SW_SRC; 10112a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mci->set_sdram_scrub_rate = NULL; 10122a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao mci->get_sdram_scrub_rate = cpc925_get_sdram_scrub_rate; 10132a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10142a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_init_csrows(mci); 10152a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10162a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* Setup memory controller registers */ 10172a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_init(mci); 10182a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10192a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (edac_mc_add_mc(mci) > 0) { 10202a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_printk(mci, KERN_ERR, "Failed edac_mc_add_mc()\n"); 10212a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao goto err3; 10222a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 10232a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10242a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_add_edac_devices(vbase); 10252a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10262a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* get this far and it's successful */ 1027956b9ba156dbfdb9cede2b2927ddf8be2233b3a7Joe Perches edac_dbg(0, "success\n"); 10282a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10292a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao res = 0; 10302a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao goto out; 10312a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10322a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaoerr3: 10332a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_exit(mci); 10342a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao edac_mc_free(mci); 10352a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaoerr2: 103630a61fff3a2b19506c66ea81fecb6a7747af3d47Julia Lawall devm_release_mem_region(&pdev->dev, r->start, resource_size(r)); 10372a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaoerr1: 10382a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao devres_release_group(&pdev->dev, cpc925_probe); 10392a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaoout: 10402a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao return res; 10412a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 10422a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10432a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic int cpc925_remove(struct platform_device *pdev) 10442a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 10452a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao struct mem_ctl_info *mci = platform_get_drvdata(pdev); 10462a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10472a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* 10482a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * Delete common edac devices before edac mc, because 10492a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao * the former share the MMIO of the latter. 10502a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao */ 10512a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_del_edac_devices(); 10522a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao cpc925_mc_exit(mci); 10532a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10542a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao edac_mc_del_mc(&pdev->dev); 10552a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao edac_mc_free(mci); 10562a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10572a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao return 0; 10582a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 10592a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10602a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic struct platform_driver cpc925_edac_driver = { 10612a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao .probe = cpc925_probe, 10622a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao .remove = cpc925_remove, 10632a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao .driver = { 10642a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao .name = "cpc925_edac", 10652a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 10662a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao}; 10672a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10682a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic int __init cpc925_edac_init(void) 10692a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 10702a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao int ret = 0; 10712a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10722a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao printk(KERN_INFO "IBM CPC925 EDAC driver " CPC925_EDAC_REVISION "\n"); 10732a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc\n"); 10742a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10752a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao /* Only support POLL mode so far */ 10762a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao edac_op_state = EDAC_OPSTATE_POLL; 10772a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10782a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao ret = platform_driver_register(&cpc925_edac_driver); 10792a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao if (ret) { 10802a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao printk(KERN_WARNING "Failed to register %s\n", 10812a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao CPC925_EDAC_MOD_STR); 10822a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao } 10832a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10842a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao return ret; 10852a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 10862a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10872a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaostatic void __exit cpc925_edac_exit(void) 10882a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao{ 10892a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao platform_driver_unregister(&cpc925_edac_driver); 10902a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao} 10912a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10922a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaomodule_init(cpc925_edac_init); 10932a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciaomodule_exit(cpc925_edac_exit); 10942a9036afffb3a174e980f90eb507c5aea6b540f6Harry Ciao 10952a9036afffb3a174e980f90eb507c5aea6b540f6Harry CiaoMODULE_LICENSE("GPL"); 10962a9036afffb3a174e980f90eb507c5aea6b540f6Harry CiaoMODULE_AUTHOR("Cao Qingtao <qingtao.cao@windriver.com>"); 10972a9036afffb3a174e980f90eb507c5aea6b540f6Harry CiaoMODULE_DESCRIPTION("IBM CPC925 Bridge and MC EDAC kernel module"); 1098