diff options
Diffstat (limited to 'drivers/infiniband/hw/amso1100/c2_vq.c')
-rw-r--r-- | drivers/infiniband/hw/amso1100/c2_vq.c | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/amso1100/c2_vq.c b/drivers/infiniband/hw/amso1100/c2_vq.c new file mode 100644 index 000000000000..40caeb5f41b4 --- /dev/null +++ b/drivers/infiniband/hw/amso1100/c2_vq.c | |||
@@ -0,0 +1,260 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005 Ammasso, Inc. All rights reserved. | ||
3 | * Copyright (c) 2005 Open Grid Computing, Inc. 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 | #include <linux/slab.h> | ||
34 | #include <linux/spinlock.h> | ||
35 | |||
36 | #include "c2_vq.h" | ||
37 | #include "c2_provider.h" | ||
38 | |||
39 | /* | ||
40 | * Verbs Request Objects: | ||
41 | * | ||
42 | * VQ Request Objects are allocated by the kernel verbs handlers. | ||
43 | * They contain a wait object, a refcnt, an atomic bool indicating that the | ||
44 | * adapter has replied, and a copy of the verb reply work request. | ||
45 | * A pointer to the VQ Request Object is passed down in the context | ||
46 | * field of the work request message, and reflected back by the adapter | ||
47 | * in the verbs reply message. The function handle_vq() in the interrupt | ||
48 | * path will use this pointer to: | ||
49 | * 1) append a copy of the verbs reply message | ||
50 | * 2) mark that the reply is ready | ||
51 | * 3) wake up the kernel verbs handler blocked awaiting the reply. | ||
52 | * | ||
53 | * | ||
54 | * The kernel verbs handlers do a "get" to put a 2nd reference on the | ||
55 | * VQ Request object. If the kernel verbs handler exits before the adapter | ||
56 | * can respond, this extra reference will keep the VQ Request object around | ||
57 | * until the adapter's reply can be processed. The reason we need this is | ||
58 | * because a pointer to this object is stuffed into the context field of | ||
59 | * the verbs work request message, and reflected back in the reply message. | ||
60 | * It is used in the interrupt handler (handle_vq()) to wake up the appropriate | ||
61 | * kernel verb handler that is blocked awaiting the verb reply. | ||
62 | * So handle_vq() will do a "put" on the object when it's done accessing it. | ||
63 | * NOTE: If we guarantee that the kernel verb handler will never bail before | ||
64 | * getting the reply, then we don't need these refcnts. | ||
65 | * | ||
66 | * | ||
67 | * VQ Request objects are freed by the kernel verbs handlers only | ||
68 | * after the verb has been processed, or when the adapter fails and | ||
69 | * does not reply. | ||
70 | * | ||
71 | * | ||
72 | * Verbs Reply Buffers: | ||
73 | * | ||
74 | * VQ Reply bufs are local host memory copies of a | ||
75 | * outstanding Verb Request reply | ||
76 | * message. The are always allocated by the kernel verbs handlers, and _may_ be | ||
77 | * freed by either the kernel verbs handler -or- the interrupt handler. The | ||
78 | * kernel verbs handler _must_ free the repbuf, then free the vq request object | ||
79 | * in that order. | ||
80 | */ | ||
81 | |||
82 | int vq_init(struct c2_dev *c2dev) | ||
83 | { | ||
84 | sprintf(c2dev->vq_cache_name, "c2-vq:dev%c", | ||
85 | (char) ('0' + c2dev->devnum)); | ||
86 | c2dev->host_msg_cache = | ||
87 | kmem_cache_create(c2dev->vq_cache_name, c2dev->rep_vq.msg_size, 0, | ||
88 | SLAB_HWCACHE_ALIGN, NULL, NULL); | ||
89 | if (c2dev->host_msg_cache == NULL) { | ||
90 | return -ENOMEM; | ||
91 | } | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | void vq_term(struct c2_dev *c2dev) | ||
96 | { | ||
97 | kmem_cache_destroy(c2dev->host_msg_cache); | ||
98 | } | ||
99 | |||
100 | /* vq_req_alloc - allocate a VQ Request Object and initialize it. | ||
101 | * The refcnt is set to 1. | ||
102 | */ | ||
103 | struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev) | ||
104 | { | ||
105 | struct c2_vq_req *r; | ||
106 | |||
107 | r = kmalloc(sizeof(struct c2_vq_req), GFP_KERNEL); | ||
108 | if (r) { | ||
109 | init_waitqueue_head(&r->wait_object); | ||
110 | r->reply_msg = (u64) NULL; | ||
111 | r->event = 0; | ||
112 | r->cm_id = NULL; | ||
113 | r->qp = NULL; | ||
114 | atomic_set(&r->refcnt, 1); | ||
115 | atomic_set(&r->reply_ready, 0); | ||
116 | } | ||
117 | return r; | ||
118 | } | ||
119 | |||
120 | |||
121 | /* vq_req_free - free the VQ Request Object. It is assumed the verbs handler | ||
122 | * has already free the VQ Reply Buffer if it existed. | ||
123 | */ | ||
124 | void vq_req_free(struct c2_dev *c2dev, struct c2_vq_req *r) | ||
125 | { | ||
126 | r->reply_msg = (u64) NULL; | ||
127 | if (atomic_dec_and_test(&r->refcnt)) { | ||
128 | kfree(r); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | /* vq_req_get - reference a VQ Request Object. Done | ||
133 | * only in the kernel verbs handlers. | ||
134 | */ | ||
135 | void vq_req_get(struct c2_dev *c2dev, struct c2_vq_req *r) | ||
136 | { | ||
137 | atomic_inc(&r->refcnt); | ||
138 | } | ||
139 | |||
140 | |||
141 | /* vq_req_put - dereference and potentially free a VQ Request Object. | ||
142 | * | ||
143 | * This is only called by handle_vq() on the | ||
144 | * interrupt when it is done processing | ||
145 | * a verb reply message. If the associated | ||
146 | * kernel verbs handler has already bailed, | ||
147 | * then this put will actually free the VQ | ||
148 | * Request object _and_ the VQ Reply Buffer | ||
149 | * if it exists. | ||
150 | */ | ||
151 | void vq_req_put(struct c2_dev *c2dev, struct c2_vq_req *r) | ||
152 | { | ||
153 | if (atomic_dec_and_test(&r->refcnt)) { | ||
154 | if (r->reply_msg != (u64) NULL) | ||
155 | vq_repbuf_free(c2dev, | ||
156 | (void *) (unsigned long) r->reply_msg); | ||
157 | kfree(r); | ||
158 | } | ||
159 | } | ||
160 | |||
161 | |||
162 | /* | ||
163 | * vq_repbuf_alloc - allocate a VQ Reply Buffer. | ||
164 | */ | ||
165 | void *vq_repbuf_alloc(struct c2_dev *c2dev) | ||
166 | { | ||
167 | return kmem_cache_alloc(c2dev->host_msg_cache, SLAB_ATOMIC); | ||
168 | } | ||
169 | |||
170 | /* | ||
171 | * vq_send_wr - post a verbs request message to the Verbs Request Queue. | ||
172 | * If a message is not available in the MQ, then block until one is available. | ||
173 | * NOTE: handle_mq() on the interrupt context will wake up threads blocked here. | ||
174 | * When the adapter drains the Verbs Request Queue, | ||
175 | * it inserts MQ index 0 in to the | ||
176 | * adapter->host activity fifo and interrupts the host. | ||
177 | */ | ||
178 | int vq_send_wr(struct c2_dev *c2dev, union c2wr *wr) | ||
179 | { | ||
180 | void *msg; | ||
181 | wait_queue_t __wait; | ||
182 | |||
183 | /* | ||
184 | * grab adapter vq lock | ||
185 | */ | ||
186 | spin_lock(&c2dev->vqlock); | ||
187 | |||
188 | /* | ||
189 | * allocate msg | ||
190 | */ | ||
191 | msg = c2_mq_alloc(&c2dev->req_vq); | ||
192 | |||
193 | /* | ||
194 | * If we cannot get a msg, then we'll wait | ||
195 | * When a messages are available, the int handler will wake_up() | ||
196 | * any waiters. | ||
197 | */ | ||
198 | while (msg == NULL) { | ||
199 | pr_debug("%s:%d no available msg in VQ, waiting...\n", | ||
200 | __FUNCTION__, __LINE__); | ||
201 | init_waitqueue_entry(&__wait, current); | ||
202 | add_wait_queue(&c2dev->req_vq_wo, &__wait); | ||
203 | spin_unlock(&c2dev->vqlock); | ||
204 | for (;;) { | ||
205 | set_current_state(TASK_INTERRUPTIBLE); | ||
206 | if (!c2_mq_full(&c2dev->req_vq)) { | ||
207 | break; | ||
208 | } | ||
209 | if (!signal_pending(current)) { | ||
210 | schedule_timeout(1 * HZ); /* 1 second... */ | ||
211 | continue; | ||
212 | } | ||
213 | set_current_state(TASK_RUNNING); | ||
214 | remove_wait_queue(&c2dev->req_vq_wo, &__wait); | ||
215 | return -EINTR; | ||
216 | } | ||
217 | set_current_state(TASK_RUNNING); | ||
218 | remove_wait_queue(&c2dev->req_vq_wo, &__wait); | ||
219 | spin_lock(&c2dev->vqlock); | ||
220 | msg = c2_mq_alloc(&c2dev->req_vq); | ||
221 | } | ||
222 | |||
223 | /* | ||
224 | * copy wr into adapter msg | ||
225 | */ | ||
226 | memcpy(msg, wr, c2dev->req_vq.msg_size); | ||
227 | |||
228 | /* | ||
229 | * post msg | ||
230 | */ | ||
231 | c2_mq_produce(&c2dev->req_vq); | ||
232 | |||
233 | /* | ||
234 | * release adapter vq lock | ||
235 | */ | ||
236 | spin_unlock(&c2dev->vqlock); | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | |||
241 | /* | ||
242 | * vq_wait_for_reply - block until the adapter posts a Verb Reply Message. | ||
243 | */ | ||
244 | int vq_wait_for_reply(struct c2_dev *c2dev, struct c2_vq_req *req) | ||
245 | { | ||
246 | if (!wait_event_timeout(req->wait_object, | ||
247 | atomic_read(&req->reply_ready), | ||
248 | 60*HZ)) | ||
249 | return -ETIMEDOUT; | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * vq_repbuf_free - Free a Verbs Reply Buffer. | ||
256 | */ | ||
257 | void vq_repbuf_free(struct c2_dev *c2dev, void *reply) | ||
258 | { | ||
259 | kmem_cache_free(c2dev->host_msg_cache, reply); | ||
260 | } | ||