xref: /linux/drivers/infiniband/core/cache.c (revision 13abf8130139c2ccd4962a7e5a8902be5e6cb5a7)
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 <linux/module.h>
39 #include <linux/errno.h>
40 #include <linux/slab.h>
41 
42 #include <rdma/ib_cache.h>
43 
44 #include "core_priv.h"
45 
46 struct ib_pkey_cache {
47 	int             table_len;
48 	u16             table[0];
49 };
50 
51 struct ib_gid_cache {
52 	int             table_len;
53 	union ib_gid    table[0];
54 };
55 
56 struct ib_update_work {
57 	struct work_struct work;
58 	struct ib_device  *device;
59 	u8                 port_num;
60 };
61 
62 static inline int start_port(struct ib_device *device)
63 {
64 	return device->node_type == IB_NODE_SWITCH ? 0 : 1;
65 }
66 
67 static inline int end_port(struct ib_device *device)
68 {
69 	return device->node_type == IB_NODE_SWITCH ? 0 : device->phys_port_cnt;
70 }
71 
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 = 0;
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 	cache = device->cache.gid_cache[port_num - start_port(device)];
87 
88 	if (index < 0 || index >= cache->table_len)
89 		ret = -EINVAL;
90 	else
91 		*gid = cache->table[index];
92 
93 	read_unlock_irqrestore(&device->cache.lock, flags);
94 
95 	return ret;
96 }
97 EXPORT_SYMBOL(ib_get_cached_gid);
98 
99 int ib_find_cached_gid(struct ib_device *device,
100 		       union ib_gid	*gid,
101 		       u8               *port_num,
102 		       u16              *index)
103 {
104 	struct ib_gid_cache *cache;
105 	unsigned long flags;
106 	int p, i;
107 	int ret = -ENOENT;
108 
109 	*port_num = -1;
110 	if (index)
111 		*index = -1;
112 
113 	read_lock_irqsave(&device->cache.lock, flags);
114 
115 	for (p = 0; p <= end_port(device) - start_port(device); ++p) {
116 		cache = device->cache.gid_cache[p];
117 		for (i = 0; i < cache->table_len; ++i) {
118 			if (!memcmp(gid, &cache->table[i], sizeof *gid)) {
119 				*port_num = p + start_port(device);
120 				if (index)
121 					*index = i;
122 				ret = 0;
123 				goto found;
124 			}
125 		}
126 	}
127 found:
128 	read_unlock_irqrestore(&device->cache.lock, flags);
129 
130 	return ret;
131 }
132 EXPORT_SYMBOL(ib_find_cached_gid);
133 
134 int ib_get_cached_pkey(struct ib_device *device,
135 		       u8                port_num,
136 		       int               index,
137 		       u16              *pkey)
138 {
139 	struct ib_pkey_cache *cache;
140 	unsigned long flags;
141 	int ret = 0;
142 
143 	if (port_num < start_port(device) || port_num > end_port(device))
144 		return -EINVAL;
145 
146 	read_lock_irqsave(&device->cache.lock, flags);
147 
148 	cache = device->cache.pkey_cache[port_num - start_port(device)];
149 
150 	if (index < 0 || index >= cache->table_len)
151 		ret = -EINVAL;
152 	else
153 		*pkey = cache->table[index];
154 
155 	read_unlock_irqrestore(&device->cache.lock, flags);
156 
157 	return ret;
158 }
159 EXPORT_SYMBOL(ib_get_cached_pkey);
160 
161 int ib_find_cached_pkey(struct ib_device *device,
162 			u8                port_num,
163 			u16               pkey,
164 			u16              *index)
165 {
166 	struct ib_pkey_cache *cache;
167 	unsigned long flags;
168 	int i;
169 	int ret = -ENOENT;
170 
171 	if (port_num < start_port(device) || port_num > end_port(device))
172 		return -EINVAL;
173 
174 	read_lock_irqsave(&device->cache.lock, flags);
175 
176 	cache = device->cache.pkey_cache[port_num - start_port(device)];
177 
178 	*index = -1;
179 
180 	for (i = 0; i < cache->table_len; ++i)
181 		if ((cache->table[i] & 0x7fff) == (pkey & 0x7fff)) {
182 			*index = i;
183 			ret = 0;
184 			break;
185 		}
186 
187 	read_unlock_irqrestore(&device->cache.lock, flags);
188 
189 	return ret;
190 }
191 EXPORT_SYMBOL(ib_find_cached_pkey);
192 
193 static void ib_cache_update(struct ib_device *device,
194 			    u8                port)
195 {
196 	struct ib_port_attr       *tprops = NULL;
197 	struct ib_pkey_cache      *pkey_cache = NULL, *old_pkey_cache;
198 	struct ib_gid_cache       *gid_cache = NULL, *old_gid_cache;
199 	int                        i;
200 	int                        ret;
201 
202 	tprops = kmalloc(sizeof *tprops, GFP_KERNEL);
203 	if (!tprops)
204 		return;
205 
206 	ret = ib_query_port(device, port, tprops);
207 	if (ret) {
208 		printk(KERN_WARNING "ib_query_port failed (%d) for %s\n",
209 		       ret, device->name);
210 		goto err;
211 	}
212 
213 	pkey_cache = kmalloc(sizeof *pkey_cache + tprops->pkey_tbl_len *
214 			     sizeof *pkey_cache->table, GFP_KERNEL);
215 	if (!pkey_cache)
216 		goto err;
217 
218 	pkey_cache->table_len = tprops->pkey_tbl_len;
219 
220 	gid_cache = kmalloc(sizeof *gid_cache + tprops->gid_tbl_len *
221 			    sizeof *gid_cache->table, GFP_KERNEL);
222 	if (!gid_cache)
223 		goto err;
224 
225 	gid_cache->table_len = tprops->gid_tbl_len;
226 
227 	for (i = 0; i < pkey_cache->table_len; ++i) {
228 		ret = ib_query_pkey(device, port, i, pkey_cache->table + i);
229 		if (ret) {
230 			printk(KERN_WARNING "ib_query_pkey failed (%d) for %s (index %d)\n",
231 			       ret, device->name, i);
232 			goto err;
233 		}
234 	}
235 
236 	for (i = 0; i < gid_cache->table_len; ++i) {
237 		ret = ib_query_gid(device, port, i, gid_cache->table + i);
238 		if (ret) {
239 			printk(KERN_WARNING "ib_query_gid failed (%d) for %s (index %d)\n",
240 			       ret, device->name, i);
241 			goto err;
242 		}
243 	}
244 
245 	write_lock_irq(&device->cache.lock);
246 
247 	old_pkey_cache = device->cache.pkey_cache[port - start_port(device)];
248 	old_gid_cache  = device->cache.gid_cache [port - start_port(device)];
249 
250 	device->cache.pkey_cache[port - start_port(device)] = pkey_cache;
251 	device->cache.gid_cache [port - start_port(device)] = gid_cache;
252 
253 	write_unlock_irq(&device->cache.lock);
254 
255 	kfree(old_pkey_cache);
256 	kfree(old_gid_cache);
257 	kfree(tprops);
258 	return;
259 
260 err:
261 	kfree(pkey_cache);
262 	kfree(gid_cache);
263 	kfree(tprops);
264 }
265 
266 static void ib_cache_task(void *work_ptr)
267 {
268 	struct ib_update_work *work = work_ptr;
269 
270 	ib_cache_update(work->device, work->port_num);
271 	kfree(work);
272 }
273 
274 static void ib_cache_event(struct ib_event_handler *handler,
275 			   struct ib_event *event)
276 {
277 	struct ib_update_work *work;
278 
279 	if (event->event == IB_EVENT_PORT_ERR    ||
280 	    event->event == IB_EVENT_PORT_ACTIVE ||
281 	    event->event == IB_EVENT_LID_CHANGE  ||
282 	    event->event == IB_EVENT_PKEY_CHANGE ||
283 	    event->event == IB_EVENT_SM_CHANGE) {
284 		work = kmalloc(sizeof *work, GFP_ATOMIC);
285 		if (work) {
286 			INIT_WORK(&work->work, ib_cache_task, work);
287 			work->device   = event->device;
288 			work->port_num = event->element.port_num;
289 			schedule_work(&work->work);
290 		}
291 	}
292 }
293 
294 static void ib_cache_setup_one(struct ib_device *device)
295 {
296 	int p;
297 
298 	rwlock_init(&device->cache.lock);
299 
300 	device->cache.pkey_cache =
301 		kmalloc(sizeof *device->cache.pkey_cache *
302 			(end_port(device) - start_port(device) + 1), GFP_KERNEL);
303 	device->cache.gid_cache =
304 		kmalloc(sizeof *device->cache.pkey_cache *
305 			(end_port(device) - start_port(device) + 1), GFP_KERNEL);
306 
307 	if (!device->cache.pkey_cache || !device->cache.gid_cache) {
308 		printk(KERN_WARNING "Couldn't allocate cache "
309 		       "for %s\n", device->name);
310 		goto err;
311 	}
312 
313 	for (p = 0; p <= end_port(device) - start_port(device); ++p) {
314 		device->cache.pkey_cache[p] = NULL;
315 		device->cache.gid_cache [p] = NULL;
316 		ib_cache_update(device, p + start_port(device));
317 	}
318 
319 	INIT_IB_EVENT_HANDLER(&device->cache.event_handler,
320 			      device, ib_cache_event);
321 	if (ib_register_event_handler(&device->cache.event_handler))
322 		goto err_cache;
323 
324 	return;
325 
326 err_cache:
327 	for (p = 0; p <= end_port(device) - start_port(device); ++p) {
328 		kfree(device->cache.pkey_cache[p]);
329 		kfree(device->cache.gid_cache[p]);
330 	}
331 
332 err:
333 	kfree(device->cache.pkey_cache);
334 	kfree(device->cache.gid_cache);
335 }
336 
337 static void ib_cache_cleanup_one(struct ib_device *device)
338 {
339 	int p;
340 
341 	ib_unregister_event_handler(&device->cache.event_handler);
342 	flush_scheduled_work();
343 
344 	for (p = 0; p <= end_port(device) - start_port(device); ++p) {
345 		kfree(device->cache.pkey_cache[p]);
346 		kfree(device->cache.gid_cache[p]);
347 	}
348 
349 	kfree(device->cache.pkey_cache);
350 	kfree(device->cache.gid_cache);
351 }
352 
353 static struct ib_client cache_client = {
354 	.name   = "cache",
355 	.add    = ib_cache_setup_one,
356 	.remove = ib_cache_cleanup_one
357 };
358 
359 int __init ib_cache_setup(void)
360 {
361 	return ib_register_client(&cache_client);
362 }
363 
364 void __exit ib_cache_cleanup(void)
365 {
366 	ib_unregister_client(&cache_client);
367 }
368