aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/hw/mthca/mthca_catas.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband/hw/mthca/mthca_catas.c')
-rw-r--r--drivers/infiniband/hw/mthca/mthca_catas.c62
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
49static DEFINE_SPINLOCK(catas_lock); 50static DEFINE_SPINLOCK(catas_lock);
50 51
52static LIST_HEAD(catas_list);
53static struct workqueue_struct *catas_wq;
54static struct work_struct catas_work;
55
56static int catas_reset_disable;
57module_param_named(catas_reset_disable, catas_reset_disable, int, 0644);
58MODULE_PARM_DESC(catas_reset_disable, "disable reset on catastrophic event if nonzero");
59
60static 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
51static void handle_catas(struct mthca_dev *dev) 83static 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
87static void poll_catas(unsigned long dev_ptr) 128static 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
204int __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
215void mthca_catas_cleanup(void)
216{
217 destroy_workqueue(catas_wq);
156} 218}