amd64_edac_inj.c 6.2 KB
Newer Older
1 2
#include "amd64_edac.h"

3 4 5
static ssize_t amd64_inject_section_show(struct device *dev,
					 struct device_attribute *mattr,
					 char *buf)
6
{
7
	struct mem_ctl_info *mci = to_mci(dev);
8 9 10 11
	struct amd64_pvt *pvt = mci->pvt_info;
	return sprintf(buf, "0x%x\n", pvt->injection.section);
}

12 13 14 15 16 17
/*
 * store error injection section value which refers to one of 4 16-byte sections
 * within a 64-byte cacheline
 *
 * range: 0..3
 */
18 19
static ssize_t amd64_inject_section_store(struct device *dev,
					  struct device_attribute *mattr,
20 21
					  const char *data, size_t count)
{
22
	struct mem_ctl_info *mci = to_mci(dev);
23 24 25 26 27 28
	struct amd64_pvt *pvt = mci->pvt_info;
	unsigned long value;
	int ret = 0;

	ret = strict_strtoul(data, 10, &value);
	if (ret != -EINVAL) {
29 30

		if (value > 3) {
31
			amd64_warn("%s: invalid section 0x%lx\n", __func__, value);
32 33 34
			return -EINVAL;
		}

35 36 37 38 39 40
		pvt->injection.section = (u32) value;
		return count;
	}
	return ret;
}

41 42 43
static ssize_t amd64_inject_word_show(struct device *dev,
					struct device_attribute *mattr,
					char *buf)
44
{
45
	struct mem_ctl_info *mci = to_mci(dev);
46 47 48 49
	struct amd64_pvt *pvt = mci->pvt_info;
	return sprintf(buf, "0x%x\n", pvt->injection.word);
}

50 51 52 53 54 55
/*
 * 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
 */
56 57 58
static ssize_t amd64_inject_word_store(struct device *dev,
				       struct device_attribute *mattr,
				       const char *data, size_t count)
59
{
60
	struct mem_ctl_info *mci = to_mci(dev);
61 62 63 64 65 66 67
	struct amd64_pvt *pvt = mci->pvt_info;
	unsigned long value;
	int ret = 0;

	ret = strict_strtoul(data, 10, &value);
	if (ret != -EINVAL) {

68
		if (value > 8) {
69
			amd64_warn("%s: invalid word 0x%lx\n", __func__, value);
70 71
			return -EINVAL;
		}
72

73
		pvt->injection.word = (u32) value;
74 75 76 77 78
		return count;
	}
	return ret;
}

79 80 81
static ssize_t amd64_inject_ecc_vector_show(struct device *dev,
					    struct device_attribute *mattr,
					    char *buf)
82
{
83
	struct mem_ctl_info *mci = to_mci(dev);
84 85 86 87
	struct amd64_pvt *pvt = mci->pvt_info;
	return sprintf(buf, "0x%x\n", pvt->injection.bit_map);
}

88 89 90 91 92
/*
 * 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.
 */
93 94 95
static ssize_t amd64_inject_ecc_vector_store(struct device *dev,
				       struct device_attribute *mattr,
				       const char *data, size_t count)
96
{
97
	struct mem_ctl_info *mci = to_mci(dev);
98 99 100 101 102 103 104
	struct amd64_pvt *pvt = mci->pvt_info;
	unsigned long value;
	int ret = 0;

	ret = strict_strtoul(data, 16, &value);
	if (ret != -EINVAL) {

105
		if (value & 0xFFFF0000) {
106 107
			amd64_warn("%s: invalid EccVector: 0x%lx\n",
				   __func__, value);
108 109
			return -EINVAL;
		}
110

111
		pvt->injection.bit_map = (u32) value;
112 113 114 115 116 117 118 119 120
		return count;
	}
	return ret;
}

/*
 * 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.
 */
121 122 123
static ssize_t amd64_inject_read_store(struct device *dev,
				       struct device_attribute *mattr,
				       const char *data, size_t count)
