aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/core/cm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband/core/cm.c')
-rw-r--r--drivers/infiniband/core/cm.c119
1 files changed, 88 insertions, 31 deletions
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 86fee43502cd..450adfe0a4f1 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -32,7 +32,7 @@
32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 * SOFTWARE. 33 * SOFTWARE.
34 * 34 *
35 * $Id: cm.c 2821 2005-07-08 17:07:28Z sean.hefty $ 35 * $Id: cm.c 4311 2005-12-05 18:42:01Z sean.hefty $
36 */ 36 */
37 37
38#include <linux/completion.h> 38#include <linux/completion.h>
@@ -132,6 +132,7 @@ struct cm_id_private {
132 /* todo: use alternate port on send failure */ 132 /* todo: use alternate port on send failure */
133 struct cm_av av; 133 struct cm_av av;
134 struct cm_av alt_av; 134 struct cm_av alt_av;
135 struct ib_cm_compare_data *compare_data;
135 136
136 void *private_data; 137 void *private_data;
137 __be64 tid; 138 __be64 tid;
@@ -253,23 +254,13 @@ static void cm_set_private_data(struct cm_id_private *cm_id_priv,
253 cm_id_priv->private_data_len = private_data_len; 254 cm_id_priv->private_data_len = private_data_len;
254} 255}
255 256
256static void cm_set_ah_attr(struct ib_ah_attr *ah_attr, u8 port_num, 257static void cm_init_av_for_response(struct cm_port *port, struct ib_wc *wc,
257 u16 dlid, u8 sl, u16 src_path_bits) 258 struct ib_grh *grh, struct cm_av *av)
258{
259 memset(ah_attr, 0, sizeof ah_attr);
260 ah_attr->dlid = dlid;
261 ah_attr->sl = sl;
262 ah_attr->src_path_bits = src_path_bits;
263 ah_attr->port_num = port_num;
264}
265
266static void cm_init_av_for_response(struct cm_port *port,
267 struct ib_wc *wc, struct cm_av *av)
268{ 259{
269 av->port = port; 260 av->port = port;
270 av->pkey_index = wc->pkey_index; 261 av->pkey_index = wc->pkey_index;
271 cm_set_ah_attr(&av->ah_attr, port->port_num, wc->slid, 262 ib_init_ah_from_wc(port->cm_dev->device, port->port_num, wc,
272 wc->sl, wc->dlid_path_bits); 263 grh, &av->ah_attr);
273} 264}
274 265
275static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av) 266static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
@@ -299,9 +290,8 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
299 return ret; 290 return ret;
300 291
301 av->port = port; 292 av->port = port;
302 cm_set_ah_attr(&av->ah_attr, av->port->port_num, 293 ib_init_ah_from_path(cm_dev->device, port->port_num, path,
303 be16_to_cpu(path->dlid), path->sl, 294 &av->ah_attr);
304 be16_to_cpu(path->slid) & 0x7F);
305 av->packet_life_time = path->packet_life_time; 295 av->packet_life_time = path->packet_life_time;
306 return 0; 296 return 0;
307} 297}
@@ -357,6 +347,41 @@ static struct cm_id_private * cm_acquire_id(__be32 local_id, __be32 remote_id)
357 return cm_id_priv; 347 return cm_id_priv;
358} 348}
359 349
350static void cm_mask_copy(u8 *dst, u8 *src, u8 *mask)
351{
352 int i;
353
354 for (i = 0; i < IB_CM_COMPARE_SIZE / sizeof(unsigned long); i++)
355 ((unsigned long *) dst)[i] = ((unsigned long *) src)[i] &
356 ((unsigned long *) mask)[i];
357}
358
359static int cm_compare_data(struct ib_cm_compare_data *src_data,
360 struct ib_cm_compare_data *dst_data)
361{
362 u8 src[IB_CM_COMPARE_SIZE];
363 u8 dst[IB_CM_COMPARE_SIZE];
364
365 if (!src_data || !dst_data)
366 return 0;
367
368 cm_mask_copy(src, src_data->data, dst_data->mask);
369 cm_mask_copy(dst, dst_data->data, src_data->mask);
370 return memcmp(src, dst, IB_CM_COMPARE_SIZE);
371}
372
373static int cm_compare_private_data(u8 *private_data,
374 struct ib_cm_compare_data *dst_data)
375{
376 u8 src[IB_CM_COMPARE_SIZE];
377
378 if (!dst_data)
379 return 0;
380
381 cm_mask_copy(src, private_data, dst_data->mask);
382 return memcmp(src, dst_data->data, IB_CM_COMPARE_SIZE);
383}
384
360static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) 385static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
361{ 386{
362 struct rb_node **link = &cm.listen_service_table.rb_node; 387 struct rb_node **link = &cm.listen_service_table.rb_node;
@@ -364,14 +389,18 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
364 struct cm_id_private *cur_cm_id_priv; 389 struct cm_id_private *cur_cm_id_priv;
365 __be64 service_id = cm_id_priv->id.service_id; 390 __be64 service_id = cm_id_priv->id.service_id;
366 __be64 service_mask = cm_id_priv->id.service_mask; 391 __be64 service_mask = cm_id_priv->id.service_mask;
392 int data_cmp;
367 393
368 while (*link) { 394 while (*link) {
369 parent = *link; 395 parent = *link;
370 cur_cm_id_priv = rb_entry(parent, struct cm_id_private, 396 cur_cm_id_priv = rb_entry(parent, struct cm_id_private,
371 service_node); 397 service_node);
398 data_cmp = cm_compare_data(cm_id_priv->compare_data,
399 cur_cm_id_priv->compare_data);
372 if ((cur_cm_id_priv->id.service_mask & service_id) == 400 if ((cur_cm_id_priv->id.service_mask & service_id) ==
373 (service_mask & cur_cm_id_priv->id.service_id) && 401 (service_mask & cur_cm_id_priv->id.service_id) &&
374 (cm_id_priv->id.device == cur_cm_id_priv->id.device)) 402 (cm_id_priv->id.device == cur_cm_id_priv->id.device) &&
403 !data_cmp)
375 return cur_cm_id_priv; 404 return cur_cm_id_priv;
376 405
377 if (cm_id_priv->id.device < cur_cm_id_priv->id.device) 406 if (cm_id_priv->id.device < cur_cm_id_priv->id.device)
@@ -380,6 +409,10 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
380 link = &(*link)->rb_right; 409 link = &(*link)->rb_right;
381 else if (service_id < cur_cm_id_priv->id.service_id) 410 else if (service_id < cur_cm_id_priv->id.service_id)
382 link = &(*link)->rb_left; 411 link = &(*link)->rb_left;
412 else if (service_id > cur_cm_id_priv->id.service_id)
413 link = &(*link)->rb_right;
414 else if (data_cmp < 0)
415 link = &(*link)->rb_left;
383 else 416 else
384 link = &(*link)->rb_right; 417 link = &(*link)->rb_right;
385 } 418 }
@@ -389,16 +422,20 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv)
389} 422}
390 423
391static struct cm_id_private * cm_find_listen(struct ib_device *device, 424static struct cm_id_private * cm_find_listen(struct ib_device *device,
392 __be64 service_id) 425 __be64 service_id,
426 u8 *private_data)
393{ 427{
394 struct rb_node *node = cm.listen_service_table.rb_node; 428 struct rb_node *node = cm.listen_service_table.rb_node;
395 struct cm_id_private *cm_id_priv; 429 struct cm_id_private *cm_id_priv;
430 int data_cmp;
396 431
397 while (node) { 432 while (node) {
398 cm_id_priv = rb_entry(node, struct cm_id_private, service_node); 433 cm_id_priv = rb_entry(node, struct cm_id_private, service_node);
434 data_cmp = cm_compare_private_data(private_data,
435 cm_id_priv->compare_data);
399 if ((cm_id_priv->id.service_mask & service_id) == 436 if ((cm_id_priv->id.service_mask & service_id) ==
400 cm_id_priv->id.service_id && 437 cm_id_priv->id.service_id &&
401 (cm_id_priv->id.device == device)) 438 (cm_id_priv->id.device == device) && !data_cmp)
402 return cm_id_priv; 439 return cm_id_priv;
403 440
404 if (device < cm_id_priv->id.device) 441 if (device < cm_id_priv->id.device)
@@ -407,6 +444,10 @@ static struct cm_id_private * cm_find_listen(struct ib_device *device,
407 node = node->rb_right; 444 node = node->rb_right;
408 else if (service_id < cm_id_priv->id.service_id) 445 else if (service_id < cm_id_priv->id.service_id)
409 node = node->rb_left; 446 node = node->rb_left;
447 else if (service_id > cm_id_priv->id.service_id)
448 node = node->rb_right;
449 else if (data_cmp < 0)
450 node = node->rb_left;
410 else 451 else
411 node = node->rb_right; 452 node = node->rb_right;
412 } 453 }
@@ -730,15 +771,14 @@ retest:
730 wait_for_completion(&cm_id_priv->comp); 771 wait_for_completion(&cm_id_priv->comp);
731 while ((work = cm_dequeue_work(cm_id_priv)) != NULL) 772 while ((work = cm_dequeue_work(cm_id_priv)) != NULL)
732 cm_free_work(work); 773 cm_free_work(work);
733 if (cm_id_priv->private_data && cm_id_priv->private_data_len) 774 kfree(cm_id_priv->compare_data);
734 kfree(cm_id_priv->private_data); 775 kfree(cm_id_priv->private_data);
735 kfree(cm_id_priv); 776 kfree(cm_id_priv);
736} 777}
737EXPORT_SYMBOL(ib_destroy_cm_id); 778EXPORT_SYMBOL(ib_destroy_cm_id);
738 779
739int ib_cm_listen(struct ib_cm_id *cm_id, 780int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask,
740 __be64 service_id, 781 struct ib_cm_compare_data *compare_data)
741 __be64 service_mask)
742{ 782{
743 struct cm_id_private *cm_id_priv, *cur_cm_id_priv; 783 struct cm_id_private *cm_id_priv, *cur_cm_id_priv;
744 unsigned long flags; 784 unsigned long flags;
@@ -752,7 +792,19 @@ int ib_cm_listen(struct ib_cm_id *cm_id,
752 return -EINVAL; 792 return -EINVAL;
753 793
754 cm_id_priv = container_of(cm_id, struct cm_id_private, id); 794 cm_id_priv = container_of(cm_id, struct cm_id_private, id);
755 BUG_ON(cm_id->state != IB_CM_IDLE); 795 if (cm_id->state != IB_CM_IDLE)
796 return -EINVAL;
797
798 if (compare_data) {
799 cm_id_priv->compare_data = kzalloc(sizeof *compare_data,
800 GFP_KERNEL);
801 if (!cm_id_priv->compare_data)
802 return -ENOMEM;
803 cm_mask_copy(cm_id_priv->compare_data->data,
804 compare_data->data, compare_data->mask);
805 memcpy(cm_id_priv->compare_data->mask, compare_data->mask,
806 IB_CM_COMPARE_SIZE);
807 }
756 808
757 cm_id->state = IB_CM_LISTEN; 809 cm_id->state = IB_CM_LISTEN;
758 810
@@ -769,6 +821,8 @@ int ib_cm_listen(struct ib_cm_id *cm_id,
769 821
770 if (cur_cm_id_priv) { 822 if (cur_cm_id_priv) {
771 cm_id->state = IB_CM_IDLE; 823 cm_id->state = IB_CM_IDLE;
824 kfree(cm_id_priv->compare_data);
825 cm_id_priv->compare_data = NULL;
772 ret = -EBUSY; 826 ret = -EBUSY;
773 } 827 }
774 return ret; 828 return ret;
@@ -1241,7 +1295,8 @@ static struct cm_id_private * cm_match_req(struct cm_work *work,
1241 1295
1242 /* Find matching listen request. */ 1296 /* Find matching listen request. */
1243 listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device, 1297 listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device,
1244 req_msg->service_id); 1298 req_msg->service_id,
1299 req_msg->private_data);
1245 if (!listen_cm_id_priv) { 1300 if (!listen_cm_id_priv) {
1246 spin_unlock_irqrestore(&cm.lock, flags); 1301 spin_unlock_irqrestore(&cm.lock, flags);
1247 cm_issue_rej(work->port, work->mad_recv_wc, 1302 cm_issue_rej(work->port, work->mad_recv_wc,
@@ -1276,6 +1331,7 @@ static int cm_req_handler(struct cm_work *work)
1276 cm_id_priv = container_of(cm_id, struct cm_id_private, id); 1331 cm_id_priv = container_of(cm_id, struct cm_id_private, id);
1277 cm_id_priv->id.remote_id = req_msg->local_comm_id; 1332 cm_id_priv->id.remote_id = req_msg->local_comm_id;
1278 cm_init_av_for_response(work->port, work->mad_recv_wc->wc, 1333 cm_init_av_for_response(work->port, work->mad_recv_wc->wc,
1334 work->mad_recv_wc->recv_buf.grh,
1279 &cm_id_priv->av); 1335 &cm_id_priv->av);
1280 cm_id_priv->timewait_info = cm_create_timewait_info(cm_id_priv-> 1336 cm_id_priv->timewait_info = cm_create_timewait_info(cm_id_priv->
1281 id.local_id); 1337 id.local_id);
@@ -2549,7 +2605,7 @@ static void cm_format_sidr_req(struct cm_sidr_req_msg *sidr_req_msg,
2549 cm_format_mad_hdr(&sidr_req_msg->hdr, CM_SIDR_REQ_ATTR_ID, 2605 cm_format_mad_hdr(&sidr_req_msg->hdr, CM_SIDR_REQ_ATTR_ID,
2550 cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_SIDR)); 2606 cm_form_tid(cm_id_priv, CM_MSG_SEQUENCE_SIDR));
2551 sidr_req_msg->request_id = cm_id_priv->id.local_id; 2607 sidr_req_msg->request_id = cm_id_priv->id.local_id;
2552 sidr_req_msg->pkey = cpu_to_be16(param->pkey); 2608 sidr_req_msg->pkey = cpu_to_be16(param->path->pkey);
2553 sidr_req_msg->service_id = param->service_id; 2609 sidr_req_msg->service_id = param->service_id;
2554 2610
2555 if (param->private_data && param->private_data_len) 2611 if (param->private_data && param->private_data_len)
@@ -2641,6 +2697,7 @@ static int cm_sidr_req_handler(struct cm_work *work)
2641 cm_id_priv->av.dgid.global.subnet_prefix = cpu_to_be64(wc->slid); 2697 cm_id_priv->av.dgid.global.subnet_prefix = cpu_to_be64(wc->slid);
2642 cm_id_priv->av.dgid.global.interface_id = 0; 2698 cm_id_priv->av.dgid.global.interface_id = 0;
2643 cm_init_av_for_response(work->port, work->mad_recv_wc->wc, 2699 cm_init_av_for_response(work->port, work->mad_recv_wc->wc,
2700 work->mad_recv_wc->recv_buf.grh,
2644 &cm_id_priv->av); 2701 &cm_id_priv->av);
2645 cm_id_priv->id.remote_id = sidr_req_msg->request_id; 2702 cm_id_priv->id.remote_id = sidr_req_msg->request_id;
2646 cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD; 2703 cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD;
@@ -2654,7 +2711,8 @@ static int cm_sidr_req_handler(struct cm_work *work)
2654 goto out; /* Duplicate message. */ 2711 goto out; /* Duplicate message. */
2655 } 2712 }
2656 cur_cm_id_priv = cm_find_listen(cm_id->device, 2713 cur_cm_id_priv = cm_find_listen(cm_id->device,
2657 sidr_req_msg->service_id); 2714 sidr_req_msg->service_id,
2715 sidr_req_msg->private_data);
2658 if (!cur_cm_id_priv) { 2716 if (!cur_cm_id_priv) {
2659 rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); 2717 rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table);
2660 spin_unlock_irqrestore(&cm.lock, flags); 2718 spin_unlock_irqrestore(&cm.lock, flags);
@@ -3291,7 +3349,6 @@ error:
3291 3349
3292static void __exit ib_cm_cleanup(void) 3350static void __exit ib_cm_cleanup(void)
3293{ 3351{
3294 flush_workqueue(cm.wq);
3295 destroy_workqueue(cm.wq); 3352 destroy_workqueue(cm.wq);
3296 ib_unregister_client(&cm_client); 3353 ib_unregister_client(&cm_client);
3297 idr_destroy(&cm.local_id_table); 3354 idr_destroy(&cm.local_id_table);