Merge branch 'tracing-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / drivers / net / mlx4 / srq.c
1 /*
2  * Copyright (c) 2006, 2007 Cisco Systems, Inc. All rights reserved.
3  * Copyright (c) 2007, 2008 Mellanox Technologies. All rights reserved.
4  *
5  * This software is available to you under a choice of one of two
6  * licenses.  You may choose to be licensed under the terms of the GNU
7  * General Public License (GPL) Version 2, available from the file
8  * COPYING in the main directory of this source tree, or the
9  * OpenIB.org BSD license below:
10  *
11  *     Redistribution and use in source and binary forms, with or
12  *     without modification, are permitted provided that the following
13  *     conditions are met:
14  *
15  *      - Redistributions of source code must retain the above
16  *        copyright notice, this list of conditions and the following
17  *        disclaimer.
18  *
19  *      - Redistributions in binary form must reproduce the above
20  *        copyright notice, this list of conditions and the following
21  *        disclaimer in the documentation and/or other materials
22  *        provided with the distribution.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31  * SOFTWARE.
32  */
33
34 #include <linux/mlx4/cmd.h>
35
36 #include "mlx4.h"
37 #include "icm.h"
38
39 struct mlx4_srq_context {
40         __be32                  state_logsize_srqn;
41         u8                      logstride;
42         u8                      reserved1[3];
43         u8                      pg_offset;
44         u8                      reserved2[3];
45         u32                     reserved3;
46         u8                      log_page_size;
47         u8                      reserved4[2];
48         u8                      mtt_base_addr_h;
49         __be32                  mtt_base_addr_l;
50         __be32                  pd;
51         __be16                  limit_watermark;
52         __be16                  wqe_cnt;
53         u16                     reserved5;
54         __be16                  wqe_counter;
55         u32                     reserved6;
56         __be64                  db_rec_addr;
57 };
58
59 void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type)
60 {
61         struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
62         struct mlx4_srq *srq;
63
64         spin_lock(&srq_table->lock);
65
66         srq = radix_tree_lookup(&srq_table->tree, srqn & (dev->caps.num_srqs - 1));
67         if (srq)
68                 atomic_inc(&srq->refcount);
69
70         spin_unlock(&srq_table->lock);
71
72         if (!srq) {
73                 mlx4_warn(dev, "Async event for bogus SRQ %08x\n", srqn);
74                 return;
75         }
76
77         srq->event(srq, event_type);
78
79         if (atomic_dec_and_test(&srq->refcount))
80                 complete(&srq->free);
81 }
82
83 static int mlx4_SW2HW_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
84                           int srq_num)
85 {
86         return mlx4_cmd(dev, mailbox->dma, srq_num, 0, MLX4_CMD_SW2HW_SRQ,
87                         MLX4_CMD_TIME_CLASS_A);
88 }
89
90 static int mlx4_HW2SW_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
91                           int srq_num)
92 {
93         return mlx4_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, srq_num,
94                             mailbox ? 0 : 1, MLX4_CMD_HW2SW_SRQ,
95                             MLX4_CMD_TIME_CLASS_A);
96 }
97
98 static int mlx4_ARM_SRQ(struct mlx4_dev *dev, int srq_num, int limit_watermark)
99 {
100         return mlx4_cmd(dev, limit_watermark, srq_num, 0, MLX4_CMD_ARM_SRQ,
101                         MLX4_CMD_TIME_CLASS_B);
102 }
103
104 static int mlx4_QUERY_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
105                           int srq_num)
106 {
107         return mlx4_cmd_box(dev, 0, mailbox->dma, srq_num, 0, MLX4_CMD_QUERY_SRQ,
108                             MLX4_CMD_TIME_CLASS_A);
109 }
110
111 int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, struct mlx4_mtt *mtt,
112                    u64 db_rec, struct mlx4_srq *srq)
113 {
114         struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
115         struct mlx4_cmd_mailbox *mailbox;
116         struct mlx4_srq_context *srq_context;
117         u64 mtt_addr;
118         int err;
119
120         srq->srqn = mlx4_bitmap_alloc(&srq_table->bitmap);
121         if (srq->srqn == -1)
122                 return -ENOMEM;
123
124         err = mlx4_table_get(dev, &srq_table->table, srq->srqn);
125         if (err)
126                 goto err_out;
127
128         err = mlx4_table_get(dev, &srq_table->cmpt_table, srq->srqn);
129         if (err)
130                 goto err_put;
131
132         spin_lock_irq(&srq_table->lock);
133         err = radix_tree_insert(&srq_table->tree, srq->srqn, srq);
134         spin_unlock_irq(&srq_table->lock);
135         if (err)
136                 goto err_cmpt_put;
137
138         mailbox = mlx4_alloc_cmd_mailbox(dev);
139         if (IS_ERR(mailbox)) {
140                 err = PTR_ERR(mailbox);
141                 goto err_radix;
142         }
143
144         srq_context = mailbox->buf;
145         memset(srq_context, 0, sizeof *srq_context);
146
147         srq_context->state_logsize_srqn = cpu_to_be32((ilog2(srq->max) << 24) |
148                                                       srq->srqn);
149         srq_context->logstride          = srq->wqe_shift - 4;
150         srq_context->log_page_size      = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
151
152         mtt_addr = mlx4_mtt_addr(dev, mtt);
153         srq_context->mtt_base_addr_h    = mtt_addr >> 32;
154         srq_context->mtt_base_addr_l    = cpu_to_be32(mtt_addr & 0xffffffff);
155         srq_context->pd                 = cpu_to_be32(pdn);
156         srq_context->db_rec_addr        = cpu_to_be64(db_rec);
157
158         err = mlx4_SW2HW_SRQ(dev, mailbox, srq->srqn);
159         mlx4_free_cmd_mailbox(dev, mailbox);
160         if (err)
161                 goto err_radix;
162
163         atomic_set(&srq->refcount, 1);
164         init_completion(&srq->free);
165
166         return 0;
167
168 err_radix:
169         spin_lock_irq(&srq_table->lock);
170         radix_tree_delete(&srq_table->tree, srq->srqn);
171         spin_unlock_irq(&srq_table->lock);
172
173 err_cmpt_put:
174         mlx4_table_put(dev, &srq_table->cmpt_table, srq->srqn);
175
176 err_put:
177         mlx4_table_put(dev, &srq_table->table, srq->srqn);
178
179 err_out:
180         mlx4_bitmap_free(&srq_table->bitmap, srq->srqn);
181
182         return err;
183 }
184 EXPORT_SYMBOL_GPL(mlx4_srq_alloc);
185
186 void mlx4_srq_free(struct mlx4_dev *dev, struct mlx4_srq *srq)
187 {
188         struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
189         int err;
190
191         err = mlx4_HW2SW_SRQ(dev, NULL, srq->srqn);
192         if (err)
193                 mlx4_warn(dev, "HW2SW_SRQ failed (%d) for SRQN %06x\n", err, srq->srqn);
194
195         spin_lock_irq(&srq_table->lock);
196         radix_tree_delete(&srq_table->tree, srq->srqn);
197         spin_unlock_irq(&srq_table->lock);
198
199         if (atomic_dec_and_test(&srq->refcount))
200                 complete(&srq->free);
201         wait_for_completion(&srq->free);
202
203         mlx4_table_put(dev, &srq_table->table, srq->srqn);
204         mlx4_bitmap_free(&srq_table->bitmap, srq->srqn);
205 }
206 EXPORT_SYMBOL_GPL(mlx4_srq_free);
207
208 int mlx4_srq_arm(struct mlx4_dev *dev, struct mlx4_srq *srq, int limit_watermark)
209 {
210         return mlx4_ARM_SRQ(dev, srq->srqn, limit_watermark);
211 }
212 EXPORT_SYMBOL_GPL(mlx4_srq_arm);
213
214 int mlx4_srq_query(struct mlx4_dev *dev, struct mlx4_srq *srq, int *limit_watermark)
215 {
216         struct mlx4_cmd_mailbox *mailbox;
217         struct mlx4_srq_context *srq_context;
218         int err;
219
220         mailbox = mlx4_alloc_cmd_mailbox(dev);
221         if (IS_ERR(mailbox))
222                 return PTR_ERR(mailbox);
223
224         srq_context = mailbox->buf;
225
226         err = mlx4_QUERY_SRQ(dev, mailbox, srq->srqn);
227         if (err)
228                 goto err_out;
229         *limit_watermark = be16_to_cpu(srq_context->limit_watermark);
230
231 err_out:
232         mlx4_free_cmd_mailbox(dev, mailbox);
233         return err;
234 }
235 EXPORT_SYMBOL_GPL(mlx4_srq_query);
236
237 int mlx4_init_srq_table(struct mlx4_dev *dev)
238 {
239         struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
240         int err;
241
242         spin_lock_init(&srq_table->lock);
243         INIT_RADIX_TREE(&srq_table->tree, GFP_ATOMIC);
244
245         err = mlx4_bitmap_init(&srq_table->bitmap, dev->caps.num_srqs,
246                                dev->caps.num_srqs - 1, dev->caps.reserved_srqs, 0);
247         if (err)
248                 return err;
249
250         return 0;
251 }
252
253 void mlx4_cleanup_srq_table(struct mlx4_dev *dev)
254 {
255         mlx4_bitmap_cleanup(&mlx4_priv(dev)->srq_table.bitmap);
256 }