aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDave Jiang <djiang@mvista.com>2007-07-19 04:49:52 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-19 13:04:54 -0400
commit91b99041c1d577ded1da599ddc28cec2e07253cf (patch)
tree21b132d19166dca5c363b98e20741b78df4ad68a /drivers
parent81d87cb13e367bb804bf44889ae0de7369705d6c (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')
-rw-r--r--drivers/edac/Makefile5
-rw-r--r--drivers/edac/e752x_edac.c16
-rw-r--r--drivers/edac/edac_core.h120
-rw-r--r--drivers/edac/edac_device.c23
-rw-r--r--drivers/edac/edac_module.c32
-rw-r--r--drivers/edac/edac_pci.c451
-rw-r--r--drivers/edac/edac_pci_sysfs.c279
7 files changed, 861 insertions, 65 deletions
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 547ea135b64e..6a5e5d18db69 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -11,9 +11,12 @@ obj-$(CONFIG_EDAC) := edac_stub.o
11obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o 11obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o
12 12
13edac_core-objs := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o 13edac_core-objs := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o
14
15edac_core-objs += edac_module.o edac_device_sysfs.o 14edac_core-objs += edac_module.o edac_device_sysfs.o
16 15
16ifdef CONFIG_PCI
17edac_core-objs += edac_pci.o edac_pci_sysfs.o
18endif
19
17obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o 20obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o
18obj-$(CONFIG_EDAC_I5000) += i5000_edac.o 21obj-$(CONFIG_EDAC_I5000) += i5000_edac.o
19obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o 22obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index 10f84995472d..d8b86584afbb 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -30,6 +30,8 @@
30 30
31static int force_function_unhide; 31static int force_function_unhide;
32 32
33static struct edac_pci_ctl_info *e752x_pci;
34
33#define e752x_printk(level, fmt, arg...) \ 35#define e752x_printk(level, fmt, arg...) \
34 edac_printk(level, "e752x", fmt, ##arg) 36 edac_printk(level, "e752x", fmt, ##arg)
35 37
@@ -1040,6 +1042,17 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
1040 e752x_init_error_reporting_regs(pvt); 1042 e752x_init_error_reporting_regs(pvt);
1041 e752x_get_error_info(mci, &discard); /* clear other MCH errors */ 1043 e752x_get_error_info(mci, &discard); /* clear other MCH errors */
1042 1044
1045 /* allocating generic PCI control info */
1046 e752x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
1047 if (!e752x_pci) {
1048 printk(KERN_WARNING
1049 "%s(): Unable to create PCI control\n",
1050 __func__);
1051 printk(KERN_WARNING
1052 "%s(): PCI error report via EDAC not setup\n",
1053 __func__);
1054 }
1055
1043 /* get this far and it's successful */ 1056 /* get this far and it's successful */
1044 debugf3("%s(): success\n", __func__); 1057 debugf3("%s(): success\n", __func__);
1045 return 0; 1058 return 0;
@@ -1073,6 +1086,9 @@ static void __devexit e752x_remove_one(struct pci_dev *pdev)
1073 1086
1074 debugf0("%s()\n", __func__); 1087 debugf0("%s()\n", __func__);
1075 1088
1089 if (e752x_pci)
1090 edac_pci_release_generic_ctl(e752x_pci);
1091
1076 if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL) 1092 if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
1077 return; 1093 return;
1078 1094
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index b73d659a4bb2..febff4111428 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -60,6 +60,10 @@
60#define edac_device_printk(ctl, level, fmt, arg...) \ 60#define edac_device_printk(ctl, level, fmt, arg...) \
61 printk(level "EDAC DEVICE%d: " fmt, ctl->dev_idx, ##arg) 61 printk(level "EDAC DEVICE%d: " fmt, ctl->dev_idx, ##arg)
62 62
63/* edac_pci printk */
64#define edac_pci_printk(ctl, level, fmt, arg...) \
65 printk(level "EDAC PCI%d: " fmt, ctl->pci_idx, ##arg)
66
63/* prefixes for edac_printk() and edac_mc_printk() */ 67/* prefixes for edac_printk() and edac_mc_printk() */
64#define EDAC_MC "MC" 68#define EDAC_MC "MC"
65#define EDAC_PCI "PCI" 69#define EDAC_PCI "PCI"
@@ -200,6 +204,13 @@ enum scrub_type {
200 204
201/* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */ 205/* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */
202 206
207/* EDAC internal operation states */
208#define OP_ALLOC 0x100
209#define OP_RUNNING_POLL 0x201
210#define OP_RUNNING_INTERRUPT 0x202
211#define OP_RUNNING_POLL_INTR 0x203
212#define OP_OFFLINE 0x300
213
203extern char * edac_align_ptr(void *ptr, unsigned size); 214extern char * edac_align_ptr(void *ptr, unsigned size);
204 215
205/* 216/*
@@ -520,12 +531,6 @@ struct edac_device_ctl_info {
520 531
521 /* the internal state of this controller instance */ 532 /* the internal state of this controller instance */
522 int op_state; 533 int op_state;
523#define OP_ALLOC 0x100
524#define OP_RUNNING_POLL 0x201
525#define OP_RUNNING_INTERRUPT 0x202
526#define OP_RUNNING_POLL_INTR 0x203
527#define OP_OFFLINE 0x300
528
529 /* work struct for this instance */ 534 /* work struct for this instance */
530#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) 535#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
531 struct delayed_work work; 536 struct delayed_work work;
@@ -626,6 +631,84 @@ extern void edac_device_free_ctl_info( struct edac_device_ctl_info *ctl_info);
626 631
627#ifdef CONFIG_PCI 632#ifdef CONFIG_PCI
628 633
634struct edac_pci_counter {
635 atomic_t pe_count;
636 atomic_t npe_count;
637};
638
639/*
640 * Abstract edac_pci control info structure
641 *
642 */
643struct edac_pci_ctl_info {
644 /* for global list of edac_pci_ctl_info structs */
645 struct list_head link;
646
647 int pci_idx;
648
649 /* Per instance controls for this edac_device */
650 int check_parity_error; /* boolean for checking parity errs */
651 int log_parity_error; /* boolean for logging parity errs */
652 int panic_on_pe; /* boolean for panic'ing on a PE */
653 unsigned poll_msec; /* number of milliseconds to poll interval */
654 unsigned long delay; /* number of jiffies for poll_msec */
655
656 struct sysdev_class *edac_class; /* pointer to class */
657
658 /* the internal state of this controller instance */
659 int op_state;
660 /* work struct for this instance */
661#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
662 struct delayed_work work;
663#else
664 struct work_struct work;
665#endif
666
667 /* pointer to edac polling checking routine:
668 * If NOT NULL: points to polling check routine
669 * If NULL: Then assumes INTERRUPT operation, where
670 * MC driver will receive events
671 */
672 void (*edac_check) (struct edac_pci_ctl_info * edac_dev);
673
674 struct device *dev; /* pointer to device structure */
675
676 const char *mod_name; /* module name */
677 const char *ctl_name; /* edac controller name */
678 const char *dev_name; /* pci/platform/etc... name */
679
680 void *pvt_info; /* pointer to 'private driver' info */
681
682 unsigned long start_time;/* edac_pci load start time (jiffies)*/
683
684 /* these are for safe removal of devices from global list while
685 * NMI handlers may be traversing list
686 */
687 struct rcu_head rcu;
688 struct completion complete;
689
690 /* sysfs top name under 'edac' directory
691 * and instance name:
692 * cpu/cpu0/...
693 * cpu/cpu1/...
694 * cpu/cpu2/...
695 * ...
696 */
697 char name[EDAC_DEVICE_NAME_LEN + 1];
698
699 /* Event counters for the this whole EDAC Device */
700 struct edac_pci_counter counters;
701
702 /* edac sysfs device control for the 'name'
703 * device this structure controls
704 */
705 struct kobject kobj;
706 struct completion kobj_complete;
707};
708
709#define to_edac_pci_ctl_work(w) \
710 container_of(w, struct edac_pci_ctl_info,work)
711
629/* write all or some bits in a byte-register*/ 712/* write all or some bits in a byte-register*/
630static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value, 713static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value,
631 u8 mask) 714 u8 mask)
@@ -726,5 +809,30 @@ extern void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev,
726extern void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev, 809extern void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev,
727 int inst_nr, int block_nr, const char *msg); 810 int inst_nr, int block_nr, const char *msg);
728 811
812/*
813 * edac_pci APIs
814 */
815extern struct edac_pci_ctl_info *
816edac_pci_alloc_ctl_info(unsigned int sz_pvt, const char *edac_pci_name);
817
818extern void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci);
819
820extern void
821edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci, unsigned long value);
822
823extern int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx);
824extern struct edac_pci_ctl_info * edac_pci_del_device(struct device *dev);
825
826extern struct edac_pci_ctl_info *
827edac_pci_create_generic_ctl(struct device *dev, const char *mod_name);
828
829extern void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci);
830extern int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci);
831extern void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci);
832
833/*
834 * edac misc APIs
835 */
836extern char * edac_op_state_toString(int op_state);
729 837
730#endif /* _EDAC_CORE_H_ */ 838#endif /* _EDAC_CORE_H_ */
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c
index 3f4c8a28154a..3db8effa1fd0 100644
--- a/drivers/edac/edac_device.c
+++ b/drivers/edac/edac_device.c
@@ -418,27 +418,6 @@ void edac_device_reset_delay_period(
418 unlock_device_list(); 418 unlock_device_list();
419} 419}
420 420
421/*
422 * edac_op_state_toString(edac_dev)
423 */
424static char *edac_op_state_toString(struct edac_device_ctl_info *edac_dev)
425{
426 int opstate = edac_dev->op_state;
427
428 if (opstate == OP_RUNNING_POLL)
429 return "POLLED";
430 else if (opstate == OP_RUNNING_INTERRUPT)
431 return "INTERRUPT";
432 else if (opstate == OP_RUNNING_POLL_INTR)
433 return "POLL-INTR";
434 else if (opstate == OP_ALLOC)
435 return "ALLOC";
436 else if (opstate == OP_OFFLINE)
437 return "OFFLINE";
438
439 return "UNKNOWN";
440}
441
442/** 421/**
443 * edac_device_add_device: Insert the 'edac_dev' structure into the 422 * edac_device_add_device: Insert the 'edac_dev' structure into the
444 * edac_device global list and create sysfs entries associated with 423 * edac_device global list and create sysfs entries associated with
@@ -496,7 +475,7 @@ int edac_device_add_device(struct edac_device_ctl_info *edac_dev, int edac_idx)
496 edac_dev->mod_name, 475 edac_dev->mod_name,
497 edac_dev->ctl_name, 476 edac_dev->ctl_name,
498 dev_name(edac_dev), 477 dev_name(edac_dev),
499 edac_op_state_toString(edac_dev) 478 edac_op_state_toString(edac_dev->op_state)
500 ); 479 );
501 480
502 unlock_device_list(); 481 unlock_device_list();
diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c
index dc900ed75178..38e4a71380aa 100644
--- a/drivers/edac/edac_module.c
+++ b/drivers/edac/edac_module.c
@@ -35,6 +35,25 @@ static struct sysdev_class edac_class = {
35static int edac_class_valid = 0; 35static int edac_class_valid = 0;
36 36
37/* 37/*
38 * edac_op_state_toString()
39 */
40char * edac_op_state_toString(int opstate)
41{
42 if (opstate == OP_RUNNING_POLL)
43 return "POLLED";
44 else if (opstate == OP_RUNNING_INTERRUPT)
45 return "INTERRUPT";
46 else if (opstate == OP_RUNNING_POLL_INTR)
47 return "POLL-INTR";
48 else if (opstate == OP_ALLOC)
49 return "ALLOC";
50 else if (opstate == OP_OFFLINE)
51 return "OFFLINE";
52
53 return "UNKNOWN";
54}
55
56/*
38 * edac_get_edac_class() 57 * edac_get_edac_class()
39 * 58 *
40 * return pointer to the edac class of 'edac' 59 * return pointer to the edac class of 'edac'
@@ -153,26 +172,16 @@ static int __init edac_init(void)
153 goto error_sysfs; 172 goto error_sysfs;
154 } 173 }
155 174
156 /* Create the PCI parity sysfs entries */
157 if (edac_sysfs_pci_setup()) {
158 edac_printk(KERN_ERR, EDAC_MC,
159 "PCI: Error initializing sysfs code\n");
160 err = -ENODEV;
161 goto error_mem;
162 }
163
164 /* Setup/Initialize the edac_device system */ 175 /* Setup/Initialize the edac_device system */
165 err = edac_workqueue_setup(); 176 err = edac_workqueue_setup();
166 if (err) { 177 if (err) {
167 edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n"); 178 edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
168 goto error_pci; 179 goto error_mem;
169 } 180 }
170 181
171 return 0; 182 return 0;
172 183
173 /* Error teardown stack */ 184 /* Error teardown stack */
174error_pci:
175 edac_sysfs_pci_teardown();
176error_mem: 185error_mem:
177 edac_sysfs_memctrl_teardown(); 186 edac_sysfs_memctrl_teardown();
178error_sysfs: 187error_sysfs:
@@ -192,7 +201,6 @@ static void __exit edac_exit(void)
192 /* tear down the various subsystems*/ 201 /* tear down the various subsystems*/
193 edac_workqueue_teardown(); 202 edac_workqueue_teardown();
194 edac_sysfs_memctrl_teardown(); 203 edac_sysfs_memctrl_teardown();
195 edac_sysfs_pci_teardown();
196 edac_unregister_sysfs_edac_name(); 204 edac_unregister_sysfs_edac_name();
197} 205}
198 206
diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c
new file mode 100644
index 000000000000..677c603f5596
--- /dev/null
+++ b/drivers/edac/edac_pci.c
@@ -0,0 +1,451 @@
1/*
2 * EDAC PCI component
3 *
4 * Author: Dave Jiang <djiang@mvista.com>
5 *
6 * 2007 (c) MontaVista Software, Inc. This file is licensed under
7 * the terms of the GNU General Public License version 2. This program
8 * is licensed "as is" without any warranty of any kind, whether express
9 * or implied.
10 *
11 */
12#include <linux/module.h>
13#include <linux/types.h>
14#include <linux/smp.h>
15#include <linux/init.h>
16#include <linux/sysctl.h>
17#include <linux/highmem.h>
18#include <linux/timer.h>
19#include <linux/slab.h>
20#include <linux/spinlock.h>
21#include <linux/list.h>
22#include <linux/sysdev.h>
23#include <linux/ctype.h>
24#include <linux/workqueue.h>
25#include <asm/uaccess.h>
26#include <asm/page.h>
27
28#include "edac_core.h"
29#include "edac_module.h"
30
31static DEFINE_MUTEX(edac_pci_ctls_mutex);
32static struct list_head edac_pci_list = LIST_HEAD_INIT(edac_pci_list);
33
34static inline void edac_lock_pci_list(void)
35{
36 mutex_lock(&edac_pci_ctls_mutex);
37}
38
39static inline void edac_unlock_pci_list(void)
40{
41 mutex_unlock(&edac_pci_ctls_mutex);
42}
43
44/*
45 * The alloc() and free() functions for the 'edac_pci' control info
46 * structure. The chip driver will allocate one of these for each
47 * edac_pci it is going to control/register with the EDAC CORE.
48 */
49struct edac_pci_ctl_info * edac_pci_alloc_ctl_info(
50 unsigned int sz_pvt,
51 const char *edac_pci_name)
52{
53 struct edac_pci_ctl_info *pci;
54 void *pvt;
55 unsigned int size;
56
57 pci = (struct edac_pci_ctl_info *)0;
58 pvt = edac_align_ptr(&pci[1], sz_pvt);
59 size = ((unsigned long)pvt) + sz_pvt;
60
61 if ((pci = kzalloc(size, GFP_KERNEL)) == NULL)
62 return NULL;
63
64 pvt = sz_pvt ? ((char *)pci) + ((unsigned long)pvt) : NULL;
65
66 pci->pvt_info = pvt;
67
68 pci->op_state = OP_ALLOC;
69
70 snprintf(pci->name, strlen(edac_pci_name)+1, "%s", edac_pci_name);
71
72 return pci;
73}
74EXPORT_SYMBOL_GPL(edac_pci_alloc_ctl_info);
75
76/*
77 * edac_pci_free_ctl_info()
78 * frees the memory allocated by edac_pci_alloc_ctl_info() function
79 */
80void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci)
81{
82 kfree(pci);
83}
84EXPORT_SYMBOL_GPL(edac_pci_free_ctl_info);
85
86/*
87 * find_edac_pci_by_dev()
88 * scans the edac_pci list for a specific 'struct device *'
89 */
90static struct edac_pci_ctl_info * find_edac_pci_by_dev(struct device *dev)
91{
92 struct edac_pci_ctl_info *pci;
93 struct list_head *item;
94
95 debugf3("%s()\n", __func__);
96
97 list_for_each(item, &edac_pci_list) {
98 pci = list_entry(item, struct edac_pci_ctl_info, link);
99
100 if (pci->dev == dev)
101 return pci;
102 }
103
104 return NULL;
105}
106
107/*
108 * add_edac_pci_to_global_list
109 * Before calling this function, caller must assign a unique value to
110 * edac_dev->pci_idx.
111 * Return:
112 * 0 on success
113 * 1 on failure
114 */
115static int add_edac_pci_to_global_list(struct edac_pci_ctl_info *pci)
116{
117 struct list_head *item, *insert_before;
118 struct edac_pci_ctl_info *rover;
119
120 insert_before = &edac_pci_list;
121
122 /* Determine if already on the list */
123 if (unlikely((rover = find_edac_pci_by_dev(pci->dev)) != NULL))
124 goto fail0;
125
126 /* Insert in ascending order by 'pci_idx', so find position */
127 list_for_each(item, &edac_pci_list) {
128 rover = list_entry(item, struct edac_pci_ctl_info, link);
129
130 if (rover->pci_idx >= pci->pci_idx) {
131 if (unlikely(rover->pci_idx == pci->pci_idx))
132 goto fail1;
133
134 insert_before = item;
135 break;
136 }
137 }
138
139 list_add_tail_rcu(&pci->link, insert_before);
140 return 0;
141
142fail0:
143 edac_printk(KERN_WARNING, EDAC_PCI,
144 "%s (%s) %s %s already assigned %d\n",
145 rover->dev->bus_id, dev_name(rover),
146 rover->mod_name, rover->ctl_name, rover->pci_idx);
147 return 1;
148
149fail1:
150 edac_printk(KERN_WARNING, EDAC_PCI,
151 "but in low-level driver: attempt to assign\n"
152 "\tduplicate pci_idx %d in %s()\n", rover->pci_idx, __func__);
153 return 1;
154}
155
156/*
157 * complete_edac_pci_list_del
158 */
159static void complete_edac_pci_list_del(struct rcu_head *head)
160{
161 struct edac_pci_ctl_info *pci;
162
163 pci = container_of(head, struct edac_pci_ctl_info, rcu);
164 INIT_LIST_HEAD(&pci->link);
165 complete(&pci->complete);
166}
167
168/*
169 * del_edac_pci_from_global_list
170 */
171static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci)
172{
173 list_del_rcu(&pci->link);
174 init_completion(&pci->complete);
175 call_rcu(&pci->rcu, complete_edac_pci_list_del);
176 wait_for_completion(&pci->complete);
177}
178
179/*
180 * edac_pci_find()
181 * Search for an edac_pci_ctl_info structure whose index is 'idx'
182 *
183 * If found, return a pointer to the structure
184 * Else return NULL.
185 *
186 * Caller must hold pci_ctls_mutex.
187 */
188struct edac_pci_ctl_info * edac_pci_find(int idx)
189{
190 struct list_head *item;
191 struct edac_pci_ctl_info *pci;
192
193 /* Iterage over list, looking for exact match of ID */
194 list_for_each(item, &edac_pci_list) {
195 pci = list_entry(item, struct edac_pci_ctl_info, link);
196
197 if (pci->pci_idx >= idx) {
198 if (pci->pci_idx == idx)
199 return pci;
200
201 /* not on list, so terminate early */
202 break;
203 }
204 }
205
206 return NULL;
207}
208EXPORT_SYMBOL_GPL(edac_pci_find);
209
210/*
211 * edac_pci_workq_function()
212 * performs the operation scheduled by a workq request
213 */
214#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
215static void edac_pci_workq_function(struct work_struct *work_req)
216{
217 struct delayed_work *d_work = (struct delayed_work *)work_req;
218 struct edac_pci_ctl_info *pci = to_edac_pci_ctl_work(d_work);
219#else
220static void edac_pci_workq_function(void *ptr)
221{
222 struct edac_pci_ctl_info *pci = ptr;
223#endif
224
225 edac_lock_pci_list();
226
227 if ((pci->op_state == OP_RUNNING_POLL) &&
228 (pci->edac_check != NULL) &&
229 (pci->check_parity_error))
230 pci->edac_check(pci);
231
232 edac_unlock_pci_list();
233
234 /* Reschedule */
235 queue_delayed_work(edac_workqueue, &pci->work, pci->delay);
236}
237
238/*
239 * edac_pci_workq_setup()
240 * initialize a workq item for this edac_pci instance
241 * passing in the new delay period in msec
242 */
243static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci,
244 unsigned int msec)
245{
246 debugf0("%s()\n", __func__);
247
248 pci->poll_msec = msec;
249 edac_calc_delay(pci);
250
251#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
252 INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function);
253#else
254 INIT_WORK(&pci->work, edac_pci_workq_function, pci);
255#endif
256 queue_delayed_work(edac_workqueue, &pci->work, pci->delay);
257}
258
259/*
260 * edac_pci_workq_teardown()
261 * stop the workq processing on this edac_pci instance
262 */
263static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
264{
265 int status;
266
267 status = cancel_delayed_work(&pci->work);
268 if (status == 0)
269 flush_workqueue(edac_workqueue);
270}
271
272/*
273 * edac_pci_reset_delay_period
274 */
275void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
276 unsigned long value)
277{
278 edac_lock_pci_list();
279
280 edac_pci_workq_teardown(pci);
281
282 edac_pci_workq_setup(pci, value);
283
284 edac_unlock_pci_list();
285}
286EXPORT_SYMBOL_GPL(edac_pci_reset_delay_period);
287
288/*
289 * edac_pci_add_device: Insert the 'edac_dev' structure into the
290 * edac_pci global list and create sysfs entries associated with
291 * edac_pci structure.
292 * @pci: pointer to the edac_device structure to be added to the list
293 * @edac_idx: A unique numeric identifier to be assigned to the
294 * 'edac_pci' structure.
295 *
296 * Return:
297 * 0 Success
298 * !0 Failure
299 */
300int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx)
301{
302 debugf0("%s()\n", __func__);
303
304 pci->pci_idx = edac_idx;
305
306 edac_lock_pci_list();
307
308 if (add_edac_pci_to_global_list(pci))
309 goto fail0;
310
311 pci->start_time = jiffies;
312
313 if (edac_pci_create_sysfs(pci)) {
314 edac_pci_printk(pci, KERN_WARNING,
315 "failed to create sysfs pci\n");
316 goto fail1;
317 }
318
319 if (pci->edac_check != NULL) {
320 pci->op_state = OP_RUNNING_POLL;
321
322 edac_pci_workq_setup(pci, 1000);
323 } else {
324 pci->op_state = OP_RUNNING_INTERRUPT;
325 }
326
327 edac_pci_printk(pci, KERN_INFO,
328 "Giving out device to module '%s' controller '%s':"
329 " DEV '%s' (%s)\n",
330 pci->mod_name,
331 pci->ctl_name,
332 dev_name(pci),
333 edac_op_state_toString(pci->op_state));
334
335 edac_unlock_pci_list();
336 return 0;
337
338fail1:
339 del_edac_pci_from_global_list(pci);
340fail0:
341 edac_unlock_pci_list();
342 return 1;
343}
344EXPORT_SYMBOL_GPL(edac_pci_add_device);
345
346/*
347 * edac_pci_del_device()
348 * Remove sysfs entries for specified edac_pci structure and
349 * then remove edac_pci structure from global list
350 *
351 * @dev:
352 * Pointer to 'struct device' representing edac_pci structure
353 * to remove
354 *
355 * Return:
356 * Pointer to removed edac_pci structure,
357 * or NULL if device not found
358 */
359struct edac_pci_ctl_info * edac_pci_del_device(struct device *dev)
360{
361 struct edac_pci_ctl_info *pci;
362
363 debugf0("%s()\n", __func__);
364
365 edac_lock_pci_list();
366
367 if ((pci = find_edac_pci_by_dev(dev)) == NULL) {
368 edac_unlock_pci_list();
369 return NULL;
370 }
371
372 pci->op_state = OP_OFFLINE;
373
374 edac_pci_workq_teardown(pci);
375
376 edac_pci_remove_sysfs(pci);
377
378 del_edac_pci_from_global_list(pci);
379
380 edac_unlock_pci_list();
381
382 edac_printk(KERN_INFO, EDAC_PCI,
383 "Removed device %d for %s %s: DEV %s\n",
384 pci->pci_idx,
385 pci->mod_name,
386 pci->ctl_name,
387 dev_name(pci));
388
389 return pci;
390}
391EXPORT_SYMBOL_GPL(edac_pci_del_device);
392
393static inline int edac_pci_get_log_pe(struct edac_pci_ctl_info *pci)
394{
395 return pci->log_parity_error;
396}
397
398static inline int edac_pci_get_panic_on_pe(struct edac_pci_ctl_info *pci)
399{
400 return pci->panic_on_pe;
401}
402
403void edac_pci_generic_check(struct edac_pci_ctl_info *pci)
404{
405 edac_pci_do_parity_check();
406}
407
408static int edac_pci_idx = 0;
409#define EDAC_PCI_GENCTL_NAME "EDAC PCI controller"
410
411struct edac_pci_gen_data {
412 int edac_idx;
413};
414
415struct edac_pci_ctl_info *
416edac_pci_create_generic_ctl(struct device *dev, const char *mod_name)
417{
418 struct edac_pci_ctl_info *pci;
419 struct edac_pci_gen_data *pdata;
420
421 pci = edac_pci_alloc_ctl_info(sizeof(*pdata), EDAC_PCI_GENCTL_NAME);
422 if (!pci)
423 return NULL;
424
425 pdata = pci->pvt_info;
426 pci->dev = dev;
427 dev_set_drvdata(pci->dev, pci);
428 pci->dev_name = pci_name(to_pci_dev(dev));
429
430 pci->mod_name = mod_name;
431 pci->ctl_name = EDAC_PCI_GENCTL_NAME;
432 pci->edac_check = edac_pci_generic_check;
433
434 pdata->edac_idx = edac_pci_idx++;
435
436 if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
437 debugf3("%s(): failed edac_pci_add_device()\n", __func__);
438 edac_pci_free_ctl_info(pci);
439 return NULL;
440 }
441
442 return pci;
443}
444EXPORT_SYMBOL_GPL(edac_pci_create_generic_ctl);
445
446void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci)
447{
448 edac_pci_del_device(pci->dev);
449 edac_pci_free_ctl_info(pci);
450}
451EXPORT_SYMBOL_GPL(edac_pci_release_generic_ctl);
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
18static int check_pci_parity = 0; /* default YES check PCI parity */ 18
19static int panic_on_pci_parity; /* default no panic on PCI Parity */ 19#define EDAC_PCI_SYMLINK "device"
20
21static int check_pci_errors = 0; /* default YES check PCI parity */
22static int panic_on_pci_parity = 0; /* default no panic on PCI Parity */
23static int log_pci_errs = 1;
20static atomic_t pci_parity_count = ATOMIC_INIT(0); 24static atomic_t pci_parity_count = ATOMIC_INIT(0);
25static atomic_t pci_nonparity_count = ATOMIC_INIT(0);
21 26
22static struct kobject edac_pci_kobj; /* /sys/devices/system/edac/pci */ 27static struct kobject edac_pci_kobj; /* /sys/devices/system/edac/pci */
23static struct completion edac_pci_kobj_complete; 28static struct completion edac_pci_kobj_complete;
29static atomic_t edac_pci_sysfs_refcount = ATOMIC_INIT(0);
30
31/**************************** EDAC PCI sysfs instance *******************/
32static 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
37static 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 */
47static 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 */
58struct 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 */
65static 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 */
79static 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
91static 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) \
97static struct instance_attribute attr_instance_##_name = { \
98 .attr = {.name = __stringify(_name), .mode = _mode }, \
99 .show = _show, \
100 .store = _store, \
101};
102
103INSTANCE_ATTR(pe_count, S_IRUGO, instance_pe_count_show, NULL);
104INSTANCE_ATTR(npe_count, S_IRUGO, instance_npe_count_show, NULL);
105
106/* pci instance attributes */
107static 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 */
114static 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
120static 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
143static void
144edac_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
26static ssize_t edac_pci_int_show(void *ptr, char *buffer) 155static 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 */
94EDAC_PCI_ATTR(check_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show, 223EDAC_PCI_ATTR(check_pci_errors, S_IRUGO|S_IWUSR, edac_pci_int_show,
224 edac_pci_int_store);
225EDAC_PCI_ATTR(log_pci_errs, S_IRUGO|S_IWUSR, edac_pci_int_show,
95 edac_pci_int_store); 226 edac_pci_int_store);
96EDAC_PCI_ATTR(panic_on_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show, 227EDAC_PCI_ATTR(panic_on_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show,
97 edac_pci_int_store); 228 edac_pci_int_store);
98EDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL); 229EDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL);
230EDAC_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 */
101static struct edac_pci_dev_attribute *edac_pci_attr[] = { 233static 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 */
109static void edac_pci_release(struct kobject *kobj) 243static 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
115static struct kobj_type ktype_edac_pci = { 253static 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 */
127int edac_sysfs_pci_setup(void) 265int 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 */
160void edac_sysfs_pci_teardown(void) 305void 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
313int 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
347void 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 *************************/
169static u16 get_pci_parity_status(struct pci_dev *dev, int secondary) 360static 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}
546void 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}
563EXPORT_SYMBOL_GPL(edac_pci_handle_pe);
351 564
565void 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}
582EXPORT_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 */
356module_param(check_pci_parity, int, 0644); 587module_param(check_pci_errors, int, 0644);
357MODULE_PARM_DESC(check_pci_parity, "Check for PCI bus parity errors: 0=off 1=on"); 588MODULE_PARM_DESC(check_pci_errors, "Check for PCI bus parity errors: 0=off 1=on");
358module_param(panic_on_pci_parity, int, 0644); 589module_param(panic_on_pci_parity, int, 0644);
359MODULE_PARM_DESC(panic_on_pci_parity, "Panic on PCI Bus Parity error: 0=off 1=on"); 590MODULE_PARM_DESC(panic_on_pci_parity, "Panic on PCI Bus Parity error: 0=off 1=on");
360 591