diff options
Diffstat (limited to 'drivers/infiniband/hw/cxgb3/iwch.c')
-rw-r--r-- | drivers/infiniband/hw/cxgb3/iwch.c | 80 |
1 files changed, 76 insertions, 4 deletions
diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c index b0ea0105ddf6..ee1d8b4d4541 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.c +++ b/drivers/infiniband/hw/cxgb3/iwch.c | |||
@@ -65,6 +65,46 @@ struct cxgb3_client t3c_client = { | |||
65 | static LIST_HEAD(dev_list); | 65 | static LIST_HEAD(dev_list); |
66 | static DEFINE_MUTEX(dev_mutex); | 66 | static DEFINE_MUTEX(dev_mutex); |
67 | 67 | ||
68 | static int disable_qp_db(int id, void *p, void *data) | ||
69 | { | ||
70 | struct iwch_qp *qhp = p; | ||
71 | |||
72 | cxio_disable_wq_db(&qhp->wq); | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static int enable_qp_db(int id, void *p, void *data) | ||
77 | { | ||
78 | struct iwch_qp *qhp = p; | ||
79 | |||
80 | if (data) | ||
81 | ring_doorbell(qhp->rhp->rdev.ctrl_qp.doorbell, qhp->wq.qpid); | ||
82 | cxio_enable_wq_db(&qhp->wq); | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static void disable_dbs(struct iwch_dev *rnicp) | ||
87 | { | ||
88 | spin_lock_irq(&rnicp->lock); | ||
89 | idr_for_each(&rnicp->qpidr, disable_qp_db, NULL); | ||
90 | spin_unlock_irq(&rnicp->lock); | ||
91 | } | ||
92 | |||
93 | static void enable_dbs(struct iwch_dev *rnicp, int ring_db) | ||
94 | { | ||
95 | spin_lock_irq(&rnicp->lock); | ||
96 | idr_for_each(&rnicp->qpidr, enable_qp_db, | ||
97 | (void *)(unsigned long)ring_db); | ||
98 | spin_unlock_irq(&rnicp->lock); | ||
99 | } | ||
100 | |||
101 | static void iwch_db_drop_task(struct work_struct *work) | ||
102 | { | ||
103 | struct iwch_dev *rnicp = container_of(work, struct iwch_dev, | ||
104 | db_drop_task.work); | ||
105 | enable_dbs(rnicp, 1); | ||
106 | } | ||
107 | |||
68 | static void rnic_init(struct iwch_dev *rnicp) | 108 | static void rnic_init(struct iwch_dev *rnicp) |
69 | { | 109 | { |
70 | PDBG("%s iwch_dev %p\n", __func__, rnicp); | 110 | PDBG("%s iwch_dev %p\n", __func__, rnicp); |
@@ -72,6 +112,7 @@ static void rnic_init(struct iwch_dev *rnicp) | |||
72 | idr_init(&rnicp->qpidr); | 112 | idr_init(&rnicp->qpidr); |
73 | idr_init(&rnicp->mmidr); | 113 | idr_init(&rnicp->mmidr); |
74 | spin_lock_init(&rnicp->lock); | 114 | spin_lock_init(&rnicp->lock); |
115 | INIT_DELAYED_WORK(&rnicp->db_drop_task, iwch_db_drop_task); | ||
75 | 116 | ||
76 | rnicp->attr.max_qps = T3_MAX_NUM_QP - 32; | 117 | rnicp->attr.max_qps = T3_MAX_NUM_QP - 32; |
77 | rnicp->attr.max_wrs = T3_MAX_QP_DEPTH; | 118 | rnicp->attr.max_wrs = T3_MAX_QP_DEPTH; |
@@ -147,6 +188,8 @@ static void close_rnic_dev(struct t3cdev *tdev) | |||
147 | mutex_lock(&dev_mutex); | 188 | mutex_lock(&dev_mutex); |
148 | list_for_each_entry_safe(dev, tmp, &dev_list, entry) { | 189 | list_for_each_entry_safe(dev, tmp, &dev_list, entry) { |
149 | if (dev->rdev.t3cdev_p == tdev) { | 190 | if (dev->rdev.t3cdev_p == tdev) { |
191 | dev->rdev.flags = CXIO_ERROR_FATAL; | ||
192 | cancel_delayed_work_sync(&dev->db_drop_task); | ||
150 | list_del(&dev->entry); | 193 | list_del(&dev->entry); |
151 | iwch_unregister_device(dev); | 194 | iwch_unregister_device(dev); |
152 | cxio_rdev_close(&dev->rdev); | 195 | cxio_rdev_close(&dev->rdev); |
@@ -165,7 +208,8 @@ static void iwch_event_handler(struct t3cdev *tdev, u32 evt, u32 port_id) | |||
165 | struct cxio_rdev *rdev = tdev->ulp; | 208 | struct cxio_rdev *rdev = tdev->ulp; |
166 | struct iwch_dev *rnicp; | 209 | struct iwch_dev *rnicp; |
167 | struct ib_event event; | 210 | struct ib_event event; |
168 | u32 portnum = port_id + 1; | 211 | u32 portnum = port_id + 1; |
212 | int dispatch = 0; | ||
169 | 213 | ||
170 | if (!rdev) | 214 | if (!rdev) |
171 | return; | 215 | return; |
@@ -174,21 +218,49 @@ static void iwch_event_handler(struct t3cdev *tdev, u32 evt, u32 port_id) | |||
174 | case OFFLOAD_STATUS_DOWN: { | 218 | case OFFLOAD_STATUS_DOWN: { |
175 | rdev->flags = CXIO_ERROR_FATAL; | 219 | rdev->flags = CXIO_ERROR_FATAL; |
176 | event.event = IB_EVENT_DEVICE_FATAL; | 220 | event.event = IB_EVENT_DEVICE_FATAL; |
221 | dispatch = 1; | ||
177 | break; | 222 | break; |
178 | } | 223 | } |
179 | case OFFLOAD_PORT_DOWN: { | 224 | case OFFLOAD_PORT_DOWN: { |
180 | event.event = IB_EVENT_PORT_ERR; | 225 | event.event = IB_EVENT_PORT_ERR; |
226 | dispatch = 1; | ||
181 | break; | 227 | break; |
182 | } | 228 | } |
183 | case OFFLOAD_PORT_UP: { | 229 | case OFFLOAD_PORT_UP: { |
184 | event.event = IB_EVENT_PORT_ACTIVE; | 230 | event.event = IB_EVENT_PORT_ACTIVE; |
231 | dispatch = 1; | ||
232 | break; | ||
233 | } | ||
234 | case OFFLOAD_DB_FULL: { | ||
235 | disable_dbs(rnicp); | ||
236 | break; | ||
237 | } | ||
238 | case OFFLOAD_DB_EMPTY: { | ||
239 | enable_dbs(rnicp, 1); | ||
240 | break; | ||
241 | } | ||
242 | case OFFLOAD_DB_DROP: { | ||
243 | unsigned long delay = 1000; | ||
244 | unsigned short r; | ||
245 | |||
246 | disable_dbs(rnicp); | ||
247 | get_random_bytes(&r, 2); | ||
248 | delay += r & 1023; | ||
249 | |||
250 | /* | ||
251 | * delay is between 1000-2023 usecs. | ||
252 | */ | ||
253 | schedule_delayed_work(&rnicp->db_drop_task, | ||
254 | usecs_to_jiffies(delay)); | ||
185 | break; | 255 | break; |
186 | } | 256 | } |
187 | } | 257 | } |
188 | 258 | ||
189 | event.device = &rnicp->ibdev; | 259 | if (dispatch) { |
190 | event.element.port_num = portnum; | 260 | event.device = &rnicp->ibdev; |
191 | ib_dispatch_event(&event); | 261 | event.element.port_num = portnum; |
262 | ib_dispatch_event(&event); | ||
263 | } | ||
192 | 264 | ||
193 | return; | 265 | return; |
194 | } | 266 | } |