diff options
author | Yosef Etigin <yosefe@voltaire.com> | 2007-05-14 00:26:51 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2007-05-19 11:51:53 -0400 |
commit | 5eb620c81ce35aa0c533131bf4d06c4c8c2bfadf (patch) | |
tree | 8c6346a3af0611b7b2e1b8df41cb058b5fc145e5 /drivers | |
parent | 8b8c8bca3a63073bac20f0fca178e00fdf7f5a09 (diff) |
IB/core: Add helpers for uncached GID and P_Key searches
Add ib_find_gid() and ib_find_pkey() functions that use uncached device
queries. The calls might block but the returns are always up-to-date.
Cache P_Key and GID table lengths in core to avoid extra port info queries.
Signed-off-by: Yosef Etigin <yosefe@voltaire.com>
Acked-by: Michael S. Tsirkin <mst@dev.mellanox.co.il>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/infiniband/core/device.c | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 592c90aa3183..b448e0b2b6b4 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c | |||
@@ -149,6 +149,18 @@ static int alloc_name(char *name) | |||
149 | return 0; | 149 | return 0; |
150 | } | 150 | } |
151 | 151 | ||
152 | static int start_port(struct ib_device *device) | ||
153 | { | ||
154 | return (device->node_type == RDMA_NODE_IB_SWITCH) ? 0 : 1; | ||
155 | } | ||
156 | |||
157 | |||
158 | static int end_port(struct ib_device *device) | ||
159 | { | ||
160 | return (device->node_type == RDMA_NODE_IB_SWITCH) ? | ||
161 | 0 : device->phys_port_cnt; | ||
162 | } | ||
163 | |||
152 | /** | 164 | /** |
153 | * ib_alloc_device - allocate an IB device struct | 165 | * ib_alloc_device - allocate an IB device struct |
154 | * @size:size of structure to allocate | 166 | * @size:size of structure to allocate |
@@ -208,6 +220,45 @@ static int add_client_context(struct ib_device *device, struct ib_client *client | |||
208 | return 0; | 220 | return 0; |
209 | } | 221 | } |
210 | 222 | ||
223 | static int read_port_table_lengths(struct ib_device *device) | ||
224 | { | ||
225 | struct ib_port_attr *tprops = NULL; | ||
226 | int num_ports, ret = -ENOMEM; | ||
227 | u8 port_index; | ||
228 | |||
229 | tprops = kmalloc(sizeof *tprops, GFP_KERNEL); | ||
230 | if (!tprops) | ||
231 | goto out; | ||
232 | |||
233 | num_ports = end_port(device) - start_port(device) + 1; | ||
234 | |||
235 | device->pkey_tbl_len = kmalloc(sizeof *device->pkey_tbl_len * num_ports, | ||
236 | GFP_KERNEL); | ||
237 | device->gid_tbl_len = kmalloc(sizeof *device->gid_tbl_len * num_ports, | ||
238 | GFP_KERNEL); | ||
239 | if (!device->pkey_tbl_len || !device->gid_tbl_len) | ||
240 | goto err; | ||
241 | |||
242 | for (port_index = 0; port_index < num_ports; ++port_index) { | ||
243 | ret = ib_query_port(device, port_index + start_port(device), | ||
244 | tprops); | ||
245 | if (ret) | ||
246 | goto err; | ||
247 | device->pkey_tbl_len[port_index] = tprops->pkey_tbl_len; | ||
248 | device->gid_tbl_len[port_index] = tprops->gid_tbl_len; | ||
249 | } | ||
250 | |||
251 | ret = 0; | ||
252 | goto out; | ||
253 | |||
254 | err: | ||
255 | kfree(device->gid_tbl_len); | ||
256 | kfree(device->pkey_tbl_len); | ||
257 | out: | ||
258 | kfree(tprops); | ||
259 | return ret; | ||
260 | } | ||
261 | |||
211 | /** | 262 | /** |
212 | * ib_register_device - Register an IB device with IB core | 263 | * ib_register_device - Register an IB device with IB core |
213 | * @device:Device to register | 264 | * @device:Device to register |
@@ -239,10 +290,19 @@ int ib_register_device(struct ib_device *device) | |||
239 | spin_lock_init(&device->event_handler_lock); | 290 | spin_lock_init(&device->event_handler_lock); |
240 | spin_lock_init(&device->client_data_lock); | 291 | spin_lock_init(&device->client_data_lock); |
241 | 292 | ||
293 | ret = read_port_table_lengths(device); | ||
294 | if (ret) { | ||
295 | printk(KERN_WARNING "Couldn't create table lengths cache for device %s\n", | ||
296 | device->name); | ||
297 | goto out; | ||
298 | } | ||
299 | |||
242 | ret = ib_device_register_sysfs(device); | 300 | ret = ib_device_register_sysfs(device); |
243 | if (ret) { | 301 | if (ret) { |
244 | printk(KERN_WARNING "Couldn't register device %s with driver model\n", | 302 | printk(KERN_WARNING "Couldn't register device %s with driver model\n", |
245 | device->name); | 303 | device->name); |
304 | kfree(device->gid_tbl_len); | ||
305 | kfree(device->pkey_tbl_len); | ||
246 | goto out; | 306 | goto out; |
247 | } | 307 | } |
248 | 308 | ||
@@ -284,6 +344,9 @@ void ib_unregister_device(struct ib_device *device) | |||
284 | 344 | ||
285 | list_del(&device->core_list); | 345 | list_del(&device->core_list); |
286 | 346 | ||
347 | kfree(device->gid_tbl_len); | ||
348 | kfree(device->pkey_tbl_len); | ||
349 | |||
287 | mutex_unlock(&device_mutex); | 350 | mutex_unlock(&device_mutex); |
288 | 351 | ||
289 | spin_lock_irqsave(&device->client_data_lock, flags); | 352 | spin_lock_irqsave(&device->client_data_lock, flags); |
@@ -592,6 +655,68 @@ int ib_modify_port(struct ib_device *device, | |||
592 | } | 655 | } |
593 | EXPORT_SYMBOL(ib_modify_port); | 656 | EXPORT_SYMBOL(ib_modify_port); |
594 | 657 | ||
658 | /** | ||
659 | * ib_find_gid - Returns the port number and GID table index where | ||
660 | * a specified GID value occurs. | ||
661 | * @device: The device to query. | ||
662 | * @gid: The GID value to search for. | ||
663 | * @port_num: The port number of the device where the GID value was found. | ||
664 | * @index: The index into the GID table where the GID was found. This | ||
665 | * parameter may be NULL. | ||
666 | */ | ||
667 | int ib_find_gid(struct ib_device *device, union ib_gid *gid, | ||
668 | u8 *port_num, u16 *index) | ||
669 | { | ||
670 | union ib_gid tmp_gid; | ||
671 | int ret, port, i; | ||
672 | |||
673 | for (port = start_port(device); port <= end_port(device); ++port) { | ||
674 | for (i = 0; i < device->gid_tbl_len[port - start_port(device)]; ++i) { | ||
675 | ret = ib_query_gid(device, port, i, &tmp_gid); | ||
676 | if (ret) | ||
677 | return ret; | ||
678 | if (!memcmp(&tmp_gid, gid, sizeof *gid)) { | ||
679 | *port_num = port; | ||
680 | if (index) | ||
681 | *index = i; | ||
682 | return 0; | ||
683 | } | ||
684 | } | ||
685 | } | ||
686 | |||
687 | return -ENOENT; | ||
688 | } | ||
689 | EXPORT_SYMBOL(ib_find_gid); | ||
690 | |||
691 | /** | ||
692 | * ib_find_pkey - Returns the PKey table index where a specified | ||
693 | * PKey value occurs. | ||
694 | * @device: The device to query. | ||
695 | * @port_num: The port number of the device to search for the PKey. | ||
696 | * @pkey: The PKey value to search for. | ||
697 | * @index: The index into the PKey table where the PKey was found. | ||
698 | */ | ||
699 | int ib_find_pkey(struct ib_device *device, | ||
700 | u8 port_num, u16 pkey, u16 *index) | ||
701 | { | ||
702 | int ret, i; | ||
703 | u16 tmp_pkey; | ||
704 | |||
705 | for (i = 0; i < device->pkey_tbl_len[port_num - start_port(device)]; ++i) { | ||
706 | ret = ib_query_pkey(device, port_num, i, &tmp_pkey); | ||
707 | if (ret) | ||
708 | return ret; | ||
709 | |||
710 | if (pkey == tmp_pkey) { | ||
711 | *index = i; | ||
712 | return 0; | ||
713 | } | ||
714 | } | ||
715 | |||
716 | return -ENOENT; | ||
717 | } | ||
718 | EXPORT_SYMBOL(ib_find_pkey); | ||
719 | |||
595 | static int __init ib_core_init(void) | 720 | static int __init ib_core_init(void) |
596 | { | 721 | { |
597 | int ret; | 722 | int ret; |