diff options
Diffstat (limited to 'drivers/infiniband/hw/mthca/mthca_catas.c')
-rw-r--r-- | drivers/infiniband/hw/mthca/mthca_catas.c | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c index c3bec7490f52..cd044ea2dfa4 100644 --- a/drivers/infiniband/hw/mthca/mthca_catas.c +++ b/drivers/infiniband/hw/mthca/mthca_catas.c | |||
@@ -34,6 +34,7 @@ | |||
34 | 34 | ||
35 | #include <linux/jiffies.h> | 35 | #include <linux/jiffies.h> |
36 | #include <linux/timer.h> | 36 | #include <linux/timer.h> |
37 | #include <linux/workqueue.h> | ||
37 | 38 | ||
38 | #include "mthca_dev.h" | 39 | #include "mthca_dev.h" |
39 | 40 | ||
@@ -48,9 +49,41 @@ enum { | |||
48 | 49 | ||
49 | static DEFINE_SPINLOCK(catas_lock); | 50 | static DEFINE_SPINLOCK(catas_lock); |
50 | 51 | ||
52 | static LIST_HEAD(catas_list); | ||
53 | static struct workqueue_struct *catas_wq; | ||
54 | static struct work_struct catas_work; | ||
55 | |||
56 | static int catas_reset_disable; | ||
57 | module_param_named(catas_reset_disable, catas_reset_disable, int, 0644); | ||
58 | MODULE_PARM_DESC(catas_reset_disable, "disable reset on catastrophic event if nonzero"); | ||
59 | |||
60 | static void catas_reset(void *work_ptr) | ||
61 | { | ||
62 | struct mthca_dev *dev, *tmpdev; | ||
63 | LIST_HEAD(tlist); | ||
64 | int ret; | ||
65 | |||
66 | mutex_lock(&mthca_device_mutex); | ||
67 | |||
68 | spin_lock_irq(&catas_lock); | ||
69 | list_splice_init(&catas_list, &tlist); | ||
70 | spin_unlock_irq(&catas_lock); | ||
71 | |||
72 | list_for_each_entry_safe(dev, tmpdev, &tlist, catas_err.list) { | ||
73 | ret = __mthca_restart_one(dev->pdev); | ||
74 | if (ret) | ||
75 | mthca_err(dev, "Reset failed (%d)\n", ret); | ||
76 | else | ||
77 | mthca_dbg(dev, "Reset succeeded\n"); | ||
78 | } | ||
79 | |||
80 | mutex_unlock(&mthca_device_mutex); | ||
81 | } | ||
82 | |||
51 | static void handle_catas(struct mthca_dev *dev) | 83 | static void handle_catas(struct mthca_dev *dev) |
52 | { | 84 | { |
53 | struct ib_event event; | 85 | struct ib_event event; |
86 | unsigned long flags; | ||
54 | const char *type; | 87 | const char *type; |
55 | int i; | 88 | int i; |
56 | 89 | ||
@@ -82,6 +115,14 @@ static void handle_catas(struct mthca_dev *dev) | |||
82 | for (i = 0; i < dev->catas_err.size; ++i) | 115 | for (i = 0; i < dev->catas_err.size; ++i) |
83 | mthca_err(dev, " buf[%02x]: %08x\n", | 116 | mthca_err(dev, " buf[%02x]: %08x\n", |
84 | i, swab32(readl(dev->catas_err.map + i))); | 117 | i, swab32(readl(dev->catas_err.map + i))); |
118 | |||
119 | if (catas_reset_disable) | ||
120 | return; | ||
121 | |||
122 | spin_lock_irqsave(&catas_lock, flags); | ||
123 | list_add(&dev->catas_err.list, &catas_list); | ||
124 | queue_work(catas_wq, &catas_work); | ||
125 | spin_unlock_irqrestore(&catas_lock, flags); | ||
85 | } | 126 | } |
86 | 127 | ||
87 | static void poll_catas(unsigned long dev_ptr) | 128 | static void poll_catas(unsigned long dev_ptr) |
@@ -135,6 +176,7 @@ void mthca_start_catas_poll(struct mthca_dev *dev) | |||
135 | dev->catas_err.timer.data = (unsigned long) dev; | 176 | dev->catas_err.timer.data = (unsigned long) dev; |
136 | dev->catas_err.timer.function = poll_catas; | 177 | dev->catas_err.timer.function = poll_catas; |
137 | dev->catas_err.timer.expires = jiffies + MTHCA_CATAS_POLL_INTERVAL; | 178 | dev->catas_err.timer.expires = jiffies + MTHCA_CATAS_POLL_INTERVAL; |
179 | INIT_LIST_HEAD(&dev->catas_err.list); | ||
138 | add_timer(&dev->catas_err.timer); | 180 | add_timer(&dev->catas_err.timer); |
139 | } | 181 | } |
140 | 182 | ||
@@ -153,4 +195,24 @@ void mthca_stop_catas_poll(struct mthca_dev *dev) | |||
153 | dev->catas_err.addr), | 195 | dev->catas_err.addr), |
154 | dev->catas_err.size * 4); | 196 | dev->catas_err.size * 4); |
155 | } | 197 | } |
198 | |||
199 | spin_lock_irq(&catas_lock); | ||
200 | list_del(&dev->catas_err.list); | ||
201 | spin_unlock_irq(&catas_lock); | ||
202 | } | ||
203 | |||
204 | int __init mthca_catas_init(void) | ||
205 | { | ||
206 | INIT_WORK(&catas_work, catas_reset, NULL); | ||
207 | |||
208 | catas_wq = create_singlethread_workqueue("mthca_catas"); | ||
209 | if (!catas_wq) | ||
210 | return -ENOMEM; | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | void mthca_catas_cleanup(void) | ||
216 | { | ||
217 | destroy_workqueue(catas_wq); | ||
156 | } | 218 | } |