[PATCH] EDAC: amd76x pci_dev_get/pci_dev_put fixes
[safe/jmp/linux-2.6] / drivers / edac / amd76x_edac.c
1 /*
2  * AMD 76x Memory Controller kernel module
3  * (C) 2003 Linux Networx (http://lnxi.com)
4  * This file may be distributed under the terms of the
5  * GNU General Public License.
6  *
7  * Written by Thayne Harbaugh
8  * Based on work by Dan Hollis <goemon at anime dot net> and others.
9  *      http://www.anime.net/~goemon/linux-ecc/
10  *
11  * $Id: edac_amd76x.c,v 1.4.2.5 2005/10/05 00:43:44 dsp_llnl Exp $
12  *
13  */
14
15
16 #include <linux/config.h>
17 #include <linux/module.h>
18 #include <linux/init.h>
19
20 #include <linux/pci.h>
21 #include <linux/pci_ids.h>
22
23 #include <linux/slab.h>
24
25 #include "edac_mc.h"
26
27
28 #define amd76x_printk(level, fmt, arg...) \
29     edac_printk(level, "amd76x", fmt, ##arg)
30
31
32 #define amd76x_mc_printk(mci, level, fmt, arg...) \
33     edac_mc_chipset_printk(mci, level, "amd76x", fmt, ##arg)
34
35
36 #define AMD76X_NR_CSROWS 8
37 #define AMD76X_NR_CHANS  1
38 #define AMD76X_NR_DIMMS  4
39
40
41 /* AMD 76x register addresses - device 0 function 0 - PCI bridge */
42 #define AMD76X_ECC_MODE_STATUS  0x48    /* Mode and status of ECC (32b)
43                                          *
44                                          * 31:16 reserved
45                                          * 15:14 SERR enabled: x1=ue 1x=ce
46                                          * 13    reserved
47                                          * 12    diag: disabled, enabled
48                                          * 11:10 mode: dis, EC, ECC, ECC+scrub
49                                          *  9:8  status: x1=ue 1x=ce
50                                          *  7:4  UE cs row
51                                          *  3:0  CE cs row
52                                          */
53 #define AMD76X_DRAM_MODE_STATUS 0x58    /* DRAM Mode and status (32b)
54                                          *
55                                          * 31:26 clock disable 5 - 0
56                                          * 25    SDRAM init
57                                          * 24    reserved
58                                          * 23    mode register service
59                                          * 22:21 suspend to RAM
60                                          * 20    burst refresh enable
61                                          * 19    refresh disable
62                                          * 18    reserved
63                                          * 17:16 cycles-per-refresh
64                                          * 15:8  reserved
65                                          *  7:0  x4 mode enable 7 - 0
66                                          */
67 #define AMD76X_MEM_BASE_ADDR    0xC0    /* Memory base address (8 x 32b)
68                                          *
69                                          * 31:23 chip-select base
70                                          * 22:16 reserved
71                                          * 15:7  chip-select mask
72                                          *  6:3  reserved
73                                          *  2:1  address mode
74                                          *  0    chip-select enable
75                                          */
76
77
78 struct amd76x_error_info {
79         u32 ecc_mode_status;
80 };
81
82
83 enum amd76x_chips {
84         AMD761 = 0,
85         AMD762
86 };
87
88
89 struct amd76x_dev_info {
90         const char *ctl_name;
91 };
92
93
94 static const struct amd76x_dev_info amd76x_devs[] = {
95         [AMD761] = {.ctl_name = "AMD761"},
96         [AMD762] = {.ctl_name = "AMD762"},
97 };
98
99
100 /**
101  *      amd76x_get_error_info   -       fetch error information
102  *      @mci: Memory controller
103  *      @info: Info to fill in
104  *
105  *      Fetch and store the AMD76x ECC status. Clear pending status
106  *      on the chip so that further errors will be reported
107  */
108
109 static void amd76x_get_error_info (struct mem_ctl_info *mci,
110                                    struct amd76x_error_info *info)
111 {
112         pci_read_config_dword(mci->pdev, AMD76X_ECC_MODE_STATUS,
113                                 &info->ecc_mode_status);
114
115         if (info->ecc_mode_status & BIT(8))
116                 pci_write_bits32(mci->pdev, AMD76X_ECC_MODE_STATUS,
117                                    (u32) BIT(8), (u32) BIT(8));
118
119         if (info->ecc_mode_status & BIT(9))
120                 pci_write_bits32(mci->pdev, AMD76X_ECC_MODE_STATUS,
121                                    (u32) BIT(9), (u32) BIT(9));
122 }
123
124
125 /**
126  *      amd76x_process_error_info       -       Error check
127  *      @mci: Memory controller
128  *      @info: Previously fetched information from chip
129  *      @handle_errors: 1 if we should do recovery
130  *
131  *      Process the chip state and decide if an error has occurred.
132  *      A return of 1 indicates an error. Also if handle_errors is true
133  *      then attempt to handle and clean up after the error
134  */
135
136 static int amd76x_process_error_info (struct mem_ctl_info *mci,
137                 struct amd76x_error_info *info, int handle_errors)
138 {
139         int error_found;
140         u32 row;
141
142         error_found = 0;
143
144         /*
145          *      Check for an uncorrectable error
146          */
147         if (info->ecc_mode_status & BIT(8)) {
148                 error_found = 1;
149
150                 if (handle_errors) {
151                         row = (info->ecc_mode_status >> 4) & 0xf;
152                         edac_mc_handle_ue(mci,
153                             mci->csrows[row].first_page, 0, row,
154                             mci->ctl_name);
155                 }
156         }
157
158         /*
159          *      Check for a correctable error
160          */
161         if (info->ecc_mode_status & BIT(9)) {
162                 error_found = 1;
163
164                 if (handle_errors) {
165                         row = info->ecc_mode_status & 0xf;
166                         edac_mc_handle_ce(mci,
167                             mci->csrows[row].first_page, 0, 0, row, 0,
168                             mci->ctl_name);
169                 }
170         }
171         return error_found;
172 }
173
174 /**
175  *      amd76x_check    -       Poll the controller
176  *      @mci: Memory controller
177  *
178  *      Called by the poll handlers this function reads the status
179  *      from the controller and checks for errors.
180  */
181
182 static void amd76x_check(struct mem_ctl_info *mci)
183 {
184         struct amd76x_error_info info;
185         debugf3("%s()\n", __func__);
186         amd76x_get_error_info(mci, &info);
187         amd76x_process_error_info(mci, &info, 1);
188 }
189
190
191 /**
192  *      amd76x_probe1   -       Perform set up for detected device
193  *      @pdev; PCI device detected
194  *      @dev_idx: Device type index
195  *
196  *      We have found an AMD76x and now need to set up the memory
197  *      controller status reporting. We configure and set up the
198  *      memory controller reporting and claim the device.
199  */
200
201 static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
202 {
203         int rc = -ENODEV;
204         int index;
205         struct mem_ctl_info *mci = NULL;
206         enum edac_type ems_modes[] = {
207                 EDAC_NONE,
208                 EDAC_EC,
209                 EDAC_SECDED,
210                 EDAC_SECDED
211         };
212         u32 ems;
213         u32 ems_mode;
214
215         debugf0("%s()\n", __func__);
216
217         pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &ems);
218         ems_mode = (ems >> 10) & 0x3;
219
220         mci = edac_mc_alloc(0, AMD76X_NR_CSROWS, AMD76X_NR_CHANS);
221
222         if (mci == NULL) {
223                 rc = -ENOMEM;
224                 goto fail;
225         }
226
227         debugf0("%s(): mci = %p\n", __func__, mci);
228
229         mci->pdev = pdev;
230         mci->mtype_cap = MEM_FLAG_RDDR;
231
232         mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
233         mci->edac_cap = ems_mode ?
234             (EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_NONE;
235
236         mci->mod_name = EDAC_MOD_STR;
237         mci->mod_ver = "$Revision: 1.4.2.5 $";
238         mci->ctl_name = amd76x_devs[dev_idx].ctl_name;
239         mci->edac_check = amd76x_check;
240         mci->ctl_page_to_phys = NULL;
241
242         for (index = 0; index < mci->nr_csrows; index++) {
243                 struct csrow_info *csrow = &mci->csrows[index];
244                 u32 mba;
245                 u32 mba_base;
246                 u32 mba_mask;
247                 u32 dms;
248
249                 /* find the DRAM Chip Select Base address and mask */
250                 pci_read_config_dword(mci->pdev,
251                                       AMD76X_MEM_BASE_ADDR + (index * 4),
252                                       &mba);
253
254                 if (!(mba & BIT(0)))
255                         continue;
256
257                 mba_base = mba & 0xff800000UL;
258                 mba_mask = ((mba & 0xff80) << 16) | 0x7fffffUL;
259
260                 pci_read_config_dword(mci->pdev, AMD76X_DRAM_MODE_STATUS,
261                                       &dms);
262
263                 csrow->first_page = mba_base >> PAGE_SHIFT;
264                 csrow->nr_pages = (mba_mask + 1) >> PAGE_SHIFT;
265                 csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
266                 csrow->page_mask = mba_mask >> PAGE_SHIFT;
267                 csrow->grain = csrow->nr_pages << PAGE_SHIFT;
268                 csrow->mtype = MEM_RDDR;
269                 csrow->dtype = ((dms >> index) & 0x1) ? DEV_X4 : DEV_UNKNOWN;
270                 csrow->edac_mode = ems_modes[ems_mode];
271         }
272
273         /* clear counters */
274         pci_write_bits32(mci->pdev, AMD76X_ECC_MODE_STATUS, (u32) (0x3 << 8),
275                          (u32) (0x3 << 8));
276
277         if (edac_mc_add_mc(mci)) {
278                 debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
279                 goto fail;
280         }
281
282         /* get this far and it's successful */
283         debugf3("%s(): success\n", __func__);
284         return 0;
285
286 fail:
287         if (mci != NULL)
288                 edac_mc_free(mci);
289         return rc;
290 }
291
292 /* returns count (>= 0), or negative on error */
293 static int __devinit amd76x_init_one(struct pci_dev *pdev,
294                                      const struct pci_device_id *ent)
295 {
296         debugf0("%s()\n", __func__);
297
298         /* don't need to call pci_device_enable() */
299         return amd76x_probe1(pdev, ent->driver_data);
300 }
301
302
303 /**
304  *      amd76x_remove_one       -       driver shutdown
305  *      @pdev: PCI device being handed back
306  *
307  *      Called when the driver is unloaded. Find the matching mci
308  *      structure for the device then delete the mci and free the
309  *      resources.
310  */
311
312 static void __devexit amd76x_remove_one(struct pci_dev *pdev)
313 {
314         struct mem_ctl_info *mci;
315
316         debugf0("%s()\n", __func__);
317
318         if ((mci = edac_mc_find_mci_by_pdev(pdev)) == NULL)
319                 return;
320         if (edac_mc_del_mc(mci))
321                 return;
322         edac_mc_free(mci);
323 }
324
325
326 static const struct pci_device_id amd76x_pci_tbl[] __devinitdata = {
327         {PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
328          AMD762},
329         {PCI_VEND_DEV(AMD, FE_GATE_700E), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
330          AMD761},
331         {0,}                    /* 0 terminated list. */
332 };
333
334 MODULE_DEVICE_TABLE(pci, amd76x_pci_tbl);
335
336
337 static struct pci_driver amd76x_driver = {
338         .name = EDAC_MOD_STR,
339         .probe = amd76x_init_one,
340         .remove = __devexit_p(amd76x_remove_one),
341         .id_table = amd76x_pci_tbl,
342 };
343
344 static int __init amd76x_init(void)
345 {
346         return pci_register_driver(&amd76x_driver);
347 }
348
349 static void __exit amd76x_exit(void)
350 {
351         pci_unregister_driver(&amd76x_driver);
352 }
353
354 module_init(amd76x_init);
355 module_exit(amd76x_exit);
356
357 MODULE_LICENSE("GPL");
358 MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh");
359 MODULE_DESCRIPTION("MC support for AMD 76x memory controllers");