diff options
author | Dmitry Torokhov <dtor_core@ameritech.net> | 2006-04-02 00:08:05 -0500 |
---|---|---|
committer | Dmitry Torokhov <dtor_core@ameritech.net> | 2006-04-02 00:08:05 -0500 |
commit | 95d465fd750897ab32462a6702fbfe1b122cbbc0 (patch) | |
tree | 65c38b2f11c51bb6932e44dd6c92f15b0091abfe /drivers/edac | |
parent | 642fde17dceceb56c7ba2762733ac688666ae657 (diff) | |
parent | 683aa4012f53b2ada0f430487e05d37b0d94e90a (diff) |
Manual merge with Linus.
Conflicts:
arch/powerpc/kernel/setup-common.c
drivers/input/keyboard/hil_kbd.c
drivers/input/mouse/hil_ptr.c
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/Kconfig | 10 | ||||
-rw-r--r-- | drivers/edac/amd76x_edac.c | 126 | ||||
-rw-r--r-- | drivers/edac/e752x_edac.c | 354 | ||||
-rw-r--r-- | drivers/edac/e7xxx_edac.c | 228 | ||||
-rw-r--r-- | drivers/edac/edac_mc.c | 854 | ||||
-rw-r--r-- | drivers/edac/edac_mc.h | 133 | ||||
-rw-r--r-- | drivers/edac/i82860_edac.c | 127 | ||||
-rw-r--r-- | drivers/edac/i82875p_edac.c | 208 | ||||
-rw-r--r-- | drivers/edac/r82600_edac.c | 140 |
9 files changed, 1030 insertions, 1150 deletions
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 52f3eb45d2b9..4f0898400c6d 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig | |||
@@ -64,35 +64,35 @@ config EDAC_AMD76X | |||
64 | 64 | ||
65 | config EDAC_E7XXX | 65 | config EDAC_E7XXX |
66 | tristate "Intel e7xxx (e7205, e7500, e7501, e7505)" | 66 | tristate "Intel e7xxx (e7205, e7500, e7501, e7505)" |
67 | depends on EDAC_MM_EDAC && PCI | 67 | depends on EDAC_MM_EDAC && PCI && X86_32 |
68 | help | 68 | help |
69 | Support for error detection and correction on the Intel | 69 | Support for error detection and correction on the Intel |
70 | E7205, E7500, E7501 and E7505 server chipsets. | 70 | E7205, E7500, E7501 and E7505 server chipsets. |
71 | 71 | ||
72 | config EDAC_E752X | 72 | config EDAC_E752X |
73 | tristate "Intel e752x (e7520, e7525, e7320)" | 73 | tristate "Intel e752x (e7520, e7525, e7320)" |
74 | depends on EDAC_MM_EDAC && PCI | 74 | depends on EDAC_MM_EDAC && PCI && X86 && HOTPLUG |
75 | help | 75 | help |
76 | Support for error detection and correction on the Intel | 76 | Support for error detection and correction on the Intel |
77 | E7520, E7525, E7320 server chipsets. | 77 | E7520, E7525, E7320 server chipsets. |
78 | 78 | ||
79 | config EDAC_I82875P | 79 | config EDAC_I82875P |
80 | tristate "Intel 82875p (D82875P, E7210)" | 80 | tristate "Intel 82875p (D82875P, E7210)" |
81 | depends on EDAC_MM_EDAC && PCI | 81 | depends on EDAC_MM_EDAC && PCI && X86_32 |
82 | help | 82 | help |
83 | Support for error detection and correction on the Intel | 83 | Support for error detection and correction on the Intel |
84 | DP82785P and E7210 server chipsets. | 84 | DP82785P and E7210 server chipsets. |
85 | 85 | ||
86 | config EDAC_I82860 | 86 | config EDAC_I82860 |
87 | tristate "Intel 82860" | 87 | tristate "Intel 82860" |
88 | depends on EDAC_MM_EDAC && PCI | 88 | depends on EDAC_MM_EDAC && PCI && X86_32 |
89 | help | 89 | help |
90 | Support for error detection and correction on the Intel | 90 | Support for error detection and correction on the Intel |
91 | 82860 chipset. | 91 | 82860 chipset. |
92 | 92 | ||
93 | config EDAC_R82600 | 93 | config EDAC_R82600 |
94 | tristate "Radisys 82600 embedded chipset" | 94 | tristate "Radisys 82600 embedded chipset" |
95 | depends on EDAC_MM_EDAC | 95 | depends on EDAC_MM_EDAC && PCI && X86_32 |
96 | help | 96 | help |
97 | Support for error detection and correction on the Radisys | 97 | Support for error detection and correction on the Radisys |
98 | 82600 embedded chipset. | 98 | 82600 embedded chipset. |
diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c index 2fcc8120b53c..53423ad6d4a3 100644 --- a/drivers/edac/amd76x_edac.c +++ b/drivers/edac/amd76x_edac.c | |||
@@ -12,25 +12,26 @@ | |||
12 | * | 12 | * |
13 | */ | 13 | */ |
14 | 14 | ||
15 | |||
16 | #include <linux/config.h> | 15 | #include <linux/config.h> |
17 | #include <linux/module.h> | 16 | #include <linux/module.h> |
18 | #include <linux/init.h> | 17 | #include <linux/init.h> |
19 | |||
20 | #include <linux/pci.h> | 18 | #include <linux/pci.h> |
21 | #include <linux/pci_ids.h> | 19 | #include <linux/pci_ids.h> |
22 | |||
23 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
24 | |||
25 | #include "edac_mc.h" | 21 | #include "edac_mc.h" |
26 | 22 | ||
23 | #define amd76x_printk(level, fmt, arg...) \ | ||
24 | edac_printk(level, "amd76x", fmt, ##arg) | ||
25 | |||
26 | #define amd76x_mc_printk(mci, level, fmt, arg...) \ | ||
27 | edac_mc_chipset_printk(mci, level, "amd76x", fmt, ##arg) | ||
27 | 28 | ||
28 | #define AMD76X_NR_CSROWS 8 | 29 | #define AMD76X_NR_CSROWS 8 |
29 | #define AMD76X_NR_CHANS 1 | 30 | #define AMD76X_NR_CHANS 1 |
30 | #define AMD76X_NR_DIMMS 4 | 31 | #define AMD76X_NR_DIMMS 4 |
31 | 32 | ||
32 | |||
33 | /* AMD 76x register addresses - device 0 function 0 - PCI bridge */ | 33 | /* AMD 76x register addresses - device 0 function 0 - PCI bridge */ |
34 | |||
34 | #define AMD76X_ECC_MODE_STATUS 0x48 /* Mode and status of ECC (32b) | 35 | #define AMD76X_ECC_MODE_STATUS 0x48 /* Mode and status of ECC (32b) |
35 | * | 36 | * |
36 | * 31:16 reserved | 37 | * 31:16 reserved |
@@ -42,6 +43,7 @@ | |||
42 | * 7:4 UE cs row | 43 | * 7:4 UE cs row |
43 | * 3:0 CE cs row | 44 | * 3:0 CE cs row |
44 | */ | 45 | */ |
46 | |||
45 | #define AMD76X_DRAM_MODE_STATUS 0x58 /* DRAM Mode and status (32b) | 47 | #define AMD76X_DRAM_MODE_STATUS 0x58 /* DRAM Mode and status (32b) |
46 | * | 48 | * |
47 | * 31:26 clock disable 5 - 0 | 49 | * 31:26 clock disable 5 - 0 |
@@ -56,6 +58,7 @@ | |||
56 | * 15:8 reserved | 58 | * 15:8 reserved |
57 | * 7:0 x4 mode enable 7 - 0 | 59 | * 7:0 x4 mode enable 7 - 0 |
58 | */ | 60 | */ |
61 | |||
59 | #define AMD76X_MEM_BASE_ADDR 0xC0 /* Memory base address (8 x 32b) | 62 | #define AMD76X_MEM_BASE_ADDR 0xC0 /* Memory base address (8 x 32b) |
60 | * | 63 | * |
61 | * 31:23 chip-select base | 64 | * 31:23 chip-select base |
@@ -66,29 +69,28 @@ | |||
66 | * 0 chip-select enable | 69 | * 0 chip-select enable |
67 | */ | 70 | */ |
68 | 71 | ||
69 | |||
70 | struct amd76x_error_info { | 72 | struct amd76x_error_info { |
71 | u32 ecc_mode_status; | 73 | u32 ecc_mode_status; |
72 | }; | 74 | }; |
73 | 75 | ||
74 | |||
75 | enum amd76x_chips { | 76 | enum amd76x_chips { |
76 | AMD761 = 0, | 77 | AMD761 = 0, |
77 | AMD762 | 78 | AMD762 |
78 | }; | 79 | }; |
79 | 80 | ||
80 | |||
81 | struct amd76x_dev_info { | 81 | struct amd76x_dev_info { |
82 | const char *ctl_name; | 82 | const char *ctl_name; |
83 | }; | 83 | }; |
84 | 84 | ||
85 | |||
86 | static const struct amd76x_dev_info amd76x_devs[] = { | 85 | static const struct amd76x_dev_info amd76x_devs[] = { |
87 | [AMD761] = {.ctl_name = "AMD761"}, | 86 | [AMD761] = { |
88 | [AMD762] = {.ctl_name = "AMD762"}, | 87 | .ctl_name = "AMD761" |
88 | }, | ||
89 | [AMD762] = { | ||
90 | .ctl_name = "AMD762" | ||
91 | }, | ||
89 | }; | 92 | }; |
90 | 93 | ||
91 | |||
92 | /** | 94 | /** |
93 | * amd76x_get_error_info - fetch error information | 95 | * amd76x_get_error_info - fetch error information |
94 | * @mci: Memory controller | 96 | * @mci: Memory controller |
@@ -97,23 +99,21 @@ static const struct amd76x_dev_info amd76x_devs[] = { | |||
97 | * Fetch and store the AMD76x ECC status. Clear pending status | 99 | * Fetch and store the AMD76x ECC status. Clear pending status |
98 | * on the chip so that further errors will be reported | 100 | * on the chip so that further errors will be reported |
99 | */ | 101 | */ |
100 | 102 | static void amd76x_get_error_info(struct mem_ctl_info *mci, | |
101 | static void amd76x_get_error_info (struct mem_ctl_info *mci, | 103 | struct amd76x_error_info *info) |
102 | struct amd76x_error_info *info) | ||
103 | { | 104 | { |
104 | pci_read_config_dword(mci->pdev, AMD76X_ECC_MODE_STATUS, | 105 | pci_read_config_dword(mci->pdev, AMD76X_ECC_MODE_STATUS, |
105 | &info->ecc_mode_status); | 106 | &info->ecc_mode_status); |
106 | 107 | ||
107 | if (info->ecc_mode_status & BIT(8)) | 108 | if (info->ecc_mode_status & BIT(8)) |
108 | pci_write_bits32(mci->pdev, AMD76X_ECC_MODE_STATUS, | 109 | pci_write_bits32(mci->pdev, AMD76X_ECC_MODE_STATUS, |
109 | (u32) BIT(8), (u32) BIT(8)); | 110 | (u32) BIT(8), (u32) BIT(8)); |
110 | 111 | ||
111 | if (info->ecc_mode_status & BIT(9)) | 112 | if (info->ecc_mode_status & BIT(9)) |
112 | pci_write_bits32(mci->pdev, AMD76X_ECC_MODE_STATUS, | 113 | pci_write_bits32(mci->pdev, AMD76X_ECC_MODE_STATUS, |
113 | (u32) BIT(9), (u32) BIT(9)); | 114 | (u32) BIT(9), (u32) BIT(9)); |
114 | } | 115 | } |
115 | 116 | ||
116 | |||
117 | /** | 117 | /** |
118 | * amd76x_process_error_info - Error check | 118 | * amd76x_process_error_info - Error check |
119 | * @mci: Memory controller | 119 | * @mci: Memory controller |
@@ -124,8 +124,7 @@ static void amd76x_get_error_info (struct mem_ctl_info *mci, | |||
124 | * A return of 1 indicates an error. Also if handle_errors is true | 124 | * A return of 1 indicates an error. Also if handle_errors is true |
125 | * then attempt to handle and clean up after the error | 125 | * then attempt to handle and clean up after the error |
126 | */ | 126 | */ |
127 | 127 | static int amd76x_process_error_info(struct mem_ctl_info *mci, | |
128 | static int amd76x_process_error_info (struct mem_ctl_info *mci, | ||
129 | struct amd76x_error_info *info, int handle_errors) | 128 | struct amd76x_error_info *info, int handle_errors) |
130 | { | 129 | { |
131 | int error_found; | 130 | int error_found; |
@@ -141,9 +140,8 @@ static int amd76x_process_error_info (struct mem_ctl_info *mci, | |||
141 | 140 | ||
142 | if (handle_errors) { | 141 | if (handle_errors) { |
143 | row = (info->ecc_mode_status >> 4) & 0xf; | 142 | row = (info->ecc_mode_status >> 4) & 0xf; |
144 | edac_mc_handle_ue(mci, | 143 | edac_mc_handle_ue(mci, mci->csrows[row].first_page, 0, |
145 | mci->csrows[row].first_page, 0, row, | 144 | row, mci->ctl_name); |
146 | mci->ctl_name); | ||
147 | } | 145 | } |
148 | } | 146 | } |
149 | 147 | ||
@@ -155,11 +153,11 @@ static int amd76x_process_error_info (struct mem_ctl_info *mci, | |||
155 | 153 | ||
156 | if (handle_errors) { | 154 | if (handle_errors) { |
157 | row = info->ecc_mode_status & 0xf; | 155 | row = info->ecc_mode_status & 0xf; |
158 | edac_mc_handle_ce(mci, | 156 | edac_mc_handle_ce(mci, mci->csrows[row].first_page, 0, |
159 | mci->csrows[row].first_page, 0, 0, row, 0, | 157 | 0, row, 0, mci->ctl_name); |
160 | mci->ctl_name); | ||
161 | } | 158 | } |
162 | } | 159 | } |
160 | |||
163 | return error_found; | 161 | return error_found; |
164 | } | 162 | } |
165 | 163 | ||
@@ -170,16 +168,14 @@ static int amd76x_process_error_info (struct mem_ctl_info *mci, | |||
170 | * Called by the poll handlers this function reads the status | 168 | * Called by the poll handlers this function reads the status |
171 | * from the controller and checks for errors. | 169 | * from the controller and checks for errors. |
172 | */ | 170 | */ |
173 | |||
174 | static void amd76x_check(struct mem_ctl_info *mci) | 171 | static void amd76x_check(struct mem_ctl_info *mci) |
175 | { | 172 | { |
176 | struct amd76x_error_info info; | 173 | struct amd76x_error_info info; |
177 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 174 | debugf3("%s()\n", __func__); |
178 | amd76x_get_error_info(mci, &info); | 175 | amd76x_get_error_info(mci, &info); |
179 | amd76x_process_error_info(mci, &info, 1); | 176 | amd76x_process_error_info(mci, &info, 1); |
180 | } | 177 | } |
181 | 178 | ||
182 | |||
183 | /** | 179 | /** |
184 | * amd76x_probe1 - Perform set up for detected device | 180 | * amd76x_probe1 - Perform set up for detected device |
185 | * @pdev; PCI device detected | 181 | * @pdev; PCI device detected |
@@ -189,7 +185,6 @@ static void amd76x_check(struct mem_ctl_info *mci) | |||
189 | * controller status reporting. We configure and set up the | 185 | * controller status reporting. We configure and set up the |
190 | * memory controller reporting and claim the device. | 186 | * memory controller reporting and claim the device. |
191 | */ | 187 | */ |
192 | |||
193 | static int amd76x_probe1(struct pci_dev *pdev, int dev_idx) | 188 | static int amd76x_probe1(struct pci_dev *pdev, int dev_idx) |
194 | { | 189 | { |
195 | int rc = -ENODEV; | 190 | int rc = -ENODEV; |
@@ -203,12 +198,11 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx) | |||
203 | }; | 198 | }; |
204 | u32 ems; | 199 | u32 ems; |
205 | u32 ems_mode; | 200 | u32 ems_mode; |
201 | struct amd76x_error_info discard; | ||
206 | 202 | ||
207 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | 203 | debugf0("%s()\n", __func__); |
208 | |||
209 | pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &ems); | 204 | pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &ems); |
210 | ems_mode = (ems >> 10) & 0x3; | 205 | ems_mode = (ems >> 10) & 0x3; |
211 | |||
212 | mci = edac_mc_alloc(0, AMD76X_NR_CSROWS, AMD76X_NR_CHANS); | 206 | mci = edac_mc_alloc(0, AMD76X_NR_CSROWS, AMD76X_NR_CHANS); |
213 | 207 | ||
214 | if (mci == NULL) { | 208 | if (mci == NULL) { |
@@ -216,16 +210,13 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx) | |||
216 | goto fail; | 210 | goto fail; |
217 | } | 211 | } |
218 | 212 | ||
219 | debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); | 213 | debugf0("%s(): mci = %p\n", __func__, mci); |
220 | 214 | mci->pdev = pdev; | |
221 | mci->pdev = pci_dev_get(pdev); | ||
222 | mci->mtype_cap = MEM_FLAG_RDDR; | 215 | mci->mtype_cap = MEM_FLAG_RDDR; |
223 | |||
224 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; | 216 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; |
225 | mci->edac_cap = ems_mode ? | 217 | mci->edac_cap = ems_mode ? |
226 | (EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_NONE; | 218 | (EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_NONE; |
227 | 219 | mci->mod_name = EDAC_MOD_STR; | |
228 | mci->mod_name = BS_MOD_STR; | ||
229 | mci->mod_ver = "$Revision: 1.4.2.5 $"; | 220 | mci->mod_ver = "$Revision: 1.4.2.5 $"; |
230 | mci->ctl_name = amd76x_devs[dev_idx].ctl_name; | 221 | mci->ctl_name = amd76x_devs[dev_idx].ctl_name; |
231 | mci->edac_check = amd76x_check; | 222 | mci->edac_check = amd76x_check; |
@@ -240,18 +231,15 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx) | |||
240 | 231 | ||
241 | /* find the DRAM Chip Select Base address and mask */ | 232 | /* find the DRAM Chip Select Base address and mask */ |
242 | pci_read_config_dword(mci->pdev, | 233 | pci_read_config_dword(mci->pdev, |
243 | AMD76X_MEM_BASE_ADDR + (index * 4), | 234 | AMD76X_MEM_BASE_ADDR + (index * 4), &mba); |
244 | &mba); | ||
245 | 235 | ||
246 | if (!(mba & BIT(0))) | 236 | if (!(mba & BIT(0))) |
247 | continue; | 237 | continue; |
248 | 238 | ||
249 | mba_base = mba & 0xff800000UL; | 239 | mba_base = mba & 0xff800000UL; |
250 | mba_mask = ((mba & 0xff80) << 16) | 0x7fffffUL; | 240 | mba_mask = ((mba & 0xff80) << 16) | 0x7fffffUL; |
251 | |||
252 | pci_read_config_dword(mci->pdev, AMD76X_DRAM_MODE_STATUS, | 241 | pci_read_config_dword(mci->pdev, AMD76X_DRAM_MODE_STATUS, |
253 | &dms); | 242 | &dms); |
254 | |||
255 | csrow->first_page = mba_base >> PAGE_SHIFT; | 243 | csrow->first_page = mba_base >> PAGE_SHIFT; |
256 | csrow->nr_pages = (mba_mask + 1) >> PAGE_SHIFT; | 244 | csrow->nr_pages = (mba_mask + 1) >> PAGE_SHIFT; |
257 | csrow->last_page = csrow->first_page + csrow->nr_pages - 1; | 245 | csrow->last_page = csrow->first_page + csrow->nr_pages - 1; |
@@ -262,40 +250,33 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx) | |||
262 | csrow->edac_mode = ems_modes[ems_mode]; | 250 | csrow->edac_mode = ems_modes[ems_mode]; |
263 | } | 251 | } |
264 | 252 | ||
265 | /* clear counters */ | 253 | amd76x_get_error_info(mci, &discard); /* clear counters */ |
266 | pci_write_bits32(mci->pdev, AMD76X_ECC_MODE_STATUS, (u32) (0x3 << 8), | ||
267 | (u32) (0x3 << 8)); | ||
268 | 254 | ||
269 | if (edac_mc_add_mc(mci)) { | 255 | if (edac_mc_add_mc(mci)) { |
270 | debugf3("MC: " __FILE__ | 256 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); |
271 | ": %s(): failed edac_mc_add_mc()\n", __func__); | ||
272 | goto fail; | 257 | goto fail; |
273 | } | 258 | } |
274 | 259 | ||
275 | /* get this far and it's successful */ | 260 | /* get this far and it's successful */ |
276 | debugf3("MC: " __FILE__ ": %s(): success\n", __func__); | 261 | debugf3("%s(): success\n", __func__); |
277 | return 0; | 262 | return 0; |
278 | 263 | ||
279 | fail: | 264 | fail: |
280 | if (mci) { | 265 | if (mci != NULL) |
281 | if(mci->pdev) | ||
282 | pci_dev_put(mci->pdev); | ||
283 | edac_mc_free(mci); | 266 | edac_mc_free(mci); |
284 | } | ||
285 | return rc; | 267 | return rc; |
286 | } | 268 | } |
287 | 269 | ||
288 | /* returns count (>= 0), or negative on error */ | 270 | /* returns count (>= 0), or negative on error */ |
289 | static int __devinit amd76x_init_one(struct pci_dev *pdev, | 271 | static int __devinit amd76x_init_one(struct pci_dev *pdev, |
290 | const struct pci_device_id *ent) | 272 | const struct pci_device_id *ent) |
291 | { | 273 | { |
292 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | 274 | debugf0("%s()\n", __func__); |
293 | 275 | ||
294 | /* don't need to call pci_device_enable() */ | 276 | /* don't need to call pci_device_enable() */ |
295 | return amd76x_probe1(pdev, ent->driver_data); | 277 | return amd76x_probe1(pdev, ent->driver_data); |
296 | } | 278 | } |
297 | 279 | ||
298 | |||
299 | /** | 280 | /** |
300 | * amd76x_remove_one - driver shutdown | 281 | * amd76x_remove_one - driver shutdown |
301 | * @pdev: PCI device being handed back | 282 | * @pdev: PCI device being handed back |
@@ -304,35 +285,36 @@ static int __devinit amd76x_init_one(struct pci_dev *pdev, | |||
304 | * structure for the device then delete the mci and free the | 285 | * structure for the device then delete the mci and free the |
305 | * resources. | 286 | * resources. |
306 | */ | 287 | */ |
307 | |||
308 | static void __devexit amd76x_remove_one(struct pci_dev *pdev) | 288 | static void __devexit amd76x_remove_one(struct pci_dev *pdev) |
309 | { | 289 | { |
310 | struct mem_ctl_info *mci; | 290 | struct mem_ctl_info *mci; |
311 | 291 | ||
312 | debugf0(__FILE__ ": %s()\n", __func__); | 292 | debugf0("%s()\n", __func__); |
313 | 293 | ||
314 | if ((mci = edac_mc_find_mci_by_pdev(pdev)) == NULL) | 294 | if ((mci = edac_mc_del_mc(pdev)) == NULL) |
315 | return; | 295 | return; |
316 | if (edac_mc_del_mc(mci)) | 296 | |
317 | return; | ||
318 | pci_dev_put(mci->pdev); | ||
319 | edac_mc_free(mci); | 297 | edac_mc_free(mci); |
320 | } | 298 | } |
321 | 299 | ||
322 | |||
323 | static const struct pci_device_id amd76x_pci_tbl[] __devinitdata = { | 300 | static const struct pci_device_id amd76x_pci_tbl[] __devinitdata = { |
324 | {PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 301 | { |
325 | AMD762}, | 302 | PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
326 | {PCI_VEND_DEV(AMD, FE_GATE_700E), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 303 | AMD762 |
327 | AMD761}, | 304 | }, |
328 | {0,} /* 0 terminated list. */ | 305 | { |
306 | PCI_VEND_DEV(AMD, FE_GATE_700E), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | ||
307 | AMD761 | ||
308 | }, | ||
309 | { | ||
310 | 0, | ||
311 | } /* 0 terminated list. */ | ||
329 | }; | 312 | }; |
330 | 313 | ||
331 | MODULE_DEVICE_TABLE(pci, amd76x_pci_tbl); | 314 | MODULE_DEVICE_TABLE(pci, amd76x_pci_tbl); |
332 | 315 | ||
333 | |||
334 | static struct pci_driver amd76x_driver = { | 316 | static struct pci_driver amd76x_driver = { |
335 | .name = BS_MOD_STR, | 317 | .name = EDAC_MOD_STR, |
336 | .probe = amd76x_init_one, | 318 | .probe = amd76x_init_one, |
337 | .remove = __devexit_p(amd76x_remove_one), | 319 | .remove = __devexit_p(amd76x_remove_one), |
338 | .id_table = amd76x_pci_tbl, | 320 | .id_table = amd76x_pci_tbl, |
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index c454ded2b060..66572c5323ad 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c | |||
@@ -17,18 +17,19 @@ | |||
17 | * | 17 | * |
18 | */ | 18 | */ |
19 | 19 | ||
20 | |||
21 | #include <linux/config.h> | 20 | #include <linux/config.h> |
22 | #include <linux/module.h> | 21 | #include <linux/module.h> |
23 | #include <linux/init.h> | 22 | #include <linux/init.h> |
24 | |||
25 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
26 | #include <linux/pci_ids.h> | 24 | #include <linux/pci_ids.h> |
27 | |||
28 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
29 | |||
30 | #include "edac_mc.h" | 26 | #include "edac_mc.h" |
31 | 27 | ||
28 | #define e752x_printk(level, fmt, arg...) \ | ||
29 | edac_printk(level, "e752x", fmt, ##arg) | ||
30 | |||
31 | #define e752x_mc_printk(mci, level, fmt, arg...) \ | ||
32 | edac_mc_chipset_printk(mci, level, "e752x", fmt, ##arg) | ||
32 | 33 | ||
33 | #ifndef PCI_DEVICE_ID_INTEL_7520_0 | 34 | #ifndef PCI_DEVICE_ID_INTEL_7520_0 |
34 | #define PCI_DEVICE_ID_INTEL_7520_0 0x3590 | 35 | #define PCI_DEVICE_ID_INTEL_7520_0 0x3590 |
@@ -56,7 +57,6 @@ | |||
56 | 57 | ||
57 | #define E752X_NR_CSROWS 8 /* number of csrows */ | 58 | #define E752X_NR_CSROWS 8 /* number of csrows */ |
58 | 59 | ||
59 | |||
60 | /* E752X register addresses - device 0 function 0 */ | 60 | /* E752X register addresses - device 0 function 0 */ |
61 | #define E752X_DRB 0x60 /* DRAM row boundary register (8b) */ | 61 | #define E752X_DRB 0x60 /* DRAM row boundary register (8b) */ |
62 | #define E752X_DRA 0x70 /* DRAM row attribute register (8b) */ | 62 | #define E752X_DRA 0x70 /* DRAM row attribute register (8b) */ |
@@ -156,7 +156,6 @@ enum e752x_chips { | |||
156 | E7320 = 2 | 156 | E7320 = 2 |
157 | }; | 157 | }; |
158 | 158 | ||
159 | |||
160 | struct e752x_pvt { | 159 | struct e752x_pvt { |
161 | struct pci_dev *bridge_ck; | 160 | struct pci_dev *bridge_ck; |
162 | struct pci_dev *dev_d0f0; | 161 | struct pci_dev *dev_d0f0; |
@@ -170,9 +169,9 @@ struct e752x_pvt { | |||
170 | const struct e752x_dev_info *dev_info; | 169 | const struct e752x_dev_info *dev_info; |
171 | }; | 170 | }; |
172 | 171 | ||
173 | |||
174 | struct e752x_dev_info { | 172 | struct e752x_dev_info { |
175 | u16 err_dev; | 173 | u16 err_dev; |
174 | u16 ctl_dev; | ||
176 | const char *ctl_name; | 175 | const char *ctl_name; |
177 | }; | 176 | }; |
178 | 177 | ||
@@ -198,38 +197,47 @@ struct e752x_error_info { | |||
198 | 197 | ||
199 | static const struct e752x_dev_info e752x_devs[] = { | 198 | static const struct e752x_dev_info e752x_devs[] = { |
200 | [E7520] = { | 199 | [E7520] = { |
201 | .err_dev = PCI_DEVICE_ID_INTEL_7520_1_ERR, | 200 | .err_dev = PCI_DEVICE_ID_INTEL_7520_1_ERR, |
202 | .ctl_name = "E7520"}, | 201 | .ctl_dev = PCI_DEVICE_ID_INTEL_7520_0, |
202 | .ctl_name = "E7520" | ||
203 | }, | ||
203 | [E7525] = { | 204 | [E7525] = { |
204 | .err_dev = PCI_DEVICE_ID_INTEL_7525_1_ERR, | 205 | .err_dev = PCI_DEVICE_ID_INTEL_7525_1_ERR, |
205 | .ctl_name = "E7525"}, | 206 | .ctl_dev = PCI_DEVICE_ID_INTEL_7525_0, |
207 | .ctl_name = "E7525" | ||
208 | }, | ||
206 | [E7320] = { | 209 | [E7320] = { |
207 | .err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR, | 210 | .err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR, |
208 | .ctl_name = "E7320"}, | 211 | .ctl_dev = PCI_DEVICE_ID_INTEL_7320_0, |
212 | .ctl_name = "E7320" | ||
213 | }, | ||
209 | }; | 214 | }; |
210 | 215 | ||
211 | |||
212 | static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, | 216 | static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, |
213 | unsigned long page) | 217 | unsigned long page) |
214 | { | 218 | { |
215 | u32 remap; | 219 | u32 remap; |
216 | struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; | 220 | struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; |
217 | 221 | ||
218 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 222 | debugf3("%s()\n", __func__); |
219 | 223 | ||
220 | if (page < pvt->tolm) | 224 | if (page < pvt->tolm) |
221 | return page; | 225 | return page; |
226 | |||
222 | if ((page >= 0x100000) && (page < pvt->remapbase)) | 227 | if ((page >= 0x100000) && (page < pvt->remapbase)) |
223 | return page; | 228 | return page; |
229 | |||
224 | remap = (page - pvt->tolm) + pvt->remapbase; | 230 | remap = (page - pvt->tolm) + pvt->remapbase; |
231 | |||
225 | if (remap < pvt->remaplimit) | 232 | if (remap < pvt->remaplimit) |
226 | return remap; | 233 | return remap; |
227 | printk(KERN_ERR "Invalid page %lx - out of range\n", page); | 234 | |
235 | e752x_printk(KERN_ERR, "Invalid page %lx - out of range\n", page); | ||
228 | return pvt->tolm - 1; | 236 | return pvt->tolm - 1; |
229 | } | 237 | } |
230 | 238 | ||
231 | static void do_process_ce(struct mem_ctl_info *mci, u16 error_one, | 239 | static void do_process_ce(struct mem_ctl_info *mci, u16 error_one, |
232 | u32 sec1_add, u16 sec1_syndrome) | 240 | u32 sec1_add, u16 sec1_syndrome) |
233 | { | 241 | { |
234 | u32 page; | 242 | u32 page; |
235 | int row; | 243 | int row; |
@@ -237,7 +245,7 @@ static void do_process_ce(struct mem_ctl_info *mci, u16 error_one, | |||
237 | int i; | 245 | int i; |
238 | struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; | 246 | struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; |
239 | 247 | ||
240 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 248 | debugf3("%s()\n", __func__); |
241 | 249 | ||
242 | /* convert the addr to 4k page */ | 250 | /* convert the addr to 4k page */ |
243 | page = sec1_add >> (PAGE_SHIFT - 4); | 251 | page = sec1_add >> (PAGE_SHIFT - 4); |
@@ -246,36 +254,37 @@ static void do_process_ce(struct mem_ctl_info *mci, u16 error_one, | |||
246 | if (pvt->mc_symmetric) { | 254 | if (pvt->mc_symmetric) { |
247 | /* chip select are bits 14 & 13 */ | 255 | /* chip select are bits 14 & 13 */ |
248 | row = ((page >> 1) & 3); | 256 | row = ((page >> 1) & 3); |
249 | printk(KERN_WARNING | 257 | e752x_printk(KERN_WARNING, |
250 | "Test row %d Table %d %d %d %d %d %d %d %d\n", | 258 | "Test row %d Table %d %d %d %d %d %d %d %d\n", row, |
251 | row, pvt->map[0], pvt->map[1], pvt->map[2], | 259 | pvt->map[0], pvt->map[1], pvt->map[2], pvt->map[3], |
252 | pvt->map[3], pvt->map[4], pvt->map[5], | 260 | pvt->map[4], pvt->map[5], pvt->map[6], pvt->map[7]); |
253 | pvt->map[6], pvt->map[7]); | ||
254 | 261 | ||
255 | /* test for channel remapping */ | 262 | /* test for channel remapping */ |
256 | for (i = 0; i < 8; i++) { | 263 | for (i = 0; i < 8; i++) { |
257 | if (pvt->map[i] == row) | 264 | if (pvt->map[i] == row) |
258 | break; | 265 | break; |
259 | } | 266 | } |
260 | printk(KERN_WARNING "Test computed row %d\n", i); | 267 | |
268 | e752x_printk(KERN_WARNING, "Test computed row %d\n", i); | ||
269 | |||
261 | if (i < 8) | 270 | if (i < 8) |
262 | row = i; | 271 | row = i; |
263 | else | 272 | else |
264 | printk(KERN_WARNING | 273 | e752x_mc_printk(mci, KERN_WARNING, |
265 | "MC%d: row %d not found in remap table\n", | 274 | "row %d not found in remap table\n", row); |
266 | mci->mc_idx, row); | ||
267 | } else | 275 | } else |
268 | row = edac_mc_find_csrow_by_page(mci, page); | 276 | row = edac_mc_find_csrow_by_page(mci, page); |
277 | |||
269 | /* 0 = channel A, 1 = channel B */ | 278 | /* 0 = channel A, 1 = channel B */ |
270 | channel = !(error_one & 1); | 279 | channel = !(error_one & 1); |
271 | 280 | ||
272 | if (!pvt->map_type) | 281 | if (!pvt->map_type) |
273 | row = 7 - row; | 282 | row = 7 - row; |
283 | |||
274 | edac_mc_handle_ce(mci, page, 0, sec1_syndrome, row, channel, | 284 | edac_mc_handle_ce(mci, page, 0, sec1_syndrome, row, channel, |
275 | "e752x CE"); | 285 | "e752x CE"); |
276 | } | 286 | } |
277 | 287 | ||
278 | |||
279 | static inline void process_ce(struct mem_ctl_info *mci, u16 error_one, | 288 | static inline void process_ce(struct mem_ctl_info *mci, u16 error_one, |
280 | u32 sec1_add, u16 sec1_syndrome, int *error_found, | 289 | u32 sec1_add, u16 sec1_syndrome, int *error_found, |
281 | int handle_error) | 290 | int handle_error) |
@@ -286,36 +295,42 @@ static inline void process_ce(struct mem_ctl_info *mci, u16 error_one, | |||
286 | do_process_ce(mci, error_one, sec1_add, sec1_syndrome); | 295 | do_process_ce(mci, error_one, sec1_add, sec1_syndrome); |
287 | } | 296 | } |
288 | 297 | ||
289 | static void do_process_ue(struct mem_ctl_info *mci, u16 error_one, u32 ded_add, | 298 | static void do_process_ue(struct mem_ctl_info *mci, u16 error_one, |
290 | u32 scrb_add) | 299 | u32 ded_add, u32 scrb_add) |
291 | { | 300 | { |
292 | u32 error_2b, block_page; | 301 | u32 error_2b, block_page; |
293 | int row; | 302 | int row; |
294 | struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; | 303 | struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; |
295 | 304 | ||
296 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 305 | debugf3("%s()\n", __func__); |
297 | 306 | ||
298 | if (error_one & 0x0202) { | 307 | if (error_one & 0x0202) { |
299 | error_2b = ded_add; | 308 | error_2b = ded_add; |
309 | |||
300 | /* convert to 4k address */ | 310 | /* convert to 4k address */ |
301 | block_page = error_2b >> (PAGE_SHIFT - 4); | 311 | block_page = error_2b >> (PAGE_SHIFT - 4); |
312 | |||
302 | row = pvt->mc_symmetric ? | 313 | row = pvt->mc_symmetric ? |
303 | /* chip select are bits 14 & 13 */ | 314 | /* chip select are bits 14 & 13 */ |
304 | ((block_page >> 1) & 3) : | 315 | ((block_page >> 1) & 3) : |
305 | edac_mc_find_csrow_by_page(mci, block_page); | 316 | edac_mc_find_csrow_by_page(mci, block_page); |
317 | |||
306 | edac_mc_handle_ue(mci, block_page, 0, row, | 318 | edac_mc_handle_ue(mci, block_page, 0, row, |
307 | "e752x UE from Read"); | 319 | "e752x UE from Read"); |
308 | } | 320 | } |
309 | if (error_one & 0x0404) { | 321 | if (error_one & 0x0404) { |
310 | error_2b = scrb_add; | 322 | error_2b = scrb_add; |
323 | |||
311 | /* convert to 4k address */ | 324 | /* convert to 4k address */ |
312 | block_page = error_2b >> (PAGE_SHIFT - 4); | 325 | block_page = error_2b >> (PAGE_SHIFT - 4); |
326 | |||
313 | row = pvt->mc_symmetric ? | 327 | row = pvt->mc_symmetric ? |
314 | /* chip select are bits 14 & 13 */ | 328 | /* chip select are bits 14 & 13 */ |
315 | ((block_page >> 1) & 3) : | 329 | ((block_page >> 1) & 3) : |
316 | edac_mc_find_csrow_by_page(mci, block_page); | 330 | edac_mc_find_csrow_by_page(mci, block_page); |
331 | |||
317 | edac_mc_handle_ue(mci, block_page, 0, row, | 332 | edac_mc_handle_ue(mci, block_page, 0, row, |
318 | "e752x UE from Scruber"); | 333 | "e752x UE from Scruber"); |
319 | } | 334 | } |
320 | } | 335 | } |
321 | 336 | ||
@@ -336,7 +351,7 @@ static inline void process_ue_no_info_wr(struct mem_ctl_info *mci, | |||
336 | if (!handle_error) | 351 | if (!handle_error) |
337 | return; | 352 | return; |
338 | 353 | ||
339 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 354 | debugf3("%s()\n", __func__); |
340 | edac_mc_handle_ue_no_info(mci, "e752x UE log memory write"); | 355 | edac_mc_handle_ue_no_info(mci, "e752x UE log memory write"); |
341 | } | 356 | } |
342 | 357 | ||
@@ -348,13 +363,13 @@ static void do_process_ded_retry(struct mem_ctl_info *mci, u16 error, | |||
348 | struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; | 363 | struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info; |
349 | 364 | ||
350 | error_1b = retry_add; | 365 | error_1b = retry_add; |
351 | page = error_1b >> (PAGE_SHIFT - 4); /* convert the addr to 4k page */ | 366 | page = error_1b >> (PAGE_SHIFT - 4); /* convert the addr to 4k page */ |
352 | row = pvt->mc_symmetric ? | 367 | row = pvt->mc_symmetric ? |
353 | ((page >> 1) & 3) : /* chip select are bits 14 & 13 */ | 368 | ((page >> 1) & 3) : /* chip select are bits 14 & 13 */ |
354 | edac_mc_find_csrow_by_page(mci, page); | 369 | edac_mc_find_csrow_by_page(mci, page); |
355 | printk(KERN_WARNING | 370 | e752x_mc_printk(mci, KERN_WARNING, |
356 | "MC%d: CE page 0x%lx, row %d : Memory read retry\n", | 371 | "CE page 0x%lx, row %d : Memory read retry\n", |
357 | mci->mc_idx, (long unsigned int) page, row); | 372 | (long unsigned int) page, row); |
358 | } | 373 | } |
359 | 374 | ||
360 | static inline void process_ded_retry(struct mem_ctl_info *mci, u16 error, | 375 | static inline void process_ded_retry(struct mem_ctl_info *mci, u16 error, |
@@ -372,8 +387,7 @@ static inline void process_threshold_ce(struct mem_ctl_info *mci, u16 error, | |||
372 | *error_found = 1; | 387 | *error_found = 1; |
373 | 388 | ||
374 | if (handle_error) | 389 | if (handle_error) |
375 | printk(KERN_WARNING "MC%d: Memory threshold CE\n", | 390 | e752x_mc_printk(mci, KERN_WARNING, "Memory threshold CE\n"); |
376 | mci->mc_idx); | ||
377 | } | 391 | } |
378 | 392 | ||
379 | static char *global_message[11] = { | 393 | static char *global_message[11] = { |
@@ -391,8 +405,8 @@ static void do_global_error(int fatal, u32 errors) | |||
391 | 405 | ||
392 | for (i = 0; i < 11; i++) { | 406 | for (i = 0; i < 11; i++) { |
393 | if (errors & (1 << i)) | 407 | if (errors & (1 << i)) |
394 | printk(KERN_WARNING "%sError %s\n", | 408 | e752x_printk(KERN_WARNING, "%sError %s\n", |
395 | fatal_message[fatal], global_message[i]); | 409 | fatal_message[fatal], global_message[i]); |
396 | } | 410 | } |
397 | } | 411 | } |
398 | 412 | ||
@@ -418,8 +432,8 @@ static void do_hub_error(int fatal, u8 errors) | |||
418 | 432 | ||
419 | for (i = 0; i < 7; i++) { | 433 | for (i = 0; i < 7; i++) { |
420 | if (errors & (1 << i)) | 434 | if (errors & (1 << i)) |
421 | printk(KERN_WARNING "%sError %s\n", | 435 | e752x_printk(KERN_WARNING, "%sError %s\n", |
422 | fatal_message[fatal], hub_message[i]); | 436 | fatal_message[fatal], hub_message[i]); |
423 | } | 437 | } |
424 | } | 438 | } |
425 | 439 | ||
@@ -445,8 +459,8 @@ static void do_membuf_error(u8 errors) | |||
445 | 459 | ||
446 | for (i = 0; i < 4; i++) { | 460 | for (i = 0; i < 4; i++) { |
447 | if (errors & (1 << i)) | 461 | if (errors & (1 << i)) |
448 | printk(KERN_WARNING "Non-Fatal Error %s\n", | 462 | e752x_printk(KERN_WARNING, "Non-Fatal Error %s\n", |
449 | membuf_message[i]); | 463 | membuf_message[i]); |
450 | } | 464 | } |
451 | } | 465 | } |
452 | 466 | ||
@@ -458,8 +472,7 @@ static inline void membuf_error(u8 errors, int *error_found, int handle_error) | |||
458 | do_membuf_error(errors); | 472 | do_membuf_error(errors); |
459 | } | 473 | } |
460 | 474 | ||
461 | #if 0 | 475 | static char *sysbus_message[10] = { |
462 | char *sysbus_message[10] = { | ||
463 | "Addr or Request Parity", | 476 | "Addr or Request Parity", |
464 | "Data Strobe Glitch", | 477 | "Data Strobe Glitch", |
465 | "Addr Strobe Glitch", | 478 | "Addr Strobe Glitch", |
@@ -470,7 +483,6 @@ char *sysbus_message[10] = { | |||
470 | "Memory Parity", | 483 | "Memory Parity", |
471 | "IO Subsystem Parity" | 484 | "IO Subsystem Parity" |
472 | }; | 485 | }; |
473 | #endif /* 0 */ | ||
474 | 486 | ||
475 | static void do_sysbus_error(int fatal, u32 errors) | 487 | static void do_sysbus_error(int fatal, u32 errors) |
476 | { | 488 | { |
@@ -478,8 +490,8 @@ static void do_sysbus_error(int fatal, u32 errors) | |||
478 | 490 | ||
479 | for (i = 0; i < 10; i++) { | 491 | for (i = 0; i < 10; i++) { |
480 | if (errors & (1 << i)) | 492 | if (errors & (1 << i)) |
481 | printk(KERN_WARNING "%sError System Bus %s\n", | 493 | e752x_printk(KERN_WARNING, "%sError System Bus %s\n", |
482 | fatal_message[fatal], global_message[i]); | 494 | fatal_message[fatal], sysbus_message[i]); |
483 | } | 495 | } |
484 | } | 496 | } |
485 | 497 | ||
@@ -492,33 +504,42 @@ static inline void sysbus_error(int fatal, u32 errors, int *error_found, | |||
492 | do_sysbus_error(fatal, errors); | 504 | do_sysbus_error(fatal, errors); |
493 | } | 505 | } |
494 | 506 | ||
495 | static void e752x_check_hub_interface (struct e752x_error_info *info, | 507 | static void e752x_check_hub_interface(struct e752x_error_info *info, |
496 | int *error_found, int handle_error) | 508 | int *error_found, int handle_error) |
497 | { | 509 | { |
498 | u8 stat8; | 510 | u8 stat8; |
499 | 511 | ||
500 | //pci_read_config_byte(dev,E752X_HI_FERR,&stat8); | 512 | //pci_read_config_byte(dev,E752X_HI_FERR,&stat8); |
513 | |||
501 | stat8 = info->hi_ferr; | 514 | stat8 = info->hi_ferr; |
515 | |||
502 | if(stat8 & 0x7f) { /* Error, so process */ | 516 | if(stat8 & 0x7f) { /* Error, so process */ |
503 | stat8 &= 0x7f; | 517 | stat8 &= 0x7f; |
518 | |||
504 | if(stat8 & 0x2b) | 519 | if(stat8 & 0x2b) |
505 | hub_error(1, stat8 & 0x2b, error_found, handle_error); | 520 | hub_error(1, stat8 & 0x2b, error_found, handle_error); |
521 | |||
506 | if(stat8 & 0x54) | 522 | if(stat8 & 0x54) |
507 | hub_error(0, stat8 & 0x54, error_found, handle_error); | 523 | hub_error(0, stat8 & 0x54, error_found, handle_error); |
508 | } | 524 | } |
525 | |||
509 | //pci_read_config_byte(dev,E752X_HI_NERR,&stat8); | 526 | //pci_read_config_byte(dev,E752X_HI_NERR,&stat8); |
527 | |||
510 | stat8 = info->hi_nerr; | 528 | stat8 = info->hi_nerr; |
529 | |||
511 | if(stat8 & 0x7f) { /* Error, so process */ | 530 | if(stat8 & 0x7f) { /* Error, so process */ |
512 | stat8 &= 0x7f; | 531 | stat8 &= 0x7f; |
532 | |||
513 | if (stat8 & 0x2b) | 533 | if (stat8 & 0x2b) |
514 | hub_error(1, stat8 & 0x2b, error_found, handle_error); | 534 | hub_error(1, stat8 & 0x2b, error_found, handle_error); |
535 | |||
515 | if(stat8 & 0x54) | 536 | if(stat8 & 0x54) |
516 | hub_error(0, stat8 & 0x54, error_found, handle_error); | 537 | hub_error(0, stat8 & 0x54, error_found, handle_error); |
517 | } | 538 | } |
518 | } | 539 | } |
519 | 540 | ||
520 | static void e752x_check_sysbus (struct e752x_error_info *info, int *error_found, | 541 | static void e752x_check_sysbus(struct e752x_error_info *info, |
521 | int handle_error) | 542 | int *error_found, int handle_error) |
522 | { | 543 | { |
523 | u32 stat32, error32; | 544 | u32 stat32, error32; |
524 | 545 | ||
@@ -530,27 +551,34 @@ static void e752x_check_sysbus (struct e752x_error_info *info, int *error_found, | |||
530 | 551 | ||
531 | error32 = (stat32 >> 16) & 0x3ff; | 552 | error32 = (stat32 >> 16) & 0x3ff; |
532 | stat32 = stat32 & 0x3ff; | 553 | stat32 = stat32 & 0x3ff; |
554 | |||
533 | if(stat32 & 0x083) | 555 | if(stat32 & 0x083) |
534 | sysbus_error(1, stat32 & 0x083, error_found, handle_error); | 556 | sysbus_error(1, stat32 & 0x083, error_found, handle_error); |
557 | |||
535 | if(stat32 & 0x37c) | 558 | if(stat32 & 0x37c) |
536 | sysbus_error(0, stat32 & 0x37c, error_found, handle_error); | 559 | sysbus_error(0, stat32 & 0x37c, error_found, handle_error); |
560 | |||
537 | if(error32 & 0x083) | 561 | if(error32 & 0x083) |
538 | sysbus_error(1, error32 & 0x083, error_found, handle_error); | 562 | sysbus_error(1, error32 & 0x083, error_found, handle_error); |
563 | |||
539 | if(error32 & 0x37c) | 564 | if(error32 & 0x37c) |
540 | sysbus_error(0, error32 & 0x37c, error_found, handle_error); | 565 | sysbus_error(0, error32 & 0x37c, error_found, handle_error); |
541 | } | 566 | } |
542 | 567 | ||
543 | static void e752x_check_membuf (struct e752x_error_info *info, int *error_found, | 568 | static void e752x_check_membuf (struct e752x_error_info *info, |
544 | int handle_error) | 569 | int *error_found, int handle_error) |
545 | { | 570 | { |
546 | u8 stat8; | 571 | u8 stat8; |
547 | 572 | ||
548 | stat8 = info->buf_ferr; | 573 | stat8 = info->buf_ferr; |
574 | |||
549 | if (stat8 & 0x0f) { /* Error, so process */ | 575 | if (stat8 & 0x0f) { /* Error, so process */ |
550 | stat8 &= 0x0f; | 576 | stat8 &= 0x0f; |
551 | membuf_error(stat8, error_found, handle_error); | 577 | membuf_error(stat8, error_found, handle_error); |
552 | } | 578 | } |
579 | |||
553 | stat8 = info->buf_nerr; | 580 | stat8 = info->buf_nerr; |
581 | |||
554 | if (stat8 & 0x0f) { /* Error, so process */ | 582 | if (stat8 & 0x0f) { /* Error, so process */ |
555 | stat8 &= 0x0f; | 583 | stat8 &= 0x0f; |
556 | membuf_error(stat8, error_found, handle_error); | 584 | membuf_error(stat8, error_found, handle_error); |
@@ -558,7 +586,8 @@ static void e752x_check_membuf (struct e752x_error_info *info, int *error_found, | |||
558 | } | 586 | } |
559 | 587 | ||
560 | static void e752x_check_dram (struct mem_ctl_info *mci, | 588 | static void e752x_check_dram (struct mem_ctl_info *mci, |
561 | struct e752x_error_info *info, int *error_found, int handle_error) | 589 | struct e752x_error_info *info, int *error_found, |
590 | int handle_error) | ||
562 | { | 591 | { |
563 | u16 error_one, error_next; | 592 | u16 error_one, error_next; |
564 | 593 | ||
@@ -608,7 +637,7 @@ static void e752x_check_dram (struct mem_ctl_info *mci, | |||
608 | } | 637 | } |
609 | 638 | ||
610 | static void e752x_get_error_info (struct mem_ctl_info *mci, | 639 | static void e752x_get_error_info (struct mem_ctl_info *mci, |
611 | struct e752x_error_info *info) | 640 | struct e752x_error_info *info) |
612 | { | 641 | { |
613 | struct pci_dev *dev; | 642 | struct pci_dev *dev; |
614 | struct e752x_pvt *pvt; | 643 | struct e752x_pvt *pvt; |
@@ -616,7 +645,6 @@ static void e752x_get_error_info (struct mem_ctl_info *mci, | |||
616 | memset(info, 0, sizeof(*info)); | 645 | memset(info, 0, sizeof(*info)); |
617 | pvt = (struct e752x_pvt *) mci->pvt_info; | 646 | pvt = (struct e752x_pvt *) mci->pvt_info; |
618 | dev = pvt->dev_d0f1; | 647 | dev = pvt->dev_d0f1; |
619 | |||
620 | pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global); | 648 | pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global); |
621 | 649 | ||
622 | if (info->ferr_global) { | 650 | if (info->ferr_global) { |
@@ -727,7 +755,8 @@ static int e752x_process_error_info (struct mem_ctl_info *mci, | |||
727 | static void e752x_check(struct mem_ctl_info *mci) | 755 | static void e752x_check(struct mem_ctl_info *mci) |
728 | { | 756 | { |
729 | struct e752x_error_info info; | 757 | struct e752x_error_info info; |
730 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 758 | |
759 | debugf3("%s()\n", __func__); | ||
731 | e752x_get_error_info(mci, &info); | 760 | e752x_get_error_info(mci, &info); |
732 | e752x_process_error_info(mci, &info, 1); | 761 | e752x_process_error_info(mci, &info, 1); |
733 | } | 762 | } |
@@ -736,23 +765,21 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | |||
736 | { | 765 | { |
737 | int rc = -ENODEV; | 766 | int rc = -ENODEV; |
738 | int index; | 767 | int index; |
739 | u16 pci_data, stat; | 768 | u16 pci_data; |
740 | u32 stat32; | ||
741 | u16 stat16; | ||
742 | u8 stat8; | 769 | u8 stat8; |
743 | struct mem_ctl_info *mci = NULL; | 770 | struct mem_ctl_info *mci = NULL; |
744 | struct e752x_pvt *pvt = NULL; | 771 | struct e752x_pvt *pvt = NULL; |
745 | u16 ddrcsr; | 772 | u16 ddrcsr; |
746 | u32 drc; | 773 | u32 drc; |
747 | int drc_chan; /* Number of channels 0=1chan,1=2chan */ | 774 | int drc_chan; /* Number of channels 0=1chan,1=2chan */ |
748 | int drc_drbg; /* DRB granularity 0=64mb,1=128mb */ | 775 | int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */ |
749 | int drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ | 776 | int drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ |
750 | u32 dra; | 777 | u32 dra; |
751 | unsigned long last_cumul_size; | 778 | unsigned long last_cumul_size; |
752 | struct pci_dev *pres_dev; | ||
753 | struct pci_dev *dev = NULL; | 779 | struct pci_dev *dev = NULL; |
780 | struct e752x_error_info discard; | ||
754 | 781 | ||
755 | debugf0("MC: " __FILE__ ": %s(): mci\n", __func__); | 782 | debugf0("%s(): mci\n", __func__); |
756 | debugf0("Starting Probe1\n"); | 783 | debugf0("Starting Probe1\n"); |
757 | 784 | ||
758 | /* enable device 0 function 1 */ | 785 | /* enable device 0 function 1 */ |
@@ -776,34 +803,35 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | |||
776 | goto fail; | 803 | goto fail; |
777 | } | 804 | } |
778 | 805 | ||
779 | debugf3("MC: " __FILE__ ": %s(): init mci\n", __func__); | 806 | debugf3("%s(): init mci\n", __func__); |
780 | |||
781 | mci->mtype_cap = MEM_FLAG_RDDR; | 807 | mci->mtype_cap = MEM_FLAG_RDDR; |
782 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | | 808 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | |
783 | EDAC_FLAG_S4ECD4ED; | 809 | EDAC_FLAG_S4ECD4ED; |
784 | /* FIXME - what if different memory types are in different csrows? */ | 810 | /* FIXME - what if different memory types are in different csrows? */ |
785 | mci->mod_name = BS_MOD_STR; | 811 | mci->mod_name = EDAC_MOD_STR; |
786 | mci->mod_ver = "$Revision: 1.5.2.11 $"; | 812 | mci->mod_ver = "$Revision: 1.5.2.11 $"; |
787 | mci->pdev = pdev; | 813 | mci->pdev = pdev; |
788 | 814 | ||
789 | debugf3("MC: " __FILE__ ": %s(): init pvt\n", __func__); | 815 | debugf3("%s(): init pvt\n", __func__); |
790 | pvt = (struct e752x_pvt *) mci->pvt_info; | 816 | pvt = (struct e752x_pvt *) mci->pvt_info; |
791 | pvt->dev_info = &e752x_devs[dev_idx]; | 817 | pvt->dev_info = &e752x_devs[dev_idx]; |
792 | pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL, | 818 | pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL, |
793 | pvt->dev_info->err_dev, | 819 | pvt->dev_info->err_dev, |
794 | pvt->bridge_ck); | 820 | pvt->bridge_ck); |
821 | |||
795 | if (pvt->bridge_ck == NULL) | 822 | if (pvt->bridge_ck == NULL) |
796 | pvt->bridge_ck = pci_scan_single_device(pdev->bus, | 823 | pvt->bridge_ck = pci_scan_single_device(pdev->bus, |
797 | PCI_DEVFN(0, 1)); | 824 | PCI_DEVFN(0, 1)); |
825 | |||
798 | if (pvt->bridge_ck == NULL) { | 826 | if (pvt->bridge_ck == NULL) { |
799 | printk(KERN_ERR "MC: error reporting device not found:" | 827 | e752x_printk(KERN_ERR, "error reporting device not found:" |
800 | "vendor %x device 0x%x (broken BIOS?)\n", | 828 | "vendor %x device 0x%x (broken BIOS?)\n", |
801 | PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev); | 829 | PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev); |
802 | goto fail; | 830 | goto fail; |
803 | } | 831 | } |
804 | pvt->mc_symmetric = ((ddrcsr & 0x10) != 0); | ||
805 | 832 | ||
806 | debugf3("MC: " __FILE__ ": %s(): more mci init\n", __func__); | 833 | pvt->mc_symmetric = ((ddrcsr & 0x10) != 0); |
834 | debugf3("%s(): more mci init\n", __func__); | ||
807 | mci->ctl_name = pvt->dev_info->ctl_name; | 835 | mci->ctl_name = pvt->dev_info->ctl_name; |
808 | mci->edac_check = e752x_check; | 836 | mci->edac_check = e752x_check; |
809 | mci->ctl_page_to_phys = ctl_page_to_phys; | 837 | mci->ctl_page_to_phys = ctl_page_to_phys; |
@@ -820,6 +848,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | |||
820 | for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { | 848 | for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) { |
821 | u8 value; | 849 | u8 value; |
822 | u32 cumul_size; | 850 | u32 cumul_size; |
851 | |||
823 | /* mem_dev 0=x8, 1=x4 */ | 852 | /* mem_dev 0=x8, 1=x4 */ |
824 | int mem_dev = (dra >> (index * 4 + 2)) & 0x3; | 853 | int mem_dev = (dra >> (index * 4 + 2)) & 0x3; |
825 | struct csrow_info *csrow = &mci->csrows[index]; | 854 | struct csrow_info *csrow = &mci->csrows[index]; |
@@ -828,17 +857,18 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | |||
828 | pci_read_config_byte(mci->pdev, E752X_DRB + index, &value); | 857 | pci_read_config_byte(mci->pdev, E752X_DRB + index, &value); |
829 | /* convert a 128 or 64 MiB DRB to a page size. */ | 858 | /* convert a 128 or 64 MiB DRB to a page size. */ |
830 | cumul_size = value << (25 + drc_drbg - PAGE_SHIFT); | 859 | cumul_size = value << (25 + drc_drbg - PAGE_SHIFT); |
831 | debugf3("MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n", | 860 | debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index, |
832 | __func__, index, cumul_size); | 861 | cumul_size); |
862 | |||
833 | if (cumul_size == last_cumul_size) | 863 | if (cumul_size == last_cumul_size) |
834 | continue; /* not populated */ | 864 | continue; /* not populated */ |
835 | 865 | ||
836 | csrow->first_page = last_cumul_size; | 866 | csrow->first_page = last_cumul_size; |
837 | csrow->last_page = cumul_size - 1; | 867 | csrow->last_page = cumul_size - 1; |
838 | csrow->nr_pages = cumul_size - last_cumul_size; | 868 | csrow->nr_pages = cumul_size - last_cumul_size; |
839 | last_cumul_size = cumul_size; | 869 | last_cumul_size = cumul_size; |
840 | csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */ | 870 | csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */ |
841 | csrow->mtype = MEM_RDDR; /* only one type supported */ | 871 | csrow->mtype = MEM_RDDR; /* only one type supported */ |
842 | csrow->dtype = mem_dev ? DEV_X4 : DEV_X8; | 872 | csrow->dtype = mem_dev ? DEV_X4 : DEV_X8; |
843 | 873 | ||
844 | /* | 874 | /* |
@@ -862,29 +892,32 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | |||
862 | u8 value; | 892 | u8 value; |
863 | u8 last = 0; | 893 | u8 last = 0; |
864 | u8 row = 0; | 894 | u8 row = 0; |
865 | for (index = 0; index < 8; index += 2) { | ||
866 | 895 | ||
896 | for (index = 0; index < 8; index += 2) { | ||
867 | pci_read_config_byte(mci->pdev, E752X_DRB + index, | 897 | pci_read_config_byte(mci->pdev, E752X_DRB + index, |
868 | &value); | 898 | &value); |
899 | |||
869 | /* test if there is a dimm in this slot */ | 900 | /* test if there is a dimm in this slot */ |
870 | if (value == last) { | 901 | if (value == last) { |
871 | /* no dimm in the slot, so flag it as empty */ | 902 | /* no dimm in the slot, so flag it as empty */ |
872 | pvt->map[index] = 0xff; | 903 | pvt->map[index] = 0xff; |
873 | pvt->map[index + 1] = 0xff; | 904 | pvt->map[index + 1] = 0xff; |
874 | } else { /* there is a dimm in the slot */ | 905 | } else { /* there is a dimm in the slot */ |
875 | pvt->map[index] = row; | 906 | pvt->map[index] = row; |
876 | row++; | 907 | row++; |
877 | last = value; | 908 | last = value; |
878 | /* test the next value to see if the dimm is | 909 | /* test the next value to see if the dimm is |
879 | double sided */ | 910 | double sided */ |
880 | pci_read_config_byte(mci->pdev, | 911 | pci_read_config_byte(mci->pdev, |
881 | E752X_DRB + index + 1, | 912 | E752X_DRB + index + 1, |
882 | &value); | 913 | &value); |
883 | pvt->map[index + 1] = (value == last) ? | 914 | pvt->map[index + 1] = (value == last) ? |
884 | 0xff : /* the dimm is single sided, | 915 | 0xff : /* the dimm is single sided, |
885 | so flag as empty */ | 916 | * so flag as empty |
886 | row; /* this is a double sided dimm | 917 | */ |
887 | to save the next row # */ | 918 | row; /* this is a double sided dimm |
919 | * to save the next row # | ||
920 | */ | ||
888 | row++; | 921 | row++; |
889 | last = value; | 922 | last = value; |
890 | } | 923 | } |
@@ -896,9 +929,8 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | |||
896 | pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f)); | 929 | pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f)); |
897 | 930 | ||
898 | mci->edac_cap |= EDAC_FLAG_NONE; | 931 | mci->edac_cap |= EDAC_FLAG_NONE; |
932 | debugf3("%s(): tolm, remapbase, remaplimit\n", __func__); | ||
899 | 933 | ||
900 | debugf3("MC: " __FILE__ ": %s(): tolm, remapbase, remaplimit\n", | ||
901 | __func__); | ||
902 | /* load the top of low memory, remap base, and remap limit vars */ | 934 | /* load the top of low memory, remap base, and remap limit vars */ |
903 | pci_read_config_word(mci->pdev, E752X_TOLM, &pci_data); | 935 | pci_read_config_word(mci->pdev, E752X_TOLM, &pci_data); |
904 | pvt->tolm = ((u32) pci_data) << 4; | 936 | pvt->tolm = ((u32) pci_data) << 4; |
@@ -906,43 +938,18 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | |||
906 | pvt->remapbase = ((u32) pci_data) << 14; | 938 | pvt->remapbase = ((u32) pci_data) << 14; |
907 | pci_read_config_word(mci->pdev, E752X_REMAPLIMIT, &pci_data); | 939 | pci_read_config_word(mci->pdev, E752X_REMAPLIMIT, &pci_data); |
908 | pvt->remaplimit = ((u32) pci_data) << 14; | 940 | pvt->remaplimit = ((u32) pci_data) << 14; |
909 | printk("tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm, | 941 | e752x_printk(KERN_INFO, |
910 | pvt->remapbase, pvt->remaplimit); | 942 | "tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm, |
943 | pvt->remapbase, pvt->remaplimit); | ||
911 | 944 | ||
912 | if (edac_mc_add_mc(mci)) { | 945 | if (edac_mc_add_mc(mci)) { |
913 | debugf3("MC: " __FILE__ | 946 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); |
914 | ": %s(): failed edac_mc_add_mc()\n", | ||
915 | __func__); | ||
916 | goto fail; | 947 | goto fail; |
917 | } | 948 | } |
918 | 949 | ||
919 | /* Walk through the PCI table and clear errors */ | 950 | dev = pci_get_device(PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].ctl_dev, |
920 | switch (dev_idx) { | 951 | NULL); |
921 | case E7520: | ||
922 | dev = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
923 | PCI_DEVICE_ID_INTEL_7520_0, NULL); | ||
924 | break; | ||
925 | case E7525: | ||
926 | dev = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
927 | PCI_DEVICE_ID_INTEL_7525_0, NULL); | ||
928 | break; | ||
929 | case E7320: | ||
930 | dev = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
931 | PCI_DEVICE_ID_INTEL_7320_0, NULL); | ||
932 | break; | ||
933 | } | ||
934 | |||
935 | |||
936 | pvt->dev_d0f0 = dev; | 952 | pvt->dev_d0f0 = dev; |
937 | for (pres_dev = dev; | ||
938 | ((struct pci_dev *) pres_dev->global_list.next != dev); | ||
939 | pres_dev = (struct pci_dev *) pres_dev->global_list.next) { | ||
940 | pci_read_config_dword(pres_dev, PCI_COMMAND, &stat32); | ||
941 | stat = (u16) (stat32 >> 16); | ||
942 | /* clear any error bits */ | ||
943 | if (stat32 & ((1 << 6) + (1 << 8))) | ||
944 | pci_write_config_word(pres_dev, PCI_STATUS, stat); | ||
945 | } | ||
946 | /* find the error reporting device and clear errors */ | 953 | /* find the error reporting device and clear errors */ |
947 | dev = pvt->dev_d0f1 = pci_dev_get(pvt->bridge_ck); | 954 | dev = pvt->dev_d0f1 = pci_dev_get(pvt->bridge_ck); |
948 | /* Turn off error disable & SMI in case the BIOS turned it on */ | 955 | /* Turn off error disable & SMI in case the BIOS turned it on */ |
@@ -954,67 +961,51 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | |||
954 | pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00); | 961 | pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00); |
955 | pci_write_config_byte(dev, E752X_DRAM_ERRMASK, 0x00); | 962 | pci_write_config_byte(dev, E752X_DRAM_ERRMASK, 0x00); |
956 | pci_write_config_byte(dev, E752X_DRAM_SMICMD, 0x00); | 963 | pci_write_config_byte(dev, E752X_DRAM_SMICMD, 0x00); |
957 | /* clear other MCH errors */ | 964 | |
958 | pci_read_config_dword(dev, E752X_FERR_GLOBAL, &stat32); | 965 | e752x_get_error_info(mci, &discard); /* clear other MCH errors */ |
959 | pci_write_config_dword(dev, E752X_FERR_GLOBAL, stat32); | ||
960 | pci_read_config_dword(dev, E752X_NERR_GLOBAL, &stat32); | ||
961 | pci_write_config_dword(dev, E752X_NERR_GLOBAL, stat32); | ||
962 | pci_read_config_byte(dev, E752X_HI_FERR, &stat8); | ||
963 | pci_write_config_byte(dev, E752X_HI_FERR, stat8); | ||
964 | pci_read_config_byte(dev, E752X_HI_NERR, &stat8); | ||
965 | pci_write_config_byte(dev, E752X_HI_NERR, stat8); | ||
966 | pci_read_config_dword(dev, E752X_SYSBUS_FERR, &stat32); | ||
967 | pci_write_config_dword(dev, E752X_SYSBUS_FERR, stat32); | ||
968 | pci_read_config_byte(dev, E752X_BUF_FERR, &stat8); | ||
969 | pci_write_config_byte(dev, E752X_BUF_FERR, stat8); | ||
970 | pci_read_config_byte(dev, E752X_BUF_NERR, &stat8); | ||
971 | pci_write_config_byte(dev, E752X_BUF_NERR, stat8); | ||
972 | pci_read_config_word(dev, E752X_DRAM_FERR, &stat16); | ||
973 | pci_write_config_word(dev, E752X_DRAM_FERR, stat16); | ||
974 | pci_read_config_word(dev, E752X_DRAM_NERR, &stat16); | ||
975 | pci_write_config_word(dev, E752X_DRAM_NERR, stat16); | ||
976 | 966 | ||
977 | /* get this far and it's successful */ | 967 | /* get this far and it's successful */ |
978 | debugf3("MC: " __FILE__ ": %s(): success\n", __func__); | 968 | debugf3("%s(): success\n", __func__); |
979 | return 0; | 969 | return 0; |
980 | 970 | ||
981 | fail: | 971 | fail: |
982 | if (mci) { | 972 | if (mci) { |
983 | if (pvt->dev_d0f0) | 973 | if (pvt->dev_d0f0) |
984 | pci_dev_put(pvt->dev_d0f0); | 974 | pci_dev_put(pvt->dev_d0f0); |
975 | |||
985 | if (pvt->dev_d0f1) | 976 | if (pvt->dev_d0f1) |
986 | pci_dev_put(pvt->dev_d0f1); | 977 | pci_dev_put(pvt->dev_d0f1); |
978 | |||
987 | if (pvt->bridge_ck) | 979 | if (pvt->bridge_ck) |
988 | pci_dev_put(pvt->bridge_ck); | 980 | pci_dev_put(pvt->bridge_ck); |
981 | |||
989 | edac_mc_free(mci); | 982 | edac_mc_free(mci); |
990 | } | 983 | } |
984 | |||
991 | return rc; | 985 | return rc; |
992 | } | 986 | } |
993 | 987 | ||
994 | /* returns count (>= 0), or negative on error */ | 988 | /* returns count (>= 0), or negative on error */ |
995 | static int __devinit e752x_init_one(struct pci_dev *pdev, | 989 | static int __devinit e752x_init_one(struct pci_dev *pdev, |
996 | const struct pci_device_id *ent) | 990 | const struct pci_device_id *ent) |
997 | { | 991 | { |
998 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | 992 | debugf0("%s()\n", __func__); |
999 | 993 | ||
1000 | /* wake up and enable device */ | 994 | /* wake up and enable device */ |
1001 | if(pci_enable_device(pdev) < 0) | 995 | if(pci_enable_device(pdev) < 0) |
1002 | return -EIO; | 996 | return -EIO; |
997 | |||
1003 | return e752x_probe1(pdev, ent->driver_data); | 998 | return e752x_probe1(pdev, ent->driver_data); |
1004 | } | 999 | } |
1005 | 1000 | ||
1006 | |||
1007 | static void __devexit e752x_remove_one(struct pci_dev *pdev) | 1001 | static void __devexit e752x_remove_one(struct pci_dev *pdev) |
1008 | { | 1002 | { |
1009 | struct mem_ctl_info *mci; | 1003 | struct mem_ctl_info *mci; |
1010 | struct e752x_pvt *pvt; | 1004 | struct e752x_pvt *pvt; |
1011 | 1005 | ||
1012 | debugf0(__FILE__ ": %s()\n", __func__); | 1006 | debugf0("%s()\n", __func__); |
1013 | |||
1014 | if ((mci = edac_mc_find_mci_by_pdev(pdev)) == NULL) | ||
1015 | return; | ||
1016 | 1007 | ||
1017 | if (edac_mc_del_mc(mci)) | 1008 | if ((mci = edac_mc_del_mc(pdev)) == NULL) |
1018 | return; | 1009 | return; |
1019 | 1010 | ||
1020 | pvt = (struct e752x_pvt *) mci->pvt_info; | 1011 | pvt = (struct e752x_pvt *) mci->pvt_info; |
@@ -1024,45 +1015,48 @@ static void __devexit e752x_remove_one(struct pci_dev *pdev) | |||
1024 | edac_mc_free(mci); | 1015 | edac_mc_free(mci); |
1025 | } | 1016 | } |
1026 | 1017 | ||
1027 | |||
1028 | static const struct pci_device_id e752x_pci_tbl[] __devinitdata = { | 1018 | static const struct pci_device_id e752x_pci_tbl[] __devinitdata = { |
1029 | {PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 1019 | { |
1030 | E7520}, | 1020 | PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
1031 | {PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 1021 | E7520 |
1032 | E7525}, | 1022 | }, |
1033 | {PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 1023 | { |
1034 | E7320}, | 1024 | PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
1035 | {0,} /* 0 terminated list. */ | 1025 | E7525 |
1026 | }, | ||
1027 | { | ||
1028 | PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | ||
1029 | E7320 | ||
1030 | }, | ||
1031 | { | ||
1032 | 0, | ||
1033 | } /* 0 terminated list. */ | ||
1036 | }; | 1034 | }; |
1037 | 1035 | ||
1038 | MODULE_DEVICE_TABLE(pci, e752x_pci_tbl); | 1036 | MODULE_DEVICE_TABLE(pci, e752x_pci_tbl); |
1039 | 1037 | ||
1040 | |||
1041 | static struct pci_driver e752x_driver = { | 1038 | static struct pci_driver e752x_driver = { |
1042 | .name = BS_MOD_STR, | 1039 | .name = EDAC_MOD_STR, |
1043 | .probe = e752x_init_one, | 1040 | .probe = e752x_init_one, |
1044 | .remove = __devexit_p(e752x_remove_one), | 1041 | .remove = __devexit_p(e752x_remove_one), |
1045 | .id_table = e752x_pci_tbl, | 1042 | .id_table = e752x_pci_tbl, |
1046 | }; | 1043 | }; |
1047 | 1044 | ||
1048 | |||
1049 | static int __init e752x_init(void) | 1045 | static int __init e752x_init(void) |
1050 | { | 1046 | { |
1051 | int pci_rc; | 1047 | int pci_rc; |
1052 | 1048 | ||
1053 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 1049 | debugf3("%s()\n", __func__); |
1054 | pci_rc = pci_register_driver(&e752x_driver); | 1050 | pci_rc = pci_register_driver(&e752x_driver); |
1055 | return (pci_rc < 0) ? pci_rc : 0; | 1051 | return (pci_rc < 0) ? pci_rc : 0; |
1056 | } | 1052 | } |
1057 | 1053 | ||
1058 | |||
1059 | static void __exit e752x_exit(void) | 1054 | static void __exit e752x_exit(void) |
1060 | { | 1055 | { |
1061 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 1056 | debugf3("%s()\n", __func__); |
1062 | pci_unregister_driver(&e752x_driver); | 1057 | pci_unregister_driver(&e752x_driver); |
1063 | } | 1058 | } |
1064 | 1059 | ||
1065 | |||
1066 | module_init(e752x_init); | 1060 | module_init(e752x_init); |
1067 | module_exit(e752x_exit); | 1061 | module_exit(e752x_exit); |
1068 | 1062 | ||
diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c index d5e320dfc66f..a9518d3e4be4 100644 --- a/drivers/edac/e7xxx_edac.c +++ b/drivers/edac/e7xxx_edac.c | |||
@@ -11,9 +11,9 @@ | |||
11 | * http://www.anime.net/~goemon/linux-ecc/ | 11 | * http://www.anime.net/~goemon/linux-ecc/ |
12 | * | 12 | * |
13 | * Contributors: | 13 | * Contributors: |
14 | * Eric Biederman (Linux Networx) | 14 | * Eric Biederman (Linux Networx) |
15 | * Tom Zimmerman (Linux Networx) | 15 | * Tom Zimmerman (Linux Networx) |
16 | * Jim Garlick (Lawrence Livermore National Labs) | 16 | * Jim Garlick (Lawrence Livermore National Labs) |
17 | * Dave Peterson (Lawrence Livermore National Labs) | 17 | * Dave Peterson (Lawrence Livermore National Labs) |
18 | * That One Guy (Some other place) | 18 | * That One Guy (Some other place) |
19 | * Wang Zhenyu (intel.com) | 19 | * Wang Zhenyu (intel.com) |
@@ -22,7 +22,6 @@ | |||
22 | * | 22 | * |
23 | */ | 23 | */ |
24 | 24 | ||
25 | |||
26 | #include <linux/config.h> | 25 | #include <linux/config.h> |
27 | #include <linux/module.h> | 26 | #include <linux/module.h> |
28 | #include <linux/init.h> | 27 | #include <linux/init.h> |
@@ -31,6 +30,11 @@ | |||
31 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
32 | #include "edac_mc.h" | 31 | #include "edac_mc.h" |
33 | 32 | ||
33 | #define e7xxx_printk(level, fmt, arg...) \ | ||
34 | edac_printk(level, "e7xxx", fmt, ##arg) | ||
35 | |||
36 | #define e7xxx_mc_printk(mci, level, fmt, arg...) \ | ||
37 | edac_mc_chipset_printk(mci, level, "e7xxx", fmt, ##arg) | ||
34 | 38 | ||
35 | #ifndef PCI_DEVICE_ID_INTEL_7205_0 | 39 | #ifndef PCI_DEVICE_ID_INTEL_7205_0 |
36 | #define PCI_DEVICE_ID_INTEL_7205_0 0x255d | 40 | #define PCI_DEVICE_ID_INTEL_7205_0 0x255d |
@@ -64,11 +68,9 @@ | |||
64 | #define PCI_DEVICE_ID_INTEL_7505_1_ERR 0x2551 | 68 | #define PCI_DEVICE_ID_INTEL_7505_1_ERR 0x2551 |
65 | #endif /* PCI_DEVICE_ID_INTEL_7505_1_ERR */ | 69 | #endif /* PCI_DEVICE_ID_INTEL_7505_1_ERR */ |
66 | 70 | ||
67 | |||
68 | #define E7XXX_NR_CSROWS 8 /* number of csrows */ | 71 | #define E7XXX_NR_CSROWS 8 /* number of csrows */ |
69 | #define E7XXX_NR_DIMMS 8 /* FIXME - is this correct? */ | 72 | #define E7XXX_NR_DIMMS 8 /* FIXME - is this correct? */ |
70 | 73 | ||
71 | |||
72 | /* E7XXX register addresses - device 0 function 0 */ | 74 | /* E7XXX register addresses - device 0 function 0 */ |
73 | #define E7XXX_DRB 0x60 /* DRAM row boundary register (8b) */ | 75 | #define E7XXX_DRB 0x60 /* DRAM row boundary register (8b) */ |
74 | #define E7XXX_DRA 0x70 /* DRAM row attribute register (8b) */ | 76 | #define E7XXX_DRA 0x70 /* DRAM row attribute register (8b) */ |
@@ -118,7 +120,6 @@ enum e7xxx_chips { | |||
118 | E7205, | 120 | E7205, |
119 | }; | 121 | }; |
120 | 122 | ||
121 | |||
122 | struct e7xxx_pvt { | 123 | struct e7xxx_pvt { |
123 | struct pci_dev *bridge_ck; | 124 | struct pci_dev *bridge_ck; |
124 | u32 tolm; | 125 | u32 tolm; |
@@ -127,13 +128,11 @@ struct e7xxx_pvt { | |||
127 | const struct e7xxx_dev_info *dev_info; | 128 | const struct e7xxx_dev_info *dev_info; |
128 | }; | 129 | }; |
129 | 130 | ||
130 | |||
131 | struct e7xxx_dev_info { | 131 | struct e7xxx_dev_info { |
132 | u16 err_dev; | 132 | u16 err_dev; |
133 | const char *ctl_name; | 133 | const char *ctl_name; |
134 | }; | 134 | }; |
135 | 135 | ||
136 | |||
137 | struct e7xxx_error_info { | 136 | struct e7xxx_error_info { |
138 | u8 dram_ferr; | 137 | u8 dram_ferr; |
139 | u8 dram_nerr; | 138 | u8 dram_nerr; |
@@ -144,108 +143,110 @@ struct e7xxx_error_info { | |||
144 | 143 | ||
145 | static const struct e7xxx_dev_info e7xxx_devs[] = { | 144 | static const struct e7xxx_dev_info e7xxx_devs[] = { |
146 | [E7500] = { | 145 | [E7500] = { |
147 | .err_dev = PCI_DEVICE_ID_INTEL_7500_1_ERR, | 146 | .err_dev = PCI_DEVICE_ID_INTEL_7500_1_ERR, |
148 | .ctl_name = "E7500"}, | 147 | .ctl_name = "E7500" |
148 | }, | ||
149 | [E7501] = { | 149 | [E7501] = { |
150 | .err_dev = PCI_DEVICE_ID_INTEL_7501_1_ERR, | 150 | .err_dev = PCI_DEVICE_ID_INTEL_7501_1_ERR, |
151 | .ctl_name = "E7501"}, | 151 | .ctl_name = "E7501" |
152 | }, | ||
152 | [E7505] = { | 153 | [E7505] = { |
153 | .err_dev = PCI_DEVICE_ID_INTEL_7505_1_ERR, | 154 | .err_dev = PCI_DEVICE_ID_INTEL_7505_1_ERR, |
154 | .ctl_name = "E7505"}, | 155 | .ctl_name = "E7505" |
156 | }, | ||
155 | [E7205] = { | 157 | [E7205] = { |
156 | .err_dev = PCI_DEVICE_ID_INTEL_7205_1_ERR, | 158 | .err_dev = PCI_DEVICE_ID_INTEL_7205_1_ERR, |
157 | .ctl_name = "E7205"}, | 159 | .ctl_name = "E7205" |
160 | }, | ||
158 | }; | 161 | }; |
159 | 162 | ||
160 | |||
161 | /* FIXME - is this valid for both SECDED and S4ECD4ED? */ | 163 | /* FIXME - is this valid for both SECDED and S4ECD4ED? */ |
162 | static inline int e7xxx_find_channel(u16 syndrome) | 164 | static inline int e7xxx_find_channel(u16 syndrome) |
163 | { | 165 | { |
164 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 166 | debugf3("%s()\n", __func__); |
165 | 167 | ||
166 | if ((syndrome & 0xff00) == 0) | 168 | if ((syndrome & 0xff00) == 0) |
167 | return 0; | 169 | return 0; |
170 | |||
168 | if ((syndrome & 0x00ff) == 0) | 171 | if ((syndrome & 0x00ff) == 0) |
169 | return 1; | 172 | return 1; |
173 | |||
170 | if ((syndrome & 0xf000) == 0 || (syndrome & 0x0f00) == 0) | 174 | if ((syndrome & 0xf000) == 0 || (syndrome & 0x0f00) == 0) |
171 | return 0; | 175 | return 0; |
176 | |||
172 | return 1; | 177 | return 1; |
173 | } | 178 | } |
174 | 179 | ||
175 | 180 | static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, | |
176 | static unsigned long | 181 | unsigned long page) |
177 | ctl_page_to_phys(struct mem_ctl_info *mci, unsigned long page) | ||
178 | { | 182 | { |
179 | u32 remap; | 183 | u32 remap; |
180 | struct e7xxx_pvt *pvt = (struct e7xxx_pvt *) mci->pvt_info; | 184 | struct e7xxx_pvt *pvt = (struct e7xxx_pvt *) mci->pvt_info; |
181 | 185 | ||
182 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 186 | debugf3("%s()\n", __func__); |
183 | 187 | ||
184 | if ((page < pvt->tolm) || | 188 | if ((page < pvt->tolm) || |
185 | ((page >= 0x100000) && (page < pvt->remapbase))) | 189 | ((page >= 0x100000) && (page < pvt->remapbase))) |
186 | return page; | 190 | return page; |
191 | |||
187 | remap = (page - pvt->tolm) + pvt->remapbase; | 192 | remap = (page - pvt->tolm) + pvt->remapbase; |
193 | |||
188 | if (remap < pvt->remaplimit) | 194 | if (remap < pvt->remaplimit) |
189 | return remap; | 195 | return remap; |
190 | printk(KERN_ERR "Invalid page %lx - out of range\n", page); | 196 | |
197 | e7xxx_printk(KERN_ERR, "Invalid page %lx - out of range\n", page); | ||
191 | return pvt->tolm - 1; | 198 | return pvt->tolm - 1; |
192 | } | 199 | } |
193 | 200 | ||
194 | 201 | static void process_ce(struct mem_ctl_info *mci, | |
195 | static void process_ce(struct mem_ctl_info *mci, struct e7xxx_error_info *info) | 202 | struct e7xxx_error_info *info) |
196 | { | 203 | { |
197 | u32 error_1b, page; | 204 | u32 error_1b, page; |
198 | u16 syndrome; | 205 | u16 syndrome; |
199 | int row; | 206 | int row; |
200 | int channel; | 207 | int channel; |
201 | 208 | ||
202 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 209 | debugf3("%s()\n", __func__); |
203 | |||
204 | /* read the error address */ | 210 | /* read the error address */ |
205 | error_1b = info->dram_celog_add; | 211 | error_1b = info->dram_celog_add; |
206 | /* FIXME - should use PAGE_SHIFT */ | 212 | /* FIXME - should use PAGE_SHIFT */ |
207 | page = error_1b >> 6; /* convert the address to 4k page */ | 213 | page = error_1b >> 6; /* convert the address to 4k page */ |
208 | /* read the syndrome */ | 214 | /* read the syndrome */ |
209 | syndrome = info->dram_celog_syndrome; | 215 | syndrome = info->dram_celog_syndrome; |
210 | /* FIXME - check for -1 */ | 216 | /* FIXME - check for -1 */ |
211 | row = edac_mc_find_csrow_by_page(mci, page); | 217 | row = edac_mc_find_csrow_by_page(mci, page); |
212 | /* convert syndrome to channel */ | 218 | /* convert syndrome to channel */ |
213 | channel = e7xxx_find_channel(syndrome); | 219 | channel = e7xxx_find_channel(syndrome); |
214 | edac_mc_handle_ce(mci, page, 0, syndrome, row, channel, | 220 | edac_mc_handle_ce(mci, page, 0, syndrome, row, channel, "e7xxx CE"); |
215 | "e7xxx CE"); | ||
216 | } | 221 | } |
217 | 222 | ||
218 | |||
219 | static void process_ce_no_info(struct mem_ctl_info *mci) | 223 | static void process_ce_no_info(struct mem_ctl_info *mci) |
220 | { | 224 | { |
221 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 225 | debugf3("%s()\n", __func__); |
222 | edac_mc_handle_ce_no_info(mci, "e7xxx CE log register overflow"); | 226 | edac_mc_handle_ce_no_info(mci, "e7xxx CE log register overflow"); |
223 | } | 227 | } |
224 | 228 | ||
225 | 229 | static void process_ue(struct mem_ctl_info *mci, | |
226 | static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info) | 230 | struct e7xxx_error_info *info) |
227 | { | 231 | { |
228 | u32 error_2b, block_page; | 232 | u32 error_2b, block_page; |
229 | int row; | 233 | int row; |
230 | 234 | ||
231 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 235 | debugf3("%s()\n", __func__); |
232 | |||
233 | /* read the error address */ | 236 | /* read the error address */ |
234 | error_2b = info->dram_uelog_add; | 237 | error_2b = info->dram_uelog_add; |
235 | /* FIXME - should use PAGE_SHIFT */ | 238 | /* FIXME - should use PAGE_SHIFT */ |
236 | block_page = error_2b >> 6; /* convert to 4k address */ | 239 | block_page = error_2b >> 6; /* convert to 4k address */ |
237 | row = edac_mc_find_csrow_by_page(mci, block_page); | 240 | row = edac_mc_find_csrow_by_page(mci, block_page); |
238 | edac_mc_handle_ue(mci, block_page, 0, row, "e7xxx UE"); | 241 | edac_mc_handle_ue(mci, block_page, 0, row, "e7xxx UE"); |
239 | } | 242 | } |
240 | 243 | ||
241 | |||
242 | static void process_ue_no_info(struct mem_ctl_info *mci) | 244 | static void process_ue_no_info(struct mem_ctl_info *mci) |
243 | { | 245 | { |
244 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 246 | debugf3("%s()\n", __func__); |
245 | edac_mc_handle_ue_no_info(mci, "e7xxx UE log register overflow"); | 247 | edac_mc_handle_ue_no_info(mci, "e7xxx UE log register overflow"); |
246 | } | 248 | } |
247 | 249 | ||
248 | |||
249 | static void e7xxx_get_error_info (struct mem_ctl_info *mci, | 250 | static void e7xxx_get_error_info (struct mem_ctl_info *mci, |
250 | struct e7xxx_error_info *info) | 251 | struct e7xxx_error_info *info) |
251 | { | 252 | { |
@@ -253,31 +254,29 @@ static void e7xxx_get_error_info (struct mem_ctl_info *mci, | |||
253 | 254 | ||
254 | pvt = (struct e7xxx_pvt *) mci->pvt_info; | 255 | pvt = (struct e7xxx_pvt *) mci->pvt_info; |
255 | pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_FERR, | 256 | pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_FERR, |
256 | &info->dram_ferr); | 257 | &info->dram_ferr); |
257 | pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_NERR, | 258 | pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_NERR, |
258 | &info->dram_nerr); | 259 | &info->dram_nerr); |
259 | 260 | ||
260 | if ((info->dram_ferr & 1) || (info->dram_nerr & 1)) { | 261 | if ((info->dram_ferr & 1) || (info->dram_nerr & 1)) { |
261 | pci_read_config_dword(pvt->bridge_ck, E7XXX_DRAM_CELOG_ADD, | 262 | pci_read_config_dword(pvt->bridge_ck, E7XXX_DRAM_CELOG_ADD, |
262 | &info->dram_celog_add); | 263 | &info->dram_celog_add); |
263 | pci_read_config_word(pvt->bridge_ck, | 264 | pci_read_config_word(pvt->bridge_ck, |
264 | E7XXX_DRAM_CELOG_SYNDROME, &info->dram_celog_syndrome); | 265 | E7XXX_DRAM_CELOG_SYNDROME, |
266 | &info->dram_celog_syndrome); | ||
265 | } | 267 | } |
266 | 268 | ||
267 | if ((info->dram_ferr & 2) || (info->dram_nerr & 2)) | 269 | if ((info->dram_ferr & 2) || (info->dram_nerr & 2)) |
268 | pci_read_config_dword(pvt->bridge_ck, E7XXX_DRAM_UELOG_ADD, | 270 | pci_read_config_dword(pvt->bridge_ck, E7XXX_DRAM_UELOG_ADD, |
269 | &info->dram_uelog_add); | 271 | &info->dram_uelog_add); |
270 | 272 | ||
271 | if (info->dram_ferr & 3) | 273 | if (info->dram_ferr & 3) |
272 | pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_FERR, 0x03, | 274 | pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_FERR, 0x03, 0x03); |
273 | 0x03); | ||
274 | 275 | ||
275 | if (info->dram_nerr & 3) | 276 | if (info->dram_nerr & 3) |
276 | pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, | 277 | pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03); |
277 | 0x03); | ||
278 | } | 278 | } |
279 | 279 | ||
280 | |||
281 | static int e7xxx_process_error_info (struct mem_ctl_info *mci, | 280 | static int e7xxx_process_error_info (struct mem_ctl_info *mci, |
282 | struct e7xxx_error_info *info, int handle_errors) | 281 | struct e7xxx_error_info *info, int handle_errors) |
283 | { | 282 | { |
@@ -325,17 +324,15 @@ static int e7xxx_process_error_info (struct mem_ctl_info *mci, | |||
325 | return error_found; | 324 | return error_found; |
326 | } | 325 | } |
327 | 326 | ||
328 | |||
329 | static void e7xxx_check(struct mem_ctl_info *mci) | 327 | static void e7xxx_check(struct mem_ctl_info *mci) |
330 | { | 328 | { |
331 | struct e7xxx_error_info info; | 329 | struct e7xxx_error_info info; |
332 | 330 | ||
333 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 331 | debugf3("%s()\n", __func__); |
334 | e7xxx_get_error_info(mci, &info); | 332 | e7xxx_get_error_info(mci, &info); |
335 | e7xxx_process_error_info(mci, &info, 1); | 333 | e7xxx_process_error_info(mci, &info, 1); |
336 | } | 334 | } |
337 | 335 | ||
338 | |||
339 | static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) | 336 | static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) |
340 | { | 337 | { |
341 | int rc = -ENODEV; | 338 | int rc = -ENODEV; |
@@ -349,19 +346,20 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) | |||
349 | int drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ | 346 | int drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ |
350 | u32 dra; | 347 | u32 dra; |
351 | unsigned long last_cumul_size; | 348 | unsigned long last_cumul_size; |
349 | struct e7xxx_error_info discard; | ||
352 | 350 | ||
353 | 351 | debugf0("%s(): mci\n", __func__); | |
354 | debugf0("MC: " __FILE__ ": %s(): mci\n", __func__); | ||
355 | 352 | ||
356 | /* need to find out the number of channels */ | 353 | /* need to find out the number of channels */ |
357 | pci_read_config_dword(pdev, E7XXX_DRC, &drc); | 354 | pci_read_config_dword(pdev, E7XXX_DRC, &drc); |
355 | |||
358 | /* only e7501 can be single channel */ | 356 | /* only e7501 can be single channel */ |
359 | if (dev_idx == E7501) { | 357 | if (dev_idx == E7501) { |
360 | drc_chan = ((drc >> 22) & 0x1); | 358 | drc_chan = ((drc >> 22) & 0x1); |
361 | drc_drbg = (drc >> 18) & 0x3; | 359 | drc_drbg = (drc >> 18) & 0x3; |
362 | } | 360 | } |
363 | drc_ddim = (drc >> 20) & 0x3; | ||
364 | 361 | ||
362 | drc_ddim = (drc >> 20) & 0x3; | ||
365 | mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1); | 363 | mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1); |
366 | 364 | ||
367 | if (mci == NULL) { | 365 | if (mci == NULL) { |
@@ -369,33 +367,31 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) | |||
369 | goto fail; | 367 | goto fail; |
370 | } | 368 | } |
371 | 369 | ||
372 | debugf3("MC: " __FILE__ ": %s(): init mci\n", __func__); | 370 | debugf3("%s(): init mci\n", __func__); |
373 | |||
374 | mci->mtype_cap = MEM_FLAG_RDDR; | 371 | mci->mtype_cap = MEM_FLAG_RDDR; |
375 | mci->edac_ctl_cap = | 372 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | |
376 | EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED; | 373 | EDAC_FLAG_S4ECD4ED; |
377 | /* FIXME - what if different memory types are in different csrows? */ | 374 | /* FIXME - what if different memory types are in different csrows? */ |
378 | mci->mod_name = BS_MOD_STR; | 375 | mci->mod_name = EDAC_MOD_STR; |
379 | mci->mod_ver = "$Revision: 1.5.2.9 $"; | 376 | mci->mod_ver = "$Revision: 1.5.2.9 $"; |
380 | mci->pdev = pdev; | 377 | mci->pdev = pdev; |
381 | 378 | ||
382 | debugf3("MC: " __FILE__ ": %s(): init pvt\n", __func__); | 379 | debugf3("%s(): init pvt\n", __func__); |
383 | pvt = (struct e7xxx_pvt *) mci->pvt_info; | 380 | pvt = (struct e7xxx_pvt *) mci->pvt_info; |
384 | pvt->dev_info = &e7xxx_devs[dev_idx]; | 381 | pvt->dev_info = &e7xxx_devs[dev_idx]; |
385 | pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL, | 382 | pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL, |
386 | pvt->dev_info->err_dev, | 383 | pvt->dev_info->err_dev, |
387 | pvt->bridge_ck); | 384 | pvt->bridge_ck); |
385 | |||
388 | if (!pvt->bridge_ck) { | 386 | if (!pvt->bridge_ck) { |
389 | printk(KERN_ERR | 387 | e7xxx_printk(KERN_ERR, "error reporting device not found:" |
390 | "MC: error reporting device not found:" | 388 | "vendor %x device 0x%x (broken BIOS?)\n", |
391 | "vendor %x device 0x%x (broken BIOS?)\n", | 389 | PCI_VENDOR_ID_INTEL, e7xxx_devs[dev_idx].err_dev); |
392 | PCI_VENDOR_ID_INTEL, e7xxx_devs[dev_idx].err_dev); | ||
393 | goto fail; | 390 | goto fail; |
394 | } | 391 | } |
395 | 392 | ||
396 | debugf3("MC: " __FILE__ ": %s(): more mci init\n", __func__); | 393 | debugf3("%s(): more mci init\n", __func__); |
397 | mci->ctl_name = pvt->dev_info->ctl_name; | 394 | mci->ctl_name = pvt->dev_info->ctl_name; |
398 | |||
399 | mci->edac_check = e7xxx_check; | 395 | mci->edac_check = e7xxx_check; |
400 | mci->ctl_page_to_phys = ctl_page_to_phys; | 396 | mci->ctl_page_to_phys = ctl_page_to_phys; |
401 | 397 | ||
@@ -418,17 +414,18 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) | |||
418 | pci_read_config_byte(mci->pdev, E7XXX_DRB + index, &value); | 414 | pci_read_config_byte(mci->pdev, E7XXX_DRB + index, &value); |
419 | /* convert a 64 or 32 MiB DRB to a page size. */ | 415 | /* convert a 64 or 32 MiB DRB to a page size. */ |
420 | cumul_size = value << (25 + drc_drbg - PAGE_SHIFT); | 416 | cumul_size = value << (25 + drc_drbg - PAGE_SHIFT); |
421 | debugf3("MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n", | 417 | debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index, |
422 | __func__, index, cumul_size); | 418 | cumul_size); |
419 | |||
423 | if (cumul_size == last_cumul_size) | 420 | if (cumul_size == last_cumul_size) |
424 | continue; /* not populated */ | 421 | continue; /* not populated */ |
425 | 422 | ||
426 | csrow->first_page = last_cumul_size; | 423 | csrow->first_page = last_cumul_size; |
427 | csrow->last_page = cumul_size - 1; | 424 | csrow->last_page = cumul_size - 1; |
428 | csrow->nr_pages = cumul_size - last_cumul_size; | 425 | csrow->nr_pages = cumul_size - last_cumul_size; |
429 | last_cumul_size = cumul_size; | 426 | last_cumul_size = cumul_size; |
430 | csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */ | 427 | csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */ |
431 | csrow->mtype = MEM_RDDR; /* only one type supported */ | 428 | csrow->mtype = MEM_RDDR; /* only one type supported */ |
432 | csrow->dtype = mem_dev ? DEV_X4 : DEV_X8; | 429 | csrow->dtype = mem_dev ? DEV_X4 : DEV_X8; |
433 | 430 | ||
434 | /* | 431 | /* |
@@ -449,8 +446,7 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) | |||
449 | 446 | ||
450 | mci->edac_cap |= EDAC_FLAG_NONE; | 447 | mci->edac_cap |= EDAC_FLAG_NONE; |
451 | 448 | ||
452 | debugf3("MC: " __FILE__ ": %s(): tolm, remapbase, remaplimit\n", | 449 | debugf3("%s(): tolm, remapbase, remaplimit\n", __func__); |
453 | __func__); | ||
454 | /* load the top of low memory, remap base, and remap limit vars */ | 450 | /* load the top of low memory, remap base, and remap limit vars */ |
455 | pci_read_config_word(mci->pdev, E7XXX_TOLM, &pci_data); | 451 | pci_read_config_word(mci->pdev, E7XXX_TOLM, &pci_data); |
456 | pvt->tolm = ((u32) pci_data) << 4; | 452 | pvt->tolm = ((u32) pci_data) << 4; |
@@ -458,22 +454,20 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) | |||
458 | pvt->remapbase = ((u32) pci_data) << 14; | 454 | pvt->remapbase = ((u32) pci_data) << 14; |
459 | pci_read_config_word(mci->pdev, E7XXX_REMAPLIMIT, &pci_data); | 455 | pci_read_config_word(mci->pdev, E7XXX_REMAPLIMIT, &pci_data); |
460 | pvt->remaplimit = ((u32) pci_data) << 14; | 456 | pvt->remaplimit = ((u32) pci_data) << 14; |
461 | printk("tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm, | 457 | e7xxx_printk(KERN_INFO, |
462 | pvt->remapbase, pvt->remaplimit); | 458 | "tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm, |
459 | pvt->remapbase, pvt->remaplimit); | ||
463 | 460 | ||
464 | /* clear any pending errors, or initial state bits */ | 461 | /* clear any pending errors, or initial state bits */ |
465 | pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_FERR, 0x03, 0x03); | 462 | e7xxx_get_error_info(mci, &discard); |
466 | pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03); | ||
467 | 463 | ||
468 | if (edac_mc_add_mc(mci) != 0) { | 464 | if (edac_mc_add_mc(mci) != 0) { |
469 | debugf3("MC: " __FILE__ | 465 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); |
470 | ": %s(): failed edac_mc_add_mc()\n", | ||
471 | __func__); | ||
472 | goto fail; | 466 | goto fail; |
473 | } | 467 | } |
474 | 468 | ||
475 | /* get this far and it's successful */ | 469 | /* get this far and it's successful */ |
476 | debugf3("MC: " __FILE__ ": %s(): success\n", __func__); | 470 | debugf3("%s(): success\n", __func__); |
477 | return 0; | 471 | return 0; |
478 | 472 | ||
479 | fail: | 473 | fail: |
@@ -487,62 +481,67 @@ fail: | |||
487 | } | 481 | } |
488 | 482 | ||
489 | /* returns count (>= 0), or negative on error */ | 483 | /* returns count (>= 0), or negative on error */ |
490 | static int __devinit | 484 | static int __devinit e7xxx_init_one(struct pci_dev *pdev, |
491 | e7xxx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | 485 | const struct pci_device_id *ent) |
492 | { | 486 | { |
493 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | 487 | debugf0("%s()\n", __func__); |
494 | 488 | ||
495 | /* wake up and enable device */ | 489 | /* wake up and enable device */ |
496 | return pci_enable_device(pdev) ? | 490 | return pci_enable_device(pdev) ? |
497 | -EIO : e7xxx_probe1(pdev, ent->driver_data); | 491 | -EIO : e7xxx_probe1(pdev, ent->driver_data); |
498 | } | 492 | } |
499 | 493 | ||
500 | |||
501 | static void __devexit e7xxx_remove_one(struct pci_dev *pdev) | 494 | static void __devexit e7xxx_remove_one(struct pci_dev *pdev) |
502 | { | 495 | { |
503 | struct mem_ctl_info *mci; | 496 | struct mem_ctl_info *mci; |
504 | struct e7xxx_pvt *pvt; | 497 | struct e7xxx_pvt *pvt; |
505 | 498 | ||
506 | debugf0(__FILE__ ": %s()\n", __func__); | 499 | debugf0("%s()\n", __func__); |
507 | 500 | ||
508 | if (((mci = edac_mc_find_mci_by_pdev(pdev)) != 0) && | 501 | if ((mci = edac_mc_del_mc(pdev)) == NULL) |
509 | edac_mc_del_mc(mci)) { | 502 | return; |
510 | pvt = (struct e7xxx_pvt *) mci->pvt_info; | ||
511 | pci_dev_put(pvt->bridge_ck); | ||
512 | edac_mc_free(mci); | ||
513 | } | ||
514 | } | ||
515 | 503 | ||
504 | pvt = (struct e7xxx_pvt *) mci->pvt_info; | ||
505 | pci_dev_put(pvt->bridge_ck); | ||
506 | edac_mc_free(mci); | ||
507 | } | ||
516 | 508 | ||
517 | static const struct pci_device_id e7xxx_pci_tbl[] __devinitdata = { | 509 | static const struct pci_device_id e7xxx_pci_tbl[] __devinitdata = { |
518 | {PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 510 | { |
519 | E7205}, | 511 | PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
520 | {PCI_VEND_DEV(INTEL, 7500_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 512 | E7205 |
521 | E7500}, | 513 | }, |
522 | {PCI_VEND_DEV(INTEL, 7501_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 514 | { |
523 | E7501}, | 515 | PCI_VEND_DEV(INTEL, 7500_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
524 | {PCI_VEND_DEV(INTEL, 7505_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 516 | E7500 |
525 | E7505}, | 517 | }, |
526 | {0,} /* 0 terminated list. */ | 518 | { |
519 | PCI_VEND_DEV(INTEL, 7501_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | ||
520 | E7501 | ||
521 | }, | ||
522 | { | ||
523 | PCI_VEND_DEV(INTEL, 7505_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | ||
524 | E7505 | ||
525 | }, | ||
526 | { | ||
527 | 0, | ||
528 | } /* 0 terminated list. */ | ||
527 | }; | 529 | }; |
528 | 530 | ||
529 | MODULE_DEVICE_TABLE(pci, e7xxx_pci_tbl); | 531 | MODULE_DEVICE_TABLE(pci, e7xxx_pci_tbl); |
530 | 532 | ||
531 | |||
532 | static struct pci_driver e7xxx_driver = { | 533 | static struct pci_driver e7xxx_driver = { |
533 | .name = BS_MOD_STR, | 534 | .name = EDAC_MOD_STR, |
534 | .probe = e7xxx_init_one, | 535 | .probe = e7xxx_init_one, |
535 | .remove = __devexit_p(e7xxx_remove_one), | 536 | .remove = __devexit_p(e7xxx_remove_one), |
536 | .id_table = e7xxx_pci_tbl, | 537 | .id_table = e7xxx_pci_tbl, |
537 | }; | 538 | }; |
538 | 539 | ||
539 | |||
540 | static int __init e7xxx_init(void) | 540 | static int __init e7xxx_init(void) |
541 | { | 541 | { |
542 | return pci_register_driver(&e7xxx_driver); | 542 | return pci_register_driver(&e7xxx_driver); |
543 | } | 543 | } |
544 | 544 | ||
545 | |||
546 | static void __exit e7xxx_exit(void) | 545 | static void __exit e7xxx_exit(void) |
547 | { | 546 | { |
548 | pci_unregister_driver(&e7xxx_driver); | 547 | pci_unregister_driver(&e7xxx_driver); |
@@ -551,8 +550,7 @@ static void __exit e7xxx_exit(void) | |||
551 | module_init(e7xxx_init); | 550 | module_init(e7xxx_init); |
552 | module_exit(e7xxx_exit); | 551 | module_exit(e7xxx_exit); |
553 | 552 | ||
554 | |||
555 | MODULE_LICENSE("GPL"); | 553 | MODULE_LICENSE("GPL"); |
556 | MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n" | 554 | MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n" |
557 | "Based on.work by Dan Hollis et al"); | 555 | "Based on.work by Dan Hollis et al"); |
558 | MODULE_DESCRIPTION("MC support for Intel e7xxx memory controllers"); | 556 | MODULE_DESCRIPTION("MC support for Intel e7xxx memory controllers"); |
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 262e44544dc8..ea06e3a4dc35 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c | |||
@@ -12,7 +12,6 @@ | |||
12 | * | 12 | * |
13 | */ | 13 | */ |
14 | 14 | ||
15 | |||
16 | #include <linux/config.h> | 15 | #include <linux/config.h> |
17 | #include <linux/module.h> | 16 | #include <linux/module.h> |
18 | #include <linux/proc_fs.h> | 17 | #include <linux/proc_fs.h> |
@@ -29,25 +28,30 @@ | |||
29 | #include <linux/list.h> | 28 | #include <linux/list.h> |
30 | #include <linux/sysdev.h> | 29 | #include <linux/sysdev.h> |
31 | #include <linux/ctype.h> | 30 | #include <linux/ctype.h> |
32 | 31 | #include <linux/kthread.h> | |
33 | #include <asm/uaccess.h> | 32 | #include <asm/uaccess.h> |
34 | #include <asm/page.h> | 33 | #include <asm/page.h> |
35 | #include <asm/edac.h> | 34 | #include <asm/edac.h> |
36 | |||
37 | #include "edac_mc.h" | 35 | #include "edac_mc.h" |
38 | 36 | ||
39 | #define EDAC_MC_VERSION "edac_mc Ver: 2.0.0 " __DATE__ | 37 | #define EDAC_MC_VERSION "Ver: 2.0.0 " __DATE__ |
38 | |||
39 | /* For now, disable the EDAC sysfs code. The sysfs interface that EDAC | ||
40 | * presents to user space needs more thought, and is likely to change | ||
41 | * substantially. | ||
42 | */ | ||
43 | #define DISABLE_EDAC_SYSFS | ||
40 | 44 | ||
41 | #ifdef CONFIG_EDAC_DEBUG | 45 | #ifdef CONFIG_EDAC_DEBUG |
42 | /* Values of 0 to 4 will generate output */ | 46 | /* Values of 0 to 4 will generate output */ |
43 | int edac_debug_level = 1; | 47 | int edac_debug_level = 1; |
44 | EXPORT_SYMBOL(edac_debug_level); | 48 | EXPORT_SYMBOL_GPL(edac_debug_level); |
45 | #endif | 49 | #endif |
46 | 50 | ||
47 | /* EDAC Controls, setable by module parameter, and sysfs */ | 51 | /* EDAC Controls, setable by module parameter, and sysfs */ |
48 | static int log_ue = 1; | 52 | static int log_ue = 1; |
49 | static int log_ce = 1; | 53 | static int log_ce = 1; |
50 | static int panic_on_ue = 1; | 54 | static int panic_on_ue; |
51 | static int poll_msec = 1000; | 55 | static int poll_msec = 1000; |
52 | 56 | ||
53 | static int check_pci_parity = 0; /* default YES check PCI parity */ | 57 | static int check_pci_parity = 0; /* default YES check PCI parity */ |
@@ -58,13 +62,14 @@ static atomic_t pci_parity_count = ATOMIC_INIT(0); | |||
58 | static DECLARE_MUTEX(mem_ctls_mutex); | 62 | static DECLARE_MUTEX(mem_ctls_mutex); |
59 | static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices); | 63 | static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices); |
60 | 64 | ||
65 | static struct task_struct *edac_thread; | ||
66 | |||
61 | /* Structure of the whitelist and blacklist arrays */ | 67 | /* Structure of the whitelist and blacklist arrays */ |
62 | struct edac_pci_device_list { | 68 | struct edac_pci_device_list { |
63 | unsigned int vendor; /* Vendor ID */ | 69 | unsigned int vendor; /* Vendor ID */ |
64 | unsigned int device; /* Deviice ID */ | 70 | unsigned int device; /* Deviice ID */ |
65 | }; | 71 | }; |
66 | 72 | ||
67 | |||
68 | #define MAX_LISTED_PCI_DEVICES 32 | 73 | #define MAX_LISTED_PCI_DEVICES 32 |
69 | 74 | ||
70 | /* List of PCI devices (vendor-id:device-id) that should be skipped */ | 75 | /* List of PCI devices (vendor-id:device-id) that should be skipped */ |
@@ -77,6 +82,8 @@ static int pci_whitelist_count ; | |||
77 | 82 | ||
78 | /* START sysfs data and methods */ | 83 | /* START sysfs data and methods */ |
79 | 84 | ||
85 | #ifndef DISABLE_EDAC_SYSFS | ||
86 | |||
80 | static const char *mem_types[] = { | 87 | static const char *mem_types[] = { |
81 | [MEM_EMPTY] = "Empty", | 88 | [MEM_EMPTY] = "Empty", |
82 | [MEM_RESERVED] = "Reserved", | 89 | [MEM_RESERVED] = "Reserved", |
@@ -115,7 +122,6 @@ static const char *edac_caps[] = { | |||
115 | [EDAC_S16ECD16ED] = "S16ECD16ED" | 122 | [EDAC_S16ECD16ED] = "S16ECD16ED" |
116 | }; | 123 | }; |
117 | 124 | ||
118 | |||
119 | /* sysfs object: /sys/devices/system/edac */ | 125 | /* sysfs object: /sys/devices/system/edac */ |
120 | static struct sysdev_class edac_class = { | 126 | static struct sysdev_class edac_class = { |
121 | set_kset_name("edac"), | 127 | set_kset_name("edac"), |
@@ -128,9 +134,15 @@ static struct sysdev_class edac_class = { | |||
128 | static struct kobject edac_memctrl_kobj; | 134 | static struct kobject edac_memctrl_kobj; |
129 | static struct kobject edac_pci_kobj; | 135 | static struct kobject edac_pci_kobj; |
130 | 136 | ||
137 | /* We use these to wait for the reference counts on edac_memctrl_kobj and | ||
138 | * edac_pci_kobj to reach 0. | ||
139 | */ | ||
140 | static struct completion edac_memctrl_kobj_complete; | ||
141 | static struct completion edac_pci_kobj_complete; | ||
142 | |||
131 | /* | 143 | /* |
132 | * /sys/devices/system/edac/mc; | 144 | * /sys/devices/system/edac/mc; |
133 | * data structures and methods | 145 | * data structures and methods |
134 | */ | 146 | */ |
135 | #if 0 | 147 | #if 0 |
136 | static ssize_t memctrl_string_show(void *ptr, char *buffer) | 148 | static ssize_t memctrl_string_show(void *ptr, char *buffer) |
@@ -157,33 +169,34 @@ static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count) | |||
157 | } | 169 | } |
158 | 170 | ||
159 | struct memctrl_dev_attribute { | 171 | struct memctrl_dev_attribute { |
160 | struct attribute attr; | 172 | struct attribute attr; |
161 | void *value; | 173 | void *value; |
162 | ssize_t (*show)(void *,char *); | 174 | ssize_t (*show)(void *,char *); |
163 | ssize_t (*store)(void *, const char *, size_t); | 175 | ssize_t (*store)(void *, const char *, size_t); |
164 | }; | 176 | }; |
165 | 177 | ||
166 | /* Set of show/store abstract level functions for memory control object */ | 178 | /* Set of show/store abstract level functions for memory control object */ |
167 | static ssize_t | 179 | static ssize_t memctrl_dev_show(struct kobject *kobj, |
168 | memctrl_dev_show(struct kobject *kobj, struct attribute *attr, char *buffer) | 180 | struct attribute *attr, char *buffer) |
169 | { | 181 | { |
170 | struct memctrl_dev_attribute *memctrl_dev; | 182 | struct memctrl_dev_attribute *memctrl_dev; |
171 | memctrl_dev = (struct memctrl_dev_attribute*)attr; | 183 | memctrl_dev = (struct memctrl_dev_attribute*)attr; |
172 | 184 | ||
173 | if (memctrl_dev->show) | 185 | if (memctrl_dev->show) |
174 | return memctrl_dev->show(memctrl_dev->value, buffer); | 186 | return memctrl_dev->show(memctrl_dev->value, buffer); |
187 | |||
175 | return -EIO; | 188 | return -EIO; |
176 | } | 189 | } |
177 | 190 | ||
178 | static ssize_t | 191 | static ssize_t memctrl_dev_store(struct kobject *kobj, struct attribute *attr, |
179 | memctrl_dev_store(struct kobject *kobj, struct attribute *attr, | 192 | const char *buffer, size_t count) |
180 | const char *buffer, size_t count) | ||
181 | { | 193 | { |
182 | struct memctrl_dev_attribute *memctrl_dev; | 194 | struct memctrl_dev_attribute *memctrl_dev; |
183 | memctrl_dev = (struct memctrl_dev_attribute*)attr; | 195 | memctrl_dev = (struct memctrl_dev_attribute*)attr; |
184 | 196 | ||
185 | if (memctrl_dev->store) | 197 | if (memctrl_dev->store) |
186 | return memctrl_dev->store(memctrl_dev->value, buffer, count); | 198 | return memctrl_dev->store(memctrl_dev->value, buffer, count); |
199 | |||
187 | return -EIO; | 200 | return -EIO; |
188 | } | 201 | } |
189 | 202 | ||
@@ -219,7 +232,6 @@ MEMCTRL_ATTR(log_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store); | |||
219 | MEMCTRL_ATTR(log_ce,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store); | 232 | MEMCTRL_ATTR(log_ce,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store); |
220 | MEMCTRL_ATTR(poll_msec,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store); | 233 | MEMCTRL_ATTR(poll_msec,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store); |
221 | 234 | ||
222 | |||
223 | /* Base Attributes of the memory ECC object */ | 235 | /* Base Attributes of the memory ECC object */ |
224 | static struct memctrl_dev_attribute *memctrl_attr[] = { | 236 | static struct memctrl_dev_attribute *memctrl_attr[] = { |
225 | &attr_panic_on_ue, | 237 | &attr_panic_on_ue, |
@@ -232,15 +244,17 @@ static struct memctrl_dev_attribute *memctrl_attr[] = { | |||
232 | /* Main MC kobject release() function */ | 244 | /* Main MC kobject release() function */ |
233 | static void edac_memctrl_master_release(struct kobject *kobj) | 245 | static void edac_memctrl_master_release(struct kobject *kobj) |
234 | { | 246 | { |
235 | debugf1("EDAC MC: " __FILE__ ": %s()\n", __func__); | 247 | debugf1("%s()\n", __func__); |
248 | complete(&edac_memctrl_kobj_complete); | ||
236 | } | 249 | } |
237 | 250 | ||
238 | static struct kobj_type ktype_memctrl = { | 251 | static struct kobj_type ktype_memctrl = { |
239 | .release = edac_memctrl_master_release, | 252 | .release = edac_memctrl_master_release, |
240 | .sysfs_ops = &memctrlfs_ops, | 253 | .sysfs_ops = &memctrlfs_ops, |
241 | .default_attrs = (struct attribute **) memctrl_attr, | 254 | .default_attrs = (struct attribute **) memctrl_attr, |
242 | }; | 255 | }; |
243 | 256 | ||
257 | #endif /* DISABLE_EDAC_SYSFS */ | ||
244 | 258 | ||
245 | /* Initialize the main sysfs entries for edac: | 259 | /* Initialize the main sysfs entries for edac: |
246 | * /sys/devices/system/edac | 260 | * /sys/devices/system/edac |
@@ -251,38 +265,43 @@ static struct kobj_type ktype_memctrl = { | |||
251 | * !0 FAILURE | 265 | * !0 FAILURE |
252 | */ | 266 | */ |
253 | static int edac_sysfs_memctrl_setup(void) | 267 | static int edac_sysfs_memctrl_setup(void) |
268 | #ifdef DISABLE_EDAC_SYSFS | ||
269 | { | ||
270 | return 0; | ||
271 | } | ||
272 | #else | ||
254 | { | 273 | { |
255 | int err=0; | 274 | int err=0; |
256 | 275 | ||
257 | debugf1("MC: " __FILE__ ": %s()\n", __func__); | 276 | debugf1("%s()\n", __func__); |
258 | 277 | ||
259 | /* create the /sys/devices/system/edac directory */ | 278 | /* create the /sys/devices/system/edac directory */ |
260 | err = sysdev_class_register(&edac_class); | 279 | err = sysdev_class_register(&edac_class); |
280 | |||
261 | if (!err) { | 281 | if (!err) { |
262 | /* Init the MC's kobject */ | 282 | /* Init the MC's kobject */ |
263 | memset(&edac_memctrl_kobj, 0, sizeof (edac_memctrl_kobj)); | 283 | memset(&edac_memctrl_kobj, 0, sizeof (edac_memctrl_kobj)); |
264 | kobject_init(&edac_memctrl_kobj); | ||
265 | |||
266 | edac_memctrl_kobj.parent = &edac_class.kset.kobj; | 284 | edac_memctrl_kobj.parent = &edac_class.kset.kobj; |
267 | edac_memctrl_kobj.ktype = &ktype_memctrl; | 285 | edac_memctrl_kobj.ktype = &ktype_memctrl; |
268 | 286 | ||
269 | /* generate sysfs "..../edac/mc" */ | 287 | /* generate sysfs "..../edac/mc" */ |
270 | err = kobject_set_name(&edac_memctrl_kobj,"mc"); | 288 | err = kobject_set_name(&edac_memctrl_kobj,"mc"); |
289 | |||
271 | if (!err) { | 290 | if (!err) { |
272 | /* FIXME: maybe new sysdev_create_subdir() */ | 291 | /* FIXME: maybe new sysdev_create_subdir() */ |
273 | err = kobject_register(&edac_memctrl_kobj); | 292 | err = kobject_register(&edac_memctrl_kobj); |
274 | if (err) { | 293 | |
294 | if (err) | ||
275 | debugf1("Failed to register '.../edac/mc'\n"); | 295 | debugf1("Failed to register '.../edac/mc'\n"); |
276 | } else { | 296 | else |
277 | debugf1("Registered '.../edac/mc' kobject\n"); | 297 | debugf1("Registered '.../edac/mc' kobject\n"); |
278 | } | ||
279 | } | 298 | } |
280 | } else { | 299 | } else |
281 | debugf1(KERN_WARNING "__FILE__ %s() error=%d\n", __func__,err); | 300 | debugf1("%s() error=%d\n", __func__, err); |
282 | } | ||
283 | 301 | ||
284 | return err; | 302 | return err; |
285 | } | 303 | } |
304 | #endif /* DISABLE_EDAC_SYSFS */ | ||
286 | 305 | ||
287 | /* | 306 | /* |
288 | * MC teardown: | 307 | * MC teardown: |
@@ -290,18 +309,23 @@ static int edac_sysfs_memctrl_setup(void) | |||
290 | */ | 309 | */ |
291 | static void edac_sysfs_memctrl_teardown(void) | 310 | static void edac_sysfs_memctrl_teardown(void) |
292 | { | 311 | { |
312 | #ifndef DISABLE_EDAC_SYSFS | ||
293 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | 313 | debugf0("MC: " __FILE__ ": %s()\n", __func__); |
294 | 314 | ||
295 | /* Unregister the MC's kobject */ | 315 | /* Unregister the MC's kobject and wait for reference count to reach |
316 | * 0. | ||
317 | */ | ||
318 | init_completion(&edac_memctrl_kobj_complete); | ||
296 | kobject_unregister(&edac_memctrl_kobj); | 319 | kobject_unregister(&edac_memctrl_kobj); |
297 | 320 | wait_for_completion(&edac_memctrl_kobj_complete); | |
298 | /* release the master edac mc kobject */ | ||
299 | kobject_put(&edac_memctrl_kobj); | ||
300 | 321 | ||
301 | /* Unregister the 'edac' object */ | 322 | /* Unregister the 'edac' object */ |
302 | sysdev_class_unregister(&edac_class); | 323 | sysdev_class_unregister(&edac_class); |
324 | #endif /* DISABLE_EDAC_SYSFS */ | ||
303 | } | 325 | } |
304 | 326 | ||
327 | #ifndef DISABLE_EDAC_SYSFS | ||
328 | |||
305 | /* | 329 | /* |
306 | * /sys/devices/system/edac/pci; | 330 | * /sys/devices/system/edac/pci; |
307 | * data structures and methods | 331 | * data structures and methods |
@@ -312,7 +336,6 @@ struct list_control { | |||
312 | int *count; | 336 | int *count; |
313 | }; | 337 | }; |
314 | 338 | ||
315 | |||
316 | #if 0 | 339 | #if 0 |
317 | /* Output the list as: vendor_id:device:id<,vendor_id:device_id> */ | 340 | /* Output the list as: vendor_id:device:id<,vendor_id:device_id> */ |
318 | static ssize_t edac_pci_list_string_show(void *ptr, char *buffer) | 341 | static ssize_t edac_pci_list_string_show(void *ptr, char *buffer) |
@@ -337,7 +360,6 @@ static ssize_t edac_pci_list_string_show(void *ptr, char *buffer) | |||
337 | } | 360 | } |
338 | 361 | ||
339 | len += snprintf(p + len,(PAGE_SIZE-len), "\n"); | 362 | len += snprintf(p + len,(PAGE_SIZE-len), "\n"); |
340 | |||
341 | return (ssize_t) len; | 363 | return (ssize_t) len; |
342 | } | 364 | } |
343 | 365 | ||
@@ -359,7 +381,7 @@ static int parse_one_device(const char **s,const char **e, | |||
359 | 381 | ||
360 | /* if null byte, we are done */ | 382 | /* if null byte, we are done */ |
361 | if (!**s) { | 383 | if (!**s) { |
362 | (*s)++; /* keep *s moving */ | 384 | (*s)++; /* keep *s moving */ |
363 | return 0; | 385 | return 0; |
364 | } | 386 | } |
365 | 387 | ||
@@ -376,6 +398,7 @@ static int parse_one_device(const char **s,const char **e, | |||
376 | 398 | ||
377 | /* parse vendor_id */ | 399 | /* parse vendor_id */ |
378 | runner = *s; | 400 | runner = *s; |
401 | |||
379 | while (runner < *e) { | 402 | while (runner < *e) { |
380 | /* scan for vendor:device delimiter */ | 403 | /* scan for vendor:device delimiter */ |
381 | if (*runner == ':') { | 404 | if (*runner == ':') { |
@@ -383,6 +406,7 @@ static int parse_one_device(const char **s,const char **e, | |||
383 | runner = p + 1; | 406 | runner = p + 1; |
384 | break; | 407 | break; |
385 | } | 408 | } |
409 | |||
386 | runner++; | 410 | runner++; |
387 | } | 411 | } |
388 | 412 | ||
@@ -398,12 +422,11 @@ static int parse_one_device(const char **s,const char **e, | |||
398 | } | 422 | } |
399 | 423 | ||
400 | *s = runner; | 424 | *s = runner; |
401 | |||
402 | return 1; | 425 | return 1; |
403 | } | 426 | } |
404 | 427 | ||
405 | static ssize_t edac_pci_list_string_store(void *ptr, const char *buffer, | 428 | static ssize_t edac_pci_list_string_store(void *ptr, const char *buffer, |
406 | size_t count) | 429 | size_t count) |
407 | { | 430 | { |
408 | struct list_control *listctl; | 431 | struct list_control *listctl; |
409 | struct edac_pci_device_list *list; | 432 | struct edac_pci_device_list *list; |
@@ -413,14 +436,12 @@ static ssize_t edac_pci_list_string_store(void *ptr, const char *buffer, | |||
413 | 436 | ||
414 | s = (char*)buffer; | 437 | s = (char*)buffer; |
415 | e = s + count; | 438 | e = s + count; |
416 | |||
417 | listctl = ptr; | 439 | listctl = ptr; |
418 | list = listctl->list; | 440 | list = listctl->list; |
419 | index = listctl->count; | 441 | index = listctl->count; |
420 | |||
421 | *index = 0; | 442 | *index = 0; |
422 | while (*index < MAX_LISTED_PCI_DEVICES) { | ||
423 | 443 | ||
444 | while (*index < MAX_LISTED_PCI_DEVICES) { | ||
424 | if (parse_one_device(&s,&e,&vendor_id,&device_id)) { | 445 | if (parse_one_device(&s,&e,&vendor_id,&device_id)) { |
425 | list[ *index ].vendor = vendor_id; | 446 | list[ *index ].vendor = vendor_id; |
426 | list[ *index ].device = device_id; | 447 | list[ *index ].device = device_id; |
@@ -453,15 +474,15 @@ static ssize_t edac_pci_int_store(void *ptr, const char *buffer, size_t count) | |||
453 | } | 474 | } |
454 | 475 | ||
455 | struct edac_pci_dev_attribute { | 476 | struct edac_pci_dev_attribute { |
456 | struct attribute attr; | 477 | struct attribute attr; |
457 | void *value; | 478 | void *value; |
458 | ssize_t (*show)(void *,char *); | 479 | ssize_t (*show)(void *,char *); |
459 | ssize_t (*store)(void *, const char *,size_t); | 480 | ssize_t (*store)(void *, const char *,size_t); |
460 | }; | 481 | }; |
461 | 482 | ||
462 | /* Set of show/store abstract level functions for PCI Parity object */ | 483 | /* Set of show/store abstract level functions for PCI Parity object */ |
463 | static ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr, | 484 | static ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr, |
464 | char *buffer) | 485 | char *buffer) |
465 | { | 486 | { |
466 | struct edac_pci_dev_attribute *edac_pci_dev; | 487 | struct edac_pci_dev_attribute *edac_pci_dev; |
467 | edac_pci_dev= (struct edac_pci_dev_attribute*)attr; | 488 | edac_pci_dev= (struct edac_pci_dev_attribute*)attr; |
@@ -471,8 +492,8 @@ static ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr, | |||
471 | return -EIO; | 492 | return -EIO; |
472 | } | 493 | } |
473 | 494 | ||
474 | static ssize_t edac_pci_dev_store(struct kobject *kobj, struct attribute *attr, | 495 | static ssize_t edac_pci_dev_store(struct kobject *kobj, |
475 | const char *buffer, size_t count) | 496 | struct attribute *attr, const char *buffer, size_t count) |
476 | { | 497 | { |
477 | struct edac_pci_dev_attribute *edac_pci_dev; | 498 | struct edac_pci_dev_attribute *edac_pci_dev; |
478 | edac_pci_dev= (struct edac_pci_dev_attribute*)attr; | 499 | edac_pci_dev= (struct edac_pci_dev_attribute*)attr; |
@@ -487,7 +508,6 @@ static struct sysfs_ops edac_pci_sysfs_ops = { | |||
487 | .store = edac_pci_dev_store | 508 | .store = edac_pci_dev_store |
488 | }; | 509 | }; |
489 | 510 | ||
490 | |||
491 | #define EDAC_PCI_ATTR(_name,_mode,_show,_store) \ | 511 | #define EDAC_PCI_ATTR(_name,_mode,_show,_store) \ |
492 | struct edac_pci_dev_attribute edac_pci_attr_##_name = { \ | 512 | struct edac_pci_dev_attribute edac_pci_attr_##_name = { \ |
493 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | 513 | .attr = {.name = __stringify(_name), .mode = _mode }, \ |
@@ -530,9 +550,11 @@ EDAC_PCI_STRING_ATTR(pci_parity_blacklist, | |||
530 | #endif | 550 | #endif |
531 | 551 | ||
532 | /* PCI Parity control files */ | 552 | /* PCI Parity control files */ |
533 | EDAC_PCI_ATTR(check_pci_parity,S_IRUGO|S_IWUSR,edac_pci_int_show,edac_pci_int_store); | 553 | EDAC_PCI_ATTR(check_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show, |
534 | EDAC_PCI_ATTR(panic_on_pci_parity,S_IRUGO|S_IWUSR,edac_pci_int_show,edac_pci_int_store); | 554 | edac_pci_int_store); |
535 | EDAC_PCI_ATTR(pci_parity_count,S_IRUGO,edac_pci_int_show,NULL); | 555 | EDAC_PCI_ATTR(panic_on_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show, |
556 | edac_pci_int_store); | ||
557 | EDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL); | ||
536 | 558 | ||
537 | /* Base Attributes of the memory ECC object */ | 559 | /* Base Attributes of the memory ECC object */ |
538 | static struct edac_pci_dev_attribute *edac_pci_attr[] = { | 560 | static struct edac_pci_dev_attribute *edac_pci_attr[] = { |
@@ -545,53 +567,65 @@ static struct edac_pci_dev_attribute *edac_pci_attr[] = { | |||
545 | /* No memory to release */ | 567 | /* No memory to release */ |
546 | static void edac_pci_release(struct kobject *kobj) | 568 | static void edac_pci_release(struct kobject *kobj) |
547 | { | 569 | { |
548 | debugf1("EDAC PCI: " __FILE__ ": %s()\n", __func__); | 570 | debugf1("%s()\n", __func__); |
571 | complete(&edac_pci_kobj_complete); | ||
549 | } | 572 | } |
550 | 573 | ||
551 | static struct kobj_type ktype_edac_pci = { | 574 | static struct kobj_type ktype_edac_pci = { |
552 | .release = edac_pci_release, | 575 | .release = edac_pci_release, |
553 | .sysfs_ops = &edac_pci_sysfs_ops, | 576 | .sysfs_ops = &edac_pci_sysfs_ops, |
554 | .default_attrs = (struct attribute **) edac_pci_attr, | 577 | .default_attrs = (struct attribute **) edac_pci_attr, |
555 | }; | 578 | }; |
556 | 579 | ||
580 | #endif /* DISABLE_EDAC_SYSFS */ | ||
581 | |||
557 | /** | 582 | /** |
558 | * edac_sysfs_pci_setup() | 583 | * edac_sysfs_pci_setup() |
559 | * | 584 | * |
560 | */ | 585 | */ |
561 | static int edac_sysfs_pci_setup(void) | 586 | static int edac_sysfs_pci_setup(void) |
587 | #ifdef DISABLE_EDAC_SYSFS | ||
588 | { | ||
589 | return 0; | ||
590 | } | ||
591 | #else | ||
562 | { | 592 | { |
563 | int err; | 593 | int err; |
564 | 594 | ||
565 | debugf1("MC: " __FILE__ ": %s()\n", __func__); | 595 | debugf1("%s()\n", __func__); |
566 | 596 | ||
567 | memset(&edac_pci_kobj, 0, sizeof(edac_pci_kobj)); | 597 | memset(&edac_pci_kobj, 0, sizeof(edac_pci_kobj)); |
568 | |||
569 | kobject_init(&edac_pci_kobj); | ||
570 | edac_pci_kobj.parent = &edac_class.kset.kobj; | 598 | edac_pci_kobj.parent = &edac_class.kset.kobj; |
571 | edac_pci_kobj.ktype = &ktype_edac_pci; | 599 | edac_pci_kobj.ktype = &ktype_edac_pci; |
572 | |||
573 | err = kobject_set_name(&edac_pci_kobj, "pci"); | 600 | err = kobject_set_name(&edac_pci_kobj, "pci"); |
601 | |||
574 | if (!err) { | 602 | if (!err) { |
575 | /* Instanstiate the csrow object */ | 603 | /* Instanstiate the csrow object */ |
576 | /* FIXME: maybe new sysdev_create_subdir() */ | 604 | /* FIXME: maybe new sysdev_create_subdir() */ |
577 | err = kobject_register(&edac_pci_kobj); | 605 | err = kobject_register(&edac_pci_kobj); |
606 | |||
578 | if (err) | 607 | if (err) |
579 | debugf1("Failed to register '.../edac/pci'\n"); | 608 | debugf1("Failed to register '.../edac/pci'\n"); |
580 | else | 609 | else |
581 | debugf1("Registered '.../edac/pci' kobject\n"); | 610 | debugf1("Registered '.../edac/pci' kobject\n"); |
582 | } | 611 | } |
612 | |||
583 | return err; | 613 | return err; |
584 | } | 614 | } |
585 | 615 | #endif /* DISABLE_EDAC_SYSFS */ | |
586 | 616 | ||
587 | static void edac_sysfs_pci_teardown(void) | 617 | static void edac_sysfs_pci_teardown(void) |
588 | { | 618 | { |
589 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | 619 | #ifndef DISABLE_EDAC_SYSFS |
590 | 620 | debugf0("%s()\n", __func__); | |
621 | init_completion(&edac_pci_kobj_complete); | ||
591 | kobject_unregister(&edac_pci_kobj); | 622 | kobject_unregister(&edac_pci_kobj); |
592 | kobject_put(&edac_pci_kobj); | 623 | wait_for_completion(&edac_pci_kobj_complete); |
624 | #endif | ||
593 | } | 625 | } |
594 | 626 | ||
627 | #ifndef DISABLE_EDAC_SYSFS | ||
628 | |||
595 | /* EDAC sysfs CSROW data structures and methods */ | 629 | /* EDAC sysfs CSROW data structures and methods */ |
596 | 630 | ||
597 | /* Set of more detailed csrow<id> attribute show/store functions */ | 631 | /* Set of more detailed csrow<id> attribute show/store functions */ |
@@ -603,6 +637,7 @@ static ssize_t csrow_ch0_dimm_label_show(struct csrow_info *csrow, char *data) | |||
603 | size = snprintf(data, EDAC_MC_LABEL_LEN,"%s\n", | 637 | size = snprintf(data, EDAC_MC_LABEL_LEN,"%s\n", |
604 | csrow->channels[0].label); | 638 | csrow->channels[0].label); |
605 | } | 639 | } |
640 | |||
606 | return size; | 641 | return size; |
607 | } | 642 | } |
608 | 643 | ||
@@ -614,11 +649,12 @@ static ssize_t csrow_ch1_dimm_label_show(struct csrow_info *csrow, char *data) | |||
614 | size = snprintf(data, EDAC_MC_LABEL_LEN, "%s\n", | 649 | size = snprintf(data, EDAC_MC_LABEL_LEN, "%s\n", |
615 | csrow->channels[1].label); | 650 | csrow->channels[1].label); |
616 | } | 651 | } |
652 | |||
617 | return size; | 653 | return size; |
618 | } | 654 | } |
619 | 655 | ||
620 | static ssize_t csrow_ch0_dimm_label_store(struct csrow_info *csrow, | 656 | static ssize_t csrow_ch0_dimm_label_store(struct csrow_info *csrow, |
621 | const char *data, size_t size) | 657 | const char *data, size_t size) |
622 | { | 658 | { |
623 | ssize_t max_size = 0; | 659 | ssize_t max_size = 0; |
624 | 660 | ||
@@ -627,11 +663,12 @@ static ssize_t csrow_ch0_dimm_label_store(struct csrow_info *csrow, | |||
627 | strncpy(csrow->channels[0].label, data, max_size); | 663 | strncpy(csrow->channels[0].label, data, max_size); |
628 | csrow->channels[0].label[max_size] = '\0'; | 664 | csrow->channels[0].label[max_size] = '\0'; |
629 | } | 665 | } |
666 | |||
630 | return size; | 667 | return size; |
631 | } | 668 | } |
632 | 669 | ||
633 | static ssize_t csrow_ch1_dimm_label_store(struct csrow_info *csrow, | 670 | static ssize_t csrow_ch1_dimm_label_store(struct csrow_info *csrow, |
634 | const char *data, size_t size) | 671 | const char *data, size_t size) |
635 | { | 672 | { |
636 | ssize_t max_size = 0; | 673 | ssize_t max_size = 0; |
637 | 674 | ||
@@ -640,6 +677,7 @@ static ssize_t csrow_ch1_dimm_label_store(struct csrow_info *csrow, | |||
640 | strncpy(csrow->channels[1].label, data, max_size); | 677 | strncpy(csrow->channels[1].label, data, max_size); |
641 | csrow->channels[1].label[max_size] = '\0'; | 678 | csrow->channels[1].label[max_size] = '\0'; |
642 | } | 679 | } |
680 | |||
643 | return max_size; | 681 | return max_size; |
644 | } | 682 | } |
645 | 683 | ||
@@ -660,6 +698,7 @@ static ssize_t csrow_ch0_ce_count_show(struct csrow_info *csrow, char *data) | |||
660 | if (csrow->nr_channels > 0) { | 698 | if (csrow->nr_channels > 0) { |
661 | size = sprintf(data,"%u\n", csrow->channels[0].ce_count); | 699 | size = sprintf(data,"%u\n", csrow->channels[0].ce_count); |
662 | } | 700 | } |
701 | |||
663 | return size; | 702 | return size; |
664 | } | 703 | } |
665 | 704 | ||
@@ -670,6 +709,7 @@ static ssize_t csrow_ch1_ce_count_show(struct csrow_info *csrow, char *data) | |||
670 | if (csrow->nr_channels > 1) { | 709 | if (csrow->nr_channels > 1) { |
671 | size = sprintf(data,"%u\n", csrow->channels[1].ce_count); | 710 | size = sprintf(data,"%u\n", csrow->channels[1].ce_count); |
672 | } | 711 | } |
712 | |||
673 | return size; | 713 | return size; |
674 | } | 714 | } |
675 | 715 | ||
@@ -694,7 +734,7 @@ static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data) | |||
694 | } | 734 | } |
695 | 735 | ||
696 | struct csrowdev_attribute { | 736 | struct csrowdev_attribute { |
697 | struct attribute attr; | 737 | struct attribute attr; |
698 | ssize_t (*show)(struct csrow_info *,char *); | 738 | ssize_t (*show)(struct csrow_info *,char *); |
699 | ssize_t (*store)(struct csrow_info *, const char *,size_t); | 739 | ssize_t (*store)(struct csrow_info *, const char *,size_t); |
700 | }; | 740 | }; |
@@ -704,24 +744,26 @@ struct csrowdev_attribute { | |||
704 | 744 | ||
705 | /* Set of show/store higher level functions for csrow objects */ | 745 | /* Set of show/store higher level functions for csrow objects */ |
706 | static ssize_t csrowdev_show(struct kobject *kobj, struct attribute *attr, | 746 | static ssize_t csrowdev_show(struct kobject *kobj, struct attribute *attr, |
707 | char *buffer) | 747 | char *buffer) |
708 | { | 748 | { |
709 | struct csrow_info *csrow = to_csrow(kobj); | 749 | struct csrow_info *csrow = to_csrow(kobj); |
710 | struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr); | 750 | struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr); |
711 | 751 | ||
712 | if (csrowdev_attr->show) | 752 | if (csrowdev_attr->show) |
713 | return csrowdev_attr->show(csrow, buffer); | 753 | return csrowdev_attr->show(csrow, buffer); |
754 | |||
714 | return -EIO; | 755 | return -EIO; |
715 | } | 756 | } |
716 | 757 | ||
717 | static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr, | 758 | static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr, |
718 | const char *buffer, size_t count) | 759 | const char *buffer, size_t count) |
719 | { | 760 | { |
720 | struct csrow_info *csrow = to_csrow(kobj); | 761 | struct csrow_info *csrow = to_csrow(kobj); |
721 | struct csrowdev_attribute * csrowdev_attr = to_csrowdev_attr(attr); | 762 | struct csrowdev_attribute * csrowdev_attr = to_csrowdev_attr(attr); |
722 | 763 | ||
723 | if (csrowdev_attr->store) | 764 | if (csrowdev_attr->store) |
724 | return csrowdev_attr->store(csrow, buffer, count); | 765 | return csrowdev_attr->store(csrow, buffer, count); |
766 | |||
725 | return -EIO; | 767 | return -EIO; |
726 | } | 768 | } |
727 | 769 | ||
@@ -755,7 +797,6 @@ CSROWDEV_ATTR(ch1_dimm_label,S_IRUGO|S_IWUSR, | |||
755 | csrow_ch1_dimm_label_show, | 797 | csrow_ch1_dimm_label_show, |
756 | csrow_ch1_dimm_label_store); | 798 | csrow_ch1_dimm_label_store); |
757 | 799 | ||
758 | |||
759 | /* Attributes of the CSROW<id> object */ | 800 | /* Attributes of the CSROW<id> object */ |
760 | static struct csrowdev_attribute *csrow_attr[] = { | 801 | static struct csrowdev_attribute *csrow_attr[] = { |
761 | &attr_dev_type, | 802 | &attr_dev_type, |
@@ -771,40 +812,43 @@ static struct csrowdev_attribute *csrow_attr[] = { | |||
771 | NULL, | 812 | NULL, |
772 | }; | 813 | }; |
773 | 814 | ||
774 | |||
775 | /* No memory to release */ | 815 | /* No memory to release */ |
776 | static void edac_csrow_instance_release(struct kobject *kobj) | 816 | static void edac_csrow_instance_release(struct kobject *kobj) |
777 | { | 817 | { |
778 | debugf1("EDAC MC: " __FILE__ ": %s()\n", __func__); | 818 | struct csrow_info *cs; |
819 | |||
820 | debugf1("%s()\n", __func__); | ||
821 | cs = container_of(kobj, struct csrow_info, kobj); | ||
822 | complete(&cs->kobj_complete); | ||
779 | } | 823 | } |
780 | 824 | ||
781 | static struct kobj_type ktype_csrow = { | 825 | static struct kobj_type ktype_csrow = { |
782 | .release = edac_csrow_instance_release, | 826 | .release = edac_csrow_instance_release, |
783 | .sysfs_ops = &csrowfs_ops, | 827 | .sysfs_ops = &csrowfs_ops, |
784 | .default_attrs = (struct attribute **) csrow_attr, | 828 | .default_attrs = (struct attribute **) csrow_attr, |
785 | }; | 829 | }; |
786 | 830 | ||
787 | /* Create a CSROW object under specifed edac_mc_device */ | 831 | /* Create a CSROW object under specifed edac_mc_device */ |
788 | static int edac_create_csrow_object(struct kobject *edac_mci_kobj, | 832 | static int edac_create_csrow_object(struct kobject *edac_mci_kobj, |
789 | struct csrow_info *csrow, int index ) | 833 | struct csrow_info *csrow, int index) |
790 | { | 834 | { |
791 | int err = 0; | 835 | int err = 0; |
792 | 836 | ||
793 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | 837 | debugf0("%s()\n", __func__); |
794 | |||
795 | memset(&csrow->kobj, 0, sizeof(csrow->kobj)); | 838 | memset(&csrow->kobj, 0, sizeof(csrow->kobj)); |
796 | 839 | ||
797 | /* generate ..../edac/mc/mc<id>/csrow<index> */ | 840 | /* generate ..../edac/mc/mc<id>/csrow<index> */ |
798 | 841 | ||
799 | kobject_init(&csrow->kobj); | ||
800 | csrow->kobj.parent = edac_mci_kobj; | 842 | csrow->kobj.parent = edac_mci_kobj; |
801 | csrow->kobj.ktype = &ktype_csrow; | 843 | csrow->kobj.ktype = &ktype_csrow; |
802 | 844 | ||
803 | /* name this instance of csrow<id> */ | 845 | /* name this instance of csrow<id> */ |
804 | err = kobject_set_name(&csrow->kobj,"csrow%d",index); | 846 | err = kobject_set_name(&csrow->kobj,"csrow%d",index); |
847 | |||
805 | if (!err) { | 848 | if (!err) { |
806 | /* Instanstiate the csrow object */ | 849 | /* Instanstiate the csrow object */ |
807 | err = kobject_register(&csrow->kobj); | 850 | err = kobject_register(&csrow->kobj); |
851 | |||
808 | if (err) | 852 | if (err) |
809 | debugf0("Failed to register CSROW%d\n",index); | 853 | debugf0("Failed to register CSROW%d\n",index); |
810 | else | 854 | else |
@@ -816,8 +860,8 @@ static int edac_create_csrow_object(struct kobject *edac_mci_kobj, | |||
816 | 860 | ||
817 | /* sysfs data structures and methods for the MCI kobjects */ | 861 | /* sysfs data structures and methods for the MCI kobjects */ |
818 | 862 | ||
819 | static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci, | 863 | static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci, |
820 | const char *data, size_t count ) | 864 | const char *data, size_t count) |
821 | { | 865 | { |
822 | int row, chan; | 866 | int row, chan; |
823 | 867 | ||
@@ -825,16 +869,18 @@ static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci, | |||
825 | mci->ce_noinfo_count = 0; | 869 | mci->ce_noinfo_count = 0; |
826 | mci->ue_count = 0; | 870 | mci->ue_count = 0; |
827 | mci->ce_count = 0; | 871 | mci->ce_count = 0; |
872 | |||
828 | for (row = 0; row < mci->nr_csrows; row++) { | 873 | for (row = 0; row < mci->nr_csrows; row++) { |
829 | struct csrow_info *ri = &mci->csrows[row]; | 874 | struct csrow_info *ri = &mci->csrows[row]; |
830 | 875 | ||
831 | ri->ue_count = 0; | 876 | ri->ue_count = 0; |
832 | ri->ce_count = 0; | 877 | ri->ce_count = 0; |
878 | |||
833 | for (chan = 0; chan < ri->nr_channels; chan++) | 879 | for (chan = 0; chan < ri->nr_channels; chan++) |
834 | ri->channels[chan].ce_count = 0; | 880 | ri->channels[chan].ce_count = 0; |
835 | } | 881 | } |
836 | mci->start_time = jiffies; | ||
837 | 882 | ||
883 | mci->start_time = jiffies; | ||
838 | return count; | 884 | return count; |
839 | } | 885 | } |
840 | 886 | ||
@@ -892,18 +938,16 @@ static ssize_t mci_edac_capability_show(struct mem_ctl_info *mci, char *data) | |||
892 | 938 | ||
893 | p += mci_output_edac_cap(p,mci->edac_ctl_cap); | 939 | p += mci_output_edac_cap(p,mci->edac_ctl_cap); |
894 | p += sprintf(p, "\n"); | 940 | p += sprintf(p, "\n"); |
895 | |||
896 | return p - data; | 941 | return p - data; |
897 | } | 942 | } |
898 | 943 | ||
899 | static ssize_t mci_edac_current_capability_show(struct mem_ctl_info *mci, | 944 | static ssize_t mci_edac_current_capability_show(struct mem_ctl_info *mci, |
900 | char *data) | 945 | char *data) |
901 | { | 946 | { |
902 | char *p = data; | 947 | char *p = data; |
903 | 948 | ||
904 | p += mci_output_edac_cap(p,mci->edac_cap); | 949 | p += mci_output_edac_cap(p,mci->edac_cap); |
905 | p += sprintf(p, "\n"); | 950 | p += sprintf(p, "\n"); |
906 | |||
907 | return p - data; | 951 | return p - data; |
908 | } | 952 | } |
909 | 953 | ||
@@ -920,13 +964,13 @@ static int mci_output_mtype_cap(char *buf, unsigned long mtype_cap) | |||
920 | return p - buf; | 964 | return p - buf; |
921 | } | 965 | } |
922 | 966 | ||
923 | static ssize_t mci_supported_mem_type_show(struct mem_ctl_info *mci, char *data) | 967 | static ssize_t mci_supported_mem_type_show(struct mem_ctl_info *mci, |
968 | char *data) | ||
924 | { | 969 | { |
925 | char *p = data; | 970 | char *p = data; |
926 | 971 | ||
927 | p += mci_output_mtype_cap(p,mci->mtype_cap); | 972 | p += mci_output_mtype_cap(p,mci->mtype_cap); |
928 | p += sprintf(p, "\n"); | 973 | p += sprintf(p, "\n"); |
929 | |||
930 | return p - data; | 974 | return p - data; |
931 | } | 975 | } |
932 | 976 | ||
@@ -940,6 +984,7 @@ static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data) | |||
940 | 984 | ||
941 | if (!csrow->nr_pages) | 985 | if (!csrow->nr_pages) |
942 | continue; | 986 | continue; |
987 | |||
943 | total_pages += csrow->nr_pages; | 988 | total_pages += csrow->nr_pages; |
944 | } | 989 | } |
945 | 990 | ||
@@ -947,7 +992,7 @@ static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data) | |||
947 | } | 992 | } |
948 | 993 | ||
949 | struct mcidev_attribute { | 994 | struct mcidev_attribute { |
950 | struct attribute attr; | 995 | struct attribute attr; |
951 | ssize_t (*show)(struct mem_ctl_info *,char *); | 996 | ssize_t (*show)(struct mem_ctl_info *,char *); |
952 | ssize_t (*store)(struct mem_ctl_info *, const char *,size_t); | 997 | ssize_t (*store)(struct mem_ctl_info *, const char *,size_t); |
953 | }; | 998 | }; |
@@ -956,30 +1001,32 @@ struct mcidev_attribute { | |||
956 | #define to_mcidev_attr(a) container_of(a, struct mcidev_attribute, attr) | 1001 | #define to_mcidev_attr(a) container_of(a, struct mcidev_attribute, attr) |
957 | 1002 | ||
958 | static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr, | 1003 | static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr, |
959 | char *buffer) | 1004 | char *buffer) |
960 | { | 1005 | { |
961 | struct mem_ctl_info *mem_ctl_info = to_mci(kobj); | 1006 | struct mem_ctl_info *mem_ctl_info = to_mci(kobj); |
962 | struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr); | 1007 | struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr); |
963 | 1008 | ||
964 | if (mcidev_attr->show) | 1009 | if (mcidev_attr->show) |
965 | return mcidev_attr->show(mem_ctl_info, buffer); | 1010 | return mcidev_attr->show(mem_ctl_info, buffer); |
1011 | |||
966 | return -EIO; | 1012 | return -EIO; |
967 | } | 1013 | } |
968 | 1014 | ||
969 | static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr, | 1015 | static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr, |
970 | const char *buffer, size_t count) | 1016 | const char *buffer, size_t count) |
971 | { | 1017 | { |
972 | struct mem_ctl_info *mem_ctl_info = to_mci(kobj); | 1018 | struct mem_ctl_info *mem_ctl_info = to_mci(kobj); |
973 | struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr); | 1019 | struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr); |
974 | 1020 | ||
975 | if (mcidev_attr->store) | 1021 | if (mcidev_attr->store) |
976 | return mcidev_attr->store(mem_ctl_info, buffer, count); | 1022 | return mcidev_attr->store(mem_ctl_info, buffer, count); |
1023 | |||
977 | return -EIO; | 1024 | return -EIO; |
978 | } | 1025 | } |
979 | 1026 | ||
980 | static struct sysfs_ops mci_ops = { | 1027 | static struct sysfs_ops mci_ops = { |
981 | .show = mcidev_show, | 1028 | .show = mcidev_show, |
982 | .store = mcidev_store | 1029 | .store = mcidev_store |
983 | }; | 1030 | }; |
984 | 1031 | ||
985 | #define MCIDEV_ATTR(_name,_mode,_show,_store) \ | 1032 | #define MCIDEV_ATTR(_name,_mode,_show,_store) \ |
@@ -1007,7 +1054,6 @@ MCIDEV_ATTR(edac_current_capability,S_IRUGO, | |||
1007 | MCIDEV_ATTR(supported_mem_type,S_IRUGO, | 1054 | MCIDEV_ATTR(supported_mem_type,S_IRUGO, |
1008 | mci_supported_mem_type_show,NULL); | 1055 | mci_supported_mem_type_show,NULL); |
1009 | 1056 | ||
1010 | |||
1011 | static struct mcidev_attribute *mci_attr[] = { | 1057 | static struct mcidev_attribute *mci_attr[] = { |
1012 | &mci_attr_reset_counters, | 1058 | &mci_attr_reset_counters, |
1013 | &mci_attr_module_name, | 1059 | &mci_attr_module_name, |
@@ -1024,27 +1070,26 @@ static struct mcidev_attribute *mci_attr[] = { | |||
1024 | NULL | 1070 | NULL |
1025 | }; | 1071 | }; |
1026 | 1072 | ||
1027 | |||
1028 | /* | 1073 | /* |
1029 | * Release of a MC controlling instance | 1074 | * Release of a MC controlling instance |
1030 | */ | 1075 | */ |
1031 | static void edac_mci_instance_release(struct kobject *kobj) | 1076 | static void edac_mci_instance_release(struct kobject *kobj) |
1032 | { | 1077 | { |
1033 | struct mem_ctl_info *mci; | 1078 | struct mem_ctl_info *mci; |
1034 | mci = container_of(kobj,struct mem_ctl_info,edac_mci_kobj); | ||
1035 | |||
1036 | debugf0("MC: " __FILE__ ": %s() idx=%d calling kfree\n", | ||
1037 | __func__, mci->mc_idx); | ||
1038 | 1079 | ||
1039 | kfree(mci); | 1080 | mci = to_mci(kobj); |
1081 | debugf0("%s() idx=%d\n", __func__, mci->mc_idx); | ||
1082 | complete(&mci->kobj_complete); | ||
1040 | } | 1083 | } |
1041 | 1084 | ||
1042 | static struct kobj_type ktype_mci = { | 1085 | static struct kobj_type ktype_mci = { |
1043 | .release = edac_mci_instance_release, | 1086 | .release = edac_mci_instance_release, |
1044 | .sysfs_ops = &mci_ops, | 1087 | .sysfs_ops = &mci_ops, |
1045 | .default_attrs = (struct attribute **) mci_attr, | 1088 | .default_attrs = (struct attribute **) mci_attr, |
1046 | }; | 1089 | }; |
1047 | 1090 | ||
1091 | #endif /* DISABLE_EDAC_SYSFS */ | ||
1092 | |||
1048 | #define EDAC_DEVICE_SYMLINK "device" | 1093 | #define EDAC_DEVICE_SYMLINK "device" |
1049 | 1094 | ||
1050 | /* | 1095 | /* |
@@ -1056,19 +1101,23 @@ static struct kobj_type ktype_mci = { | |||
1056 | * !0 Failure | 1101 | * !0 Failure |
1057 | */ | 1102 | */ |
1058 | static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) | 1103 | static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) |
1104 | #ifdef DISABLE_EDAC_SYSFS | ||
1105 | { | ||
1106 | return 0; | ||
1107 | } | ||
1108 | #else | ||
1059 | { | 1109 | { |
1060 | int i; | 1110 | int i; |
1061 | int err; | 1111 | int err; |
1062 | struct csrow_info *csrow; | 1112 | struct csrow_info *csrow; |
1063 | struct kobject *edac_mci_kobj=&mci->edac_mci_kobj; | 1113 | struct kobject *edac_mci_kobj=&mci->edac_mci_kobj; |
1064 | 1114 | ||
1065 | debugf0("MC: " __FILE__ ": %s() idx=%d\n", __func__, mci->mc_idx); | 1115 | debugf0("%s() idx=%d\n", __func__, mci->mc_idx); |
1066 | |||
1067 | memset(edac_mci_kobj, 0, sizeof(*edac_mci_kobj)); | 1116 | memset(edac_mci_kobj, 0, sizeof(*edac_mci_kobj)); |
1068 | kobject_init(edac_mci_kobj); | ||
1069 | 1117 | ||
1070 | /* set the name of the mc<id> object */ | 1118 | /* set the name of the mc<id> object */ |
1071 | err = kobject_set_name(edac_mci_kobj,"mc%d",mci->mc_idx); | 1119 | err = kobject_set_name(edac_mci_kobj,"mc%d",mci->mc_idx); |
1120 | |||
1072 | if (err) | 1121 | if (err) |
1073 | return err; | 1122 | return err; |
1074 | 1123 | ||
@@ -1078,82 +1127,82 @@ static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci) | |||
1078 | 1127 | ||
1079 | /* register the mc<id> kobject */ | 1128 | /* register the mc<id> kobject */ |
1080 | err = kobject_register(edac_mci_kobj); | 1129 | err = kobject_register(edac_mci_kobj); |
1130 | |||
1081 | if (err) | 1131 | if (err) |
1082 | return err; | 1132 | return err; |
1083 | 1133 | ||
1084 | /* create a symlink for the device */ | 1134 | /* create a symlink for the device */ |
1085 | err = sysfs_create_link(edac_mci_kobj, &mci->pdev->dev.kobj, | 1135 | err = sysfs_create_link(edac_mci_kobj, &mci->pdev->dev.kobj, |
1086 | EDAC_DEVICE_SYMLINK); | 1136 | EDAC_DEVICE_SYMLINK); |
1087 | if (err) { | 1137 | |
1088 | kobject_unregister(edac_mci_kobj); | 1138 | if (err) |
1089 | return err; | 1139 | goto fail0; |
1090 | } | ||
1091 | 1140 | ||
1092 | /* Make directories for each CSROW object | 1141 | /* Make directories for each CSROW object |
1093 | * under the mc<id> kobject | 1142 | * under the mc<id> kobject |
1094 | */ | 1143 | */ |
1095 | for (i = 0; i < mci->nr_csrows; i++) { | 1144 | for (i = 0; i < mci->nr_csrows; i++) { |
1096 | |||
1097 | csrow = &mci->csrows[i]; | 1145 | csrow = &mci->csrows[i]; |
1098 | 1146 | ||
1099 | /* Only expose populated CSROWs */ | 1147 | /* Only expose populated CSROWs */ |
1100 | if (csrow->nr_pages > 0) { | 1148 | if (csrow->nr_pages > 0) { |
1101 | err = edac_create_csrow_object(edac_mci_kobj,csrow,i); | 1149 | err = edac_create_csrow_object(edac_mci_kobj,csrow,i); |
1150 | |||
1102 | if (err) | 1151 | if (err) |
1103 | goto fail; | 1152 | goto fail1; |
1104 | } | 1153 | } |
1105 | } | 1154 | } |
1106 | 1155 | ||
1107 | /* Mark this MCI instance as having sysfs entries */ | ||
1108 | mci->sysfs_active = MCI_SYSFS_ACTIVE; | ||
1109 | |||
1110 | return 0; | 1156 | return 0; |
1111 | 1157 | ||
1112 | |||
1113 | /* CSROW error: backout what has already been registered, */ | 1158 | /* CSROW error: backout what has already been registered, */ |
1114 | fail: | 1159 | fail1: |
1115 | for ( i--; i >= 0; i--) { | 1160 | for ( i--; i >= 0; i--) { |
1116 | if (csrow->nr_pages > 0) { | 1161 | if (csrow->nr_pages > 0) { |
1162 | init_completion(&csrow->kobj_complete); | ||
1117 | kobject_unregister(&mci->csrows[i].kobj); | 1163 | kobject_unregister(&mci->csrows[i].kobj); |
1118 | kobject_put(&mci->csrows[i].kobj); | 1164 | wait_for_completion(&csrow->kobj_complete); |
1119 | } | 1165 | } |
1120 | } | 1166 | } |
1121 | 1167 | ||
1168 | fail0: | ||
1169 | init_completion(&mci->kobj_complete); | ||
1122 | kobject_unregister(edac_mci_kobj); | 1170 | kobject_unregister(edac_mci_kobj); |
1123 | kobject_put(edac_mci_kobj); | 1171 | wait_for_completion(&mci->kobj_complete); |
1124 | |||
1125 | return err; | 1172 | return err; |
1126 | } | 1173 | } |
1174 | #endif /* DISABLE_EDAC_SYSFS */ | ||
1127 | 1175 | ||
1128 | /* | 1176 | /* |
1129 | * remove a Memory Controller instance | 1177 | * remove a Memory Controller instance |
1130 | */ | 1178 | */ |
1131 | static void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) | 1179 | static void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) |
1132 | { | 1180 | { |
1181 | #ifndef DISABLE_EDAC_SYSFS | ||
1133 | int i; | 1182 | int i; |
1134 | 1183 | ||
1135 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | 1184 | debugf0("%s()\n", __func__); |
1136 | 1185 | ||
1137 | /* remove all csrow kobjects */ | 1186 | /* remove all csrow kobjects */ |
1138 | for (i = 0; i < mci->nr_csrows; i++) { | 1187 | for (i = 0; i < mci->nr_csrows; i++) { |
1139 | if (mci->csrows[i].nr_pages > 0) { | 1188 | if (mci->csrows[i].nr_pages > 0) { |
1189 | init_completion(&mci->csrows[i].kobj_complete); | ||
1140 | kobject_unregister(&mci->csrows[i].kobj); | 1190 | kobject_unregister(&mci->csrows[i].kobj); |
1141 | kobject_put(&mci->csrows[i].kobj); | 1191 | wait_for_completion(&mci->csrows[i].kobj_complete); |
1142 | } | 1192 | } |
1143 | } | 1193 | } |
1144 | 1194 | ||
1145 | sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK); | 1195 | sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK); |
1146 | 1196 | init_completion(&mci->kobj_complete); | |
1147 | kobject_unregister(&mci->edac_mci_kobj); | 1197 | kobject_unregister(&mci->edac_mci_kobj); |
1148 | kobject_put(&mci->edac_mci_kobj); | 1198 | wait_for_completion(&mci->kobj_complete); |
1199 | #endif /* DISABLE_EDAC_SYSFS */ | ||
1149 | } | 1200 | } |
1150 | 1201 | ||
1151 | /* END OF sysfs data and methods */ | 1202 | /* END OF sysfs data and methods */ |
1152 | 1203 | ||
1153 | #ifdef CONFIG_EDAC_DEBUG | 1204 | #ifdef CONFIG_EDAC_DEBUG |
1154 | 1205 | ||
1155 | EXPORT_SYMBOL(edac_mc_dump_channel); | ||
1156 | |||
1157 | void edac_mc_dump_channel(struct channel_info *chan) | 1206 | void edac_mc_dump_channel(struct channel_info *chan) |
1158 | { | 1207 | { |
1159 | debugf4("\tchannel = %p\n", chan); | 1208 | debugf4("\tchannel = %p\n", chan); |
@@ -1162,9 +1211,7 @@ void edac_mc_dump_channel(struct channel_info *chan) | |||
1162 | debugf4("\tchannel->label = '%s'\n", chan->label); | 1211 | debugf4("\tchannel->label = '%s'\n", chan->label); |
1163 | debugf4("\tchannel->csrow = %p\n\n", chan->csrow); | 1212 | debugf4("\tchannel->csrow = %p\n\n", chan->csrow); |
1164 | } | 1213 | } |
1165 | 1214 | EXPORT_SYMBOL_GPL(edac_mc_dump_channel); | |
1166 | |||
1167 | EXPORT_SYMBOL(edac_mc_dump_csrow); | ||
1168 | 1215 | ||
1169 | void edac_mc_dump_csrow(struct csrow_info *csrow) | 1216 | void edac_mc_dump_csrow(struct csrow_info *csrow) |
1170 | { | 1217 | { |
@@ -1180,9 +1227,7 @@ void edac_mc_dump_csrow(struct csrow_info *csrow) | |||
1180 | debugf4("\tcsrow->channels = %p\n", csrow->channels); | 1227 | debugf4("\tcsrow->channels = %p\n", csrow->channels); |
1181 | debugf4("\tcsrow->mci = %p\n\n", csrow->mci); | 1228 | debugf4("\tcsrow->mci = %p\n\n", csrow->mci); |
1182 | } | 1229 | } |
1183 | 1230 | EXPORT_SYMBOL_GPL(edac_mc_dump_csrow); | |
1184 | |||
1185 | EXPORT_SYMBOL(edac_mc_dump_mci); | ||
1186 | 1231 | ||
1187 | void edac_mc_dump_mci(struct mem_ctl_info *mci) | 1232 | void edac_mc_dump_mci(struct mem_ctl_info *mci) |
1188 | { | 1233 | { |
@@ -1198,9 +1243,9 @@ void edac_mc_dump_mci(struct mem_ctl_info *mci) | |||
1198 | mci->mod_name, mci->ctl_name); | 1243 | mci->mod_name, mci->ctl_name); |
1199 | debugf3("\tpvt_info = %p\n\n", mci->pvt_info); | 1244 | debugf3("\tpvt_info = %p\n\n", mci->pvt_info); |
1200 | } | 1245 | } |
1246 | EXPORT_SYMBOL_GPL(edac_mc_dump_mci); | ||
1201 | 1247 | ||
1202 | 1248 | #endif /* CONFIG_EDAC_DEBUG */ | |
1203 | #endif /* CONFIG_EDAC_DEBUG */ | ||
1204 | 1249 | ||
1205 | /* 'ptr' points to a possibly unaligned item X such that sizeof(X) is 'size'. | 1250 | /* 'ptr' points to a possibly unaligned item X such that sizeof(X) is 'size'. |
1206 | * Adjust 'ptr' so that its alignment is at least as stringent as what the | 1251 | * Adjust 'ptr' so that its alignment is at least as stringent as what the |
@@ -1209,7 +1254,7 @@ void edac_mc_dump_mci(struct mem_ctl_info *mci) | |||
1209 | * If 'size' is a constant, the compiler will optimize this whole function | 1254 | * If 'size' is a constant, the compiler will optimize this whole function |
1210 | * down to either a no-op or the addition of a constant to the value of 'ptr'. | 1255 | * down to either a no-op or the addition of a constant to the value of 'ptr'. |
1211 | */ | 1256 | */ |
1212 | static inline char * align_ptr (void *ptr, unsigned size) | 1257 | static inline char * align_ptr(void *ptr, unsigned size) |
1213 | { | 1258 | { |
1214 | unsigned align, r; | 1259 | unsigned align, r; |
1215 | 1260 | ||
@@ -1236,9 +1281,6 @@ static inline char * align_ptr (void *ptr, unsigned size) | |||
1236 | return (char *) (((unsigned long) ptr) + align - r); | 1281 | return (char *) (((unsigned long) ptr) + align - r); |
1237 | } | 1282 | } |
1238 | 1283 | ||
1239 | |||
1240 | EXPORT_SYMBOL(edac_mc_alloc); | ||
1241 | |||
1242 | /** | 1284 | /** |
1243 | * edac_mc_alloc: Allocate a struct mem_ctl_info structure | 1285 | * edac_mc_alloc: Allocate a struct mem_ctl_info structure |
1244 | * @size_pvt: size of private storage needed | 1286 | * @size_pvt: size of private storage needed |
@@ -1256,7 +1298,7 @@ EXPORT_SYMBOL(edac_mc_alloc); | |||
1256 | * struct mem_ctl_info pointer | 1298 | * struct mem_ctl_info pointer |
1257 | */ | 1299 | */ |
1258 | struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, | 1300 | struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, |
1259 | unsigned nr_chans) | 1301 | unsigned nr_chans) |
1260 | { | 1302 | { |
1261 | struct mem_ctl_info *mci; | 1303 | struct mem_ctl_info *mci; |
1262 | struct csrow_info *csi, *csrow; | 1304 | struct csrow_info *csi, *csrow; |
@@ -1287,8 +1329,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, | |||
1287 | chi = (struct channel_info *) (((char *) mci) + ((unsigned long) chi)); | 1329 | chi = (struct channel_info *) (((char *) mci) + ((unsigned long) chi)); |
1288 | pvt = sz_pvt ? (((char *) mci) + ((unsigned long) pvt)) : NULL; | 1330 | pvt = sz_pvt ? (((char *) mci) + ((unsigned long) pvt)) : NULL; |
1289 | 1331 | ||
1290 | memset(mci, 0, size); /* clear all fields */ | 1332 | memset(mci, 0, size); /* clear all fields */ |
1291 | |||
1292 | mci->csrows = csi; | 1333 | mci->csrows = csi; |
1293 | mci->pvt_info = pvt; | 1334 | mci->pvt_info = pvt; |
1294 | mci->nr_csrows = nr_csrows; | 1335 | mci->nr_csrows = nr_csrows; |
@@ -1310,50 +1351,24 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, | |||
1310 | 1351 | ||
1311 | return mci; | 1352 | return mci; |
1312 | } | 1353 | } |
1313 | 1354 | EXPORT_SYMBOL_GPL(edac_mc_alloc); | |
1314 | |||
1315 | EXPORT_SYMBOL(edac_mc_free); | ||
1316 | 1355 | ||
1317 | /** | 1356 | /** |
1318 | * edac_mc_free: Free a previously allocated 'mci' structure | 1357 | * edac_mc_free: Free a previously allocated 'mci' structure |
1319 | * @mci: pointer to a struct mem_ctl_info structure | 1358 | * @mci: pointer to a struct mem_ctl_info structure |
1320 | * | ||
1321 | * Free up a previously allocated mci structure | ||
1322 | * A MCI structure can be in 2 states after being allocated | ||
1323 | * by edac_mc_alloc(). | ||
1324 | * 1) Allocated in a MC driver's probe, but not yet committed | ||
1325 | * 2) Allocated and committed, by a call to edac_mc_add_mc() | ||
1326 | * edac_mc_add_mc() is the function that adds the sysfs entries | ||
1327 | * thus, this free function must determine which state the 'mci' | ||
1328 | * structure is in, then either free it directly or | ||
1329 | * perform kobject cleanup by calling edac_remove_sysfs_mci_device(). | ||
1330 | * | ||
1331 | * VOID Return | ||
1332 | */ | 1359 | */ |
1333 | void edac_mc_free(struct mem_ctl_info *mci) | 1360 | void edac_mc_free(struct mem_ctl_info *mci) |
1334 | { | 1361 | { |
1335 | /* only if sysfs entries for this mci instance exist | 1362 | kfree(mci); |
1336 | * do we remove them and defer the actual kfree via | ||
1337 | * the kobject 'release()' callback. | ||
1338 | * | ||
1339 | * Otherwise, do a straight kfree now. | ||
1340 | */ | ||
1341 | if (mci->sysfs_active == MCI_SYSFS_ACTIVE) | ||
1342 | edac_remove_sysfs_mci_device(mci); | ||
1343 | else | ||
1344 | kfree(mci); | ||
1345 | } | 1363 | } |
1364 | EXPORT_SYMBOL_GPL(edac_mc_free); | ||
1346 | 1365 | ||
1347 | 1366 | static struct mem_ctl_info *find_mci_by_pdev(struct pci_dev *pdev) | |
1348 | |||
1349 | EXPORT_SYMBOL(edac_mc_find_mci_by_pdev); | ||
1350 | |||
1351 | struct mem_ctl_info *edac_mc_find_mci_by_pdev(struct pci_dev *pdev) | ||
1352 | { | 1367 | { |
1353 | struct mem_ctl_info *mci; | 1368 | struct mem_ctl_info *mci; |
1354 | struct list_head *item; | 1369 | struct list_head *item; |
1355 | 1370 | ||
1356 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 1371 | debugf3("%s()\n", __func__); |
1357 | 1372 | ||
1358 | list_for_each(item, &mc_devices) { | 1373 | list_for_each(item, &mc_devices) { |
1359 | mci = list_entry(item, struct mem_ctl_info, link); | 1374 | mci = list_entry(item, struct mem_ctl_info, link); |
@@ -1365,7 +1380,7 @@ struct mem_ctl_info *edac_mc_find_mci_by_pdev(struct pci_dev *pdev) | |||
1365 | return NULL; | 1380 | return NULL; |
1366 | } | 1381 | } |
1367 | 1382 | ||
1368 | static int add_mc_to_global_list (struct mem_ctl_info *mci) | 1383 | static int add_mc_to_global_list(struct mem_ctl_info *mci) |
1369 | { | 1384 | { |
1370 | struct list_head *item, *insert_before; | 1385 | struct list_head *item, *insert_before; |
1371 | struct mem_ctl_info *p; | 1386 | struct mem_ctl_info *p; |
@@ -1375,11 +1390,12 @@ static int add_mc_to_global_list (struct mem_ctl_info *mci) | |||
1375 | mci->mc_idx = 0; | 1390 | mci->mc_idx = 0; |
1376 | insert_before = &mc_devices; | 1391 | insert_before = &mc_devices; |
1377 | } else { | 1392 | } else { |
1378 | if (edac_mc_find_mci_by_pdev(mci->pdev)) { | 1393 | if (find_mci_by_pdev(mci->pdev)) { |
1379 | printk(KERN_WARNING | 1394 | edac_printk(KERN_WARNING, EDAC_MC, |
1380 | "EDAC MC: %s (%s) %s %s already assigned %d\n", | 1395 | "%s (%s) %s %s already assigned %d\n", |
1381 | mci->pdev->dev.bus_id, pci_name(mci->pdev), | 1396 | mci->pdev->dev.bus_id, |
1382 | mci->mod_name, mci->ctl_name, mci->mc_idx); | 1397 | pci_name(mci->pdev), mci->mod_name, |
1398 | mci->ctl_name, mci->mc_idx); | ||
1383 | return 1; | 1399 | return 1; |
1384 | } | 1400 | } |
1385 | 1401 | ||
@@ -1407,12 +1423,26 @@ static int add_mc_to_global_list (struct mem_ctl_info *mci) | |||
1407 | return 0; | 1423 | return 0; |
1408 | } | 1424 | } |
1409 | 1425 | ||
1426 | static void complete_mc_list_del(struct rcu_head *head) | ||
1427 | { | ||
1428 | struct mem_ctl_info *mci; | ||
1410 | 1429 | ||
1430 | mci = container_of(head, struct mem_ctl_info, rcu); | ||
1431 | INIT_LIST_HEAD(&mci->link); | ||
1432 | complete(&mci->complete); | ||
1433 | } | ||
1411 | 1434 | ||
1412 | EXPORT_SYMBOL(edac_mc_add_mc); | 1435 | static void del_mc_from_global_list(struct mem_ctl_info *mci) |
1436 | { | ||
1437 | list_del_rcu(&mci->link); | ||
1438 | init_completion(&mci->complete); | ||
1439 | call_rcu(&mci->rcu, complete_mc_list_del); | ||
1440 | wait_for_completion(&mci->complete); | ||
1441 | } | ||
1413 | 1442 | ||
1414 | /** | 1443 | /** |
1415 | * edac_mc_add_mc: Insert the 'mci' structure into the mci global list | 1444 | * edac_mc_add_mc: Insert the 'mci' structure into the mci global list and |
1445 | * create sysfs entries associated with mci structure | ||
1416 | * @mci: pointer to the mci structure to be added to the list | 1446 | * @mci: pointer to the mci structure to be added to the list |
1417 | * | 1447 | * |
1418 | * Return: | 1448 | * Return: |
@@ -1423,111 +1453,90 @@ EXPORT_SYMBOL(edac_mc_add_mc); | |||
1423 | /* FIXME - should a warning be printed if no error detection? correction? */ | 1453 | /* FIXME - should a warning be printed if no error detection? correction? */ |
1424 | int edac_mc_add_mc(struct mem_ctl_info *mci) | 1454 | int edac_mc_add_mc(struct mem_ctl_info *mci) |
1425 | { | 1455 | { |
1426 | int rc = 1; | 1456 | debugf0("%s()\n", __func__); |
1427 | |||
1428 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | ||
1429 | #ifdef CONFIG_EDAC_DEBUG | 1457 | #ifdef CONFIG_EDAC_DEBUG |
1430 | if (edac_debug_level >= 3) | 1458 | if (edac_debug_level >= 3) |
1431 | edac_mc_dump_mci(mci); | 1459 | edac_mc_dump_mci(mci); |
1460 | |||
1432 | if (edac_debug_level >= 4) { | 1461 | if (edac_debug_level >= 4) { |
1433 | int i; | 1462 | int i; |
1434 | 1463 | ||
1435 | for (i = 0; i < mci->nr_csrows; i++) { | 1464 | for (i = 0; i < mci->nr_csrows; i++) { |
1436 | int j; | 1465 | int j; |
1466 | |||
1437 | edac_mc_dump_csrow(&mci->csrows[i]); | 1467 | edac_mc_dump_csrow(&mci->csrows[i]); |
1438 | for (j = 0; j < mci->csrows[i].nr_channels; j++) | 1468 | for (j = 0; j < mci->csrows[i].nr_channels; j++) |
1439 | edac_mc_dump_channel(&mci->csrows[i]. | 1469 | edac_mc_dump_channel( |
1440 | channels[j]); | 1470 | &mci->csrows[i].channels[j]); |
1441 | } | 1471 | } |
1442 | } | 1472 | } |
1443 | #endif | 1473 | #endif |
1444 | down(&mem_ctls_mutex); | 1474 | down(&mem_ctls_mutex); |
1445 | 1475 | ||
1446 | if (add_mc_to_global_list(mci)) | 1476 | if (add_mc_to_global_list(mci)) |
1447 | goto finish; | 1477 | goto fail0; |
1448 | 1478 | ||
1449 | /* set load time so that error rate can be tracked */ | 1479 | /* set load time so that error rate can be tracked */ |
1450 | mci->start_time = jiffies; | 1480 | mci->start_time = jiffies; |
1451 | 1481 | ||
1452 | if (edac_create_sysfs_mci_device(mci)) { | 1482 | if (edac_create_sysfs_mci_device(mci)) { |
1453 | printk(KERN_WARNING | 1483 | edac_mc_printk(mci, KERN_WARNING, |
1454 | "EDAC MC%d: failed to create sysfs device\n", | 1484 | "failed to create sysfs device\n"); |
1455 | mci->mc_idx); | 1485 | goto fail1; |
1456 | /* FIXME - should there be an error code and unwind? */ | ||
1457 | goto finish; | ||
1458 | } | 1486 | } |
1459 | 1487 | ||
1460 | /* Report action taken */ | 1488 | /* Report action taken */ |
1461 | printk(KERN_INFO | 1489 | edac_mc_printk(mci, KERN_INFO, "Giving out device to %s %s: PCI %s\n", |
1462 | "EDAC MC%d: Giving out device to %s %s: PCI %s\n", | 1490 | mci->mod_name, mci->ctl_name, pci_name(mci->pdev)); |
1463 | mci->mc_idx, mci->mod_name, mci->ctl_name, | ||
1464 | pci_name(mci->pdev)); | ||
1465 | |||
1466 | 1491 | ||
1467 | rc = 0; | ||
1468 | |||
1469 | finish: | ||
1470 | up(&mem_ctls_mutex); | 1492 | up(&mem_ctls_mutex); |
1471 | return rc; | 1493 | return 0; |
1472 | } | ||
1473 | |||
1474 | |||
1475 | |||
1476 | static void complete_mc_list_del (struct rcu_head *head) | ||
1477 | { | ||
1478 | struct mem_ctl_info *mci; | ||
1479 | 1494 | ||
1480 | mci = container_of(head, struct mem_ctl_info, rcu); | 1495 | fail1: |
1481 | INIT_LIST_HEAD(&mci->link); | 1496 | del_mc_from_global_list(mci); |
1482 | complete(&mci->complete); | ||
1483 | } | ||
1484 | 1497 | ||
1485 | static void del_mc_from_global_list (struct mem_ctl_info *mci) | 1498 | fail0: |
1486 | { | 1499 | up(&mem_ctls_mutex); |
1487 | list_del_rcu(&mci->link); | 1500 | return 1; |
1488 | init_completion(&mci->complete); | ||
1489 | call_rcu(&mci->rcu, complete_mc_list_del); | ||
1490 | wait_for_completion(&mci->complete); | ||
1491 | } | 1501 | } |
1492 | 1502 | EXPORT_SYMBOL_GPL(edac_mc_add_mc); | |
1493 | EXPORT_SYMBOL(edac_mc_del_mc); | ||
1494 | 1503 | ||
1495 | /** | 1504 | /** |
1496 | * edac_mc_del_mc: Remove the specified mci structure from global list | 1505 | * edac_mc_del_mc: Remove sysfs entries for specified mci structure and |
1497 | * @mci: Pointer to struct mem_ctl_info structure | 1506 | * remove mci structure from global list |
1507 | * @pdev: Pointer to 'struct pci_dev' representing mci structure to remove. | ||
1498 | * | 1508 | * |
1499 | * Returns: | 1509 | * Return pointer to removed mci structure, or NULL if device not found. |
1500 | * 0 Success | ||
1501 | * 1 Failure | ||
1502 | */ | 1510 | */ |
1503 | int edac_mc_del_mc(struct mem_ctl_info *mci) | 1511 | struct mem_ctl_info * edac_mc_del_mc(struct pci_dev *pdev) |
1504 | { | 1512 | { |
1505 | int rc = 1; | 1513 | struct mem_ctl_info *mci; |
1506 | 1514 | ||
1507 | debugf0("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__); | 1515 | debugf0("MC: %s()\n", __func__); |
1508 | down(&mem_ctls_mutex); | 1516 | down(&mem_ctls_mutex); |
1517 | |||
1518 | if ((mci = find_mci_by_pdev(pdev)) == NULL) { | ||
1519 | up(&mem_ctls_mutex); | ||
1520 | return NULL; | ||
1521 | } | ||
1522 | |||
1523 | edac_remove_sysfs_mci_device(mci); | ||
1509 | del_mc_from_global_list(mci); | 1524 | del_mc_from_global_list(mci); |
1510 | printk(KERN_INFO | ||
1511 | "EDAC MC%d: Removed device %d for %s %s: PCI %s\n", | ||
1512 | mci->mc_idx, mci->mc_idx, mci->mod_name, mci->ctl_name, | ||
1513 | pci_name(mci->pdev)); | ||
1514 | rc = 0; | ||
1515 | up(&mem_ctls_mutex); | 1525 | up(&mem_ctls_mutex); |
1516 | 1526 | edac_printk(KERN_INFO, EDAC_MC, | |
1517 | return rc; | 1527 | "Removed device %d for %s %s: PCI %s\n", mci->mc_idx, |
1528 | mci->mod_name, mci->ctl_name, pci_name(mci->pdev)); | ||
1529 | return mci; | ||
1518 | } | 1530 | } |
1531 | EXPORT_SYMBOL_GPL(edac_mc_del_mc); | ||
1519 | 1532 | ||
1520 | 1533 | void edac_mc_scrub_block(unsigned long page, unsigned long offset, u32 size) | |
1521 | EXPORT_SYMBOL(edac_mc_scrub_block); | ||
1522 | |||
1523 | void edac_mc_scrub_block(unsigned long page, unsigned long offset, | ||
1524 | u32 size) | ||
1525 | { | 1534 | { |
1526 | struct page *pg; | 1535 | struct page *pg; |
1527 | void *virt_addr; | 1536 | void *virt_addr; |
1528 | unsigned long flags = 0; | 1537 | unsigned long flags = 0; |
1529 | 1538 | ||
1530 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 1539 | debugf3("%s()\n", __func__); |
1531 | 1540 | ||
1532 | /* ECC error page was not in our memory. Ignore it. */ | 1541 | /* ECC error page was not in our memory. Ignore it. */ |
1533 | if(!pfn_valid(page)) | 1542 | if(!pfn_valid(page)) |
@@ -1550,19 +1559,15 @@ void edac_mc_scrub_block(unsigned long page, unsigned long offset, | |||
1550 | if (PageHighMem(pg)) | 1559 | if (PageHighMem(pg)) |
1551 | local_irq_restore(flags); | 1560 | local_irq_restore(flags); |
1552 | } | 1561 | } |
1553 | 1562 | EXPORT_SYMBOL_GPL(edac_mc_scrub_block); | |
1554 | 1563 | ||
1555 | /* FIXME - should return -1 */ | 1564 | /* FIXME - should return -1 */ |
1556 | EXPORT_SYMBOL(edac_mc_find_csrow_by_page); | 1565 | int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page) |
1557 | |||
1558 | int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, | ||
1559 | unsigned long page) | ||
1560 | { | 1566 | { |
1561 | struct csrow_info *csrows = mci->csrows; | 1567 | struct csrow_info *csrows = mci->csrows; |
1562 | int row, i; | 1568 | int row, i; |
1563 | 1569 | ||
1564 | debugf1("MC%d: " __FILE__ ": %s(): 0x%lx\n", mci->mc_idx, __func__, | 1570 | debugf1("MC%d: %s(): 0x%lx\n", mci->mc_idx, __func__, page); |
1565 | page); | ||
1566 | row = -1; | 1571 | row = -1; |
1567 | 1572 | ||
1568 | for (i = 0; i < mci->nr_csrows; i++) { | 1573 | for (i = 0; i < mci->nr_csrows; i++) { |
@@ -1571,11 +1576,10 @@ int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, | |||
1571 | if (csrow->nr_pages == 0) | 1576 | if (csrow->nr_pages == 0) |
1572 | continue; | 1577 | continue; |
1573 | 1578 | ||
1574 | debugf3("MC%d: " __FILE__ | 1579 | debugf3("MC%d: %s(): first(0x%lx) page(0x%lx) last(0x%lx) " |
1575 | ": %s(): first(0x%lx) page(0x%lx)" | 1580 | "mask(0x%lx)\n", mci->mc_idx, __func__, |
1576 | " last(0x%lx) mask(0x%lx)\n", mci->mc_idx, | 1581 | csrow->first_page, page, csrow->last_page, |
1577 | __func__, csrow->first_page, page, | 1582 | csrow->page_mask); |
1578 | csrow->last_page, csrow->page_mask); | ||
1579 | 1583 | ||
1580 | if ((page >= csrow->first_page) && | 1584 | if ((page >= csrow->first_page) && |
1581 | (page <= csrow->last_page) && | 1585 | (page <= csrow->last_page) && |
@@ -1587,56 +1591,52 @@ int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, | |||
1587 | } | 1591 | } |
1588 | 1592 | ||
1589 | if (row == -1) | 1593 | if (row == -1) |
1590 | printk(KERN_ERR | 1594 | edac_mc_printk(mci, KERN_ERR, |
1591 | "EDAC MC%d: could not look up page error address %lx\n", | 1595 | "could not look up page error address %lx\n", |
1592 | mci->mc_idx, (unsigned long) page); | 1596 | (unsigned long) page); |
1593 | 1597 | ||
1594 | return row; | 1598 | return row; |
1595 | } | 1599 | } |
1596 | 1600 | EXPORT_SYMBOL_GPL(edac_mc_find_csrow_by_page); | |
1597 | |||
1598 | EXPORT_SYMBOL(edac_mc_handle_ce); | ||
1599 | 1601 | ||
1600 | /* FIXME - setable log (warning/emerg) levels */ | 1602 | /* FIXME - setable log (warning/emerg) levels */ |
1601 | /* FIXME - integrate with evlog: http://evlog.sourceforge.net/ */ | 1603 | /* FIXME - integrate with evlog: http://evlog.sourceforge.net/ */ |
1602 | void edac_mc_handle_ce(struct mem_ctl_info *mci, | 1604 | void edac_mc_handle_ce(struct mem_ctl_info *mci, |
1603 | unsigned long page_frame_number, | 1605 | unsigned long page_frame_number, unsigned long offset_in_page, |
1604 | unsigned long offset_in_page, | 1606 | unsigned long syndrome, int row, int channel, const char *msg) |
1605 | unsigned long syndrome, int row, int channel, | ||
1606 | const char *msg) | ||
1607 | { | 1607 | { |
1608 | unsigned long remapped_page; | 1608 | unsigned long remapped_page; |
1609 | 1609 | ||
1610 | debugf3("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__); | 1610 | debugf3("MC%d: %s()\n", mci->mc_idx, __func__); |
1611 | 1611 | ||
1612 | /* FIXME - maybe make panic on INTERNAL ERROR an option */ | 1612 | /* FIXME - maybe make panic on INTERNAL ERROR an option */ |
1613 | if (row >= mci->nr_csrows || row < 0) { | 1613 | if (row >= mci->nr_csrows || row < 0) { |
1614 | /* something is wrong */ | 1614 | /* something is wrong */ |
1615 | printk(KERN_ERR | 1615 | edac_mc_printk(mci, KERN_ERR, |
1616 | "EDAC MC%d: INTERNAL ERROR: row out of range (%d >= %d)\n", | 1616 | "INTERNAL ERROR: row out of range " |
1617 | mci->mc_idx, row, mci->nr_csrows); | 1617 | "(%d >= %d)\n", row, mci->nr_csrows); |
1618 | edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); | 1618 | edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); |
1619 | return; | 1619 | return; |
1620 | } | 1620 | } |
1621 | |||
1621 | if (channel >= mci->csrows[row].nr_channels || channel < 0) { | 1622 | if (channel >= mci->csrows[row].nr_channels || channel < 0) { |
1622 | /* something is wrong */ | 1623 | /* something is wrong */ |
1623 | printk(KERN_ERR | 1624 | edac_mc_printk(mci, KERN_ERR, |
1624 | "EDAC MC%d: INTERNAL ERROR: channel out of range " | 1625 | "INTERNAL ERROR: channel out of range " |
1625 | "(%d >= %d)\n", | 1626 | "(%d >= %d)\n", channel, |
1626 | mci->mc_idx, channel, mci->csrows[row].nr_channels); | 1627 | mci->csrows[row].nr_channels); |
1627 | edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); | 1628 | edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR"); |
1628 | return; | 1629 | return; |
1629 | } | 1630 | } |
1630 | 1631 | ||
1631 | if (log_ce) | 1632 | if (log_ce) |
1632 | /* FIXME - put in DIMM location */ | 1633 | /* FIXME - put in DIMM location */ |
1633 | printk(KERN_WARNING | 1634 | edac_mc_printk(mci, KERN_WARNING, |
1634 | "EDAC MC%d: CE page 0x%lx, offset 0x%lx," | 1635 | "CE page 0x%lx, offset 0x%lx, grain %d, syndrome " |
1635 | " grain %d, syndrome 0x%lx, row %d, channel %d," | 1636 | "0x%lx, row %d, channel %d, label \"%s\": %s\n", |
1636 | " label \"%s\": %s\n", mci->mc_idx, | 1637 | page_frame_number, offset_in_page, |
1637 | page_frame_number, offset_in_page, | 1638 | mci->csrows[row].grain, syndrome, row, channel, |
1638 | mci->csrows[row].grain, syndrome, row, channel, | 1639 | mci->csrows[row].channels[channel].label, msg); |
1639 | mci->csrows[row].channels[channel].label, msg); | ||
1640 | 1640 | ||
1641 | mci->ce_count++; | 1641 | mci->ce_count++; |
1642 | mci->csrows[row].ce_count++; | 1642 | mci->csrows[row].ce_count++; |
@@ -1657,31 +1657,25 @@ void edac_mc_handle_ce(struct mem_ctl_info *mci, | |||
1657 | page_frame_number; | 1657 | page_frame_number; |
1658 | 1658 | ||
1659 | edac_mc_scrub_block(remapped_page, offset_in_page, | 1659 | edac_mc_scrub_block(remapped_page, offset_in_page, |
1660 | mci->csrows[row].grain); | 1660 | mci->csrows[row].grain); |
1661 | } | 1661 | } |
1662 | } | 1662 | } |
1663 | EXPORT_SYMBOL_GPL(edac_mc_handle_ce); | ||
1663 | 1664 | ||
1664 | 1665 | void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg) | |
1665 | EXPORT_SYMBOL(edac_mc_handle_ce_no_info); | ||
1666 | |||
1667 | void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, | ||
1668 | const char *msg) | ||
1669 | { | 1666 | { |
1670 | if (log_ce) | 1667 | if (log_ce) |
1671 | printk(KERN_WARNING | 1668 | edac_mc_printk(mci, KERN_WARNING, |
1672 | "EDAC MC%d: CE - no information available: %s\n", | 1669 | "CE - no information available: %s\n", msg); |
1673 | mci->mc_idx, msg); | 1670 | |
1674 | mci->ce_noinfo_count++; | 1671 | mci->ce_noinfo_count++; |
1675 | mci->ce_count++; | 1672 | mci->ce_count++; |
1676 | } | 1673 | } |
1677 | 1674 | EXPORT_SYMBOL_GPL(edac_mc_handle_ce_no_info); | |
1678 | |||
1679 | EXPORT_SYMBOL(edac_mc_handle_ue); | ||
1680 | 1675 | ||
1681 | void edac_mc_handle_ue(struct mem_ctl_info *mci, | 1676 | void edac_mc_handle_ue(struct mem_ctl_info *mci, |
1682 | unsigned long page_frame_number, | 1677 | unsigned long page_frame_number, unsigned long offset_in_page, |
1683 | unsigned long offset_in_page, int row, | 1678 | int row, const char *msg) |
1684 | const char *msg) | ||
1685 | { | 1679 | { |
1686 | int len = EDAC_MC_LABEL_LEN * 4; | 1680 | int len = EDAC_MC_LABEL_LEN * 4; |
1687 | char labels[len + 1]; | 1681 | char labels[len + 1]; |
@@ -1689,65 +1683,61 @@ void edac_mc_handle_ue(struct mem_ctl_info *mci, | |||
1689 | int chan; | 1683 | int chan; |
1690 | int chars; | 1684 | int chars; |
1691 | 1685 | ||
1692 | debugf3("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__); | 1686 | debugf3("MC%d: %s()\n", mci->mc_idx, __func__); |
1693 | 1687 | ||
1694 | /* FIXME - maybe make panic on INTERNAL ERROR an option */ | 1688 | /* FIXME - maybe make panic on INTERNAL ERROR an option */ |
1695 | if (row >= mci->nr_csrows || row < 0) { | 1689 | if (row >= mci->nr_csrows || row < 0) { |
1696 | /* something is wrong */ | 1690 | /* something is wrong */ |
1697 | printk(KERN_ERR | 1691 | edac_mc_printk(mci, KERN_ERR, |
1698 | "EDAC MC%d: INTERNAL ERROR: row out of range (%d >= %d)\n", | 1692 | "INTERNAL ERROR: row out of range " |
1699 | mci->mc_idx, row, mci->nr_csrows); | 1693 | "(%d >= %d)\n", row, mci->nr_csrows); |
1700 | edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR"); | 1694 | edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR"); |
1701 | return; | 1695 | return; |
1702 | } | 1696 | } |
1703 | 1697 | ||
1704 | chars = snprintf(pos, len + 1, "%s", | 1698 | chars = snprintf(pos, len + 1, "%s", |
1705 | mci->csrows[row].channels[0].label); | 1699 | mci->csrows[row].channels[0].label); |
1706 | len -= chars; | 1700 | len -= chars; |
1707 | pos += chars; | 1701 | pos += chars; |
1702 | |||
1708 | for (chan = 1; (chan < mci->csrows[row].nr_channels) && (len > 0); | 1703 | for (chan = 1; (chan < mci->csrows[row].nr_channels) && (len > 0); |
1709 | chan++) { | 1704 | chan++) { |
1710 | chars = snprintf(pos, len + 1, ":%s", | 1705 | chars = snprintf(pos, len + 1, ":%s", |
1711 | mci->csrows[row].channels[chan].label); | 1706 | mci->csrows[row].channels[chan].label); |
1712 | len -= chars; | 1707 | len -= chars; |
1713 | pos += chars; | 1708 | pos += chars; |
1714 | } | 1709 | } |
1715 | 1710 | ||
1716 | if (log_ue) | 1711 | if (log_ue) |
1717 | printk(KERN_EMERG | 1712 | edac_mc_printk(mci, KERN_EMERG, |
1718 | "EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, row %d," | 1713 | "UE page 0x%lx, offset 0x%lx, grain %d, row %d, " |
1719 | " labels \"%s\": %s\n", mci->mc_idx, | 1714 | "labels \"%s\": %s\n", page_frame_number, |
1720 | page_frame_number, offset_in_page, | 1715 | offset_in_page, mci->csrows[row].grain, row, labels, |
1721 | mci->csrows[row].grain, row, labels, msg); | 1716 | msg); |
1722 | 1717 | ||
1723 | if (panic_on_ue) | 1718 | if (panic_on_ue) |
1724 | panic | 1719 | panic("EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, " |
1725 | ("EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, row %d," | 1720 | "row %d, labels \"%s\": %s\n", mci->mc_idx, |
1726 | " labels \"%s\": %s\n", mci->mc_idx, | 1721 | page_frame_number, offset_in_page, |
1727 | page_frame_number, offset_in_page, | 1722 | mci->csrows[row].grain, row, labels, msg); |
1728 | mci->csrows[row].grain, row, labels, msg); | ||
1729 | 1723 | ||
1730 | mci->ue_count++; | 1724 | mci->ue_count++; |
1731 | mci->csrows[row].ue_count++; | 1725 | mci->csrows[row].ue_count++; |
1732 | } | 1726 | } |
1727 | EXPORT_SYMBOL_GPL(edac_mc_handle_ue); | ||
1733 | 1728 | ||
1734 | 1729 | void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg) | |
1735 | EXPORT_SYMBOL(edac_mc_handle_ue_no_info); | ||
1736 | |||
1737 | void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, | ||
1738 | const char *msg) | ||
1739 | { | 1730 | { |
1740 | if (panic_on_ue) | 1731 | if (panic_on_ue) |
1741 | panic("EDAC MC%d: Uncorrected Error", mci->mc_idx); | 1732 | panic("EDAC MC%d: Uncorrected Error", mci->mc_idx); |
1742 | 1733 | ||
1743 | if (log_ue) | 1734 | if (log_ue) |
1744 | printk(KERN_WARNING | 1735 | edac_mc_printk(mci, KERN_WARNING, |
1745 | "EDAC MC%d: UE - no information available: %s\n", | 1736 | "UE - no information available: %s\n", msg); |
1746 | mci->mc_idx, msg); | ||
1747 | mci->ue_noinfo_count++; | 1737 | mci->ue_noinfo_count++; |
1748 | mci->ue_count++; | 1738 | mci->ue_count++; |
1749 | } | 1739 | } |
1750 | 1740 | EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info); | |
1751 | 1741 | ||
1752 | #ifdef CONFIG_PCI | 1742 | #ifdef CONFIG_PCI |
1753 | 1743 | ||
@@ -1759,18 +1749,22 @@ static u16 get_pci_parity_status(struct pci_dev *dev, int secondary) | |||
1759 | where = secondary ? PCI_SEC_STATUS : PCI_STATUS; | 1749 | where = secondary ? PCI_SEC_STATUS : PCI_STATUS; |
1760 | pci_read_config_word(dev, where, &status); | 1750 | pci_read_config_word(dev, where, &status); |
1761 | 1751 | ||
1762 | /* If we get back 0xFFFF then we must suspect that the card has been pulled but | 1752 | /* If we get back 0xFFFF then we must suspect that the card has been |
1763 | the Linux PCI layer has not yet finished cleaning up. We don't want to report | 1753 | * pulled but the Linux PCI layer has not yet finished cleaning up. |
1764 | on such devices */ | 1754 | * We don't want to report on such devices |
1755 | */ | ||
1765 | 1756 | ||
1766 | if (status == 0xFFFF) { | 1757 | if (status == 0xFFFF) { |
1767 | u32 sanity; | 1758 | u32 sanity; |
1759 | |||
1768 | pci_read_config_dword(dev, 0, &sanity); | 1760 | pci_read_config_dword(dev, 0, &sanity); |
1761 | |||
1769 | if (sanity == 0xFFFFFFFF) | 1762 | if (sanity == 0xFFFFFFFF) |
1770 | return 0; | 1763 | return 0; |
1771 | } | 1764 | } |
1765 | |||
1772 | status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR | | 1766 | status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR | |
1773 | PCI_STATUS_PARITY; | 1767 | PCI_STATUS_PARITY; |
1774 | 1768 | ||
1775 | if (status) | 1769 | if (status) |
1776 | /* reset only the bits we are interested in */ | 1770 | /* reset only the bits we are interested in */ |
@@ -1782,7 +1776,7 @@ static u16 get_pci_parity_status(struct pci_dev *dev, int secondary) | |||
1782 | typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev); | 1776 | typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev); |
1783 | 1777 | ||
1784 | /* Clear any PCI parity errors logged by this device. */ | 1778 | /* Clear any PCI parity errors logged by this device. */ |
1785 | static void edac_pci_dev_parity_clear( struct pci_dev *dev ) | 1779 | static void edac_pci_dev_parity_clear(struct pci_dev *dev) |
1786 | { | 1780 | { |
1787 | u8 header_type; | 1781 | u8 header_type; |
1788 | 1782 | ||
@@ -1813,25 +1807,22 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev) | |||
1813 | /* check the status reg for errors */ | 1807 | /* check the status reg for errors */ |
1814 | if (status) { | 1808 | if (status) { |
1815 | if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) | 1809 | if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) |
1816 | printk(KERN_CRIT | 1810 | edac_printk(KERN_CRIT, EDAC_PCI, |
1817 | "EDAC PCI- " | ||
1818 | "Signaled System Error on %s\n", | 1811 | "Signaled System Error on %s\n", |
1819 | pci_name (dev)); | 1812 | pci_name(dev)); |
1820 | 1813 | ||
1821 | if (status & (PCI_STATUS_PARITY)) { | 1814 | if (status & (PCI_STATUS_PARITY)) { |
1822 | printk(KERN_CRIT | 1815 | edac_printk(KERN_CRIT, EDAC_PCI, |
1823 | "EDAC PCI- " | ||
1824 | "Master Data Parity Error on %s\n", | 1816 | "Master Data Parity Error on %s\n", |
1825 | pci_name (dev)); | 1817 | pci_name(dev)); |
1826 | 1818 | ||
1827 | atomic_inc(&pci_parity_count); | 1819 | atomic_inc(&pci_parity_count); |
1828 | } | 1820 | } |
1829 | 1821 | ||
1830 | if (status & (PCI_STATUS_DETECTED_PARITY)) { | 1822 | if (status & (PCI_STATUS_DETECTED_PARITY)) { |
1831 | printk(KERN_CRIT | 1823 | edac_printk(KERN_CRIT, EDAC_PCI, |
1832 | "EDAC PCI- " | ||
1833 | "Detected Parity Error on %s\n", | 1824 | "Detected Parity Error on %s\n", |
1834 | pci_name (dev)); | 1825 | pci_name(dev)); |
1835 | 1826 | ||
1836 | atomic_inc(&pci_parity_count); | 1827 | atomic_inc(&pci_parity_count); |
1837 | } | 1828 | } |
@@ -1852,25 +1843,22 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev) | |||
1852 | /* check the secondary status reg for errors */ | 1843 | /* check the secondary status reg for errors */ |
1853 | if (status) { | 1844 | if (status) { |
1854 | if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) | 1845 | if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) |
1855 | printk(KERN_CRIT | 1846 | edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " |
1856 | "EDAC PCI-Bridge- " | ||
1857 | "Signaled System Error on %s\n", | 1847 | "Signaled System Error on %s\n", |
1858 | pci_name (dev)); | 1848 | pci_name(dev)); |
1859 | 1849 | ||
1860 | if (status & (PCI_STATUS_PARITY)) { | 1850 | if (status & (PCI_STATUS_PARITY)) { |
1861 | printk(KERN_CRIT | 1851 | edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " |
1862 | "EDAC PCI-Bridge- " | 1852 | "Master Data Parity Error on " |
1863 | "Master Data Parity Error on %s\n", | 1853 | "%s\n", pci_name(dev)); |
1864 | pci_name (dev)); | ||
1865 | 1854 | ||
1866 | atomic_inc(&pci_parity_count); | 1855 | atomic_inc(&pci_parity_count); |
1867 | } | 1856 | } |
1868 | 1857 | ||
1869 | if (status & (PCI_STATUS_DETECTED_PARITY)) { | 1858 | if (status & (PCI_STATUS_DETECTED_PARITY)) { |
1870 | printk(KERN_CRIT | 1859 | edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " |
1871 | "EDAC PCI-Bridge- " | ||
1872 | "Detected Parity Error on %s\n", | 1860 | "Detected Parity Error on %s\n", |
1873 | pci_name (dev)); | 1861 | pci_name(dev)); |
1874 | 1862 | ||
1875 | atomic_inc(&pci_parity_count); | 1863 | atomic_inc(&pci_parity_count); |
1876 | } | 1864 | } |
@@ -1889,58 +1877,55 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev) | |||
1889 | * Returns: 0 not found | 1877 | * Returns: 0 not found |
1890 | * 1 found on list | 1878 | * 1 found on list |
1891 | */ | 1879 | */ |
1892 | static int check_dev_on_list(struct edac_pci_device_list *list, int free_index, | 1880 | static int check_dev_on_list(struct edac_pci_device_list *list, |
1893 | struct pci_dev *dev) | 1881 | int free_index, struct pci_dev *dev) |
1894 | { | 1882 | { |
1895 | int i; | 1883 | int i; |
1896 | int rc = 0; /* Assume not found */ | 1884 | int rc = 0; /* Assume not found */ |
1897 | unsigned short vendor=dev->vendor; | 1885 | unsigned short vendor=dev->vendor; |
1898 | unsigned short device=dev->device; | 1886 | unsigned short device=dev->device; |
1899 | 1887 | ||
1900 | /* Scan the list, looking for a vendor/device match | 1888 | /* Scan the list, looking for a vendor/device match */ |
1901 | */ | 1889 | for (i = 0; i < free_index; i++, list++ ) { |
1902 | for (i = 0; i < free_index; i++, list++ ) { | 1890 | if ((list->vendor == vendor ) && (list->device == device )) { |
1903 | if ( (list->vendor == vendor ) && | 1891 | rc = 1; |
1904 | (list->device == device )) { | 1892 | break; |
1905 | rc = 1; | 1893 | } |
1906 | break; | 1894 | } |
1907 | } | ||
1908 | } | ||
1909 | 1895 | ||
1910 | return rc; | 1896 | return rc; |
1911 | } | 1897 | } |
1912 | 1898 | ||
1913 | /* | 1899 | /* |
1914 | * pci_dev parity list iterator | 1900 | * pci_dev parity list iterator |
1915 | * Scan the PCI device list for one iteration, looking for SERRORs | 1901 | * Scan the PCI device list for one iteration, looking for SERRORs |
1916 | * Master Parity ERRORS or Parity ERRORs on primary or secondary devices | 1902 | * Master Parity ERRORS or Parity ERRORs on primary or secondary devices |
1917 | */ | 1903 | */ |
1918 | static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn) | 1904 | static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn) |
1919 | { | 1905 | { |
1920 | struct pci_dev *dev=NULL; | 1906 | struct pci_dev *dev = NULL; |
1921 | 1907 | ||
1922 | /* request for kernel access to the next PCI device, if any, | 1908 | /* request for kernel access to the next PCI device, if any, |
1923 | * and while we are looking at it have its reference count | 1909 | * and while we are looking at it have its reference count |
1924 | * bumped until we are done with it | 1910 | * bumped until we are done with it |
1925 | */ | 1911 | */ |
1926 | while((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { | 1912 | while((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { |
1927 | 1913 | /* if whitelist exists then it has priority, so only scan | |
1928 | /* if whitelist exists then it has priority, so only scan those | 1914 | * those devices on the whitelist |
1929 | * devices on the whitelist | 1915 | */ |
1930 | */ | 1916 | if (pci_whitelist_count > 0 ) { |
1931 | if (pci_whitelist_count > 0 ) { | 1917 | if (check_dev_on_list(pci_whitelist, |
1932 | if (check_dev_on_list(pci_whitelist, | ||
1933 | pci_whitelist_count, dev)) | 1918 | pci_whitelist_count, dev)) |
1934 | fn(dev); | 1919 | fn(dev); |
1935 | } else { | 1920 | } else { |
1936 | /* | 1921 | /* |
1937 | * if no whitelist, then check if this devices is | 1922 | * if no whitelist, then check if this devices is |
1938 | * blacklisted | 1923 | * blacklisted |
1939 | */ | 1924 | */ |
1940 | if (!check_dev_on_list(pci_blacklist, | 1925 | if (!check_dev_on_list(pci_blacklist, |
1941 | pci_blacklist_count, dev)) | 1926 | pci_blacklist_count, dev)) |
1942 | fn(dev); | 1927 | fn(dev); |
1943 | } | 1928 | } |
1944 | } | 1929 | } |
1945 | } | 1930 | } |
1946 | 1931 | ||
@@ -1949,7 +1934,7 @@ static void do_pci_parity_check(void) | |||
1949 | unsigned long flags; | 1934 | unsigned long flags; |
1950 | int before_count; | 1935 | int before_count; |
1951 | 1936 | ||
1952 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 1937 | debugf3("%s()\n", __func__); |
1953 | 1938 | ||
1954 | if (!check_pci_parity) | 1939 | if (!check_pci_parity) |
1955 | return; | 1940 | return; |
@@ -1971,7 +1956,6 @@ static void do_pci_parity_check(void) | |||
1971 | } | 1956 | } |
1972 | } | 1957 | } |
1973 | 1958 | ||
1974 | |||
1975 | static inline void clear_pci_parity_errors(void) | 1959 | static inline void clear_pci_parity_errors(void) |
1976 | { | 1960 | { |
1977 | /* Clear any PCI bus parity errors that devices initially have logged | 1961 | /* Clear any PCI bus parity errors that devices initially have logged |
@@ -1980,37 +1964,30 @@ static inline void clear_pci_parity_errors(void) | |||
1980 | edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear); | 1964 | edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear); |
1981 | } | 1965 | } |
1982 | 1966 | ||
1983 | |||
1984 | #else /* CONFIG_PCI */ | 1967 | #else /* CONFIG_PCI */ |
1985 | 1968 | ||
1986 | |||
1987 | static inline void do_pci_parity_check(void) | 1969 | static inline void do_pci_parity_check(void) |
1988 | { | 1970 | { |
1989 | /* no-op */ | 1971 | /* no-op */ |
1990 | } | 1972 | } |
1991 | 1973 | ||
1992 | |||
1993 | static inline void clear_pci_parity_errors(void) | 1974 | static inline void clear_pci_parity_errors(void) |
1994 | { | 1975 | { |
1995 | /* no-op */ | 1976 | /* no-op */ |
1996 | } | 1977 | } |
1997 | 1978 | ||
1998 | |||
1999 | #endif /* CONFIG_PCI */ | 1979 | #endif /* CONFIG_PCI */ |
2000 | 1980 | ||
2001 | /* | 1981 | /* |
2002 | * Iterate over all MC instances and check for ECC, et al, errors | 1982 | * Iterate over all MC instances and check for ECC, et al, errors |
2003 | */ | 1983 | */ |
2004 | static inline void check_mc_devices (void) | 1984 | static inline void check_mc_devices(void) |
2005 | { | 1985 | { |
2006 | unsigned long flags; | ||
2007 | struct list_head *item; | 1986 | struct list_head *item; |
2008 | struct mem_ctl_info *mci; | 1987 | struct mem_ctl_info *mci; |
2009 | 1988 | ||
2010 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 1989 | debugf3("%s()\n", __func__); |
2011 | 1990 | down(&mem_ctls_mutex); | |
2012 | /* during poll, have interrupts off */ | ||
2013 | local_irq_save(flags); | ||
2014 | 1991 | ||
2015 | list_for_each(item, &mc_devices) { | 1992 | list_for_each(item, &mc_devices) { |
2016 | mci = list_entry(item, struct mem_ctl_info, link); | 1993 | mci = list_entry(item, struct mem_ctl_info, link); |
@@ -2019,10 +1996,9 @@ static inline void check_mc_devices (void) | |||
2019 | mci->edac_check(mci); | 1996 | mci->edac_check(mci); |
2020 | } | 1997 | } |
2021 | 1998 | ||
2022 | local_irq_restore(flags); | 1999 | up(&mem_ctls_mutex); |
2023 | } | 2000 | } |
2024 | 2001 | ||
2025 | |||
2026 | /* | 2002 | /* |
2027 | * Check MC status every poll_msec. | 2003 | * Check MC status every poll_msec. |
2028 | * Check PCI status every poll_msec as well. | 2004 | * Check PCI status every poll_msec as well. |
@@ -2033,70 +2009,21 @@ static inline void check_mc_devices (void) | |||
2033 | */ | 2009 | */ |
2034 | static void do_edac_check(void) | 2010 | static void do_edac_check(void) |
2035 | { | 2011 | { |
2036 | 2012 | debugf3("%s()\n", __func__); | |
2037 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | ||
2038 | |||
2039 | check_mc_devices(); | 2013 | check_mc_devices(); |
2040 | |||
2041 | do_pci_parity_check(); | 2014 | do_pci_parity_check(); |
2042 | } | 2015 | } |
2043 | 2016 | ||
2044 | |||
2045 | /* | ||
2046 | * EDAC thread state information | ||
2047 | */ | ||
2048 | struct bs_thread_info | ||
2049 | { | ||
2050 | struct task_struct *task; | ||
2051 | struct completion *event; | ||
2052 | char *name; | ||
2053 | void (*run)(void); | ||
2054 | }; | ||
2055 | |||
2056 | static struct bs_thread_info bs_thread; | ||
2057 | |||
2058 | /* | ||
2059 | * edac_kernel_thread | ||
2060 | * This the kernel thread that processes edac operations | ||
2061 | * in a normal thread environment | ||
2062 | */ | ||
2063 | static int edac_kernel_thread(void *arg) | 2017 | static int edac_kernel_thread(void *arg) |
2064 | { | 2018 | { |
2065 | struct bs_thread_info *thread = (struct bs_thread_info *) arg; | 2019 | while (!kthread_should_stop()) { |
2066 | 2020 | do_edac_check(); | |
2067 | /* detach thread */ | ||
2068 | daemonize(thread->name); | ||
2069 | |||
2070 | current->exit_signal = SIGCHLD; | ||
2071 | allow_signal(SIGKILL); | ||
2072 | thread->task = current; | ||
2073 | |||
2074 | /* indicate to starting task we have started */ | ||
2075 | complete(thread->event); | ||
2076 | |||
2077 | /* loop forever, until we are told to stop */ | ||
2078 | while(thread->run != NULL) { | ||
2079 | void (*run)(void); | ||
2080 | |||
2081 | /* call the function to check the memory controllers */ | ||
2082 | run = thread->run; | ||
2083 | if (run) | ||
2084 | run(); | ||
2085 | |||
2086 | if (signal_pending(current)) | ||
2087 | flush_signals(current); | ||
2088 | |||
2089 | /* ensure we are interruptable */ | ||
2090 | set_current_state(TASK_INTERRUPTIBLE); | ||
2091 | 2021 | ||
2092 | /* goto sleep for the interval */ | 2022 | /* goto sleep for the interval */ |
2093 | schedule_timeout((HZ * poll_msec) / 1000); | 2023 | schedule_timeout_interruptible((HZ * poll_msec) / 1000); |
2094 | try_to_freeze(); | 2024 | try_to_freeze(); |
2095 | } | 2025 | } |
2096 | 2026 | ||
2097 | /* notify waiter that we are exiting */ | ||
2098 | complete(thread->event); | ||
2099 | |||
2100 | return 0; | 2027 | return 0; |
2101 | } | 2028 | } |
2102 | 2029 | ||
@@ -2106,10 +2033,7 @@ static int edac_kernel_thread(void *arg) | |||
2106 | */ | 2033 | */ |
2107 | static int __init edac_mc_init(void) | 2034 | static int __init edac_mc_init(void) |
2108 | { | 2035 | { |
2109 | int ret; | 2036 | edac_printk(KERN_INFO, EDAC_MC, EDAC_MC_VERSION "\n"); |
2110 | struct completion event; | ||
2111 | |||
2112 | printk(KERN_INFO "MC: " __FILE__ " version " EDAC_MC_VERSION "\n"); | ||
2113 | 2037 | ||
2114 | /* | 2038 | /* |
2115 | * Harvest and clear any boot/initialization PCI parity errors | 2039 | * Harvest and clear any boot/initialization PCI parity errors |
@@ -2120,80 +2044,54 @@ static int __init edac_mc_init(void) | |||
2120 | */ | 2044 | */ |
2121 | clear_pci_parity_errors(); | 2045 | clear_pci_parity_errors(); |
2122 | 2046 | ||
2123 | /* perform check for first time to harvest boot leftovers */ | 2047 | /* Create the MC sysfs entries */ |
2124 | do_edac_check(); | ||
2125 | |||
2126 | /* Create the MC sysfs entires */ | ||
2127 | if (edac_sysfs_memctrl_setup()) { | 2048 | if (edac_sysfs_memctrl_setup()) { |
2128 | printk(KERN_ERR "EDAC MC: Error initializing sysfs code\n"); | 2049 | edac_printk(KERN_ERR, EDAC_MC, |
2050 | "Error initializing sysfs code\n"); | ||
2129 | return -ENODEV; | 2051 | return -ENODEV; |
2130 | } | 2052 | } |
2131 | 2053 | ||
2132 | /* Create the PCI parity sysfs entries */ | 2054 | /* Create the PCI parity sysfs entries */ |
2133 | if (edac_sysfs_pci_setup()) { | 2055 | if (edac_sysfs_pci_setup()) { |
2134 | edac_sysfs_memctrl_teardown(); | 2056 | edac_sysfs_memctrl_teardown(); |
2135 | printk(KERN_ERR "EDAC PCI: Error initializing sysfs code\n"); | 2057 | edac_printk(KERN_ERR, EDAC_MC, |
2058 | "EDAC PCI: Error initializing sysfs code\n"); | ||
2136 | return -ENODEV; | 2059 | return -ENODEV; |
2137 | } | 2060 | } |
2138 | 2061 | ||
2139 | /* Create our kernel thread */ | ||
2140 | init_completion(&event); | ||
2141 | bs_thread.event = &event; | ||
2142 | bs_thread.name = "kedac"; | ||
2143 | bs_thread.run = do_edac_check; | ||
2144 | |||
2145 | /* create our kernel thread */ | 2062 | /* create our kernel thread */ |
2146 | ret = kernel_thread(edac_kernel_thread, &bs_thread, CLONE_KERNEL); | 2063 | edac_thread = kthread_run(edac_kernel_thread, NULL, "kedac"); |
2147 | if (ret < 0) { | 2064 | |
2065 | if (IS_ERR(edac_thread)) { | ||
2148 | /* remove the sysfs entries */ | 2066 | /* remove the sysfs entries */ |
2149 | edac_sysfs_memctrl_teardown(); | 2067 | edac_sysfs_memctrl_teardown(); |
2150 | edac_sysfs_pci_teardown(); | 2068 | edac_sysfs_pci_teardown(); |
2151 | return -ENOMEM; | 2069 | return PTR_ERR(edac_thread); |
2152 | } | 2070 | } |
2153 | 2071 | ||
2154 | /* wait for our kernel theard ack that it is up and running */ | ||
2155 | wait_for_completion(&event); | ||
2156 | |||
2157 | return 0; | 2072 | return 0; |
2158 | } | 2073 | } |
2159 | 2074 | ||
2160 | |||
2161 | /* | 2075 | /* |
2162 | * edac_mc_exit() | 2076 | * edac_mc_exit() |
2163 | * module exit/termination functioni | 2077 | * module exit/termination functioni |
2164 | */ | 2078 | */ |
2165 | static void __exit edac_mc_exit(void) | 2079 | static void __exit edac_mc_exit(void) |
2166 | { | 2080 | { |
2167 | struct completion event; | 2081 | debugf0("%s()\n", __func__); |
2168 | 2082 | kthread_stop(edac_thread); | |
2169 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | ||
2170 | |||
2171 | init_completion(&event); | ||
2172 | bs_thread.event = &event; | ||
2173 | |||
2174 | /* As soon as ->run is set to NULL, the task could disappear, | ||
2175 | * so we need to hold tasklist_lock until we have sent the signal | ||
2176 | */ | ||
2177 | read_lock(&tasklist_lock); | ||
2178 | bs_thread.run = NULL; | ||
2179 | send_sig(SIGKILL, bs_thread.task, 1); | ||
2180 | read_unlock(&tasklist_lock); | ||
2181 | wait_for_completion(&event); | ||
2182 | 2083 | ||
2183 | /* tear down the sysfs device */ | 2084 | /* tear down the sysfs device */ |
2184 | edac_sysfs_memctrl_teardown(); | 2085 | edac_sysfs_memctrl_teardown(); |
2185 | edac_sysfs_pci_teardown(); | 2086 | edac_sysfs_pci_teardown(); |
2186 | } | 2087 | } |
2187 | 2088 | ||
2188 | |||
2189 | |||
2190 | |||
2191 | module_init(edac_mc_init); | 2089 | module_init(edac_mc_init); |
2192 | module_exit(edac_mc_exit); | 2090 | module_exit(edac_mc_exit); |
2193 | 2091 | ||
2194 | MODULE_LICENSE("GPL"); | 2092 | MODULE_LICENSE("GPL"); |
2195 | MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n" | 2093 | MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n" |
2196 | "Based on.work by Dan Hollis et al"); | 2094 | "Based on work by Dan Hollis et al"); |
2197 | MODULE_DESCRIPTION("Core library routines for MC reporting"); | 2095 | MODULE_DESCRIPTION("Core library routines for MC reporting"); |
2198 | 2096 | ||
2199 | module_param(panic_on_ue, int, 0644); | 2097 | module_param(panic_on_ue, int, 0644); |
diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h index 75ecf484a43a..8d9e83909b9c 100644 --- a/drivers/edac/edac_mc.h +++ b/drivers/edac/edac_mc.h | |||
@@ -15,11 +15,9 @@ | |||
15 | * | 15 | * |
16 | */ | 16 | */ |
17 | 17 | ||
18 | |||
19 | #ifndef _EDAC_MC_H_ | 18 | #ifndef _EDAC_MC_H_ |
20 | #define _EDAC_MC_H_ | 19 | #define _EDAC_MC_H_ |
21 | 20 | ||
22 | |||
23 | #include <linux/config.h> | 21 | #include <linux/config.h> |
24 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
25 | #include <linux/types.h> | 23 | #include <linux/types.h> |
@@ -33,7 +31,6 @@ | |||
33 | #include <linux/completion.h> | 31 | #include <linux/completion.h> |
34 | #include <linux/kobject.h> | 32 | #include <linux/kobject.h> |
35 | 33 | ||
36 | |||
37 | #define EDAC_MC_LABEL_LEN 31 | 34 | #define EDAC_MC_LABEL_LEN 31 |
38 | #define MC_PROC_NAME_MAX_LEN 7 | 35 | #define MC_PROC_NAME_MAX_LEN 7 |
39 | 36 | ||
@@ -43,31 +40,53 @@ | |||
43 | #define PAGES_TO_MiB( pages ) ( ( pages ) << ( PAGE_SHIFT - 20 ) ) | 40 | #define PAGES_TO_MiB( pages ) ( ( pages ) << ( PAGE_SHIFT - 20 ) ) |
44 | #endif | 41 | #endif |
45 | 42 | ||
43 | #define edac_printk(level, prefix, fmt, arg...) \ | ||
44 | printk(level "EDAC " prefix ": " fmt, ##arg) | ||
45 | |||
46 | #define edac_mc_printk(mci, level, fmt, arg...) \ | ||
47 | printk(level "EDAC MC%d: " fmt, mci->mc_idx, ##arg) | ||
48 | |||
49 | #define edac_mc_chipset_printk(mci, level, prefix, fmt, arg...) \ | ||
50 | printk(level "EDAC " prefix " MC%d: " fmt, mci->mc_idx, ##arg) | ||
51 | |||
52 | /* prefixes for edac_printk() and edac_mc_printk() */ | ||
53 | #define EDAC_MC "MC" | ||
54 | #define EDAC_PCI "PCI" | ||
55 | #define EDAC_DEBUG "DEBUG" | ||
56 | |||
46 | #ifdef CONFIG_EDAC_DEBUG | 57 | #ifdef CONFIG_EDAC_DEBUG |
47 | extern int edac_debug_level; | 58 | extern int edac_debug_level; |
48 | #define edac_debug_printk(level, fmt, args...) \ | 59 | |
49 | do { if (level <= edac_debug_level) printk(KERN_DEBUG fmt, ##args); } while(0) | 60 | #define edac_debug_printk(level, fmt, arg...) \ |
61 | do { \ | ||
62 | if (level <= edac_debug_level) \ | ||
63 | edac_printk(KERN_DEBUG, EDAC_DEBUG, fmt, ##arg); \ | ||
64 | } while(0) | ||
65 | |||
50 | #define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ ) | 66 | #define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ ) |
51 | #define debugf1( ... ) edac_debug_printk(1, __VA_ARGS__ ) | 67 | #define debugf1( ... ) edac_debug_printk(1, __VA_ARGS__ ) |
52 | #define debugf2( ... ) edac_debug_printk(2, __VA_ARGS__ ) | 68 | #define debugf2( ... ) edac_debug_printk(2, __VA_ARGS__ ) |
53 | #define debugf3( ... ) edac_debug_printk(3, __VA_ARGS__ ) | 69 | #define debugf3( ... ) edac_debug_printk(3, __VA_ARGS__ ) |
54 | #define debugf4( ... ) edac_debug_printk(4, __VA_ARGS__ ) | 70 | #define debugf4( ... ) edac_debug_printk(4, __VA_ARGS__ ) |
55 | #else /* !CONFIG_EDAC_DEBUG */ | 71 | |
72 | #else /* !CONFIG_EDAC_DEBUG */ | ||
73 | |||
56 | #define debugf0( ... ) | 74 | #define debugf0( ... ) |
57 | #define debugf1( ... ) | 75 | #define debugf1( ... ) |
58 | #define debugf2( ... ) | 76 | #define debugf2( ... ) |
59 | #define debugf3( ... ) | 77 | #define debugf3( ... ) |
60 | #define debugf4( ... ) | 78 | #define debugf4( ... ) |
61 | #endif /* !CONFIG_EDAC_DEBUG */ | ||
62 | 79 | ||
80 | #endif /* !CONFIG_EDAC_DEBUG */ | ||
63 | 81 | ||
64 | #define bs_xstr(s) bs_str(s) | 82 | #define edac_xstr(s) edac_str(s) |
65 | #define bs_str(s) #s | 83 | #define edac_str(s) #s |
66 | #define BS_MOD_STR bs_xstr(KBUILD_BASENAME) | 84 | #define EDAC_MOD_STR edac_xstr(KBUILD_BASENAME) |
67 | 85 | ||
68 | #define BIT(x) (1 << (x)) | 86 | #define BIT(x) (1 << (x)) |
69 | 87 | ||
70 | #define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, PCI_DEVICE_ID_ ## vend ## _ ## dev | 88 | #define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \ |
89 | PCI_DEVICE_ID_ ## vend ## _ ## dev | ||
71 | 90 | ||
72 | /* memory devices */ | 91 | /* memory devices */ |
73 | enum dev_type { | 92 | enum dev_type { |
@@ -117,7 +136,6 @@ enum mem_type { | |||
117 | #define MEM_FLAG_RDDR BIT(MEM_RDDR) | 136 | #define MEM_FLAG_RDDR BIT(MEM_RDDR) |
118 | #define MEM_FLAG_RMBS BIT(MEM_RMBS) | 137 | #define MEM_FLAG_RMBS BIT(MEM_RMBS) |
119 | 138 | ||
120 | |||
121 | /* chipset Error Detection and Correction capabilities and mode */ | 139 | /* chipset Error Detection and Correction capabilities and mode */ |
122 | enum edac_type { | 140 | enum edac_type { |
123 | EDAC_UNKNOWN = 0, /* Unknown if ECC is available */ | 141 | EDAC_UNKNOWN = 0, /* Unknown if ECC is available */ |
@@ -142,7 +160,6 @@ enum edac_type { | |||
142 | #define EDAC_FLAG_S8ECD8ED BIT(EDAC_S8ECD8ED) | 160 | #define EDAC_FLAG_S8ECD8ED BIT(EDAC_S8ECD8ED) |
143 | #define EDAC_FLAG_S16ECD16ED BIT(EDAC_S16ECD16ED) | 161 | #define EDAC_FLAG_S16ECD16ED BIT(EDAC_S16ECD16ED) |
144 | 162 | ||
145 | |||
146 | /* scrubbing capabilities */ | 163 | /* scrubbing capabilities */ |
147 | enum scrub_type { | 164 | enum scrub_type { |
148 | SCRUB_UNKNOWN = 0, /* Unknown if scrubber is available */ | 165 | SCRUB_UNKNOWN = 0, /* Unknown if scrubber is available */ |
@@ -166,11 +183,6 @@ enum scrub_type { | |||
166 | #define SCRUB_FLAG_HW_PROG_SRC BIT(SCRUB_HW_PROG_SRC_CORR) | 183 | #define SCRUB_FLAG_HW_PROG_SRC BIT(SCRUB_HW_PROG_SRC_CORR) |
167 | #define SCRUB_FLAG_HW_TUN BIT(SCRUB_HW_TUNABLE) | 184 | #define SCRUB_FLAG_HW_TUN BIT(SCRUB_HW_TUNABLE) |
168 | 185 | ||
169 | enum mci_sysfs_status { | ||
170 | MCI_SYSFS_INACTIVE = 0, /* sysfs entries NOT registered */ | ||
171 | MCI_SYSFS_ACTIVE /* sysfs entries ARE registered */ | ||
172 | }; | ||
173 | |||
174 | /* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */ | 186 | /* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */ |
175 | 187 | ||
176 | /* | 188 | /* |
@@ -255,20 +267,19 @@ enum mci_sysfs_status { | |||
255 | * PS - I enjoyed writing all that about as much as you enjoyed reading it. | 267 | * PS - I enjoyed writing all that about as much as you enjoyed reading it. |
256 | */ | 268 | */ |
257 | 269 | ||
258 | |||
259 | struct channel_info { | 270 | struct channel_info { |
260 | int chan_idx; /* channel index */ | 271 | int chan_idx; /* channel index */ |
261 | u32 ce_count; /* Correctable Errors for this CHANNEL */ | 272 | u32 ce_count; /* Correctable Errors for this CHANNEL */ |
262 | char label[EDAC_MC_LABEL_LEN + 1]; /* DIMM label on motherboard */ | 273 | char label[EDAC_MC_LABEL_LEN + 1]; /* DIMM label on motherboard */ |
263 | struct csrow_info *csrow; /* the parent */ | 274 | struct csrow_info *csrow; /* the parent */ |
264 | }; | 275 | }; |
265 | 276 | ||
266 | |||
267 | struct csrow_info { | 277 | struct csrow_info { |
268 | unsigned long first_page; /* first page number in dimm */ | 278 | unsigned long first_page; /* first page number in dimm */ |
269 | unsigned long last_page; /* last page number in dimm */ | 279 | unsigned long last_page; /* last page number in dimm */ |
270 | unsigned long page_mask; /* used for interleaving - | 280 | unsigned long page_mask; /* used for interleaving - |
271 | 0UL for non intlv */ | 281 | * 0UL for non intlv |
282 | */ | ||
272 | u32 nr_pages; /* number of pages in csrow */ | 283 | u32 nr_pages; /* number of pages in csrow */ |
273 | u32 grain; /* granularity of reported error in bytes */ | 284 | u32 grain; /* granularity of reported error in bytes */ |
274 | int csrow_idx; /* the chip-select row */ | 285 | int csrow_idx; /* the chip-select row */ |
@@ -280,29 +291,28 @@ struct csrow_info { | |||
280 | struct mem_ctl_info *mci; /* the parent */ | 291 | struct mem_ctl_info *mci; /* the parent */ |
281 | 292 | ||
282 | struct kobject kobj; /* sysfs kobject for this csrow */ | 293 | struct kobject kobj; /* sysfs kobject for this csrow */ |
294 | struct completion kobj_complete; | ||
283 | 295 | ||
284 | /* FIXME the number of CHANNELs might need to become dynamic */ | 296 | /* FIXME the number of CHANNELs might need to become dynamic */ |
285 | u32 nr_channels; | 297 | u32 nr_channels; |
286 | struct channel_info *channels; | 298 | struct channel_info *channels; |
287 | }; | 299 | }; |
288 | 300 | ||
289 | |||
290 | struct mem_ctl_info { | 301 | struct mem_ctl_info { |
291 | struct list_head link; /* for global list of mem_ctl_info structs */ | 302 | struct list_head link; /* for global list of mem_ctl_info structs */ |
292 | unsigned long mtype_cap; /* memory types supported by mc */ | 303 | unsigned long mtype_cap; /* memory types supported by mc */ |
293 | unsigned long edac_ctl_cap; /* Mem controller EDAC capabilities */ | 304 | unsigned long edac_ctl_cap; /* Mem controller EDAC capabilities */ |
294 | unsigned long edac_cap; /* configuration capabilities - this is | 305 | unsigned long edac_cap; /* configuration capabilities - this is |
295 | closely related to edac_ctl_cap. The | 306 | * closely related to edac_ctl_cap. The |
296 | difference is that the controller | 307 | * difference is that the controller may be |
297 | may be capable of s4ecd4ed which would | 308 | * capable of s4ecd4ed which would be listed |
298 | be listed in edac_ctl_cap, but if | 309 | * in edac_ctl_cap, but if channels aren't |
299 | channels aren't capable of s4ecd4ed then the | 310 | * capable of s4ecd4ed then the edac_cap would |
300 | edac_cap would not have that capability. */ | 311 | * not have that capability. |
312 | */ | ||
301 | unsigned long scrub_cap; /* chipset scrub capabilities */ | 313 | unsigned long scrub_cap; /* chipset scrub capabilities */ |
302 | enum scrub_type scrub_mode; /* current scrub mode */ | 314 | enum scrub_type scrub_mode; /* current scrub mode */ |
303 | 315 | ||
304 | enum mci_sysfs_status sysfs_active; /* status of sysfs */ | ||
305 | |||
306 | /* pointer to edac checking routine */ | 316 | /* pointer to edac checking routine */ |
307 | void (*edac_check) (struct mem_ctl_info * mci); | 317 | void (*edac_check) (struct mem_ctl_info * mci); |
308 | /* | 318 | /* |
@@ -311,7 +321,7 @@ struct mem_ctl_info { | |||
311 | */ | 321 | */ |
312 | /* FIXME - why not send the phys page to begin with? */ | 322 | /* FIXME - why not send the phys page to begin with? */ |
313 | unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci, | 323 | unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci, |
314 | unsigned long page); | 324 | unsigned long page); |
315 | int mc_idx; | 325 | int mc_idx; |
316 | int nr_csrows; | 326 | int nr_csrows; |
317 | struct csrow_info *csrows; | 327 | struct csrow_info *csrows; |
@@ -340,72 +350,69 @@ struct mem_ctl_info { | |||
340 | 350 | ||
341 | /* edac sysfs device control */ | 351 | /* edac sysfs device control */ |
342 | struct kobject edac_mci_kobj; | 352 | struct kobject edac_mci_kobj; |
353 | struct completion kobj_complete; | ||
343 | }; | 354 | }; |
344 | 355 | ||
345 | |||
346 | |||
347 | /* write all or some bits in a byte-register*/ | 356 | /* write all or some bits in a byte-register*/ |
348 | static inline void pci_write_bits8(struct pci_dev *pdev, int offset, | 357 | static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value, |
349 | u8 value, u8 mask) | 358 | u8 mask) |
350 | { | 359 | { |
351 | if (mask != 0xff) { | 360 | if (mask != 0xff) { |
352 | u8 buf; | 361 | u8 buf; |
362 | |||
353 | pci_read_config_byte(pdev, offset, &buf); | 363 | pci_read_config_byte(pdev, offset, &buf); |
354 | value &= mask; | 364 | value &= mask; |
355 | buf &= ~mask; | 365 | buf &= ~mask; |
356 | value |= buf; | 366 | value |= buf; |
357 | } | 367 | } |
368 | |||
358 | pci_write_config_byte(pdev, offset, value); | 369 | pci_write_config_byte(pdev, offset, value); |
359 | } | 370 | } |
360 | 371 | ||
361 | |||
362 | /* write all or some bits in a word-register*/ | 372 | /* write all or some bits in a word-register*/ |
363 | static inline void pci_write_bits16(struct pci_dev *pdev, int offset, | 373 | static inline void pci_write_bits16(struct pci_dev *pdev, int offset, |
364 | u16 value, u16 mask) | 374 | u16 value, u16 mask) |
365 | { | 375 | { |
366 | if (mask != 0xffff) { | 376 | if (mask != 0xffff) { |
367 | u16 buf; | 377 | u16 buf; |
378 | |||
368 | pci_read_config_word(pdev, offset, &buf); | 379 | pci_read_config_word(pdev, offset, &buf); |
369 | value &= mask; | 380 | value &= mask; |
370 | buf &= ~mask; | 381 | buf &= ~mask; |
371 | value |= buf; | 382 | value |= buf; |
372 | } | 383 | } |
384 | |||
373 | pci_write_config_word(pdev, offset, value); | 385 | pci_write_config_word(pdev, offset, value); |
374 | } | 386 | } |
375 | 387 | ||
376 | |||
377 | /* write all or some bits in a dword-register*/ | 388 | /* write all or some bits in a dword-register*/ |
378 | static inline void pci_write_bits32(struct pci_dev *pdev, int offset, | 389 | static inline void pci_write_bits32(struct pci_dev *pdev, int offset, |
379 | u32 value, u32 mask) | 390 | u32 value, u32 mask) |
380 | { | 391 | { |
381 | if (mask != 0xffff) { | 392 | if (mask != 0xffff) { |
382 | u32 buf; | 393 | u32 buf; |
394 | |||
383 | pci_read_config_dword(pdev, offset, &buf); | 395 | pci_read_config_dword(pdev, offset, &buf); |
384 | value &= mask; | 396 | value &= mask; |
385 | buf &= ~mask; | 397 | buf &= ~mask; |
386 | value |= buf; | 398 | value |= buf; |
387 | } | 399 | } |
400 | |||
388 | pci_write_config_dword(pdev, offset, value); | 401 | pci_write_config_dword(pdev, offset, value); |
389 | } | 402 | } |
390 | 403 | ||
391 | |||
392 | #ifdef CONFIG_EDAC_DEBUG | 404 | #ifdef CONFIG_EDAC_DEBUG |
393 | void edac_mc_dump_channel(struct channel_info *chan); | 405 | void edac_mc_dump_channel(struct channel_info *chan); |
394 | void edac_mc_dump_mci(struct mem_ctl_info *mci); | 406 | void edac_mc_dump_mci(struct mem_ctl_info *mci); |
395 | void edac_mc_dump_csrow(struct csrow_info *csrow); | 407 | void edac_mc_dump_csrow(struct csrow_info *csrow); |
396 | #endif /* CONFIG_EDAC_DEBUG */ | 408 | #endif /* CONFIG_EDAC_DEBUG */ |
397 | 409 | ||
398 | extern int edac_mc_add_mc(struct mem_ctl_info *mci); | 410 | extern int edac_mc_add_mc(struct mem_ctl_info *mci); |
399 | extern int edac_mc_del_mc(struct mem_ctl_info *mci); | 411 | extern struct mem_ctl_info * edac_mc_del_mc(struct pci_dev *pdev); |
400 | |||
401 | extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, | 412 | extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, |
402 | unsigned long page); | 413 | unsigned long page); |
403 | 414 | extern void edac_mc_scrub_block(unsigned long page, unsigned long offset, | |
404 | extern struct mem_ctl_info *edac_mc_find_mci_by_pdev(struct pci_dev | 415 | u32 size); |
405 | *pdev); | ||
406 | |||
407 | extern void edac_mc_scrub_block(unsigned long page, | ||
408 | unsigned long offset, u32 size); | ||
409 | 416 | ||
410 | /* | 417 | /* |
411 | * The no info errors are used when error overflows are reported. | 418 | * The no info errors are used when error overflows are reported. |
@@ -418,31 +425,25 @@ extern void edac_mc_scrub_block(unsigned long page, | |||
418 | * statement clutter and extra function arguments. | 425 | * statement clutter and extra function arguments. |
419 | */ | 426 | */ |
420 | extern void edac_mc_handle_ce(struct mem_ctl_info *mci, | 427 | extern void edac_mc_handle_ce(struct mem_ctl_info *mci, |
421 | unsigned long page_frame_number, | 428 | unsigned long page_frame_number, unsigned long offset_in_page, |
422 | unsigned long offset_in_page, | 429 | unsigned long syndrome, int row, int channel, |
423 | unsigned long syndrome, | 430 | const char *msg); |
424 | int row, int channel, const char *msg); | ||
425 | |||
426 | extern void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, | 431 | extern void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, |
427 | const char *msg); | 432 | const char *msg); |
428 | |||
429 | extern void edac_mc_handle_ue(struct mem_ctl_info *mci, | 433 | extern void edac_mc_handle_ue(struct mem_ctl_info *mci, |
430 | unsigned long page_frame_number, | 434 | unsigned long page_frame_number, unsigned long offset_in_page, |
431 | unsigned long offset_in_page, | 435 | int row, const char *msg); |
432 | int row, const char *msg); | ||
433 | |||
434 | extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, | 436 | extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, |
435 | const char *msg); | 437 | const char *msg); |
436 | 438 | ||
437 | /* | 439 | /* |
438 | * This kmalloc's and initializes all the structures. | 440 | * This kmalloc's and initializes all the structures. |
439 | * Can't be used if all structures don't have the same lifetime. | 441 | * Can't be used if all structures don't have the same lifetime. |
440 | */ | 442 | */ |
441 | extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, | 443 | extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, |
442 | unsigned nr_csrows, unsigned nr_chans); | 444 | unsigned nr_chans); |
443 | 445 | ||
444 | /* Free an mc previously allocated by edac_mc_alloc() */ | 446 | /* Free an mc previously allocated by edac_mc_alloc() */ |
445 | extern void edac_mc_free(struct mem_ctl_info *mci); | 447 | extern void edac_mc_free(struct mem_ctl_info *mci); |
446 | 448 | ||
447 | |||
448 | #endif /* _EDAC_MC_H_ */ | 449 | #endif /* _EDAC_MC_H_ */ |
diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c index 52596e75f9c2..fd342163cf97 100644 --- a/drivers/edac/i82860_edac.c +++ b/drivers/edac/i82860_edac.c | |||
@@ -9,7 +9,6 @@ | |||
9 | * by Thayne Harbaugh of Linux Networx. (http://lnxi.com) | 9 | * by Thayne Harbaugh of Linux Networx. (http://lnxi.com) |
10 | */ | 10 | */ |
11 | 11 | ||
12 | |||
13 | #include <linux/config.h> | 12 | #include <linux/config.h> |
14 | #include <linux/module.h> | 13 | #include <linux/module.h> |
15 | #include <linux/init.h> | 14 | #include <linux/init.h> |
@@ -18,6 +17,11 @@ | |||
18 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
19 | #include "edac_mc.h" | 18 | #include "edac_mc.h" |
20 | 19 | ||
20 | #define i82860_printk(level, fmt, arg...) \ | ||
21 | edac_printk(level, "i82860", fmt, ##arg) | ||
22 | |||
23 | #define i82860_mc_printk(mci, level, fmt, arg...) \ | ||
24 | edac_mc_chipset_printk(mci, level, "i82860", fmt, ##arg) | ||
21 | 25 | ||
22 | #ifndef PCI_DEVICE_ID_INTEL_82860_0 | 26 | #ifndef PCI_DEVICE_ID_INTEL_82860_0 |
23 | #define PCI_DEVICE_ID_INTEL_82860_0 0x2531 | 27 | #define PCI_DEVICE_ID_INTEL_82860_0 0x2531 |
@@ -48,15 +52,15 @@ struct i82860_error_info { | |||
48 | 52 | ||
49 | static const struct i82860_dev_info i82860_devs[] = { | 53 | static const struct i82860_dev_info i82860_devs[] = { |
50 | [I82860] = { | 54 | [I82860] = { |
51 | .ctl_name = "i82860"}, | 55 | .ctl_name = "i82860" |
56 | }, | ||
52 | }; | 57 | }; |
53 | 58 | ||
54 | static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code | 59 | static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code |
55 | has already registered driver */ | 60 | * has already registered driver |
61 | */ | ||
56 | 62 | ||
57 | static int i82860_registered = 1; | 63 | static void i82860_get_error_info(struct mem_ctl_info *mci, |
58 | |||
59 | static void i82860_get_error_info (struct mem_ctl_info *mci, | ||
60 | struct i82860_error_info *info) | 64 | struct i82860_error_info *info) |
61 | { | 65 | { |
62 | /* | 66 | /* |
@@ -78,14 +82,15 @@ static void i82860_get_error_info (struct mem_ctl_info *mci, | |||
78 | */ | 82 | */ |
79 | if (!(info->errsts2 & 0x0003)) | 83 | if (!(info->errsts2 & 0x0003)) |
80 | return; | 84 | return; |
85 | |||
81 | if ((info->errsts ^ info->errsts2) & 0x0003) { | 86 | if ((info->errsts ^ info->errsts2) & 0x0003) { |
82 | pci_read_config_dword(mci->pdev, I82860_EAP, &info->eap); | 87 | pci_read_config_dword(mci->pdev, I82860_EAP, &info->eap); |
83 | pci_read_config_word(mci->pdev, I82860_DERRCTL_STS, | 88 | pci_read_config_word(mci->pdev, I82860_DERRCTL_STS, |
84 | &info->derrsyn); | 89 | &info->derrsyn); |
85 | } | 90 | } |
86 | } | 91 | } |
87 | 92 | ||
88 | static int i82860_process_error_info (struct mem_ctl_info *mci, | 93 | static int i82860_process_error_info(struct mem_ctl_info *mci, |
89 | struct i82860_error_info *info, int handle_errors) | 94 | struct i82860_error_info *info, int handle_errors) |
90 | { | 95 | { |
91 | int row; | 96 | int row; |
@@ -107,8 +112,8 @@ static int i82860_process_error_info (struct mem_ctl_info *mci, | |||
107 | if (info->errsts & 0x0002) | 112 | if (info->errsts & 0x0002) |
108 | edac_mc_handle_ue(mci, info->eap, 0, row, "i82860 UE"); | 113 | edac_mc_handle_ue(mci, info->eap, 0, row, "i82860 UE"); |
109 | else | 114 | else |
110 | edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row, | 115 | edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row, 0, |
111 | 0, "i82860 UE"); | 116 | "i82860 UE"); |
112 | 117 | ||
113 | return 1; | 118 | return 1; |
114 | } | 119 | } |
@@ -117,7 +122,7 @@ static void i82860_check(struct mem_ctl_info *mci) | |||
117 | { | 122 | { |
118 | struct i82860_error_info info; | 123 | struct i82860_error_info info; |
119 | 124 | ||
120 | debugf1("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__); | 125 | debugf1("MC%d: %s()\n", mci->mc_idx, __func__); |
121 | i82860_get_error_info(mci, &info); | 126 | i82860_get_error_info(mci, &info); |
122 | i82860_process_error_info(mci, &info, 1); | 127 | i82860_process_error_info(mci, &info, 1); |
123 | } | 128 | } |
@@ -128,6 +133,7 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx) | |||
128 | int index; | 133 | int index; |
129 | struct mem_ctl_info *mci = NULL; | 134 | struct mem_ctl_info *mci = NULL; |
130 | unsigned long last_cumul_size; | 135 | unsigned long last_cumul_size; |
136 | struct i82860_error_info discard; | ||
131 | 137 | ||
132 | u16 mchcfg_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ | 138 | u16 mchcfg_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ |
133 | 139 | ||
@@ -140,21 +146,20 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx) | |||
140 | going to make 1 channel for group. | 146 | going to make 1 channel for group. |
141 | */ | 147 | */ |
142 | mci = edac_mc_alloc(0, 16, 1); | 148 | mci = edac_mc_alloc(0, 16, 1); |
149 | |||
143 | if (!mci) | 150 | if (!mci) |
144 | return -ENOMEM; | 151 | return -ENOMEM; |
145 | 152 | ||
146 | debugf3("MC: " __FILE__ ": %s(): init mci\n", __func__); | 153 | debugf3("%s(): init mci\n", __func__); |
147 | |||
148 | mci->pdev = pdev; | 154 | mci->pdev = pdev; |
149 | mci->mtype_cap = MEM_FLAG_DDR; | 155 | mci->mtype_cap = MEM_FLAG_DDR; |
150 | 156 | ||
151 | |||
152 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; | 157 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; |
153 | /* I"m not sure about this but I think that all RDRAM is SECDED */ | 158 | /* I"m not sure about this but I think that all RDRAM is SECDED */ |
154 | mci->edac_cap = EDAC_FLAG_SECDED; | 159 | mci->edac_cap = EDAC_FLAG_SECDED; |
155 | /* adjust FLAGS */ | 160 | /* adjust FLAGS */ |
156 | 161 | ||
157 | mci->mod_name = BS_MOD_STR; | 162 | mci->mod_name = EDAC_MOD_STR; |
158 | mci->mod_ver = "$Revision: 1.1.2.6 $"; | 163 | mci->mod_ver = "$Revision: 1.1.2.6 $"; |
159 | mci->ctl_name = i82860_devs[dev_idx].ctl_name; | 164 | mci->ctl_name = i82860_devs[dev_idx].ctl_name; |
160 | mci->edac_check = i82860_check; | 165 | mci->edac_check = i82860_check; |
@@ -175,12 +180,13 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx) | |||
175 | struct csrow_info *csrow = &mci->csrows[index]; | 180 | struct csrow_info *csrow = &mci->csrows[index]; |
176 | 181 | ||
177 | pci_read_config_word(mci->pdev, I82860_GBA + index * 2, | 182 | pci_read_config_word(mci->pdev, I82860_GBA + index * 2, |
178 | &value); | 183 | &value); |
179 | 184 | ||
180 | cumul_size = (value & I82860_GBA_MASK) << | 185 | cumul_size = (value & I82860_GBA_MASK) << |
181 | (I82860_GBA_SHIFT - PAGE_SHIFT); | 186 | (I82860_GBA_SHIFT - PAGE_SHIFT); |
182 | debugf3("MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n", | 187 | debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index, |
183 | __func__, index, cumul_size); | 188 | cumul_size); |
189 | |||
184 | if (cumul_size == last_cumul_size) | 190 | if (cumul_size == last_cumul_size) |
185 | continue; /* not populated */ | 191 | continue; /* not populated */ |
186 | 192 | ||
@@ -188,42 +194,43 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx) | |||
188 | csrow->last_page = cumul_size - 1; | 194 | csrow->last_page = cumul_size - 1; |
189 | csrow->nr_pages = cumul_size - last_cumul_size; | 195 | csrow->nr_pages = cumul_size - last_cumul_size; |
190 | last_cumul_size = cumul_size; | 196 | last_cumul_size = cumul_size; |
191 | csrow->grain = 1 << 12; /* I82860_EAP has 4KiB reolution */ | 197 | csrow->grain = 1 << 12; /* I82860_EAP has 4KiB reolution */ |
192 | csrow->mtype = MEM_RMBS; | 198 | csrow->mtype = MEM_RMBS; |
193 | csrow->dtype = DEV_UNKNOWN; | 199 | csrow->dtype = DEV_UNKNOWN; |
194 | csrow->edac_mode = mchcfg_ddim ? EDAC_SECDED : EDAC_NONE; | 200 | csrow->edac_mode = mchcfg_ddim ? EDAC_SECDED : EDAC_NONE; |
195 | } | 201 | } |
196 | 202 | ||
197 | /* clear counters */ | 203 | i82860_get_error_info(mci, &discard); /* clear counters */ |
198 | pci_write_bits16(mci->pdev, I82860_ERRSTS, 0x0003, 0x0003); | ||
199 | 204 | ||
200 | if (edac_mc_add_mc(mci)) { | 205 | if (edac_mc_add_mc(mci)) { |
201 | debugf3("MC: " __FILE__ | 206 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); |
202 | ": %s(): failed edac_mc_add_mc()\n", | ||
203 | __func__); | ||
204 | edac_mc_free(mci); | 207 | edac_mc_free(mci); |
205 | } else { | 208 | } else { |
206 | /* get this far and it's successful */ | 209 | /* get this far and it's successful */ |
207 | debugf3("MC: " __FILE__ ": %s(): success\n", __func__); | 210 | debugf3("%s(): success\n", __func__); |
208 | rc = 0; | 211 | rc = 0; |
209 | } | 212 | } |
213 | |||
210 | return rc; | 214 | return rc; |
211 | } | 215 | } |
212 | 216 | ||
213 | /* returns count (>= 0), or negative on error */ | 217 | /* returns count (>= 0), or negative on error */ |
214 | static int __devinit i82860_init_one(struct pci_dev *pdev, | 218 | static int __devinit i82860_init_one(struct pci_dev *pdev, |
215 | const struct pci_device_id *ent) | 219 | const struct pci_device_id *ent) |
216 | { | 220 | { |
217 | int rc; | 221 | int rc; |
218 | 222 | ||
219 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | 223 | debugf0("%s()\n", __func__); |
224 | i82860_printk(KERN_INFO, "i82860 init one\n"); | ||
220 | 225 | ||
221 | printk(KERN_INFO "i82860 init one\n"); | 226 | if (pci_enable_device(pdev) < 0) |
222 | if(pci_enable_device(pdev) < 0) | ||
223 | return -EIO; | 227 | return -EIO; |
228 | |||
224 | rc = i82860_probe1(pdev, ent->driver_data); | 229 | rc = i82860_probe1(pdev, ent->driver_data); |
225 | if(rc == 0) | 230 | |
231 | if (rc == 0) | ||
226 | mci_pdev = pci_dev_get(pdev); | 232 | mci_pdev = pci_dev_get(pdev); |
233 | |||
227 | return rc; | 234 | return rc; |
228 | } | 235 | } |
229 | 236 | ||
@@ -231,23 +238,28 @@ static void __devexit i82860_remove_one(struct pci_dev *pdev) | |||
231 | { | 238 | { |
232 | struct mem_ctl_info *mci; | 239 | struct mem_ctl_info *mci; |
233 | 240 | ||
234 | debugf0(__FILE__ ": %s()\n", __func__); | 241 | debugf0("%s()\n", __func__); |
235 | 242 | ||
236 | mci = edac_mc_find_mci_by_pdev(pdev); | 243 | if ((mci = edac_mc_del_mc(pdev)) == NULL) |
237 | if ((mci != NULL) && (edac_mc_del_mc(mci) == 0)) | 244 | return; |
238 | edac_mc_free(mci); | 245 | |
246 | edac_mc_free(mci); | ||
239 | } | 247 | } |
240 | 248 | ||
241 | static const struct pci_device_id i82860_pci_tbl[] __devinitdata = { | 249 | static const struct pci_device_id i82860_pci_tbl[] __devinitdata = { |
242 | {PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 250 | { |
243 | I82860}, | 251 | PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
244 | {0,} /* 0 terminated list. */ | 252 | I82860 |
253 | }, | ||
254 | { | ||
255 | 0, | ||
256 | } /* 0 terminated list. */ | ||
245 | }; | 257 | }; |
246 | 258 | ||
247 | MODULE_DEVICE_TABLE(pci, i82860_pci_tbl); | 259 | MODULE_DEVICE_TABLE(pci, i82860_pci_tbl); |
248 | 260 | ||
249 | static struct pci_driver i82860_driver = { | 261 | static struct pci_driver i82860_driver = { |
250 | .name = BS_MOD_STR, | 262 | .name = EDAC_MOD_STR, |
251 | .probe = i82860_init_one, | 263 | .probe = i82860_init_one, |
252 | .remove = __devexit_p(i82860_remove_one), | 264 | .remove = __devexit_p(i82860_remove_one), |
253 | .id_table = i82860_pci_tbl, | 265 | .id_table = i82860_pci_tbl, |
@@ -257,43 +269,56 @@ static int __init i82860_init(void) | |||
257 | { | 269 | { |
258 | int pci_rc; | 270 | int pci_rc; |
259 | 271 | ||
260 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 272 | debugf3("%s()\n", __func__); |
273 | |||
261 | if ((pci_rc = pci_register_driver(&i82860_driver)) < 0) | 274 | if ((pci_rc = pci_register_driver(&i82860_driver)) < 0) |
262 | return pci_rc; | 275 | goto fail0; |
263 | 276 | ||
264 | if (!mci_pdev) { | 277 | if (!mci_pdev) { |
265 | i82860_registered = 0; | ||
266 | mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL, | 278 | mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL, |
267 | PCI_DEVICE_ID_INTEL_82860_0, NULL); | 279 | PCI_DEVICE_ID_INTEL_82860_0, NULL); |
280 | |||
268 | if (mci_pdev == NULL) { | 281 | if (mci_pdev == NULL) { |
269 | debugf0("860 pci_get_device fail\n"); | 282 | debugf0("860 pci_get_device fail\n"); |
270 | return -ENODEV; | 283 | pci_rc = -ENODEV; |
284 | goto fail1; | ||
271 | } | 285 | } |
286 | |||
272 | pci_rc = i82860_init_one(mci_pdev, i82860_pci_tbl); | 287 | pci_rc = i82860_init_one(mci_pdev, i82860_pci_tbl); |
288 | |||
273 | if (pci_rc < 0) { | 289 | if (pci_rc < 0) { |
274 | debugf0("860 init fail\n"); | 290 | debugf0("860 init fail\n"); |
275 | pci_dev_put(mci_pdev); | 291 | pci_rc = -ENODEV; |
276 | return -ENODEV; | 292 | goto fail1; |
277 | } | 293 | } |
278 | } | 294 | } |
295 | |||
279 | return 0; | 296 | return 0; |
297 | |||
298 | fail1: | ||
299 | pci_unregister_driver(&i82860_driver); | ||
300 | |||
301 | fail0: | ||
302 | if (mci_pdev != NULL) | ||
303 | pci_dev_put(mci_pdev); | ||
304 | |||
305 | return pci_rc; | ||
280 | } | 306 | } |
281 | 307 | ||
282 | static void __exit i82860_exit(void) | 308 | static void __exit i82860_exit(void) |
283 | { | 309 | { |
284 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 310 | debugf3("%s()\n", __func__); |
285 | 311 | ||
286 | pci_unregister_driver(&i82860_driver); | 312 | pci_unregister_driver(&i82860_driver); |
287 | if (!i82860_registered) { | 313 | |
288 | i82860_remove_one(mci_pdev); | 314 | if (mci_pdev != NULL) |
289 | pci_dev_put(mci_pdev); | 315 | pci_dev_put(mci_pdev); |
290 | } | ||
291 | } | 316 | } |
292 | 317 | ||
293 | module_init(i82860_init); | 318 | module_init(i82860_init); |
294 | module_exit(i82860_exit); | 319 | module_exit(i82860_exit); |
295 | 320 | ||
296 | MODULE_LICENSE("GPL"); | 321 | MODULE_LICENSE("GPL"); |
297 | MODULE_AUTHOR | 322 | MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com) " |
298 | ("Red Hat Inc. (http://www.redhat.com.com) Ben Woodard <woodard@redhat.com>"); | 323 | "Ben Woodard <woodard@redhat.com>"); |
299 | MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers"); | 324 | MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers"); |
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c index 1991f94af753..0aec92698f17 100644 --- a/drivers/edac/i82875p_edac.c +++ b/drivers/edac/i82875p_edac.c | |||
@@ -13,18 +13,19 @@ | |||
13 | * Note: E7210 appears same as D82875P - zhenyu.z.wang at intel.com | 13 | * Note: E7210 appears same as D82875P - zhenyu.z.wang at intel.com |
14 | */ | 14 | */ |
15 | 15 | ||
16 | |||
17 | #include <linux/config.h> | 16 | #include <linux/config.h> |
18 | #include <linux/module.h> | 17 | #include <linux/module.h> |
19 | #include <linux/init.h> | 18 | #include <linux/init.h> |
20 | |||
21 | #include <linux/pci.h> | 19 | #include <linux/pci.h> |
22 | #include <linux/pci_ids.h> | 20 | #include <linux/pci_ids.h> |
23 | |||
24 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
25 | |||
26 | #include "edac_mc.h" | 22 | #include "edac_mc.h" |
27 | 23 | ||
24 | #define i82875p_printk(level, fmt, arg...) \ | ||
25 | edac_printk(level, "i82875p", fmt, ##arg) | ||
26 | |||
27 | #define i82875p_mc_printk(mci, level, fmt, arg...) \ | ||
28 | edac_mc_chipset_printk(mci, level, "i82875p", fmt, ##arg) | ||
28 | 29 | ||
29 | #ifndef PCI_DEVICE_ID_INTEL_82875_0 | 30 | #ifndef PCI_DEVICE_ID_INTEL_82875_0 |
30 | #define PCI_DEVICE_ID_INTEL_82875_0 0x2578 | 31 | #define PCI_DEVICE_ID_INTEL_82875_0 0x2578 |
@@ -34,11 +35,9 @@ | |||
34 | #define PCI_DEVICE_ID_INTEL_82875_6 0x257e | 35 | #define PCI_DEVICE_ID_INTEL_82875_6 0x257e |
35 | #endif /* PCI_DEVICE_ID_INTEL_82875_6 */ | 36 | #endif /* PCI_DEVICE_ID_INTEL_82875_6 */ |
36 | 37 | ||
37 | |||
38 | /* four csrows in dual channel, eight in single channel */ | 38 | /* four csrows in dual channel, eight in single channel */ |
39 | #define I82875P_NR_CSROWS(nr_chans) (8/(nr_chans)) | 39 | #define I82875P_NR_CSROWS(nr_chans) (8/(nr_chans)) |
40 | 40 | ||
41 | |||
42 | /* Intel 82875p register addresses - device 0 function 0 - DRAM Controller */ | 41 | /* Intel 82875p register addresses - device 0 function 0 - DRAM Controller */ |
43 | #define I82875P_EAP 0x58 /* Error Address Pointer (32b) | 42 | #define I82875P_EAP 0x58 /* Error Address Pointer (32b) |
44 | * | 43 | * |
@@ -87,7 +86,6 @@ | |||
87 | * 0 reserved | 86 | * 0 reserved |
88 | */ | 87 | */ |
89 | 88 | ||
90 | |||
91 | /* Intel 82875p register addresses - device 6 function 0 - DRAM Controller */ | 89 | /* Intel 82875p register addresses - device 6 function 0 - DRAM Controller */ |
92 | #define I82875P_PCICMD6 0x04 /* PCI Command Register (16b) | 90 | #define I82875P_PCICMD6 0x04 /* PCI Command Register (16b) |
93 | * | 91 | * |
@@ -151,23 +149,19 @@ | |||
151 | * 1:0 DRAM type 01=DDR | 149 | * 1:0 DRAM type 01=DDR |
152 | */ | 150 | */ |
153 | 151 | ||
154 | |||
155 | enum i82875p_chips { | 152 | enum i82875p_chips { |
156 | I82875P = 0, | 153 | I82875P = 0, |
157 | }; | 154 | }; |
158 | 155 | ||
159 | |||
160 | struct i82875p_pvt { | 156 | struct i82875p_pvt { |
161 | struct pci_dev *ovrfl_pdev; | 157 | struct pci_dev *ovrfl_pdev; |
162 | void __iomem *ovrfl_window; | 158 | void __iomem *ovrfl_window; |
163 | }; | 159 | }; |
164 | 160 | ||
165 | |||
166 | struct i82875p_dev_info { | 161 | struct i82875p_dev_info { |
167 | const char *ctl_name; | 162 | const char *ctl_name; |
168 | }; | 163 | }; |
169 | 164 | ||
170 | |||
171 | struct i82875p_error_info { | 165 | struct i82875p_error_info { |
172 | u16 errsts; | 166 | u16 errsts; |
173 | u32 eap; | 167 | u32 eap; |
@@ -176,17 +170,19 @@ struct i82875p_error_info { | |||
176 | u16 errsts2; | 170 | u16 errsts2; |
177 | }; | 171 | }; |
178 | 172 | ||
179 | |||
180 | static const struct i82875p_dev_info i82875p_devs[] = { | 173 | static const struct i82875p_dev_info i82875p_devs[] = { |
181 | [I82875P] = { | 174 | [I82875P] = { |
182 | .ctl_name = "i82875p"}, | 175 | .ctl_name = "i82875p" |
176 | }, | ||
183 | }; | 177 | }; |
184 | 178 | ||
185 | static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code | 179 | static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code has |
186 | has already registered driver */ | 180 | * already registered driver |
181 | */ | ||
182 | |||
187 | static int i82875p_registered = 1; | 183 | static int i82875p_registered = 1; |
188 | 184 | ||
189 | static void i82875p_get_error_info (struct mem_ctl_info *mci, | 185 | static void i82875p_get_error_info(struct mem_ctl_info *mci, |
190 | struct i82875p_error_info *info) | 186 | struct i82875p_error_info *info) |
191 | { | 187 | { |
192 | /* | 188 | /* |
@@ -210,15 +206,16 @@ static void i82875p_get_error_info (struct mem_ctl_info *mci, | |||
210 | */ | 206 | */ |
211 | if (!(info->errsts2 & 0x0081)) | 207 | if (!(info->errsts2 & 0x0081)) |
212 | return; | 208 | return; |
209 | |||
213 | if ((info->errsts ^ info->errsts2) & 0x0081) { | 210 | if ((info->errsts ^ info->errsts2) & 0x0081) { |
214 | pci_read_config_dword(mci->pdev, I82875P_EAP, &info->eap); | 211 | pci_read_config_dword(mci->pdev, I82875P_EAP, &info->eap); |
215 | pci_read_config_byte(mci->pdev, I82875P_DES, &info->des); | 212 | pci_read_config_byte(mci->pdev, I82875P_DES, &info->des); |
216 | pci_read_config_byte(mci->pdev, I82875P_DERRSYN, | 213 | pci_read_config_byte(mci->pdev, I82875P_DERRSYN, |
217 | &info->derrsyn); | 214 | &info->derrsyn); |
218 | } | 215 | } |
219 | } | 216 | } |
220 | 217 | ||
221 | static int i82875p_process_error_info (struct mem_ctl_info *mci, | 218 | static int i82875p_process_error_info(struct mem_ctl_info *mci, |
222 | struct i82875p_error_info *info, int handle_errors) | 219 | struct i82875p_error_info *info, int handle_errors) |
223 | { | 220 | { |
224 | int row, multi_chan; | 221 | int row, multi_chan; |
@@ -243,23 +240,21 @@ static int i82875p_process_error_info (struct mem_ctl_info *mci, | |||
243 | edac_mc_handle_ue(mci, info->eap, 0, row, "i82875p UE"); | 240 | edac_mc_handle_ue(mci, info->eap, 0, row, "i82875p UE"); |
244 | else | 241 | else |
245 | edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row, | 242 | edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row, |
246 | multi_chan ? (info->des & 0x1) : 0, | 243 | multi_chan ? (info->des & 0x1) : 0, |
247 | "i82875p CE"); | 244 | "i82875p CE"); |
248 | 245 | ||
249 | return 1; | 246 | return 1; |
250 | } | 247 | } |
251 | 248 | ||
252 | |||
253 | static void i82875p_check(struct mem_ctl_info *mci) | 249 | static void i82875p_check(struct mem_ctl_info *mci) |
254 | { | 250 | { |
255 | struct i82875p_error_info info; | 251 | struct i82875p_error_info info; |
256 | 252 | ||
257 | debugf1("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__); | 253 | debugf1("MC%d: %s()\n", mci->mc_idx, __func__); |
258 | i82875p_get_error_info(mci, &info); | 254 | i82875p_get_error_info(mci, &info); |
259 | i82875p_process_error_info(mci, &info, 1); | 255 | i82875p_process_error_info(mci, &info, 1); |
260 | } | 256 | } |
261 | 257 | ||
262 | |||
263 | #ifdef CONFIG_PROC_FS | 258 | #ifdef CONFIG_PROC_FS |
264 | extern int pci_proc_attach_device(struct pci_dev *); | 259 | extern int pci_proc_attach_device(struct pci_dev *); |
265 | #endif | 260 | #endif |
@@ -273,15 +268,14 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx) | |||
273 | unsigned long last_cumul_size; | 268 | unsigned long last_cumul_size; |
274 | struct pci_dev *ovrfl_pdev; | 269 | struct pci_dev *ovrfl_pdev; |
275 | void __iomem *ovrfl_window = NULL; | 270 | void __iomem *ovrfl_window = NULL; |
276 | |||
277 | u32 drc; | 271 | u32 drc; |
278 | u32 drc_chan; /* Number of channels 0=1chan,1=2chan */ | 272 | u32 drc_chan; /* Number of channels 0=1chan,1=2chan */ |
279 | u32 nr_chans; | 273 | u32 nr_chans; |
280 | u32 drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ | 274 | u32 drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */ |
275 | struct i82875p_error_info discard; | ||
281 | 276 | ||
282 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | 277 | debugf0("%s()\n", __func__); |
283 | 278 | ovrfl_pdev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL); | |
284 | ovrfl_pdev = pci_find_device(PCI_VEND_DEV(INTEL, 82875_6), NULL); | ||
285 | 279 | ||
286 | if (!ovrfl_pdev) { | 280 | if (!ovrfl_pdev) { |
287 | /* | 281 | /* |
@@ -292,71 +286,69 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx) | |||
292 | */ | 286 | */ |
293 | pci_write_bits8(pdev, 0xf4, 0x2, 0x2); | 287 | pci_write_bits8(pdev, 0xf4, 0x2, 0x2); |
294 | ovrfl_pdev = | 288 | ovrfl_pdev = |
295 | pci_scan_single_device(pdev->bus, PCI_DEVFN(6, 0)); | 289 | pci_scan_single_device(pdev->bus, PCI_DEVFN(6, 0)); |
290 | |||
296 | if (!ovrfl_pdev) | 291 | if (!ovrfl_pdev) |
297 | goto fail; | 292 | return -ENODEV; |
298 | } | 293 | } |
294 | |||
299 | #ifdef CONFIG_PROC_FS | 295 | #ifdef CONFIG_PROC_FS |
300 | if (!ovrfl_pdev->procent && pci_proc_attach_device(ovrfl_pdev)) { | 296 | if (!ovrfl_pdev->procent && pci_proc_attach_device(ovrfl_pdev)) { |
301 | printk(KERN_ERR "MC: " __FILE__ | 297 | i82875p_printk(KERN_ERR, |
302 | ": %s(): Failed to attach overflow device\n", | 298 | "%s(): Failed to attach overflow device\n", __func__); |
303 | __func__); | 299 | return -ENODEV; |
304 | goto fail; | ||
305 | } | 300 | } |
306 | #endif /* CONFIG_PROC_FS */ | 301 | #endif |
302 | /* CONFIG_PROC_FS */ | ||
307 | if (pci_enable_device(ovrfl_pdev)) { | 303 | if (pci_enable_device(ovrfl_pdev)) { |
308 | printk(KERN_ERR "MC: " __FILE__ | 304 | i82875p_printk(KERN_ERR, |
309 | ": %s(): Failed to enable overflow device\n", | 305 | "%s(): Failed to enable overflow device\n", __func__); |
310 | __func__); | 306 | return -ENODEV; |
311 | goto fail; | ||
312 | } | 307 | } |
313 | 308 | ||
314 | if (pci_request_regions(ovrfl_pdev, pci_name(ovrfl_pdev))) { | 309 | if (pci_request_regions(ovrfl_pdev, pci_name(ovrfl_pdev))) { |
315 | #ifdef CORRECT_BIOS | 310 | #ifdef CORRECT_BIOS |
316 | goto fail; | 311 | goto fail0; |
317 | #endif | 312 | #endif |
318 | } | 313 | } |
314 | |||
319 | /* cache is irrelevant for PCI bus reads/writes */ | 315 | /* cache is irrelevant for PCI bus reads/writes */ |
320 | ovrfl_window = ioremap_nocache(pci_resource_start(ovrfl_pdev, 0), | 316 | ovrfl_window = ioremap_nocache(pci_resource_start(ovrfl_pdev, 0), |
321 | pci_resource_len(ovrfl_pdev, 0)); | 317 | pci_resource_len(ovrfl_pdev, 0)); |
322 | 318 | ||
323 | if (!ovrfl_window) { | 319 | if (!ovrfl_window) { |
324 | printk(KERN_ERR "MC: " __FILE__ | 320 | i82875p_printk(KERN_ERR, "%s(): Failed to ioremap bar6\n", |
325 | ": %s(): Failed to ioremap bar6\n", __func__); | 321 | __func__); |
326 | goto fail; | 322 | goto fail1; |
327 | } | 323 | } |
328 | 324 | ||
329 | /* need to find out the number of channels */ | 325 | /* need to find out the number of channels */ |
330 | drc = readl(ovrfl_window + I82875P_DRC); | 326 | drc = readl(ovrfl_window + I82875P_DRC); |
331 | drc_chan = ((drc >> 21) & 0x1); | 327 | drc_chan = ((drc >> 21) & 0x1); |
332 | nr_chans = drc_chan + 1; | 328 | nr_chans = drc_chan + 1; |
333 | drc_ddim = (drc >> 18) & 0x1; | ||
334 | 329 | ||
330 | drc_ddim = (drc >> 18) & 0x1; | ||
335 | mci = edac_mc_alloc(sizeof(*pvt), I82875P_NR_CSROWS(nr_chans), | 331 | mci = edac_mc_alloc(sizeof(*pvt), I82875P_NR_CSROWS(nr_chans), |
336 | nr_chans); | 332 | nr_chans); |
337 | 333 | ||
338 | if (!mci) { | 334 | if (!mci) { |
339 | rc = -ENOMEM; | 335 | rc = -ENOMEM; |
340 | goto fail; | 336 | goto fail2; |
341 | } | 337 | } |
342 | 338 | ||
343 | debugf3("MC: " __FILE__ ": %s(): init mci\n", __func__); | 339 | debugf3("%s(): init mci\n", __func__); |
344 | |||
345 | mci->pdev = pdev; | 340 | mci->pdev = pdev; |
346 | mci->mtype_cap = MEM_FLAG_DDR; | 341 | mci->mtype_cap = MEM_FLAG_DDR; |
347 | |||
348 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; | 342 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED; |
349 | mci->edac_cap = EDAC_FLAG_UNKNOWN; | 343 | mci->edac_cap = EDAC_FLAG_UNKNOWN; |
350 | /* adjust FLAGS */ | 344 | /* adjust FLAGS */ |
351 | 345 | ||
352 | mci->mod_name = BS_MOD_STR; | 346 | mci->mod_name = EDAC_MOD_STR; |
353 | mci->mod_ver = "$Revision: 1.5.2.11 $"; | 347 | mci->mod_ver = "$Revision: 1.5.2.11 $"; |
354 | mci->ctl_name = i82875p_devs[dev_idx].ctl_name; | 348 | mci->ctl_name = i82875p_devs[dev_idx].ctl_name; |
355 | mci->edac_check = i82875p_check; | 349 | mci->edac_check = i82875p_check; |
356 | mci->ctl_page_to_phys = NULL; | 350 | mci->ctl_page_to_phys = NULL; |
357 | 351 | debugf3("%s(): init pvt\n", __func__); | |
358 | debugf3("MC: " __FILE__ ": %s(): init pvt\n", __func__); | ||
359 | |||
360 | pvt = (struct i82875p_pvt *) mci->pvt_info; | 352 | pvt = (struct i82875p_pvt *) mci->pvt_info; |
361 | pvt->ovrfl_pdev = ovrfl_pdev; | 353 | pvt->ovrfl_pdev = ovrfl_pdev; |
362 | pvt->ovrfl_window = ovrfl_window; | 354 | pvt->ovrfl_window = ovrfl_window; |
@@ -374,8 +366,9 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx) | |||
374 | 366 | ||
375 | value = readb(ovrfl_window + I82875P_DRB + index); | 367 | value = readb(ovrfl_window + I82875P_DRB + index); |
376 | cumul_size = value << (I82875P_DRB_SHIFT - PAGE_SHIFT); | 368 | cumul_size = value << (I82875P_DRB_SHIFT - PAGE_SHIFT); |
377 | debugf3("MC: " __FILE__ ": %s(): (%d) cumul_size 0x%x\n", | 369 | debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index, |
378 | __func__, index, cumul_size); | 370 | cumul_size); |
371 | |||
379 | if (cumul_size == last_cumul_size) | 372 | if (cumul_size == last_cumul_size) |
380 | continue; /* not populated */ | 373 | continue; /* not populated */ |
381 | 374 | ||
@@ -383,71 +376,72 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx) | |||
383 | csrow->last_page = cumul_size - 1; | 376 | csrow->last_page = cumul_size - 1; |
384 | csrow->nr_pages = cumul_size - last_cumul_size; | 377 | csrow->nr_pages = cumul_size - last_cumul_size; |
385 | last_cumul_size = cumul_size; | 378 | last_cumul_size = cumul_size; |
386 | csrow->grain = 1 << 12; /* I82875P_EAP has 4KiB reolution */ | 379 | csrow->grain = 1 << 12; /* I82875P_EAP has 4KiB reolution */ |
387 | csrow->mtype = MEM_DDR; | 380 | csrow->mtype = MEM_DDR; |
388 | csrow->dtype = DEV_UNKNOWN; | 381 | csrow->dtype = DEV_UNKNOWN; |
389 | csrow->edac_mode = drc_ddim ? EDAC_SECDED : EDAC_NONE; | 382 | csrow->edac_mode = drc_ddim ? EDAC_SECDED : EDAC_NONE; |
390 | } | 383 | } |
391 | 384 | ||
392 | /* clear counters */ | 385 | i82875p_get_error_info(mci, &discard); /* clear counters */ |
393 | pci_write_bits16(mci->pdev, I82875P_ERRSTS, 0x0081, 0x0081); | ||
394 | 386 | ||
395 | if (edac_mc_add_mc(mci)) { | 387 | if (edac_mc_add_mc(mci)) { |
396 | debugf3("MC: " __FILE__ | 388 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); |
397 | ": %s(): failed edac_mc_add_mc()\n", __func__); | 389 | goto fail3; |
398 | goto fail; | ||
399 | } | 390 | } |
400 | 391 | ||
401 | /* get this far and it's successful */ | 392 | /* get this far and it's successful */ |
402 | debugf3("MC: " __FILE__ ": %s(): success\n", __func__); | 393 | debugf3("%s(): success\n", __func__); |
403 | return 0; | 394 | return 0; |
404 | 395 | ||
405 | fail: | 396 | fail3: |
406 | if (mci) | 397 | edac_mc_free(mci); |
407 | edac_mc_free(mci); | ||
408 | 398 | ||
409 | if (ovrfl_window) | 399 | fail2: |
410 | iounmap(ovrfl_window); | 400 | iounmap(ovrfl_window); |
411 | 401 | ||
412 | if (ovrfl_pdev) { | 402 | fail1: |
413 | pci_release_regions(ovrfl_pdev); | 403 | pci_release_regions(ovrfl_pdev); |
414 | pci_disable_device(ovrfl_pdev); | ||
415 | } | ||
416 | 404 | ||
405 | #ifdef CORRECT_BIOS | ||
406 | fail0: | ||
407 | #endif | ||
408 | pci_disable_device(ovrfl_pdev); | ||
417 | /* NOTE: the ovrfl proc entry and pci_dev are intentionally left */ | 409 | /* NOTE: the ovrfl proc entry and pci_dev are intentionally left */ |
418 | return rc; | 410 | return rc; |
419 | } | 411 | } |
420 | 412 | ||
421 | |||
422 | /* returns count (>= 0), or negative on error */ | 413 | /* returns count (>= 0), or negative on error */ |
423 | static int __devinit i82875p_init_one(struct pci_dev *pdev, | 414 | static int __devinit i82875p_init_one(struct pci_dev *pdev, |
424 | const struct pci_device_id *ent) | 415 | const struct pci_device_id *ent) |
425 | { | 416 | { |
426 | int rc; | 417 | int rc; |
427 | 418 | ||
428 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | 419 | debugf0("%s()\n", __func__); |
420 | i82875p_printk(KERN_INFO, "i82875p init one\n"); | ||
429 | 421 | ||
430 | printk(KERN_INFO "i82875p init one\n"); | 422 | if (pci_enable_device(pdev) < 0) |
431 | if(pci_enable_device(pdev) < 0) | ||
432 | return -EIO; | 423 | return -EIO; |
424 | |||
433 | rc = i82875p_probe1(pdev, ent->driver_data); | 425 | rc = i82875p_probe1(pdev, ent->driver_data); |
426 | |||
434 | if (mci_pdev == NULL) | 427 | if (mci_pdev == NULL) |
435 | mci_pdev = pci_dev_get(pdev); | 428 | mci_pdev = pci_dev_get(pdev); |
429 | |||
436 | return rc; | 430 | return rc; |
437 | } | 431 | } |
438 | 432 | ||
439 | |||
440 | static void __devexit i82875p_remove_one(struct pci_dev *pdev) | 433 | static void __devexit i82875p_remove_one(struct pci_dev *pdev) |
441 | { | 434 | { |
442 | struct mem_ctl_info *mci; | 435 | struct mem_ctl_info *mci; |
443 | struct i82875p_pvt *pvt = NULL; | 436 | struct i82875p_pvt *pvt = NULL; |
444 | 437 | ||
445 | debugf0(__FILE__ ": %s()\n", __func__); | 438 | debugf0("%s()\n", __func__); |
446 | 439 | ||
447 | if ((mci = edac_mc_find_mci_by_pdev(pdev)) == NULL) | 440 | if ((mci = edac_mc_del_mc(pdev)) == NULL) |
448 | return; | 441 | return; |
449 | 442 | ||
450 | pvt = (struct i82875p_pvt *) mci->pvt_info; | 443 | pvt = (struct i82875p_pvt *) mci->pvt_info; |
444 | |||
451 | if (pvt->ovrfl_window) | 445 | if (pvt->ovrfl_window) |
452 | iounmap(pvt->ovrfl_window); | 446 | iounmap(pvt->ovrfl_window); |
453 | 447 | ||
@@ -459,74 +453,84 @@ static void __devexit i82875p_remove_one(struct pci_dev *pdev) | |||
459 | pci_dev_put(pvt->ovrfl_pdev); | 453 | pci_dev_put(pvt->ovrfl_pdev); |
460 | } | 454 | } |
461 | 455 | ||
462 | if (edac_mc_del_mc(mci)) | ||
463 | return; | ||
464 | |||
465 | edac_mc_free(mci); | 456 | edac_mc_free(mci); |
466 | } | 457 | } |
467 | 458 | ||
468 | |||
469 | static const struct pci_device_id i82875p_pci_tbl[] __devinitdata = { | 459 | static const struct pci_device_id i82875p_pci_tbl[] __devinitdata = { |
470 | {PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 460 | { |
471 | I82875P}, | 461 | PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
472 | {0,} /* 0 terminated list. */ | 462 | I82875P |
463 | }, | ||
464 | { | ||
465 | 0, | ||
466 | } /* 0 terminated list. */ | ||
473 | }; | 467 | }; |
474 | 468 | ||
475 | MODULE_DEVICE_TABLE(pci, i82875p_pci_tbl); | 469 | MODULE_DEVICE_TABLE(pci, i82875p_pci_tbl); |
476 | 470 | ||
477 | |||
478 | static struct pci_driver i82875p_driver = { | 471 | static struct pci_driver i82875p_driver = { |
479 | .name = BS_MOD_STR, | 472 | .name = EDAC_MOD_STR, |
480 | .probe = i82875p_init_one, | 473 | .probe = i82875p_init_one, |
481 | .remove = __devexit_p(i82875p_remove_one), | 474 | .remove = __devexit_p(i82875p_remove_one), |
482 | .id_table = i82875p_pci_tbl, | 475 | .id_table = i82875p_pci_tbl, |
483 | }; | 476 | }; |
484 | 477 | ||
485 | |||
486 | static int __init i82875p_init(void) | 478 | static int __init i82875p_init(void) |
487 | { | 479 | { |
488 | int pci_rc; | 480 | int pci_rc; |
489 | 481 | ||
490 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 482 | debugf3("%s()\n", __func__); |
491 | pci_rc = pci_register_driver(&i82875p_driver); | 483 | pci_rc = pci_register_driver(&i82875p_driver); |
484 | |||
492 | if (pci_rc < 0) | 485 | if (pci_rc < 0) |
493 | return pci_rc; | 486 | goto fail0; |
487 | |||
494 | if (mci_pdev == NULL) { | 488 | if (mci_pdev == NULL) { |
495 | i82875p_registered = 0; | 489 | mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL, |
496 | mci_pdev = | 490 | PCI_DEVICE_ID_INTEL_82875_0, NULL); |
497 | pci_get_device(PCI_VENDOR_ID_INTEL, | 491 | |
498 | PCI_DEVICE_ID_INTEL_82875_0, NULL); | ||
499 | if (!mci_pdev) { | 492 | if (!mci_pdev) { |
500 | debugf0("875p pci_get_device fail\n"); | 493 | debugf0("875p pci_get_device fail\n"); |
501 | return -ENODEV; | 494 | pci_rc = -ENODEV; |
495 | goto fail1; | ||
502 | } | 496 | } |
497 | |||
503 | pci_rc = i82875p_init_one(mci_pdev, i82875p_pci_tbl); | 498 | pci_rc = i82875p_init_one(mci_pdev, i82875p_pci_tbl); |
499 | |||
504 | if (pci_rc < 0) { | 500 | if (pci_rc < 0) { |
505 | debugf0("875p init fail\n"); | 501 | debugf0("875p init fail\n"); |
506 | pci_dev_put(mci_pdev); | 502 | pci_rc = -ENODEV; |
507 | return -ENODEV; | 503 | goto fail1; |
508 | } | 504 | } |
509 | } | 505 | } |
506 | |||
510 | return 0; | 507 | return 0; |
511 | } | ||
512 | 508 | ||
509 | fail1: | ||
510 | pci_unregister_driver(&i82875p_driver); | ||
511 | |||
512 | fail0: | ||
513 | if (mci_pdev != NULL) | ||
514 | pci_dev_put(mci_pdev); | ||
515 | |||
516 | return pci_rc; | ||
517 | } | ||
513 | 518 | ||
514 | static void __exit i82875p_exit(void) | 519 | static void __exit i82875p_exit(void) |
515 | { | 520 | { |
516 | debugf3("MC: " __FILE__ ": %s()\n", __func__); | 521 | debugf3("%s()\n", __func__); |
517 | 522 | ||
518 | pci_unregister_driver(&i82875p_driver); | 523 | pci_unregister_driver(&i82875p_driver); |
524 | |||
519 | if (!i82875p_registered) { | 525 | if (!i82875p_registered) { |
520 | i82875p_remove_one(mci_pdev); | 526 | i82875p_remove_one(mci_pdev); |
521 | pci_dev_put(mci_pdev); | 527 | pci_dev_put(mci_pdev); |
522 | } | 528 | } |
523 | } | 529 | } |
524 | 530 | ||
525 | |||
526 | module_init(i82875p_init); | 531 | module_init(i82875p_init); |
527 | module_exit(i82875p_exit); | 532 | module_exit(i82875p_exit); |
528 | 533 | ||
529 | |||
530 | MODULE_LICENSE("GPL"); | 534 | MODULE_LICENSE("GPL"); |
531 | MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh"); | 535 | MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh"); |
532 | MODULE_DESCRIPTION("MC support for Intel 82875 memory hub controllers"); | 536 | MODULE_DESCRIPTION("MC support for Intel 82875 memory hub controllers"); |
diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c index e90892831b90..2c29fafe67c7 100644 --- a/drivers/edac/r82600_edac.c +++ b/drivers/edac/r82600_edac.c | |||
@@ -18,14 +18,17 @@ | |||
18 | #include <linux/config.h> | 18 | #include <linux/config.h> |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | |||
22 | #include <linux/pci.h> | 21 | #include <linux/pci.h> |
23 | #include <linux/pci_ids.h> | 22 | #include <linux/pci_ids.h> |
24 | |||
25 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
26 | |||
27 | #include "edac_mc.h" | 24 | #include "edac_mc.h" |
28 | 25 | ||
26 | #define r82600_printk(level, fmt, arg...) \ | ||
27 | edac_printk(level, "r82600", fmt, ##arg) | ||
28 | |||
29 | #define r82600_mc_printk(mci, level, fmt, arg...) \ | ||
30 | edac_mc_chipset_printk(mci, level, "r82600", fmt, ##arg) | ||
31 | |||
29 | /* Radisys say "The 82600 integrates a main memory SDRAM controller that | 32 | /* Radisys say "The 82600 integrates a main memory SDRAM controller that |
30 | * supports up to four banks of memory. The four banks can support a mix of | 33 | * supports up to four banks of memory. The four banks can support a mix of |
31 | * sizes of 64 bit wide (72 bits with ECC) Synchronous DRAM (SDRAM) DIMMs, | 34 | * sizes of 64 bit wide (72 bits with ECC) Synchronous DRAM (SDRAM) DIMMs, |
@@ -126,10 +129,8 @@ struct r82600_error_info { | |||
126 | u32 eapr; | 129 | u32 eapr; |
127 | }; | 130 | }; |
128 | 131 | ||
129 | |||
130 | static unsigned int disable_hardware_scrub = 0; | 132 | static unsigned int disable_hardware_scrub = 0; |
131 | 133 | ||
132 | |||
133 | static void r82600_get_error_info (struct mem_ctl_info *mci, | 134 | static void r82600_get_error_info (struct mem_ctl_info *mci, |
134 | struct r82600_error_info *info) | 135 | struct r82600_error_info *info) |
135 | { | 136 | { |
@@ -138,17 +139,16 @@ static void r82600_get_error_info (struct mem_ctl_info *mci, | |||
138 | if (info->eapr & BIT(0)) | 139 | if (info->eapr & BIT(0)) |
139 | /* Clear error to allow next error to be reported [p.62] */ | 140 | /* Clear error to allow next error to be reported [p.62] */ |
140 | pci_write_bits32(mci->pdev, R82600_EAP, | 141 | pci_write_bits32(mci->pdev, R82600_EAP, |
141 | ((u32) BIT(0) & (u32) BIT(1)), | 142 | ((u32) BIT(0) & (u32) BIT(1)), |
142 | ((u32) BIT(0) & (u32) BIT(1))); | 143 | ((u32) BIT(0) & (u32) BIT(1))); |
143 | 144 | ||
144 | if (info->eapr & BIT(1)) | 145 | if (info->eapr & BIT(1)) |
145 | /* Clear error to allow next error to be reported [p.62] */ | 146 | /* Clear error to allow next error to be reported [p.62] */ |
146 | pci_write_bits32(mci->pdev, R82600_EAP, | 147 | pci_write_bits32(mci->pdev, R82600_EAP, |
147 | ((u32) BIT(0) & (u32) BIT(1)), | 148 | ((u32) BIT(0) & (u32) BIT(1)), |
148 | ((u32) BIT(0) & (u32) BIT(1))); | 149 | ((u32) BIT(0) & (u32) BIT(1))); |
149 | } | 150 | } |
150 | 151 | ||
151 | |||
152 | static int r82600_process_error_info (struct mem_ctl_info *mci, | 152 | static int r82600_process_error_info (struct mem_ctl_info *mci, |
153 | struct r82600_error_info *info, int handle_errors) | 153 | struct r82600_error_info *info, int handle_errors) |
154 | { | 154 | { |
@@ -167,26 +167,25 @@ static int r82600_process_error_info (struct mem_ctl_info *mci, | |||
167 | * granularity (upper 19 bits only) */ | 167 | * granularity (upper 19 bits only) */ |
168 | page = eapaddr >> PAGE_SHIFT; | 168 | page = eapaddr >> PAGE_SHIFT; |
169 | 169 | ||
170 | if (info->eapr & BIT(0)) { /* CE? */ | 170 | if (info->eapr & BIT(0)) { /* CE? */ |
171 | error_found = 1; | 171 | error_found = 1; |
172 | 172 | ||
173 | if (handle_errors) | 173 | if (handle_errors) |
174 | edac_mc_handle_ce( | 174 | edac_mc_handle_ce(mci, page, 0, /* not avail */ |
175 | mci, page, 0, /* not avail */ | 175 | syndrome, |
176 | syndrome, | 176 | edac_mc_find_csrow_by_page(mci, page), |
177 | edac_mc_find_csrow_by_page(mci, page), | 177 | 0, /* channel */ |
178 | 0, /* channel */ | 178 | mci->ctl_name); |
179 | mci->ctl_name); | ||
180 | } | 179 | } |
181 | 180 | ||
182 | if (info->eapr & BIT(1)) { /* UE? */ | 181 | if (info->eapr & BIT(1)) { /* UE? */ |
183 | error_found = 1; | 182 | error_found = 1; |
184 | 183 | ||
185 | if (handle_errors) | 184 | if (handle_errors) |
186 | /* 82600 doesn't give enough info */ | 185 | /* 82600 doesn't give enough info */ |
187 | edac_mc_handle_ue(mci, page, 0, | 186 | edac_mc_handle_ue(mci, page, 0, |
188 | edac_mc_find_csrow_by_page(mci, page), | 187 | edac_mc_find_csrow_by_page(mci, page), |
189 | mci->ctl_name); | 188 | mci->ctl_name); |
190 | } | 189 | } |
191 | 190 | ||
192 | return error_found; | 191 | return error_found; |
@@ -196,7 +195,7 @@ static void r82600_check(struct mem_ctl_info *mci) | |||
196 | { | 195 | { |
197 | struct r82600_error_info info; | 196 | struct r82600_error_info info; |
198 | 197 | ||
199 | debugf1("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__); | 198 | debugf1("MC%d: %s()\n", mci->mc_idx, __func__); |
200 | r82600_get_error_info(mci, &info); | 199 | r82600_get_error_info(mci, &info); |
201 | r82600_process_error_info(mci, &info, 1); | 200 | r82600_process_error_info(mci, &info, 1); |
202 | } | 201 | } |
@@ -213,25 +212,18 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx) | |||
213 | u32 scrub_disabled; | 212 | u32 scrub_disabled; |
214 | u32 sdram_refresh_rate; | 213 | u32 sdram_refresh_rate; |
215 | u32 row_high_limit_last = 0; | 214 | u32 row_high_limit_last = 0; |
216 | u32 eap_init_bits; | 215 | struct r82600_error_info discard; |
217 | |||
218 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | ||
219 | |||
220 | 216 | ||
217 | debugf0("%s()\n", __func__); | ||
221 | pci_read_config_byte(pdev, R82600_DRAMC, &dramcr); | 218 | pci_read_config_byte(pdev, R82600_DRAMC, &dramcr); |
222 | pci_read_config_dword(pdev, R82600_EAP, &eapr); | 219 | pci_read_config_dword(pdev, R82600_EAP, &eapr); |
223 | |||
224 | ecc_on = dramcr & BIT(5); | 220 | ecc_on = dramcr & BIT(5); |
225 | reg_sdram = dramcr & BIT(4); | 221 | reg_sdram = dramcr & BIT(4); |
226 | scrub_disabled = eapr & BIT(31); | 222 | scrub_disabled = eapr & BIT(31); |
227 | sdram_refresh_rate = dramcr & (BIT(0) | BIT(1)); | 223 | sdram_refresh_rate = dramcr & (BIT(0) | BIT(1)); |
228 | 224 | debugf2("%s(): sdram refresh rate = %#0x\n", __func__, | |
229 | debugf2("MC: " __FILE__ ": %s(): sdram refresh rate = %#0x\n", | 225 | sdram_refresh_rate); |
230 | __func__, sdram_refresh_rate); | 226 | debugf2("%s(): DRAMC register = %#0x\n", __func__, dramcr); |
231 | |||
232 | debugf2("MC: " __FILE__ ": %s(): DRAMC register = %#0x\n", __func__, | ||
233 | dramcr); | ||
234 | |||
235 | mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS); | 227 | mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS); |
236 | 228 | ||
237 | if (mci == NULL) { | 229 | if (mci == NULL) { |
@@ -239,29 +231,28 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx) | |||
239 | goto fail; | 231 | goto fail; |
240 | } | 232 | } |
241 | 233 | ||
242 | debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); | 234 | debugf0("%s(): mci = %p\n", __func__, mci); |
243 | |||
244 | mci->pdev = pdev; | 235 | mci->pdev = pdev; |
245 | mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR; | 236 | mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR; |
246 | |||
247 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; | 237 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; |
248 | /* FIXME try to work out if the chip leads have been * | 238 | /* FIXME try to work out if the chip leads have been used for COM2 |
249 | * used for COM2 instead on this board? [MA6?] MAYBE: */ | 239 | * instead on this board? [MA6?] MAYBE: |
240 | */ | ||
250 | 241 | ||
251 | /* On the R82600, the pins for memory bits 72:65 - i.e. the * | 242 | /* On the R82600, the pins for memory bits 72:65 - i.e. the * |
252 | * EC bits are shared with the pins for COM2 (!), so if COM2 * | 243 | * EC bits are shared with the pins for COM2 (!), so if COM2 * |
253 | * is enabled, we assume COM2 is wired up, and thus no EDAC * | 244 | * is enabled, we assume COM2 is wired up, and thus no EDAC * |
254 | * is possible. */ | 245 | * is possible. */ |
255 | mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; | 246 | mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED; |
247 | |||
256 | if (ecc_on) { | 248 | if (ecc_on) { |
257 | if (scrub_disabled) | 249 | if (scrub_disabled) |
258 | debugf3("MC: " __FILE__ ": %s(): mci = %p - " | 250 | debugf3("%s(): mci = %p - Scrubbing disabled! EAP: " |
259 | "Scrubbing disabled! EAP: %#0x\n", __func__, | 251 | "%#0x\n", __func__, mci, eapr); |
260 | mci, eapr); | ||
261 | } else | 252 | } else |
262 | mci->edac_cap = EDAC_FLAG_NONE; | 253 | mci->edac_cap = EDAC_FLAG_NONE; |
263 | 254 | ||
264 | mci->mod_name = BS_MOD_STR; | 255 | mci->mod_name = EDAC_MOD_STR; |
265 | mci->mod_ver = "$Revision: 1.1.2.6 $"; | 256 | mci->mod_ver = "$Revision: 1.1.2.6 $"; |
266 | mci->ctl_name = "R82600"; | 257 | mci->ctl_name = "R82600"; |
267 | mci->edac_check = r82600_check; | 258 | mci->edac_check = r82600_check; |
@@ -276,23 +267,21 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx) | |||
276 | /* find the DRAM Chip Select Base address and mask */ | 267 | /* find the DRAM Chip Select Base address and mask */ |
277 | pci_read_config_byte(mci->pdev, R82600_DRBA + index, &drbar); | 268 | pci_read_config_byte(mci->pdev, R82600_DRBA + index, &drbar); |
278 | 269 | ||
279 | debugf1("MC%d: " __FILE__ ": %s() Row=%d DRBA = %#0x\n", | 270 | debugf1("MC%d: %s() Row=%d DRBA = %#0x\n", mci->mc_idx, |
280 | mci->mc_idx, __func__, index, drbar); | 271 | __func__, index, drbar); |
281 | 272 | ||
282 | row_high_limit = ((u32) drbar << 24); | 273 | row_high_limit = ((u32) drbar << 24); |
283 | /* row_high_limit = ((u32)drbar << 24) | 0xffffffUL; */ | 274 | /* row_high_limit = ((u32)drbar << 24) | 0xffffffUL; */ |
284 | 275 | ||
285 | debugf1("MC%d: " __FILE__ ": %s() Row=%d, " | 276 | debugf1("MC%d: %s() Row=%d, Boundry Address=%#0x, Last = " |
286 | "Boundry Address=%#0x, Last = %#0x \n", | 277 | "%#0x \n", mci->mc_idx, __func__, index, |
287 | mci->mc_idx, __func__, index, row_high_limit, | 278 | row_high_limit, row_high_limit_last); |
288 | row_high_limit_last); | ||
289 | 279 | ||
290 | /* Empty row [p.57] */ | 280 | /* Empty row [p.57] */ |
291 | if (row_high_limit == row_high_limit_last) | 281 | if (row_high_limit == row_high_limit_last) |
292 | continue; | 282 | continue; |
293 | 283 | ||
294 | row_base = row_high_limit_last; | 284 | row_base = row_high_limit_last; |
295 | |||
296 | csrow->first_page = row_base >> PAGE_SHIFT; | 285 | csrow->first_page = row_base >> PAGE_SHIFT; |
297 | csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1; | 286 | csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1; |
298 | csrow->nr_pages = csrow->last_page - csrow->first_page + 1; | 287 | csrow->nr_pages = csrow->last_page - csrow->first_page + 1; |
@@ -308,31 +297,22 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx) | |||
308 | row_high_limit_last = row_high_limit; | 297 | row_high_limit_last = row_high_limit; |
309 | } | 298 | } |
310 | 299 | ||
311 | /* clear counters */ | 300 | r82600_get_error_info(mci, &discard); /* clear counters */ |
312 | /* FIXME should we? */ | ||
313 | 301 | ||
314 | if (edac_mc_add_mc(mci)) { | 302 | if (edac_mc_add_mc(mci)) { |
315 | debugf3("MC: " __FILE__ | 303 | debugf3("%s(): failed edac_mc_add_mc()\n", __func__); |
316 | ": %s(): failed edac_mc_add_mc()\n", __func__); | ||
317 | goto fail; | 304 | goto fail; |
318 | } | 305 | } |
319 | 306 | ||
320 | /* get this far and it's successful */ | 307 | /* get this far and it's successful */ |
321 | 308 | ||
322 | /* Clear error flags to allow next error to be reported [p.62] */ | ||
323 | /* Test systems seem to always have the UE flag raised on boot */ | ||
324 | |||
325 | eap_init_bits = BIT(0) & BIT(1); | ||
326 | if (disable_hardware_scrub) { | 309 | if (disable_hardware_scrub) { |
327 | eap_init_bits |= BIT(31); | 310 | debugf3("%s(): Disabling Hardware Scrub (scrub on error)\n", |
328 | debugf3("MC: " __FILE__ ": %s(): Disabling Hardware Scrub " | 311 | __func__); |
329 | "(scrub on error)\n", __func__); | 312 | pci_write_bits32(mci->pdev, R82600_EAP, BIT(31), BIT(31)); |
330 | } | 313 | } |
331 | 314 | ||
332 | pci_write_bits32(mci->pdev, R82600_EAP, eap_init_bits, | 315 | debugf3("%s(): success\n", __func__); |
333 | eap_init_bits); | ||
334 | |||
335 | debugf3("MC: " __FILE__ ": %s(): success\n", __func__); | ||
336 | return 0; | 316 | return 0; |
337 | 317 | ||
338 | fail: | 318 | fail: |
@@ -344,62 +324,60 @@ fail: | |||
344 | 324 | ||
345 | /* returns count (>= 0), or negative on error */ | 325 | /* returns count (>= 0), or negative on error */ |
346 | static int __devinit r82600_init_one(struct pci_dev *pdev, | 326 | static int __devinit r82600_init_one(struct pci_dev *pdev, |
347 | const struct pci_device_id *ent) | 327 | const struct pci_device_id *ent) |
348 | { | 328 | { |
349 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | 329 | debugf0("%s()\n", __func__); |
350 | 330 | ||
351 | /* don't need to call pci_device_enable() */ | 331 | /* don't need to call pci_device_enable() */ |
352 | return r82600_probe1(pdev, ent->driver_data); | 332 | return r82600_probe1(pdev, ent->driver_data); |
353 | } | 333 | } |
354 | 334 | ||
355 | |||
356 | static void __devexit r82600_remove_one(struct pci_dev *pdev) | 335 | static void __devexit r82600_remove_one(struct pci_dev *pdev) |
357 | { | 336 | { |
358 | struct mem_ctl_info *mci; | 337 | struct mem_ctl_info *mci; |
359 | 338 | ||
360 | debugf0(__FILE__ ": %s()\n", __func__); | 339 | debugf0("%s()\n", __func__); |
361 | 340 | ||
362 | if (((mci = edac_mc_find_mci_by_pdev(pdev)) != NULL) && | 341 | if ((mci = edac_mc_del_mc(pdev)) == NULL) |
363 | !edac_mc_del_mc(mci)) | 342 | return; |
364 | edac_mc_free(mci); | ||
365 | } | ||
366 | 343 | ||
344 | edac_mc_free(mci); | ||
345 | } | ||
367 | 346 | ||
368 | static const struct pci_device_id r82600_pci_tbl[] __devinitdata = { | 347 | static const struct pci_device_id r82600_pci_tbl[] __devinitdata = { |
369 | {PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID)}, | 348 | { |
370 | {0,} /* 0 terminated list. */ | 349 | PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID) |
350 | }, | ||
351 | { | ||
352 | 0, | ||
353 | } /* 0 terminated list. */ | ||
371 | }; | 354 | }; |
372 | 355 | ||
373 | MODULE_DEVICE_TABLE(pci, r82600_pci_tbl); | 356 | MODULE_DEVICE_TABLE(pci, r82600_pci_tbl); |
374 | 357 | ||
375 | |||
376 | static struct pci_driver r82600_driver = { | 358 | static struct pci_driver r82600_driver = { |
377 | .name = BS_MOD_STR, | 359 | .name = EDAC_MOD_STR, |
378 | .probe = r82600_init_one, | 360 | .probe = r82600_init_one, |
379 | .remove = __devexit_p(r82600_remove_one), | 361 | .remove = __devexit_p(r82600_remove_one), |
380 | .id_table = r82600_pci_tbl, | 362 | .id_table = r82600_pci_tbl, |
381 | }; | 363 | }; |
382 | 364 | ||
383 | |||
384 | static int __init r82600_init(void) | 365 | static int __init r82600_init(void) |
385 | { | 366 | { |
386 | return pci_register_driver(&r82600_driver); | 367 | return pci_register_driver(&r82600_driver); |
387 | } | 368 | } |
388 | 369 | ||
389 | |||
390 | static void __exit r82600_exit(void) | 370 | static void __exit r82600_exit(void) |
391 | { | 371 | { |
392 | pci_unregister_driver(&r82600_driver); | 372 | pci_unregister_driver(&r82600_driver); |
393 | } | 373 | } |
394 | 374 | ||
395 | |||
396 | module_init(r82600_init); | 375 | module_init(r82600_init); |
397 | module_exit(r82600_exit); | 376 | module_exit(r82600_exit); |
398 | 377 | ||
399 | |||
400 | MODULE_LICENSE("GPL"); | 378 | MODULE_LICENSE("GPL"); |
401 | MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD Ltd. " | 379 | MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD Ltd. " |
402 | "on behalf of EADS Astrium"); | 380 | "on behalf of EADS Astrium"); |
403 | MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers"); | 381 | MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers"); |
404 | 382 | ||
405 | module_param(disable_hardware_scrub, bool, 0644); | 383 | module_param(disable_hardware_scrub, bool, 0644); |