124
{
125
	struct mem_ctl_info *mci = to_mci(dev);
126 127 128 129 130 131 132 133 134 135 136
	struct amd64_pvt *pvt = mci->pvt_info;
	unsigned long value;
	u32 section, word_bits;
	int ret = 0;

	ret = strict_strtoul(data, 10, &value);
	if (ret != -EINVAL) {

		/* Form value to choose 16-byte section of cacheline */
		section = F10_NB_ARRAY_DRAM_ECC |
				SET_NB_ARRAY_ADDRESS(pvt->injection.section);
137
		amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section);
138 139 140 141 142

		word_bits = SET_NB_DRAM_INJECTION_READ(pvt->injection.word,
						pvt->injection.bit_map);

		/* Issue 'word' and 'bit' along with the READ request */
143
		amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
144

145 146
		edac_dbg(0, "section=0x%x word_bits=0x%x\n",
			 section, word_bits);
147 148 149 150 151 152 153 154 155 156

		return count;
	}
	return ret;
}

/*
 * Do a DRAM ECC write. Assemble staged values in the pvt area and format into
 * fields needed by the injection registers.
 */
157 158
static ssize_t amd64_inject_write_store(struct device *dev,
					struct device_attribute *mattr,
159 160
					const char *data, size_t count)
{
161
	struct mem_ctl_info *mci = to_mci(dev);
162 163 164 165 166 167 168 169 170 171 172
	struct amd64_pvt *pvt = mci->pvt_info;
	unsigned long value;
	u32 section, word_bits;
	int ret = 0;

	ret = strict_strtoul(data, 10, &value);
	if (ret != -EINVAL) {

		/* Form value to choose 16-byte section of cacheline */
		section = F10_NB_ARRAY_DRAM_ECC |
				SET_NB_ARRAY_ADDRESS(pvt->injection.section);
173
		amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_ADDR, section);
174 175 176 177 178

		word_bits = SET_NB_DRAM_INJECTION_WRITE(pvt->injection.word,
						pvt->injection.bit_map);

		/* Issue 'word' and 'bit' along with the READ request */
179
		amd64_write_pci_cfg(pvt->F3, F10_NB_ARRAY_DATA, word_bits);
180

181 182
		edac_dbg(0, "section=0x%x word_bits=0x%x\n",
			 section, word_bits);
183 184 185 186 187 188 189 190 191

		return count;
	}
	return ret;
}

/*
 * update NUM_INJ_ATTRS in case you add new members
 */
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235

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);
static DEVICE_ATTR(inject_write, S_IRUGO | S_IWUSR,
		   NULL, amd64_inject_write_store);
static DEVICE_ATTR(inject_read, S_IRUGO | S_IWUSR,
		   NULL, amd64_inject_read_store);


int amd64_create_sysfs_inject_files(struct mem_ctl_info *mci)
{
	int rc;

	rc = device_create_file(&mci->dev, &dev_attr_inject_section);
	if (rc < 0)
		return rc;
	rc = device_create_file(&mci->dev, &dev_attr_inject_word);
	if (rc < 0)
		return rc;
	rc = device_create_file(&mci->dev, &dev_attr_inject_ecc_vector);
	if (rc < 0)
		return rc;
	rc = device_create_file(&mci->dev, &dev_attr_inject_write);
	if (rc < 0)
		return rc;
	rc = device_create_file(&mci->dev, &dev_attr_inject_read);
	if (rc < 0)
		return rc;

	return 0;
}

void amd64_remove_sysfs_inject_files(struct mem_ctl_info *mci)
{
	device_remove_file(&mci->dev, &dev_attr_inject_section);
	device_remove_file(&mci->dev, &dev_attr_inject_word);
	device_remove_file(&mci->dev, &dev_attr_inject_ecc_vector);
	device_remove_file(&mci->dev, &dev_attr_inject_write);
	device_remove_file(&mci->dev, &dev_attr_inject_read);
}