mlx4: /dev/ -> /dev_vfs/
[akaros.git] / kern / drivers / net / mlx4 / cq.c
1 /*
2  * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
3  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
4  * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved.
5  * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved.
6  * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
7  *
8  * This software is available to you under a choice of one of two
9  * licenses.  You may choose to be licensed under the terms of the GNU
10  * General Public License (GPL) Version 2, available from the file
11  * COPYING in the main directory of this source tree, or the
12  * OpenIB.org BSD license below:
13  *
14  *     Redistribution and use in source and binary forms, with or
15  *     without modification, are permitted provided that the following
16  *     conditions are met:
17  *
18  *      - Redistributions of source code must retain the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer.
21  *
22  *      - Redistributions in binary form must reproduce the above
23  *        copyright notice, this list of conditions and the following
24  *        disclaimer in the documentation and/or other materials
25  *        provided with the distribution.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
31  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
32  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
33  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34  * SOFTWARE.
35  */
36
37 #include <linux_compat.h>
38 #include <linux/mlx4/cmd.h>
39 #include <linux/mlx4/cq.h>
40
41 #include "mlx4.h"
42 #include "icm.h"
43
44 #define MLX4_CQ_STATUS_OK               ( 0 << 28)
45 #define MLX4_CQ_STATUS_OVERFLOW         ( 9 << 28)
46 #define MLX4_CQ_STATUS_WRITE_FAIL       (10 << 28)
47 #define MLX4_CQ_FLAG_CC                 ( 1 << 18)
48 #define MLX4_CQ_FLAG_OI                 ( 1 << 17)
49 #define MLX4_CQ_STATE_ARMED             ( 9 <<  8)
50 #define MLX4_CQ_STATE_ARMED_SOL         ( 6 <<  8)
51 #define MLX4_EQ_STATE_FIRED             (10 <<  8)
52
53 #define TASKLET_MAX_TIME 2
54 #if 0 // AKAROS_PORT
55 #define TASKLET_MAX_TIME_JIFFIES msecs_to_jiffies(TASKLET_MAX_TIME)
56 #endif
57
58 void mlx4_cq_tasklet_cb(unsigned long data)
59 {
60         unsigned long flags;
61 #if 0 // AKAROS_PORT
62         unsigned long end = jiffies + TASKLET_MAX_TIME_JIFFIES;
63 #else
64         unsigned long end = TASKLET_MAX_TIME;
65 #endif
66         struct mlx4_eq_tasklet *ctx = (struct mlx4_eq_tasklet *)data;
67         struct mlx4_cq *mcq, *temp;
68
69         spin_lock_irqsave(&ctx->lock);
70         list_splice_tail_init(&ctx->list, &ctx->process_list);
71         spin_unlock_irqsave(&ctx->lock);
72
73         list_for_each_entry_safe(mcq, temp, &ctx->process_list, tasklet_ctx.list) {
74                 list_del_init(&mcq->tasklet_ctx.list);
75                 mcq->tasklet_ctx.comp(mcq);
76                 if (atomic_sub_and_test(&mcq->refcount, 1))
77                         complete(&mcq->free);
78 #if 0 // AKAROS_PORT
79                 if (time_after(jiffies, end))
80 #else
81                 if ((end--) == 0)
82 #endif
83                         break;
84         }
85
86         if (!list_empty(&ctx->process_list))
87                 tasklet_schedule(&ctx->task);
88 }
89
90 static void mlx4_add_cq_to_tasklet(struct mlx4_cq *cq)
91 {
92         unsigned long flags;
93         struct mlx4_eq_tasklet *tasklet_ctx = cq->tasklet_ctx.priv;
94
95         spin_lock_irqsave(&tasklet_ctx->lock);
96         /* When migrating CQs between EQs will be implemented, please note
97          * that you need to sync this point. It is possible that
98          * while migrating a CQ, completions on the old EQs could
99          * still arrive.
100          */
101         if (list_empty_careful(&cq->tasklet_ctx.list)) {
102                 atomic_inc(&cq->refcount);
103                 list_add_tail(&cq->tasklet_ctx.list, &tasklet_ctx->list);
104         }
105         spin_unlock_irqsave(&tasklet_ctx->lock);
106 }
107
108 void mlx4_cq_completion(struct mlx4_dev *dev, uint32_t cqn)
109 {
110         struct mlx4_cq *cq;
111
112         cq = radix_tree_lookup(&mlx4_priv(dev)->cq_table.tree,
113                                cqn & (dev->caps.num_cqs - 1));
114         if (!cq) {
115                 mlx4_dbg(dev, "Completion event for bogus CQ %08x\n", cqn);
116                 return;
117         }
118
119         ++cq->arm_sn;
120
121         cq->comp(cq);
122 }
123
124 void mlx4_cq_event(struct mlx4_dev *dev, uint32_t cqn, int event_type)
125 {
126         struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table;
127         struct mlx4_cq *cq;
128
129         spin_lock_irqsave(&cq_table->lock);
130
131         cq = radix_tree_lookup(&cq_table->tree, cqn & (dev->caps.num_cqs - 1));
132         if (cq)
133                 atomic_inc(&cq->refcount);
134
135         spin_unlock_irqsave(&cq_table->lock);
136
137         if (!cq) {
138                 mlx4_warn(dev, "Async event for bogus CQ %08x\n", cqn);
139                 return;
140         }
141
142         cq->event(cq, event_type);
143
144         if (atomic_sub_and_test(&cq->refcount, 1))
145                 complete(&cq->free);
146 }
147
148 static int mlx4_SW2HW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
149                          int cq_num)
150 {
151         return mlx4_cmd(dev, mailbox->dma, cq_num, 0,
152                         MLX4_CMD_SW2HW_CQ, MLX4_CMD_TIME_CLASS_A,
153                         MLX4_CMD_WRAPPED);
154 }
155
156 static int mlx4_MODIFY_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
157                          int cq_num, uint32_t opmod)
158 {
159         return mlx4_cmd(dev, mailbox->dma, cq_num, opmod, MLX4_CMD_MODIFY_CQ,
160                         MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
161 }
162
163 static int mlx4_HW2SW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
164                          int cq_num)
165 {
166         return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma : 0,
167                             cq_num, mailbox ? 0 : 1, MLX4_CMD_HW2SW_CQ,
168                             MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
169 }
170
171 int mlx4_cq_modify(struct mlx4_dev *dev, struct mlx4_cq *cq,
172                    uint16_t count, uint16_t period)
173 {
174         struct mlx4_cmd_mailbox *mailbox;
175         struct mlx4_cq_context *cq_context;
176         int err;
177
178         mailbox = mlx4_alloc_cmd_mailbox(dev);
179         if (IS_ERR(mailbox))
180                 return PTR_ERR(mailbox);
181
182         cq_context = mailbox->buf;
183         cq_context->cq_max_count = cpu_to_be16(count);
184         cq_context->cq_period    = cpu_to_be16(period);
185
186         err = mlx4_MODIFY_CQ(dev, mailbox, cq->cqn, 1);
187
188         mlx4_free_cmd_mailbox(dev, mailbox);
189         return err;
190 }
191 EXPORT_SYMBOL_GPL(mlx4_cq_modify);
192
193 int mlx4_cq_resize(struct mlx4_dev *dev, struct mlx4_cq *cq,
194                    int entries, struct mlx4_mtt *mtt)
195 {
196         struct mlx4_cmd_mailbox *mailbox;
197         struct mlx4_cq_context *cq_context;
198         uint64_t mtt_addr;
199         int err;
200
201         mailbox = mlx4_alloc_cmd_mailbox(dev);
202         if (IS_ERR(mailbox))
203                 return PTR_ERR(mailbox);
204
205         cq_context = mailbox->buf;
206         cq_context->logsize_usrpage = cpu_to_be32(LOG2_UP(entries) << 24);
207         cq_context->log_page_size   = mtt->page_shift - 12;
208         mtt_addr = mlx4_mtt_addr(dev, mtt);
209         cq_context->mtt_base_addr_h = mtt_addr >> 32;
210         cq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff);
211
212         err = mlx4_MODIFY_CQ(dev, mailbox, cq->cqn, 0);
213
214         mlx4_free_cmd_mailbox(dev, mailbox);
215         return err;
216 }
217 EXPORT_SYMBOL_GPL(mlx4_cq_resize);
218
219 int __mlx4_cq_alloc_icm(struct mlx4_dev *dev, int *cqn)
220 {
221         struct mlx4_priv *priv = mlx4_priv(dev);
222         struct mlx4_cq_table *cq_table = &priv->cq_table;
223         int err;
224
225         *cqn = mlx4_bitmap_alloc(&cq_table->bitmap);
226         if (*cqn == -1)
227                 return -ENOMEM;
228
229         err = mlx4_table_get(dev, &cq_table->table, *cqn, MEM_WAIT);
230         if (err)
231                 goto err_out;
232
233         err = mlx4_table_get(dev, &cq_table->cmpt_table, *cqn, MEM_WAIT);
234         if (err)
235                 goto err_put;
236         return 0;
237
238 err_put:
239         mlx4_table_put(dev, &cq_table->table, *cqn);
240
241 err_out:
242         mlx4_bitmap_free(&cq_table->bitmap, *cqn, MLX4_NO_RR);
243         return err;
244 }
245
246 static int mlx4_cq_alloc_icm(struct mlx4_dev *dev, int *cqn)
247 {
248         uint64_t out_param;
249         int err;
250
251         if (mlx4_is_mfunc(dev)) {
252                 err = mlx4_cmd_imm(dev, 0, &out_param, RES_CQ,
253                                    RES_OP_RESERVE_AND_MAP, MLX4_CMD_ALLOC_RES,
254                                    MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
255                 if (err)
256                         return err;
257                 else {
258                         *cqn = get_param_l(&out_param);
259                         return 0;
260                 }
261         }
262         return __mlx4_cq_alloc_icm(dev, cqn);
263 }
264
265 void __mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn)
266 {
267         struct mlx4_priv *priv = mlx4_priv(dev);
268         struct mlx4_cq_table *cq_table = &priv->cq_table;
269
270         mlx4_table_put(dev, &cq_table->cmpt_table, cqn);
271         mlx4_table_put(dev, &cq_table->table, cqn);
272         mlx4_bitmap_free(&cq_table->bitmap, cqn, MLX4_NO_RR);
273 }
274
275 static void mlx4_cq_free_icm(struct mlx4_dev *dev, int cqn)
276 {
277         uint64_t in_param = 0;
278         int err;
279
280         if (mlx4_is_mfunc(dev)) {
281                 set_param_l(&in_param, cqn);
282                 err = mlx4_cmd(dev, in_param, RES_CQ, RES_OP_RESERVE_AND_MAP,
283                                MLX4_CMD_FREE_RES,
284                                MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
285                 if (err)
286                         mlx4_warn(dev, "Failed freeing cq:%d\n", cqn);
287         } else
288                 __mlx4_cq_free_icm(dev, cqn);
289 }
290
291 int mlx4_cq_alloc(struct mlx4_dev *dev, int nent,
292                   struct mlx4_mtt *mtt, struct mlx4_uar *uar, uint64_t db_rec,
293                   struct mlx4_cq *cq, unsigned vector, int collapsed,
294                   int timestamp_en)
295 {
296         struct mlx4_priv *priv = mlx4_priv(dev);
297         struct mlx4_cq_table *cq_table = &priv->cq_table;
298         struct mlx4_cmd_mailbox *mailbox;
299         struct mlx4_cq_context *cq_context;
300         uint64_t mtt_addr;
301         int err;
302
303         if (vector > dev->caps.num_comp_vectors + dev->caps.comp_pool)
304                 return -EINVAL;
305
306         cq->vector = vector;
307
308         err = mlx4_cq_alloc_icm(dev, &cq->cqn);
309         if (err)
310                 return err;
311
312         spin_lock_irqsave(&cq_table->lock);
313         err = radix_tree_insert(&cq_table->tree, cq->cqn, cq);
314         spin_unlock_irqsave(&cq_table->lock);
315         if (err)
316                 goto err_icm;
317
318         mailbox = mlx4_alloc_cmd_mailbox(dev);
319         if (IS_ERR(mailbox)) {
320                 err = PTR_ERR(mailbox);
321                 goto err_radix;
322         }
323
324         cq_context = mailbox->buf;
325         cq_context->flags           = cpu_to_be32(!!collapsed << 18);
326         if (timestamp_en)
327                 cq_context->flags  |= cpu_to_be32(1 << 19);
328
329         cq_context->logsize_usrpage = cpu_to_be32((LOG2_UP(nent) << 24) | uar->index);
330         cq_context->comp_eqn        = priv->eq_table.eq[vector].eqn;
331         cq_context->log_page_size   = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
332
333         mtt_addr = mlx4_mtt_addr(dev, mtt);
334         cq_context->mtt_base_addr_h = mtt_addr >> 32;
335         cq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff);
336         cq_context->db_rec_addr     = cpu_to_be64(db_rec);
337
338         err = mlx4_SW2HW_CQ(dev, mailbox, cq->cqn);
339         mlx4_free_cmd_mailbox(dev, mailbox);
340         if (err)
341                 goto err_radix;
342
343         cq->cons_index = 0;
344         cq->arm_sn     = 1;
345         cq->uar        = uar;
346         atomic_set(&cq->refcount, 1);
347         init_completion(&cq->free);
348         cq->comp = mlx4_add_cq_to_tasklet;
349         cq->tasklet_ctx.priv =
350                 &priv->eq_table.eq[cq->vector].tasklet_ctx;
351         INIT_LIST_HEAD(&cq->tasklet_ctx.list);
352
353
354 #if 0 // AKAROS_PORT
355         cq->irq = priv->eq_table.eq[cq->vector].irq;
356 #else
357         cq->irq = -1; /* FIXME */
358 #endif
359         return 0;
360
361 err_radix:
362         spin_lock_irqsave(&cq_table->lock);
363         radix_tree_delete(&cq_table->tree, cq->cqn);
364         spin_unlock_irqsave(&cq_table->lock);
365
366 err_icm:
367         mlx4_cq_free_icm(dev, cq->cqn);
368
369         return err;
370 }
371 EXPORT_SYMBOL_GPL(mlx4_cq_alloc);
372
373 void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq)
374 {
375         struct mlx4_priv *priv = mlx4_priv(dev);
376         struct mlx4_cq_table *cq_table = &priv->cq_table;
377         int err;
378
379         err = mlx4_HW2SW_CQ(dev, NULL, cq->cqn);
380         if (err)
381                 mlx4_warn(dev, "HW2SW_CQ failed (%d) for CQN %06x\n", err, cq->cqn);
382
383         synchronize_irq(priv->eq_table.eq[cq->vector].irq);
384
385         spin_lock_irqsave(&cq_table->lock);
386         radix_tree_delete(&cq_table->tree, cq->cqn);
387         spin_unlock_irqsave(&cq_table->lock);
388
389         if (atomic_sub_and_test(&cq->refcount, 1))
390                 complete(&cq->free);
391         wait_for_completion(&cq->free);
392
393         mlx4_cq_free_icm(dev, cq->cqn);
394 }
395 EXPORT_SYMBOL_GPL(mlx4_cq_free);
396
397 int mlx4_init_cq_table(struct mlx4_dev *dev)
398 {
399         struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table;
400         int err;
401
402         spinlock_init_irqsave(&cq_table->lock);
403         INIT_RADIX_TREE(&cq_table->tree, 0);
404         if (mlx4_is_slave(dev))
405                 return 0;
406
407         err = mlx4_bitmap_init(&cq_table->bitmap, dev->caps.num_cqs,
408                                dev->caps.num_cqs - 1, dev->caps.reserved_cqs, 0);
409         if (err)
410                 return err;
411
412         return 0;
413 }
414
415 void mlx4_cleanup_cq_table(struct mlx4_dev *dev)
416 {
417         if (mlx4_is_slave(dev))
418                 return;
419         /* Nothing to do to clean up radix_tree */
420         mlx4_bitmap_cleanup(&mlx4_priv(dev)->cq_table.bitmap);
421 }