2009-05-05 22:07:11 +04:00
# include "amd64_edac.h"
2012-03-21 21:00:44 +04:00
static ssize_t amd64_inject_section_show ( struct device * dev ,
struct device_attribute * mattr ,
char * buf )
2009-09-24 13:05:30 +04:00
{
2012-03-21 21:00:44 +04:00
struct mem_ctl_info * mci = to_mci ( dev ) ;
2009-09-24 13:05:30 +04:00
struct amd64_pvt * pvt = mci - > pvt_info ;
return sprintf ( buf , " 0x%x \n " , pvt - > injection . section ) ;
}
2009-05-05 22:07:11 +04:00
/*
* store error injection section value which refers to one of 4 16 - byte sections
* within a 64 - byte cacheline
*
* range : 0. .3
*/
2012-03-21 21:00:44 +04:00
static ssize_t amd64_inject_section_store ( struct device * dev ,
struct device_attribute * mattr ,
2009-05-05 22:07:11 +04:00
const char * data , size_t count )
{
2012-03-21 21:00:44 +04:00
struct mem_ctl_info * mci = to_mci ( dev ) ;
2009-05-05 22:07:11 +04:00
struct amd64_pvt * pvt = mci - > pvt_info ;
unsigned long value ;
2012-08-09 20:23:53 +04:00
int ret ;
2009-05-05 22:07:11 +04:00
2013-06-01 11:08:22 +04:00
ret = kstrtoul ( data , 10 , & value ) ;
2012-08-09 20:23:53 +04:00
if ( ret < 0 )
return ret ;
2009-09-24 13:05:30 +04:00
2012-08-09 20:23:53 +04:00
if ( value > 3 ) {
amd64_warn ( " %s: invalid section 0x%lx \n " , __func__ , value ) ;
return - EINVAL ;
2009-05-05 22:07:11 +04:00
}
2012-08-09 20:23:53 +04:00
pvt - > injection . section = ( u32 ) value ;
return count ;
2009-05-05 22:07:11 +04:00
}
2012-03-21 21:00:44 +04:00
static ssize_t amd64_inject_word_show ( struct device * dev ,
struct device_attribute * mattr ,
char * buf )
2009-09-24 13:05:30 +04:00
{
2012-03-21 21:00:44 +04:00
struct mem_ctl_info * mci = to_mci ( dev ) ;
2009-09-24 13:05:30 +04:00
struct amd64_pvt * pvt = mci - > pvt_info ;
return sprintf ( buf , " 0x%x \n " , pvt - > injection . word ) ;
}
2009-05-05 22:07:11 +04:00
/*
* store error injection word value which refers to one of 9 16 - bit word of the
* 16 - byte ( 128 - bit + ECC bits ) section
*
* range : 0. .8
*/
2012-03-21 21:00:44 +04:00
static ssize_t amd64_inject_word_store ( struct device * dev ,
struct device_attribute * mattr ,
const char * data , size_t count )
2009-05-05 22:07:11 +04:00
{
2012-03-21 21:00:44 +04:00
struct mem_ctl_info * mci = to_mci ( dev ) ;
2009-05-05 22:07:11 +04:00
struct amd64_pvt * pvt = mci - > pvt_info ;
unsigned long value ;
2012-08-09 20:23:53 +04:00
int ret ;
2009-05-05 22:07:11 +04:00
2013-06-01 11:08:22 +04:00
ret = kstrtoul ( data , 10 , & value ) ;
2012-08-09 20:23:53 +04:00
if ( ret < 0 )
return ret ;
2009-05-05 22:07:11 +04:00
2012-08-09 20:23:53 +04:00
if ( value > 8 ) {
amd64_warn ( " %s: invalid word 0x%lx \n " , __func__ , value ) ;
return - EINVAL ;
2009-05-05 22:07:11 +04:00
}
2012-08-09 20:23:53 +04:00
pvt - > injection . word = ( u32 ) value ;
return count ;
2009-05-05 22:07:11 +04:00
}
2012-03-21 21:00:44 +04:00
static ssize_t amd64_inject_ecc_vector_show ( struct device * dev ,
struct device_attribute * mattr ,
char * buf )
2009-09-24 13:05:30 +04:00
{
2012-03-21 21:00:44 +04:00
struct mem_ctl_info * mci = to_mci ( dev ) ;
2009-09-24 13:05:30 +04:00
struct amd64_pvt * pvt = mci - > pvt_info ;
return sprintf ( buf , " 0x%x \n " , pvt - > injection . bit_map ) ;
}
2009-05-05 22:07:11 +04:00
/*
* store 16 bit error injection vector which enables injecting errors to the
* corresponding bit within the error injection word above . When used during a
* DRAM ECC read , it holds the contents of the of the DRAM ECC bits .
*/
2012-03-21 21:00:44 +04:00
static ssize_t amd64_inject_ecc_vector_store ( struct device * dev ,
struct device_attribute * mattr ,
const char * data , size_t count )
2009-05-05 22:07:11 +04:00
{
2012-03-21 21:00:44 +04:00
struct mem_ctl_info * mci = to_mci ( dev ) ;
2009-05-05 22:07:11 +04:00
struct amd64_pvt * pvt = mci - > pvt_info ;
unsigned long value ;
2012-08-09 20:23:53 +04:00
int ret ;
2009-05-05 22:07:11 +04:00
2013-06-01 11:08:22 +04:00
ret = kstrtoul ( data , 16 , & value ) ;
2012-08-09 20:23:53 +04:00
if ( ret < 0 )
return ret ;
2009-05-05 22:07:11 +04:00
2012-08-09 20:23:53 +04:00
if ( value & 0xFFFF0000 ) {
amd64_warn ( " %s: invalid EccVector: 0x%lx \n " , __func__ , value ) ;
return - EINVAL ;
2009-05-05 22:07:11 +04:00
}
2012-08-09 20:23:53 +04:00
pvt - > injection . bit_map = ( u32 ) value ;
return count ;
2009-05-05 22:07:11 +04:00
}
/*
* Do a DRAM ECC read . Assemble staged values in the pvt area , format into
* fields needed by the injection registers and read the NB Array Data Port .
*/
2012-03-21 21:00:44 +04:00
static ssize_t amd64_inject_read_store ( struct device * dev ,
struct device_attribute * mattr ,
const char * data , size_t count )
2009-05-05 22:07:11 +04:00
{
2012-03-21 21:00:44 +04:00
struct mem_ctl_info * mci = to_mci ( dev ) ;
2009-05-05 22:07:11 +04:00
struct amd64_pvt * pvt = mci - > pvt_info ;
unsigned long value ;
u32 section , word_bits ;
2012-08-09 20:23:53 +04:00
int ret ;
2009-05-05 22:07:11 +04:00
2013-06-01 11:08:22 +04:00
ret = kstrtoul ( data , 10 , & value ) ;
2012-08-09 20:23:53 +04:00
if ( ret < 0 )
return ret ;
2009-05-05 22:07:11 +04:00
2012-08-09 20:23:53 +04:00
/* Form value to choose 16-byte section of cacheline */
section = F10_NB_ARRAY_DRAM | SET_NB_ARRAY_ADDR ( pvt - > injection . section ) ;
2009-05-05 22:07:11 +04:00
2012-08-09 20:23:53 +04:00
amd64_write_pci_cfg ( pvt - > F3 , F10_NB_ARRAY_ADDR , section ) ;
2009-05-05 22:07:11 +04:00
2012-08-09 20:23:53 +04:00
word_bits = SET_NB_DRAM_INJECTION_READ ( pvt - > injection ) ;
2009-05-05 22:07:11 +04:00
2012-08-09 20:23:53 +04:00
/* Issue 'word' and 'bit' along with the READ request */
amd64_write_pci_cfg ( pvt - > F3 , F10_NB_ARRAY_DATA , word_bits ) ;
2009-05-05 22:07:11 +04:00
2012-08-09 20:23:53 +04:00
edac_dbg ( 0 , " section=0x%x word_bits=0x%x \n " , section , word_bits ) ;
return count ;
2009-05-05 22:07:11 +04:00
}
/*
* Do a DRAM ECC write . Assemble staged values in the pvt area and format into
* fields needed by the injection registers .
*/
2012-03-21 21:00:44 +04:00
static ssize_t amd64_inject_write_store ( struct device * dev ,
struct device_attribute * mattr ,
2009-05-05 22:07:11 +04:00
const char * data , size_t count )
{
2012-03-21 21:00:44 +04:00
struct mem_ctl_info * mci = to_mci ( dev ) ;
2009-05-05 22:07:11 +04:00
struct amd64_pvt * pvt = mci - > pvt_info ;
2012-08-09 20:41:07 +04:00
u32 section , word_bits , tmp ;
2009-05-05 22:07:11 +04:00
unsigned long value ;
2012-08-09 20:23:53 +04:00
int ret ;
2009-05-05 22:07:11 +04:00
2013-06-01 11:08:22 +04:00
ret = kstrtoul ( data , 10 , & value ) ;
2012-08-09 20:23:53 +04:00
if ( ret < 0 )
return ret ;
2009-05-05 22:07:11 +04:00
2012-08-09 20:23:53 +04:00
/* Form value to choose 16-byte section of cacheline */
section = F10_NB_ARRAY_DRAM | SET_NB_ARRAY_ADDR ( pvt - > injection . section ) ;
2009-05-05 22:07:11 +04:00
2012-08-09 20:23:53 +04:00
amd64_write_pci_cfg ( pvt - > F3 , F10_NB_ARRAY_ADDR , section ) ;
2009-05-05 22:07:11 +04:00
2012-08-09 20:23:53 +04:00
word_bits = SET_NB_DRAM_INJECTION_WRITE ( pvt - > injection ) ;
2009-05-05 22:07:11 +04:00
2012-08-09 20:41:07 +04:00
pr_notice_once ( " Don't forget to decrease MCE polling interval in \n "
" /sys/bus/machinecheck/devices/machinecheck<CPUNUM>/check_interval \n "
" so that you can get the error report faster. \n " ) ;
on_each_cpu ( disable_caches , NULL , 1 ) ;
2012-08-09 20:23:53 +04:00
/* Issue 'word' and 'bit' along with the READ request */
amd64_write_pci_cfg ( pvt - > F3 , F10_NB_ARRAY_DATA , word_bits ) ;
2009-05-05 22:07:11 +04:00
2012-08-09 20:41:07 +04:00
retry :
/* wait until injection happens */
amd64_read_pci_cfg ( pvt - > F3 , F10_NB_ARRAY_DATA , & tmp ) ;
if ( tmp & F10_NB_ARR_ECC_WR_REQ ) {
cpu_relax ( ) ;
goto retry ;
}
on_each_cpu ( enable_caches , NULL , 1 ) ;
2012-08-09 20:23:53 +04:00
edac_dbg ( 0 , " section=0x%x word_bits=0x%x \n " , section , word_bits ) ;
return count ;
2009-05-05 22:07:11 +04:00
}
/*
* update NUM_INJ_ATTRS in case you add new members
*/
2012-03-21 21:00:44 +04:00
static DEVICE_ATTR ( inject_section , S_IRUGO | S_IWUSR ,
amd64_inject_section_show , amd64_inject_section_store ) ;
static DEVICE_ATTR ( inject_word , S_IRUGO | S_IWUSR ,
amd64_inject_word_show , amd64_inject_word_store ) ;
static DEVICE_ATTR ( inject_ecc_vector , S_IRUGO | S_IWUSR ,
amd64_inject_ecc_vector_show , amd64_inject_ecc_vector_store ) ;
2013-05-12 15:03:56 +04:00
static DEVICE_ATTR ( inject_write , S_IWUSR ,
2012-03-21 21:00:44 +04:00
NULL , amd64_inject_write_store ) ;
2013-05-12 15:03:56 +04:00
static DEVICE_ATTR ( inject_read , S_IWUSR ,
2012-03-21 21:00:44 +04:00
NULL , amd64_inject_read_store ) ;
2015-02-04 13:48:53 +03:00
static struct attribute * amd64_edac_inj_attrs [ ] = {
& dev_attr_inject_section . attr ,
& dev_attr_inject_word . attr ,
& dev_attr_inject_ecc_vector . attr ,
& dev_attr_inject_write . attr ,
& dev_attr_inject_read . attr ,
NULL
} ;
static umode_t amd64_edac_inj_is_visible ( struct kobject * kobj ,
struct attribute * attr , int idx )
2012-03-21 21:00:44 +04:00
{
2015-02-04 13:48:53 +03:00
struct device * dev = kobj_to_dev ( kobj ) ;
struct mem_ctl_info * mci = container_of ( dev , struct mem_ctl_info , dev ) ;
struct amd64_pvt * pvt = mci - > pvt_info ;
2012-03-21 21:00:44 +04:00
2015-02-04 13:48:53 +03:00
if ( pvt - > fam < 0x10 )
return 0 ;
return attr - > mode ;
2012-03-21 21:00:44 +04:00
}
2015-02-04 13:48:53 +03:00
const struct attribute_group amd64_edac_inj_group = {
. attrs = amd64_edac_inj_attrs ,
. is_visible = amd64_edac_inj_is_visible ,
} ;