diff options
author | Dave Jiang <djiang@mvista.com> | 2007-07-19 04:49:52 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-19 13:04:54 -0400 |
commit | 91b99041c1d577ded1da599ddc28cec2e07253cf (patch) | |
tree | 21b132d19166dca5c363b98e20741b78df4ad68a /drivers/edac/edac_pci_sysfs.c | |
parent | 81d87cb13e367bb804bf44889ae0de7369705d6c (diff) |
drivers/edac: updated PCI monitoring
Moving PCI to a per-instance device model
This should include the correct sysfs setup as well. Please review.
Signed-off-by: Dave Jiang <djiang@mvista.com>
Signed-off-by: Douglas Thompson <dougthompson@xmission.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/edac/edac_pci_sysfs.c')
-rw-r--r-- | drivers/edac/edac_pci_sysfs.c | 279 |
1 files changed, 255 insertions, 24 deletions
diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index 9388eaa794be..0b179e0fd112 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c | |||
@@ -15,13 +15,142 @@ | |||
15 | 15 | ||
16 | 16 | ||
17 | #ifdef CONFIG_PCI | 17 | #ifdef CONFIG_PCI |
18 | static int check_pci_parity = 0; /* default YES check PCI parity */ | 18 | |
19 | static int panic_on_pci_parity; /* default no panic on PCI Parity */ | 19 | #define EDAC_PCI_SYMLINK "device" |
20 | |||
21 | static int check_pci_errors = 0; /* default YES check PCI parity */ | ||
22 | static int panic_on_pci_parity = 0; /* default no panic on PCI Parity */ | ||
23 | static int log_pci_errs = 1; | ||
20 | static atomic_t pci_parity_count = ATOMIC_INIT(0); | 24 | static atomic_t pci_parity_count = ATOMIC_INIT(0); |
25 | static atomic_t pci_nonparity_count = ATOMIC_INIT(0); | ||
21 | 26 | ||
22 | static struct kobject edac_pci_kobj; /* /sys/devices/system/edac/pci */ | 27 | static struct kobject edac_pci_kobj; /* /sys/devices/system/edac/pci */ |
23 | static struct completion edac_pci_kobj_complete; | 28 | static struct completion edac_pci_kobj_complete; |
29 | static atomic_t edac_pci_sysfs_refcount = ATOMIC_INIT(0); | ||
30 | |||
31 | /**************************** EDAC PCI sysfs instance *******************/ | ||
32 | static ssize_t instance_pe_count_show(struct edac_pci_ctl_info *pci, char *data) | ||
33 | { | ||
34 | return sprintf(data,"%u\n", atomic_read(&pci->counters.pe_count)); | ||
35 | } | ||
36 | |||
37 | static ssize_t instance_npe_count_show(struct edac_pci_ctl_info *pci, | ||
38 | char *data) | ||
39 | { | ||
40 | return sprintf(data,"%u\n", atomic_read(&pci->counters.npe_count)); | ||
41 | } | ||
42 | |||
43 | #define to_instance(k) container_of(k, struct edac_pci_ctl_info, kobj) | ||
44 | #define to_instance_attr(a) container_of(a, struct instance_attribute, attr) | ||
45 | |||
46 | /* DEVICE instance kobject release() function */ | ||
47 | static void edac_pci_instance_release(struct kobject *kobj) | ||
48 | { | ||
49 | struct edac_pci_ctl_info *pci; | ||
50 | |||
51 | debugf1("%s()\n", __func__); | ||
52 | |||
53 | pci = to_instance(kobj); | ||
54 | complete(&pci->kobj_complete); | ||
55 | } | ||
56 | |||
57 | /* instance specific attribute structure */ | ||
58 | struct instance_attribute { | ||
59 | struct attribute attr; | ||
60 | ssize_t (*show)(struct edac_pci_ctl_info *, char *); | ||
61 | ssize_t (*store)(struct edac_pci_ctl_info *, const char *, size_t); | ||
62 | }; | ||
63 | |||
64 | /* Function to 'show' fields from the edac_pci 'instance' structure */ | ||
65 | static ssize_t edac_pci_instance_show(struct kobject *kobj, | ||
66 | struct attribute *attr, | ||
67 | char *buffer) | ||
68 | { | ||
69 | struct edac_pci_ctl_info *pci = to_instance(kobj); | ||
70 | struct instance_attribute *instance_attr = to_instance_attr(attr); | ||
71 | |||
72 | if (instance_attr->show) | ||
73 | return instance_attr->show(pci, buffer); | ||
74 | return -EIO; | ||
75 | } | ||
76 | |||
77 | |||
78 | /* Function to 'store' fields into the edac_pci 'instance' structure */ | ||
79 | static ssize_t edac_pci_instance_store(struct kobject *kobj, | ||
80 | struct attribute *attr, | ||
81 | const char *buffer, size_t count) | ||
82 | { | ||
83 | struct edac_pci_ctl_info *pci = to_instance(kobj); | ||
84 | struct instance_attribute *instance_attr = to_instance_attr(attr); | ||
85 | |||
86 | if (instance_attr->store) | ||
87 | return instance_attr->store(pci, buffer, count); | ||
88 | return -EIO; | ||
89 | } | ||
90 | |||
91 | static struct sysfs_ops pci_instance_ops = { | ||
92 | .show = edac_pci_instance_show, | ||
93 | .store = edac_pci_instance_store | ||
94 | }; | ||
95 | |||
96 | #define INSTANCE_ATTR(_name, _mode, _show, _store) \ | ||
97 | static struct instance_attribute attr_instance_##_name = { \ | ||
98 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | ||
99 | .show = _show, \ | ||
100 | .store = _store, \ | ||
101 | }; | ||
102 | |||
103 | INSTANCE_ATTR(pe_count, S_IRUGO, instance_pe_count_show, NULL); | ||
104 | INSTANCE_ATTR(npe_count, S_IRUGO, instance_npe_count_show, NULL); | ||
105 | |||
106 | /* pci instance attributes */ | ||
107 | static struct instance_attribute *pci_instance_attr[] = { | ||
108 | &attr_instance_pe_count, | ||
109 | &attr_instance_npe_count, | ||
110 | NULL | ||
111 | }; | ||
24 | 112 | ||
113 | /* the ktype for pci instance */ | ||
114 | static struct kobj_type ktype_pci_instance = { | ||
115 | .release = edac_pci_instance_release, | ||
116 | .sysfs_ops = &pci_instance_ops, | ||
117 | .default_attrs = (struct attribute **)pci_instance_attr, | ||
118 | }; | ||
119 | |||
120 | static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx) | ||
121 | { | ||
122 | int err; | ||
123 | |||
124 | pci->kobj.parent = &edac_pci_kobj; | ||
125 | pci->kobj.ktype = &ktype_pci_instance; | ||
126 | |||
127 | err = kobject_set_name(&pci->kobj, "pci%d", idx); | ||
128 | if (err) | ||
129 | return err; | ||
130 | |||
131 | err = kobject_register(&pci->kobj); | ||
132 | if (err != 0) { | ||
133 | debugf2("%s() failed to register instance pci%d\n", | ||
134 | __func__, idx); | ||
135 | return err; | ||
136 | } | ||
137 | |||
138 | debugf1("%s() Register instance 'pci%d' kobject\n", __func__, idx); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static void | ||
144 | edac_pci_delete_instance_kobj(struct edac_pci_ctl_info *pci, int idx) | ||
145 | { | ||
146 | init_completion(&pci->kobj_complete); | ||
147 | kobject_unregister(&pci->kobj); | ||
148 | wait_for_completion(&pci->kobj_complete); | ||
149 | } | ||
150 | |||
151 | /***************************** EDAC PCI sysfs root **********************/ | ||
152 | #define to_edacpci(k) container_of(k, struct edac_pci_ctl_info, kobj) | ||
153 | #define to_edacpci_attr(a) container_of(a, struct edac_pci_attr, attr) | ||
25 | 154 | ||
26 | static ssize_t edac_pci_int_show(void *ptr, char *buffer) | 155 | static ssize_t edac_pci_int_show(void *ptr, char *buffer) |
27 | { | 156 | { |
@@ -91,25 +220,34 @@ static struct edac_pci_dev_attribute edac_pci_attr_##_name = { \ | |||
91 | }; | 220 | }; |
92 | 221 | ||
93 | /* PCI Parity control files */ | 222 | /* PCI Parity control files */ |
94 | EDAC_PCI_ATTR(check_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show, | 223 | EDAC_PCI_ATTR(check_pci_errors, S_IRUGO|S_IWUSR, edac_pci_int_show, |
224 | edac_pci_int_store); | ||
225 | EDAC_PCI_ATTR(log_pci_errs, S_IRUGO|S_IWUSR, edac_pci_int_show, | ||
95 | edac_pci_int_store); | 226 | edac_pci_int_store); |
96 | EDAC_PCI_ATTR(panic_on_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show, | 227 | EDAC_PCI_ATTR(panic_on_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show, |
97 | edac_pci_int_store); | 228 | edac_pci_int_store); |
98 | EDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL); | 229 | EDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL); |
230 | EDAC_PCI_ATTR(pci_nonparity_count, S_IRUGO, edac_pci_int_show, NULL); | ||
99 | 231 | ||
100 | /* Base Attributes of the memory ECC object */ | 232 | /* Base Attributes of the memory ECC object */ |
101 | static struct edac_pci_dev_attribute *edac_pci_attr[] = { | 233 | static struct edac_pci_dev_attribute *edac_pci_attr[] = { |
102 | &edac_pci_attr_check_pci_parity, | 234 | &edac_pci_attr_check_pci_errors, |
235 | &edac_pci_attr_log_pci_errs, | ||
103 | &edac_pci_attr_panic_on_pci_parity, | 236 | &edac_pci_attr_panic_on_pci_parity, |
104 | &edac_pci_attr_pci_parity_count, | 237 | &edac_pci_attr_pci_parity_count, |
238 | &edac_pci_attr_pci_nonparity_count, | ||
105 | NULL, | 239 | NULL, |
106 | }; | 240 | }; |
107 | 241 | ||
108 | /* No memory to release */ | 242 | /* No memory to release */ |
109 | static void edac_pci_release(struct kobject *kobj) | 243 | static void edac_pci_release(struct kobject *kobj) |
110 | { | 244 | { |
245 | struct edac_pci_ctl_info *pci; | ||
246 | |||
247 | pci = to_edacpci(kobj); | ||
248 | |||
111 | debugf1("%s()\n", __func__); | 249 | debugf1("%s()\n", __func__); |
112 | complete(&edac_pci_kobj_complete); | 250 | complete(&pci->kobj_complete); |
113 | } | 251 | } |
114 | 252 | ||
115 | static struct kobj_type ktype_edac_pci = { | 253 | static struct kobj_type ktype_edac_pci = { |
@@ -124,7 +262,7 @@ static struct kobj_type ktype_edac_pci = { | |||
124 | * setup the sysfs for EDAC PCI attributes | 262 | * setup the sysfs for EDAC PCI attributes |
125 | * assumes edac_class has already been initialized | 263 | * assumes edac_class has already been initialized |
126 | */ | 264 | */ |
127 | int edac_sysfs_pci_setup(void) | 265 | int edac_pci_register_main_kobj(void) |
128 | { | 266 | { |
129 | int err; | 267 | int err; |
130 | struct sysdev_class *edac_class; | 268 | struct sysdev_class *edac_class; |
@@ -132,32 +270,39 @@ int edac_sysfs_pci_setup(void) | |||
132 | debugf1("%s()\n", __func__); | 270 | debugf1("%s()\n", __func__); |
133 | 271 | ||
134 | edac_class = edac_get_edac_class(); | 272 | edac_class = edac_get_edac_class(); |
273 | if (edac_class == NULL) { | ||
274 | debugf1("%s() no edac_class\n", __func__); | ||
275 | return -ENODEV; | ||
276 | } | ||
135 | 277 | ||
136 | memset(&edac_pci_kobj, 0, sizeof(edac_pci_kobj)); | ||
137 | edac_pci_kobj.parent = &edac_class->kset.kobj; | ||
138 | edac_pci_kobj.ktype = &ktype_edac_pci; | 278 | edac_pci_kobj.ktype = &ktype_edac_pci; |
279 | |||
280 | edac_pci_kobj.parent = &edac_class->kset.kobj; | ||
281 | |||
139 | err = kobject_set_name(&edac_pci_kobj, "pci"); | 282 | err = kobject_set_name(&edac_pci_kobj, "pci"); |
283 | if(err) | ||
284 | return err; | ||
140 | 285 | ||
141 | if (!err) { | 286 | /* Instanstiate the pci object */ |
142 | /* Instanstiate the pci object */ | 287 | /* FIXME: maybe new sysdev_create_subdir() */ |
143 | /* FIXME: maybe new sysdev_create_subdir() */ | 288 | err = kobject_register(&edac_pci_kobj); |
144 | err = kobject_register(&edac_pci_kobj); | ||
145 | 289 | ||
146 | if (err) | 290 | if (err) { |
147 | debugf1("Failed to register '.../edac/pci'\n"); | 291 | debugf1("Failed to register '.../edac/pci'\n"); |
148 | else | 292 | return err; |
149 | debugf1("Registered '.../edac/pci' kobject\n"); | ||
150 | } | 293 | } |
151 | 294 | ||
152 | return err; | 295 | debugf1("Registered '.../edac/pci' kobject\n"); |
296 | |||
297 | return 0; | ||
153 | } | 298 | } |
154 | 299 | ||
155 | /* | 300 | /* |
156 | * edac_sysfs_pci_teardown | 301 | * edac_pci_unregister_main_kobj() |
157 | * | 302 | * |
158 | * perform the sysfs teardown for the PCI attributes | 303 | * perform the sysfs teardown for the PCI attributes |
159 | */ | 304 | */ |
160 | void edac_sysfs_pci_teardown(void) | 305 | void edac_pci_unregister_main_kobj(void) |
161 | { | 306 | { |
162 | debugf0("%s()\n", __func__); | 307 | debugf0("%s()\n", __func__); |
163 | init_completion(&edac_pci_kobj_complete); | 308 | init_completion(&edac_pci_kobj_complete); |
@@ -165,7 +310,53 @@ void edac_sysfs_pci_teardown(void) | |||
165 | wait_for_completion(&edac_pci_kobj_complete); | 310 | wait_for_completion(&edac_pci_kobj_complete); |
166 | } | 311 | } |
167 | 312 | ||
313 | int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci) | ||
314 | { | ||
315 | int err; | ||
316 | struct kobject *edac_kobj = &pci->kobj; | ||
317 | |||
318 | if (atomic_inc_return(&edac_pci_sysfs_refcount) == 1) { | ||
319 | err = edac_pci_register_main_kobj(); | ||
320 | if (err) { | ||
321 | atomic_dec(&edac_pci_sysfs_refcount); | ||
322 | return err; | ||
323 | } | ||
324 | } | ||
325 | |||
326 | err = edac_pci_create_instance_kobj(pci, pci->pci_idx); | ||
327 | if (err) { | ||
328 | if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) | ||
329 | edac_pci_unregister_main_kobj(); | ||
330 | } | ||
168 | 331 | ||
332 | |||
333 | debugf0("%s() idx=%d\n", __func__, pci->pci_idx); | ||
334 | |||
335 | err = sysfs_create_link(edac_kobj, | ||
336 | &pci->dev->kobj, | ||
337 | EDAC_PCI_SYMLINK); | ||
338 | if (err) { | ||
339 | debugf0("%s() sysfs_create_link() returned err= %d\n", | ||
340 | __func__, err); | ||
341 | return err; | ||
342 | } | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci) | ||
348 | { | ||
349 | debugf0("%s()\n", __func__); | ||
350 | |||
351 | edac_pci_delete_instance_kobj(pci, pci->pci_idx); | ||
352 | |||
353 | sysfs_remove_link(&pci->kobj, EDAC_PCI_SYMLINK); | ||
354 | |||
355 | if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) | ||
356 | edac_pci_unregister_main_kobj(); | ||
357 | } | ||
358 | |||
359 | /************************ PCI error handling *************************/ | ||
169 | static u16 get_pci_parity_status(struct pci_dev *dev, int secondary) | 360 | static u16 get_pci_parity_status(struct pci_dev *dev, int secondary) |
170 | { | 361 | { |
171 | int where; | 362 | int where; |
@@ -231,10 +422,12 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev) | |||
231 | 422 | ||
232 | /* check the status reg for errors */ | 423 | /* check the status reg for errors */ |
233 | if (status) { | 424 | if (status) { |
234 | if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) | 425 | if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) { |
235 | edac_printk(KERN_CRIT, EDAC_PCI, | 426 | edac_printk(KERN_CRIT, EDAC_PCI, |
236 | "Signaled System Error on %s\n", | 427 | "Signaled System Error on %s\n", |
237 | pci_name(dev)); | 428 | pci_name(dev)); |
429 | atomic_inc(&pci_nonparity_count); | ||
430 | } | ||
238 | 431 | ||
239 | if (status & (PCI_STATUS_PARITY)) { | 432 | if (status & (PCI_STATUS_PARITY)) { |
240 | edac_printk(KERN_CRIT, EDAC_PCI, | 433 | edac_printk(KERN_CRIT, EDAC_PCI, |
@@ -267,10 +460,12 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev) | |||
267 | 460 | ||
268 | /* check the secondary status reg for errors */ | 461 | /* check the secondary status reg for errors */ |
269 | if (status) { | 462 | if (status) { |
270 | if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) | 463 | if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) { |
271 | edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " | 464 | edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " |
272 | "Signaled System Error on %s\n", | 465 | "Signaled System Error on %s\n", |
273 | pci_name(dev)); | 466 | pci_name(dev)); |
467 | atomic_inc(&pci_nonparity_count); | ||
468 | } | ||
274 | 469 | ||
275 | if (status & (PCI_STATUS_PARITY)) { | 470 | if (status & (PCI_STATUS_PARITY)) { |
276 | edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " | 471 | edac_printk(KERN_CRIT, EDAC_PCI, "Bridge " |
@@ -321,7 +516,7 @@ void edac_pci_do_parity_check(void) | |||
321 | 516 | ||
322 | debugf3("%s()\n", __func__); | 517 | debugf3("%s()\n", __func__); |
323 | 518 | ||
324 | if (!check_pci_parity) | 519 | if (!check_pci_errors) |
325 | return; | 520 | return; |
326 | 521 | ||
327 | before_count = atomic_read(&pci_parity_count); | 522 | before_count = atomic_read(&pci_parity_count); |
@@ -348,13 +543,49 @@ void edac_pci_clear_parity_errors(void) | |||
348 | */ | 543 | */ |
349 | edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear); | 544 | edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear); |
350 | } | 545 | } |
546 | void edac_pci_handle_pe(struct edac_pci_ctl_info *pci, const char *msg) | ||
547 | { | ||
548 | |||
549 | /* global PE counter incremented by edac_pci_do_parity_check() */ | ||
550 | atomic_inc(&pci->counters.pe_count); | ||
551 | |||
552 | if (log_pci_errs) | ||
553 | edac_pci_printk(pci, KERN_WARNING, | ||
554 | "Parity Error ctl: %s %d: %s\n", | ||
555 | pci->ctl_name, pci->pci_idx, msg); | ||
556 | |||
557 | /* | ||
558 | * poke all PCI devices and see which one is the troublemaker | ||
559 | * panic() is called if set | ||
560 | */ | ||
561 | edac_pci_do_parity_check(); | ||
562 | } | ||
563 | EXPORT_SYMBOL_GPL(edac_pci_handle_pe); | ||
351 | 564 | ||
565 | void edac_pci_handle_npe(struct edac_pci_ctl_info *pci, const char *msg) | ||
566 | { | ||
567 | |||
568 | /* global NPE counter incremented by edac_pci_do_parity_check() */ | ||
569 | atomic_inc(&pci->counters.npe_count); | ||
570 | |||
571 | if (log_pci_errs) | ||
572 | edac_pci_printk(pci, KERN_WARNING, | ||
573 | "Non-Parity Error ctl: %s %d: %s\n", | ||
574 | pci->ctl_name, pci->pci_idx, msg); | ||
575 | |||
576 | /* | ||
577 | * poke all PCI devices and see which one is the troublemaker | ||
578 | * panic() is called if set | ||
579 | */ | ||
580 | edac_pci_do_parity_check(); | ||
581 | } | ||
582 | EXPORT_SYMBOL_GPL(edac_pci_handle_npe); | ||
352 | 583 | ||
353 | /* | 584 | /* |
354 | * Define the PCI parameter to the module | 585 | * Define the PCI parameter to the module |
355 | */ | 586 | */ |
356 | module_param(check_pci_parity, int, 0644); | 587 | module_param(check_pci_errors, int, 0644); |
357 | MODULE_PARM_DESC(check_pci_parity, "Check for PCI bus parity errors: 0=off 1=on"); | 588 | MODULE_PARM_DESC(check_pci_errors, "Check for PCI bus parity errors: 0=off 1=on"); |
358 | module_param(panic_on_pci_parity, int, 0644); | 589 | module_param(panic_on_pci_parity, int, 0644); |
359 | MODULE_PARM_DESC(panic_on_pci_parity, "Panic on PCI Bus Parity error: 0=off 1=on"); | 590 | MODULE_PARM_DESC(panic_on_pci_parity, "Panic on PCI Bus Parity error: 0=off 1=on"); |
360 | 591 | ||