]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/contrib/rdma/rdma_cache.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / contrib / rdma / rdma_cache.c
1 /*
2  * Copyright (c) 2004 Topspin Communications.  All rights reserved.
3  * Copyright (c) 2005 Intel Corporation. All rights reserved.
4  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
5  * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
6  *
7  * This software is available to you under a choice of one of two
8  * licenses.  You may choose to be licensed under the terms of the GNU
9  * General Public License (GPL) Version 2, available from the file
10  * COPYING in the main directory of this source tree, or the
11  * OpenIB.org BSD license below:
12  *
13  *     Redistribution and use in source and binary forms, with or
14  *     without modification, are permitted provided that the following
15  *     conditions are met:
16  *
17  *      - Redistributions of source code must retain the above
18  *        copyright notice, this list of conditions and the following
19  *        disclaimer.
20  *
21  *      - Redistributions in binary form must reproduce the above
22  *        copyright notice, this list of conditions and the following
23  *        disclaimer in the documentation and/or other materials
24  *        provided with the distribution.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33  * SOFTWARE.
34  *
35  * $Id: cache.c 1349 2004-12-16 21:09:43Z roland $
36  */
37
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40
41 #include <sys/types.h>
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/malloc.h>
46 #include <sys/kernel.h>
47 #include <sys/taskqueue.h>
48 #include <sys/lock.h>
49 #include <sys/rwlock.h>
50 #include <sys/mutex.h>
51 #include <sys/module.h>
52 #include <sys/syslog.h>
53
54
55 #ifdef needed
56 #include <sys/condvar.h>
57 #include <sys/socket.h>
58 #include <sys/condvar.h>
59 #endif
60
61 #include <contrib/rdma/ib_cache.h>
62
63 #include "core_priv.h"
64
65 struct ib_pkey_cache {
66         int             table_len;
67         u16             table[0];
68 };
69
70 struct ib_gid_cache {
71         int             table_len;
72         union ib_gid    table[0];
73 };
74
75 struct ib_update_work {
76         struct task       task;
77         struct ib_device  *device;
78         u8                 port_num;
79 };
80
81 static inline int start_port(struct ib_device *device)
82 {
83         return (device->node_type == RDMA_NODE_IB_SWITCH) ? 0 : 1;
84 }
85
86 static inline int end_port(struct ib_device *device)
87 {
88         return (device->node_type == RDMA_NODE_IB_SWITCH) ?
89                 0 : device->phys_port_cnt;
90 }
91
92 int ib_get_cached_gid(struct ib_device *device,
93                       u8                port_num,
94                       int               index,
95                       union ib_gid     *gid)
96 {
97         struct ib_gid_cache *cache;
98         int ret = 0;
99
100         if (port_num < start_port(device) || port_num > end_port(device))
101                 return -EINVAL;
102
103         mtx_lock(&device->cache.lock);
104
105         cache = device->cache.gid_cache[port_num - start_port(device)];
106
107         if (index < 0 || index >= cache->table_len)
108                 ret = -EINVAL;
109         else
110                 *gid = cache->table[index];
111
112         mtx_unlock(&device->cache.lock);
113
114         return ret;
115 }
116
117 int ib_find_cached_gid(struct ib_device *device,
118                        union ib_gid     *gid,
119                        u8               *port_num,
120                        u16              *index)
121 {
122         struct ib_gid_cache *cache;
123         int p, i;
124         int ret = -ENOENT;
125
126         *port_num = -1;
127         if (index)
128                 *index = -1;
129
130         mtx_lock(&device->cache.lock);
131
132         for (p = 0; p <= end_port(device) - start_port(device); ++p) {
133                 cache = device->cache.gid_cache[p];
134                 for (i = 0; i < cache->table_len; ++i) {
135                         if (!memcmp(gid, &cache->table[i], sizeof *gid)) {
136                                 *port_num = p + start_port(device);
137                                 if (index)
138                                         *index = i;
139                                 ret = 0;
140                                 goto found;
141                         }
142                 }
143         }
144 found:
145         mtx_unlock(&device->cache.lock);
146
147         return ret;
148 }
149
150 int ib_get_cached_pkey(struct ib_device *device,
151                        u8                port_num,
152                        int               index,
153                        u16              *pkey)
154 {
155         struct ib_pkey_cache *cache;
156         int ret = 0;
157
158         if (port_num < start_port(device) || port_num > end_port(device))
159                 return -EINVAL;
160
161         mtx_lock(&device->cache.lock);
162
163         cache = device->cache.pkey_cache[port_num - start_port(device)];
164
165         if (index < 0 || index >= cache->table_len)
166                 ret = -EINVAL;
167         else
168                 *pkey = cache->table[index];
169
170         mtx_unlock(&device->cache.lock);
171
172         return ret;
173 }
174
175 int ib_find_cached_pkey(struct ib_device *device,
176                         u8                port_num,
177                         u16               pkey,
178                         u16              *index)
179 {
180         struct ib_pkey_cache *cache;
181         int i;
182         int ret = -ENOENT;
183
184         if (port_num < start_port(device) || port_num > end_port(device))
185                 return -EINVAL;
186
187         mtx_lock(&device->cache.lock);
188
189         cache = device->cache.pkey_cache[port_num - start_port(device)];
190
191         *index = -1;
192
193         for (i = 0; i < cache->table_len; ++i)
194                 if ((cache->table[i] & 0x7fff) == (pkey & 0x7fff)) {
195                         *index = i;
196                         ret = 0;
197                         break;
198                 }
199
200         mtx_unlock(&device->cache.lock);
201
202         return ret;
203 }
204
205 int ib_get_cached_lmc(struct ib_device *device,
206                       u8                port_num,
207                       u8                *lmc)
208 {
209         int ret = 0;
210
211         if (port_num < start_port(device) || port_num > end_port(device))
212                 return -EINVAL;
213
214         mtx_lock(&device->cache.lock);
215         *lmc = device->cache.lmc_cache[port_num - start_port(device)];
216         mtx_unlock(&device->cache.lock);
217
218         return ret;
219 }
220
221 static void ib_cache_update(struct ib_device *device,
222                             u8                port)
223 {
224         struct ib_port_attr       *tprops = NULL;
225         struct ib_pkey_cache      *pkey_cache = NULL, *old_pkey_cache;
226         struct ib_gid_cache       *gid_cache = NULL, *old_gid_cache;
227         int                        i;
228         int                        ret;
229
230         tprops = malloc(sizeof *tprops, M_DEVBUF, M_NOWAIT);
231         if (!tprops)
232                 return;
233
234         ret = ib_query_port(device, port, tprops);
235         if (ret) {
236                 log(LOG_WARNING, "ib_query_port failed (%d) for %s\n",
237                        ret, device->name);
238                 goto err;
239         }
240
241         pkey_cache = malloc(sizeof *pkey_cache + tprops->pkey_tbl_len *
242                              sizeof *pkey_cache->table, M_DEVBUF, M_NOWAIT);
243         if (!pkey_cache)
244                 goto err;
245
246         pkey_cache->table_len = tprops->pkey_tbl_len;
247
248         gid_cache = malloc(sizeof *gid_cache + tprops->gid_tbl_len *
249                             sizeof *gid_cache->table, M_DEVBUF, M_NOWAIT);
250         if (!gid_cache)
251                 goto err;
252
253         gid_cache->table_len = tprops->gid_tbl_len;
254
255         for (i = 0; i < pkey_cache->table_len; ++i) {
256                 ret = ib_query_pkey(device, port, i, pkey_cache->table + i);
257                 if (ret) {
258                         log(LOG_WARNING, "ib_query_pkey failed (%d) for %s (index %d)\n",
259                                ret, device->name, i);
260                         goto err;
261                 }
262         }
263
264         for (i = 0; i < gid_cache->table_len; ++i) {
265                 ret = ib_query_gid(device, port, i, gid_cache->table + i);
266                 if (ret) {
267                         log(LOG_WARNING, "ib_query_gid failed (%d) for %s (index %d)\n",
268                                ret, device->name, i);
269                         goto err;
270                 }
271         }
272
273         mtx_lock(&device->cache.lock);
274
275         old_pkey_cache = device->cache.pkey_cache[port - start_port(device)];
276         old_gid_cache  = device->cache.gid_cache [port - start_port(device)];
277
278         device->cache.pkey_cache[port - start_port(device)] = pkey_cache;
279         device->cache.gid_cache [port - start_port(device)] = gid_cache;
280
281         device->cache.lmc_cache[port - start_port(device)] = tprops->lmc;
282
283         mtx_unlock(&device->cache.lock);
284
285         free(old_pkey_cache, M_DEVBUF);
286         free(old_gid_cache, M_DEVBUF);
287         free(tprops, M_DEVBUF);
288         return;
289
290 err:
291         free(pkey_cache, M_DEVBUF);
292         free(gid_cache, M_DEVBUF);
293         free(tprops, M_DEVBUF);
294 }
295
296 static void ib_cache_task(void *context, int pending)
297 {
298         struct ib_update_work *work = context;
299
300         ib_cache_update(work->device, work->port_num);
301         free(work, M_DEVBUF);
302 }
303
304 static void ib_cache_event(struct ib_event_handler *handler,
305                            struct ib_event *event)
306 {
307         struct ib_update_work *work;
308
309         if (event->event == IB_EVENT_PORT_ERR    ||
310             event->event == IB_EVENT_PORT_ACTIVE ||
311             event->event == IB_EVENT_LID_CHANGE  ||
312             event->event == IB_EVENT_PKEY_CHANGE ||
313             event->event == IB_EVENT_SM_CHANGE   ||
314             event->event == IB_EVENT_CLIENT_REREGISTER) {
315                 work = malloc(sizeof *work, M_DEVBUF, M_NOWAIT);
316                 if (work) {
317                         TASK_INIT(&work->task, 0, ib_cache_task, work);
318                         work->device   = event->device;
319                         work->port_num = event->element.port_num;
320                         taskqueue_enqueue(taskqueue_thread, &work->task);
321                 }
322         }
323 }
324
325 static void ib_cache_setup_one(struct ib_device *device)
326 {
327         int p;
328
329         mtx_init(&device->cache.lock, "ib device cache", NULL, 
330                 MTX_DUPOK|MTX_DEF);
331
332         device->cache.pkey_cache =
333                 malloc(sizeof *device->cache.pkey_cache *
334                         (end_port(device) - start_port(device) + 1), M_DEVBUF, 
335                         M_NOWAIT);
336         device->cache.gid_cache =
337                 malloc(sizeof *device->cache.gid_cache *
338                         (end_port(device) - start_port(device) + 1), M_DEVBUF, 
339                         M_NOWAIT);
340
341         device->cache.lmc_cache = malloc(sizeof *device->cache.lmc_cache *
342                                           (end_port(device) -
343                                           start_port(device) + 1),
344                                           M_DEVBUF, M_NOWAIT);
345
346         if (!device->cache.pkey_cache || !device->cache.gid_cache ||
347             !device->cache.lmc_cache) {
348                 log(LOG_WARNING, "Couldn't allocate cache "
349                        "for %s\n", device->name);
350                 goto err;
351         }
352
353         for (p = 0; p <= end_port(device) - start_port(device); ++p) {
354                 device->cache.pkey_cache[p] = NULL;
355                 device->cache.gid_cache [p] = NULL;
356                 ib_cache_update(device, p + start_port(device));
357         }
358
359         INIT_IB_EVENT_HANDLER(&device->cache.event_handler,
360                               device, ib_cache_event);
361         if (ib_register_event_handler(&device->cache.event_handler))
362                 goto err_cache;
363
364         return;
365
366 err_cache:
367         for (p = 0; p <= end_port(device) - start_port(device); ++p) {
368                 free(device->cache.pkey_cache[p], M_DEVBUF);
369                 free(device->cache.gid_cache[p], M_DEVBUF);
370         }
371
372 err:
373         free(device->cache.pkey_cache, M_DEVBUF);
374         free(device->cache.gid_cache, M_DEVBUF);
375         free(device->cache.lmc_cache, M_DEVBUF);
376 }
377
378 static void ib_cache_cleanup_one(struct ib_device *device)
379 {
380         int p;
381
382         ib_unregister_event_handler(&device->cache.event_handler);
383 #ifdef XXX
384         flush_scheduled_work();
385 #endif
386
387         for (p = 0; p <= end_port(device) - start_port(device); ++p) {
388                 free(device->cache.pkey_cache[p], M_DEVBUF);
389                 free(device->cache.gid_cache[p], M_DEVBUF);
390         }
391
392         free(device->cache.pkey_cache, M_DEVBUF);
393         free(device->cache.gid_cache, M_DEVBUF);
394         free(device->cache.lmc_cache, M_DEVBUF);
395 }
396
397 static struct ib_client cache_client = {
398         .name   = "cache",
399         .add    = ib_cache_setup_one,
400         .remove = ib_cache_cleanup_one
401 };
402
403 int ib_cache_setup(void)
404 {
405         return ib_register_client(&cache_client);
406 }
407
408 void ib_cache_cleanup(void)
409 {
410         ib_unregister_client(&cache_client);
411 }