xref: /NextBSD/sys/ofed/drivers/infiniband/core/cache.c (revision 287e3b14e9552995def1802ec9c5034f4adf28ec)
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 
36 #include <linux/module.h>
37 #include <linux/errno.h>
38 #include <linux/slab.h>
39 #include <linux/workqueue.h>
40 
41 #include <rdma/ib_cache.h>
42 
43 #include "core_priv.h"
44 
45 struct ib_pkey_cache {
46 	int             table_len;
47 	u16             table[0];
48 };
49 
50 struct ib_gid_cache {
51 	int             table_len;
52 	union ib_gid    table[0];
53 };
54 
55 struct ib_update_work {
56 	struct work_struct work;
57 	struct ib_device  *device;
58 	u8                 port_num;
59 };
60 
start_port(struct ib_device * device)61 static inline int start_port(struct ib_device *device)
62 {
63 	return (device->node_type == RDMA_NODE_IB_SWITCH) ? 0 : 1;
64 }
65 
end_port(struct ib_device * device)66 static inline int end_port(struct ib_device *device)
67 {
68 	return (device->node_type == RDMA_NODE_IB_SWITCH) ?
69 		0 : device->phys_port_cnt;
70 }
71 
ib_get_cached_gid(struct ib_device * device,u8 port_num,int index,union ib_gid * gid)72 int ib_get_cached_gid(struct ib_device *device,
73 		      u8                port_num,
74 		      int               index,
75 		      union ib_gid     *gid)
76 {
77 	struct ib_gid_cache *cache;
78 	unsigned long flags;
79 	int ret = -EINVAL;
80 
81 	if (port_num < start_port(device) || port_num > end_port(device))
82 		return -EINVAL;
83 
84 	read_lock_irqsave(&device->cache.lock, flags);
85 
86 	if (device->cache.gid_cache) {
87 		cache = device->cache.gid_cache[port_num - start_port(device)];
88 
89 		if (cache && index >= 0 && index < cache->table_len) {
90 			*gid = cache->table[index];
91 			ret = 0;
92 		}
93 	}
94 
95 	read_unlock_irqrestore(&device->cache.lock, flags);
96 
97 	return ret;
98 }
99 EXPORT_SYMBOL(ib_get_cached_gid);
100 
ib_find_cached_gid(struct ib_device * device,union ib_gid * gid,u8 * port_num,u16 * index)101 int ib_find_cached_gid(struct ib_device *device,
102 		       union ib_gid	*gid,
103 		       u8               *port_num,
104 		       u16              *index)
105 {
106 	struct ib_gid_cache *cache;
107 	unsigned long flags;
108 	int p, i;
109 	int ret = -ENOENT;
110 
111 	*port_num = -1;
112 	if (index)
113 		*index = -1;
114 
115 	read_lock_irqsave(&device->cache.lock, flags);
116 	if (!device->cache.gid_cache)
117 		goto out;
118 	for (p = 0; p <= end_port(device) - start_port(device); ++p) {
119 		cache = device->cache.gid_cache[p];
120 		if (!cache)
121 			continue;
122 		for (i = 0; i < cache->table_len; ++i) {
123 			if (!memcmp(gid, &cache->table[i], sizeof *gid)) {
124 				*port_num = p + start_port(device);
125 				if (index)
126 					*index = i;
127 				ret = 0;
128 				goto out;
129 			}
130 		}
131 	}
132 out:
133 	read_unlock_irqrestore(&device->cache.lock, flags);
134 	return ret;
135 }
136 EXPORT_SYMBOL(ib_find_cached_gid);
137 
ib_get_cached_pkey(struct ib_device * device,u8 port_num,int index,u16 * pkey)138 int ib_get_cached_pkey(struct ib_device *device,
139 		       u8                port_num,
140 		       int               index,
141 		       u16              *pkey)
142 {
143 	struct ib_pkey_cache *cache;
144 	unsigned long flags;
145 	int ret = -EINVAL;
146 
147 	if (port_num < start_port(device) || port_num > end_port(device))
148 		return -EINVAL;
149 
150 	read_lock_irqsave(&device->cache.lock, flags);
151 
152 	if (device->cache.pkey_cache) {
153 		cache = device->cache.pkey_cache[port_num - start_port(device)];
154 
155 		if (cache && index >= 0 && index < cache->table_len) {
156 			*pkey = cache->table[index];
157 			ret = 0;
158 		}
159 	}
160 
161 	read_unlock_irqrestore(&device->cache.lock, flags);
162 
163 	return ret;
164 }
165 EXPORT_SYMBOL(ib_get_cached_pkey);
166 
ib_find_cached_pkey(struct ib_device * device,u8 port_num,u16 pkey,u16 * index)167 int ib_find_cached_pkey(struct ib_device *device,
168 			u8                port_num,
169 			u16               pkey,
170 			u16              *index)
171 {
172 	struct ib_pkey_cache *cache;
173 	unsigned long flags;
174 	int i;
175 	int ret = -ENOENT;
176 	int partial_ix = -1;
177 
178 	if (port_num < start_port(device) || port_num > end_port(device))
179 		return -EINVAL;
180 
181 	*index = -1;
182 
183 	read_lock_irqsave(&device->cache.lock, flags);
184 
185 	if (!device->cache.pkey_cache)
186 		goto out;
187 
188 	cache = device->cache.pkey_cache[port_num - start_port(device)];
189 	if (!cache)
190 		goto out;
191 
192 	for (i = 0; i < cache->table_len; ++i)
193 		if ((cache->table[i] & 0x7fff) == (pkey & 0x7fff)) {
194 			if (cache->table[i] & 0x8000) {
195 				*index = i;
196 				ret = 0;
197 				break;
198 			} else
199 				partial_ix = i;
200 		}
201 
202 	if (ret && partial_ix >= 0) {
203 		*index = partial_ix;
204 		ret = 0;
205 	}
206 out:
207 	read_unlock_irqrestore(&device->cache.lock, flags);
208 	return ret;
209 }
210 EXPORT_SYMBOL(ib_find_cached_pkey);
211 
ib_find_exact_cached_pkey(struct ib_device * device,u8 port_num,u16 pkey,u16 * index)212 int ib_find_exact_cached_pkey(struct ib_device *device,
213 			      u8                port_num,
214 			      u16               pkey,
215 			      u16              *index)
216 {
217 	struct ib_pkey_cache *cache;
218 	unsigned long flags;
219 	int i;
220 	int ret = -ENOENT;
221 
222 	if (port_num < start_port(device) || port_num > end_port(device))
223 		return -EINVAL;
224 
225 	*index = -1;
226 
227 	read_lock_irqsave(&device->cache.lock, flags);
228 
229 	if (!device->cache.pkey_cache)
230 		goto out;
231 
232 	cache = device->cache.pkey_cache[port_num - start_port(device)];
233 	if (!cache)
234 		goto out;
235 
236 	for (i = 0; i < cache->table_len; ++i)
237 		if (cache->table[i] == pkey) {
238 			*index = i;
239 			ret = 0;
240 			break;
241 		}
242 out:
243 	read_unlock_irqrestore(&device->cache.lock, flags);
244 	return ret;
245 }
246 EXPORT_SYMBOL(ib_find_exact_cached_pkey);
247 
ib_get_cached_lmc(struct ib_device * device,u8 port_num,u8 * lmc)248 int ib_get_cached_lmc(struct ib_device *device,
249 		      u8                port_num,
250 		      u8                *lmc)
251 {
252 	unsigned long flags;
253 	int ret = -EINVAL;
254 
255 	if (port_num < start_port(device) || port_num > end_port(device))
256 		return -EINVAL;
257 
258 	read_lock_irqsave(&device->cache.lock, flags);
259 	if (device->cache.lmc_cache) {
260 		*lmc = device->cache.lmc_cache[port_num - start_port(device)];
261 		ret = 0;
262 	}
263 	read_unlock_irqrestore(&device->cache.lock, flags);
264 
265 	return ret;
266 }
267 EXPORT_SYMBOL(ib_get_cached_lmc);
268 
ib_cache_update(struct ib_device * device,u8 port)269 static void ib_cache_update(struct ib_device *device,
270 			    u8                port)
271 {
272 	struct ib_port_attr       *tprops = NULL;
273 	struct ib_pkey_cache      *pkey_cache = NULL, *old_pkey_cache;
274 	struct ib_gid_cache       *gid_cache = NULL, *old_gid_cache;
275 	int                        i;
276 	int                        ret;
277 
278 	if (!(device->cache.pkey_cache && device->cache.gid_cache &&
279 	      device->cache.lmc_cache))
280 		return;
281 
282 	tprops = kmalloc(sizeof *tprops, GFP_KERNEL);
283 	if (!tprops)
284 		return;
285 
286 	ret = ib_query_port(device, port, tprops);
287 	if (ret) {
288 		printk(KERN_WARNING "ib_query_port failed (%d) for %s\n",
289 		       ret, device->name);
290 		goto err;
291 	}
292 
293 	pkey_cache = kmalloc(sizeof *pkey_cache + tprops->pkey_tbl_len *
294 			     sizeof *pkey_cache->table, GFP_KERNEL);
295 	if (!pkey_cache)
296 		goto err;
297 
298 	pkey_cache->table_len = tprops->pkey_tbl_len;
299 
300 	gid_cache = kmalloc(sizeof *gid_cache + tprops->gid_tbl_len *
301 			    sizeof *gid_cache->table, GFP_KERNEL);
302 	if (!gid_cache)
303 		goto err;
304 
305 	gid_cache->table_len = tprops->gid_tbl_len;
306 
307 	for (i = 0; i < pkey_cache->table_len; ++i) {
308 		ret = ib_query_pkey(device, port, i, pkey_cache->table + i);
309 		if (ret) {
310 			printk(KERN_WARNING "ib_query_pkey failed (%d) for %s (index %d)\n",
311 			       ret, device->name, i);
312 			goto err;
313 		}
314 	}
315 
316 	for (i = 0; i < gid_cache->table_len; ++i) {
317 		ret = ib_query_gid(device, port, i, gid_cache->table + i);
318 		if (ret) {
319 			printk(KERN_WARNING "ib_query_gid failed (%d) for %s (index %d)\n",
320 			       ret, device->name, i);
321 			goto err;
322 		}
323 	}
324 
325 	write_lock_irq(&device->cache.lock);
326 
327 	old_pkey_cache = device->cache.pkey_cache[port - start_port(device)];
328 	old_gid_cache  = device->cache.gid_cache [port - start_port(device)];
329 
330 	device->cache.pkey_cache[port - start_port(device)] = pkey_cache;
331 	device->cache.gid_cache [port - start_port(device)] = gid_cache;
332 
333 	device->cache.lmc_cache[port - start_port(device)] = tprops->lmc;
334 
335 	write_unlock_irq(&device->cache.lock);
336 
337 	kfree(old_pkey_cache);
338 	kfree(old_gid_cache);
339 	kfree(tprops);
340 	return;
341 
342 err:
343 	kfree(pkey_cache);
344 	kfree(gid_cache);
345 	kfree(tprops);
346 }
347 
ib_cache_task(struct work_struct * _work)348 static void ib_cache_task(struct work_struct *_work)
349 {
350 	struct ib_update_work *work =
351 		container_of(_work, struct ib_update_work, work);
352 
353 	ib_cache_update(work->device, work->port_num);
354 	kfree(work);
355 }
356 
ib_cache_event(struct ib_event_handler * handler,struct ib_event * event)357 static void ib_cache_event(struct ib_event_handler *handler,
358 			   struct ib_event *event)
359 {
360 	struct ib_update_work *work;
361 
362 	if (event->event == IB_EVENT_PORT_ERR    ||
363 	    event->event == IB_EVENT_PORT_ACTIVE ||
364 	    event->event == IB_EVENT_LID_CHANGE  ||
365 	    event->event == IB_EVENT_PKEY_CHANGE ||
366 	    event->event == IB_EVENT_SM_CHANGE   ||
367 	    event->event == IB_EVENT_CLIENT_REREGISTER ||
368 	    event->event == IB_EVENT_GID_CHANGE) {
369 		work = kmalloc(sizeof *work, GFP_ATOMIC);
370 		if (work) {
371 			INIT_WORK(&work->work, ib_cache_task);
372 			work->device   = event->device;
373 			work->port_num = event->element.port_num;
374 			queue_work(ib_wq, &work->work);
375 		}
376 	}
377 }
378 
ib_cache_setup_one(struct ib_device * device)379 static void ib_cache_setup_one(struct ib_device *device)
380 {
381 	int p;
382 
383 	rwlock_init(&device->cache.lock);
384 
385 	device->cache.pkey_cache =
386 		kmalloc(sizeof *device->cache.pkey_cache *
387 			(end_port(device) - start_port(device) + 1), GFP_KERNEL);
388 	device->cache.gid_cache =
389 		kmalloc(sizeof *device->cache.gid_cache *
390 			(end_port(device) - start_port(device) + 1), GFP_KERNEL);
391 
392 	device->cache.lmc_cache = kmalloc(sizeof *device->cache.lmc_cache *
393 					  (end_port(device) -
394 					   start_port(device) + 1),
395 					  GFP_KERNEL);
396 
397 	if (!device->cache.pkey_cache || !device->cache.gid_cache ||
398 	    !device->cache.lmc_cache) {
399 		printk(KERN_WARNING "Couldn't allocate cache "
400 		       "for %s\n", device->name);
401 		goto err;
402 	}
403 
404 	for (p = 0; p <= end_port(device) - start_port(device); ++p) {
405 		device->cache.pkey_cache[p] = NULL;
406 		device->cache.gid_cache [p] = NULL;
407 		ib_cache_update(device, p + start_port(device));
408 	}
409 
410 	INIT_IB_EVENT_HANDLER(&device->cache.event_handler,
411 			      device, ib_cache_event);
412 	if (ib_register_event_handler(&device->cache.event_handler))
413 		goto err_cache;
414 
415 	return;
416 
417 err_cache:
418 	for (p = 0; p <= end_port(device) - start_port(device); ++p) {
419 		kfree(device->cache.pkey_cache[p]);
420 		kfree(device->cache.gid_cache[p]);
421 	}
422 
423 err:
424 	kfree(device->cache.pkey_cache);
425 	kfree(device->cache.gid_cache);
426 	kfree(device->cache.lmc_cache);
427 	device->cache.pkey_cache = NULL;
428 	device->cache.gid_cache = NULL;
429 	device->cache.lmc_cache = NULL;
430 }
431 
ib_cache_cleanup_one(struct ib_device * device)432 static void ib_cache_cleanup_one(struct ib_device *device)
433 {
434 	int p;
435 
436 	if (!(device->cache.pkey_cache && device->cache.gid_cache &&
437 	      device->cache.lmc_cache))
438 		return;
439 
440 	ib_unregister_event_handler(&device->cache.event_handler);
441 	flush_workqueue(ib_wq);
442 
443 	for (p = 0; p <= end_port(device) - start_port(device); ++p) {
444 		kfree(device->cache.pkey_cache[p]);
445 		kfree(device->cache.gid_cache[p]);
446 	}
447 
448 	kfree(device->cache.pkey_cache);
449 	kfree(device->cache.gid_cache);
450 	kfree(device->cache.lmc_cache);
451 }
452 
453 static struct ib_client cache_client = {
454 	.name   = "cache",
455 	.add    = ib_cache_setup_one,
456 	.remove = ib_cache_cleanup_one
457 };
458 
ib_cache_setup(void)459 int __init ib_cache_setup(void)
460 {
461 	return ib_register_client(&cache_client);
462 }
463 
ib_cache_cleanup(void)464 void __exit ib_cache_cleanup(void)
465 {
466 	ib_unregister_client(&cache_client);
467 }
468