aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/core/user_mad.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@starflyer.(none)>2006-01-03 02:18:01 -0500
committerDave Airlie <airlied@linux.ie>2006-01-03 02:18:01 -0500
commit97f2aab6698f3ab2552c41c1024a65ffd0763a6d (patch)
treebb6e3b2949459f54f884c710fc74d40eef00d834 /drivers/infiniband/core/user_mad.c
parentd985c1088146607532093d9eaaaf99758f6a4d21 (diff)
parent88026842b0a760145aa71d69e74fbc9ec118ca44 (diff)
drm: merge in Linus mainline
Diffstat (limited to 'drivers/infiniband/core/user_mad.c')
-rw-r--r--drivers/infiniband/core/user_mad.c172
1 files changed, 99 insertions, 73 deletions
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index aed5ca23fb22..eb7f52537ccc 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -31,7 +31,7 @@
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 * SOFTWARE. 32 * SOFTWARE.
33 * 33 *
34 * $Id: user_mad.c 2814 2005-07-06 19:14:09Z halr $ 34 * $Id: user_mad.c 4010 2005-11-09 23:11:56Z roland $
35 */ 35 */
36 36
37#include <linux/module.h> 37#include <linux/module.h>
@@ -110,13 +110,13 @@ struct ib_umad_device {
110}; 110};
111 111
112struct ib_umad_file { 112struct ib_umad_file {
113 struct ib_umad_port *port; 113 struct ib_umad_port *port;
114 struct list_head recv_list; 114 struct list_head recv_list;
115 struct list_head port_list; 115 struct list_head port_list;
116 spinlock_t recv_lock; 116 spinlock_t recv_lock;
117 wait_queue_head_t recv_wait; 117 wait_queue_head_t recv_wait;
118 struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS]; 118 struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS];
119 struct ib_mr *mr[IB_UMAD_MAX_AGENTS]; 119 int agents_dead;
120}; 120};
121 121
122struct ib_umad_packet { 122struct ib_umad_packet {
@@ -145,6 +145,12 @@ static void ib_umad_release_dev(struct kref *ref)
145 kfree(dev); 145 kfree(dev);
146} 146}
147 147
148/* caller must hold port->mutex at least for reading */
149static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id)
150{
151 return file->agents_dead ? NULL : file->agent[id];
152}
153
148static int queue_packet(struct ib_umad_file *file, 154static int queue_packet(struct ib_umad_file *file,
149 struct ib_mad_agent *agent, 155 struct ib_mad_agent *agent,
150 struct ib_umad_packet *packet) 156 struct ib_umad_packet *packet)
@@ -152,10 +158,11 @@ static int queue_packet(struct ib_umad_file *file,
152 int ret = 1; 158 int ret = 1;
153 159
154 down_read(&file->port->mutex); 160 down_read(&file->port->mutex);
161
155 for (packet->mad.hdr.id = 0; 162 for (packet->mad.hdr.id = 0;
156 packet->mad.hdr.id < IB_UMAD_MAX_AGENTS; 163 packet->mad.hdr.id < IB_UMAD_MAX_AGENTS;
157 packet->mad.hdr.id++) 164 packet->mad.hdr.id++)
158 if (agent == file->agent[packet->mad.hdr.id]) { 165 if (agent == __get_agent(file, packet->mad.hdr.id)) {
159 spin_lock_irq(&file->recv_lock); 166 spin_lock_irq(&file->recv_lock);
160 list_add_tail(&packet->list, &file->recv_list); 167 list_add_tail(&packet->list, &file->recv_list);
161 spin_unlock_irq(&file->recv_lock); 168 spin_unlock_irq(&file->recv_lock);
@@ -303,9 +310,9 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
303 u8 method; 310 u8 method;
304 __be64 *tid; 311 __be64 *tid;
305 int ret, length, hdr_len, copy_offset; 312 int ret, length, hdr_len, copy_offset;
306 int rmpp_active = 0; 313 int rmpp_active, has_rmpp_header;
307 314
308 if (count < sizeof (struct ib_user_mad)) 315 if (count < sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR)
309 return -EINVAL; 316 return -EINVAL;
310 317
311 length = count - sizeof (struct ib_user_mad); 318 length = count - sizeof (struct ib_user_mad);
@@ -327,7 +334,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
327 334
328 down_read(&file->port->mutex); 335 down_read(&file->port->mutex);
329 336
330 agent = file->agent[packet->mad.hdr.id]; 337 agent = __get_agent(file, packet->mad.hdr.id);
331 if (!agent) { 338 if (!agent) {
332 ret = -EINVAL; 339 ret = -EINVAL;
333 goto err_up; 340 goto err_up;
@@ -353,28 +360,31 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
353 } 360 }
354 361
355 rmpp_mad = (struct ib_rmpp_mad *) packet->mad.data; 362 rmpp_mad = (struct ib_rmpp_mad *) packet->mad.data;
356 if (ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & IB_MGMT_RMPP_FLAG_ACTIVE) { 363 if (rmpp_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_ADM) {
357 /* RMPP active */ 364 hdr_len = IB_MGMT_SA_HDR;
358 if (!agent->rmpp_version) {
359 ret = -EINVAL;
360 goto err_ah;
361 }
362
363 /* Validate that the management class can support RMPP */
364 if (rmpp_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_ADM) {
365 hdr_len = IB_MGMT_SA_HDR;
366 } else if ((rmpp_mad->mad_hdr.mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) &&
367 (rmpp_mad->mad_hdr.mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END)) {
368 hdr_len = IB_MGMT_VENDOR_HDR;
369 } else {
370 ret = -EINVAL;
371 goto err_ah;
372 }
373 rmpp_active = 1;
374 copy_offset = IB_MGMT_RMPP_HDR; 365 copy_offset = IB_MGMT_RMPP_HDR;
366 has_rmpp_header = 1;
367 } else if (rmpp_mad->mad_hdr.mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START &&
368 rmpp_mad->mad_hdr.mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END) {
369 hdr_len = IB_MGMT_VENDOR_HDR;
370 copy_offset = IB_MGMT_RMPP_HDR;
371 has_rmpp_header = 1;
375 } else { 372 } else {
376 hdr_len = IB_MGMT_MAD_HDR; 373 hdr_len = IB_MGMT_MAD_HDR;
377 copy_offset = IB_MGMT_MAD_HDR; 374 copy_offset = IB_MGMT_MAD_HDR;
375 has_rmpp_header = 0;
376 }
377
378 if (has_rmpp_header)
379 rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
380 IB_MGMT_RMPP_FLAG_ACTIVE;
381 else
382 rmpp_active = 0;
383
384 /* Validate that the management class can support RMPP */
385 if (rmpp_active && !agent->rmpp_version) {
386 ret = -EINVAL;
387 goto err_ah;
378 } 388 }
379 389
380 packet->msg = ib_create_send_mad(agent, 390 packet->msg = ib_create_send_mad(agent,
@@ -481,7 +491,7 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, unsigned long arg)
481 } 491 }
482 492
483 for (agent_id = 0; agent_id < IB_UMAD_MAX_AGENTS; ++agent_id) 493 for (agent_id = 0; agent_id < IB_UMAD_MAX_AGENTS; ++agent_id)
484 if (!file->agent[agent_id]) 494 if (!__get_agent(file, agent_id))
485 goto found; 495 goto found;
486 496
487 ret = -ENOMEM; 497 ret = -ENOMEM;
@@ -505,29 +515,15 @@ found:
505 goto out; 515 goto out;
506 } 516 }
507 517
508 file->agent[agent_id] = agent;
509
510 file->mr[agent_id] = ib_get_dma_mr(agent->qp->pd, IB_ACCESS_LOCAL_WRITE);
511 if (IS_ERR(file->mr[agent_id])) {
512 ret = -ENOMEM;
513 goto err;
514 }
515
516 if (put_user(agent_id, 518 if (put_user(agent_id,
517 (u32 __user *) (arg + offsetof(struct ib_user_mad_reg_req, id)))) { 519 (u32 __user *) (arg + offsetof(struct ib_user_mad_reg_req, id)))) {
518 ret = -EFAULT; 520 ret = -EFAULT;
519 goto err_mr; 521 ib_unregister_mad_agent(agent);
522 goto out;
520 } 523 }
521 524
525 file->agent[agent_id] = agent;
522 ret = 0; 526 ret = 0;
523 goto out;
524
525err_mr:
526 ib_dereg_mr(file->mr[agent_id]);
527
528err:
529 file->agent[agent_id] = NULL;
530 ib_unregister_mad_agent(agent);
531 527
532out: 528out:
533 up_write(&file->port->mutex); 529 up_write(&file->port->mutex);
@@ -536,27 +532,29 @@ out:
536 532
537static int ib_umad_unreg_agent(struct ib_umad_file *file, unsigned long arg) 533static int ib_umad_unreg_agent(struct ib_umad_file *file, unsigned long arg)
538{ 534{
535 struct ib_mad_agent *agent = NULL;
539 u32 id; 536 u32 id;
540 int ret = 0; 537 int ret = 0;
541 538
542 down_write(&file->port->mutex); 539 if (get_user(id, (u32 __user *) arg))
540 return -EFAULT;
543 541
544 if (get_user(id, (u32 __user *) arg)) { 542 down_write(&file->port->mutex);
545 ret = -EFAULT;
546 goto out;
547 }
548 543
549 if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !file->agent[id]) { 544 if (id < 0 || id >= IB_UMAD_MAX_AGENTS || !__get_agent(file, id)) {
550 ret = -EINVAL; 545 ret = -EINVAL;
551 goto out; 546 goto out;
552 } 547 }
553 548
554 ib_dereg_mr(file->mr[id]); 549 agent = file->agent[id];
555 ib_unregister_mad_agent(file->agent[id]);
556 file->agent[id] = NULL; 550 file->agent[id] = NULL;
557 551
558out: 552out:
559 up_write(&file->port->mutex); 553 up_write(&file->port->mutex);
554
555 if (agent)
556 ib_unregister_mad_agent(agent);
557
560 return ret; 558 return ret;
561} 559}
562 560
@@ -621,23 +619,29 @@ static int ib_umad_close(struct inode *inode, struct file *filp)
621 struct ib_umad_file *file = filp->private_data; 619 struct ib_umad_file *file = filp->private_data;
622 struct ib_umad_device *dev = file->port->umad_dev; 620 struct ib_umad_device *dev = file->port->umad_dev;
623 struct ib_umad_packet *packet, *tmp; 621 struct ib_umad_packet *packet, *tmp;
622 int already_dead;
624 int i; 623 int i;
625 624
626 down_write(&file->port->mutex); 625 down_write(&file->port->mutex);
627 for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i) 626
628 if (file->agent[i]) { 627 already_dead = file->agents_dead;
629 ib_dereg_mr(file->mr[i]); 628 file->agents_dead = 1;
630 ib_unregister_mad_agent(file->agent[i]);
631 }
632 629
633 list_for_each_entry_safe(packet, tmp, &file->recv_list, list) 630 list_for_each_entry_safe(packet, tmp, &file->recv_list, list)
634 kfree(packet); 631 kfree(packet);
635 632
636 list_del(&file->port_list); 633 list_del(&file->port_list);
637 up_write(&file->port->mutex);
638 634
639 kfree(file); 635 downgrade_write(&file->port->mutex);
636
637 if (!already_dead)
638 for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i)
639 if (file->agent[i])
640 ib_unregister_mad_agent(file->agent[i]);
640 641
642 up_read(&file->port->mutex);
643
644 kfree(file);
641 kref_put(&dev->ref, ib_umad_release_dev); 645 kref_put(&dev->ref, ib_umad_release_dev);
642 646
643 return 0; 647 return 0;
@@ -801,7 +805,7 @@ static int ib_umad_init_port(struct ib_device *device, int port_num,
801 goto err_class; 805 goto err_class;
802 port->sm_dev->owner = THIS_MODULE; 806 port->sm_dev->owner = THIS_MODULE;
803 port->sm_dev->ops = &umad_sm_fops; 807 port->sm_dev->ops = &umad_sm_fops;
804 kobject_set_name(&port->dev->kobj, "issm%d", port->dev_num); 808 kobject_set_name(&port->sm_dev->kobj, "issm%d", port->dev_num);
805 if (cdev_add(port->sm_dev, base_dev + port->dev_num + IB_UMAD_MAX_PORTS, 1)) 809 if (cdev_add(port->sm_dev, base_dev + port->dev_num + IB_UMAD_MAX_PORTS, 1))
806 goto err_sm_cdev; 810 goto err_sm_cdev;
807 811
@@ -863,14 +867,36 @@ static void ib_umad_kill_port(struct ib_umad_port *port)
863 867
864 port->ib_dev = NULL; 868 port->ib_dev = NULL;
865 869
866 list_for_each_entry(file, &port->file_list, port_list) 870 /*
867 for (id = 0; id < IB_UMAD_MAX_AGENTS; ++id) { 871 * Now go through the list of files attached to this port and
868 if (!file->agent[id]) 872 * unregister all of their MAD agents. We need to hold
869 continue; 873 * port->mutex while doing this to avoid racing with
870 ib_dereg_mr(file->mr[id]); 874 * ib_umad_close(), but we can't hold the mutex for writing
871 ib_unregister_mad_agent(file->agent[id]); 875 * while calling ib_unregister_mad_agent(), since that might
872 file->agent[id] = NULL; 876 * deadlock by calling back into queue_packet(). So we
873 } 877 * downgrade our lock to a read lock, and then drop and
878 * reacquire the write lock for the next iteration.
879 *
880 * We do list_del_init() on the file's list_head so that the
881 * list_del in ib_umad_close() is still OK, even after the
882 * file is removed from the list.
883 */
884 while (!list_empty(&port->file_list)) {
885 file = list_entry(port->file_list.next, struct ib_umad_file,
886 port_list);
887
888 file->agents_dead = 1;
889 list_del_init(&file->port_list);
890
891 downgrade_write(&port->mutex);
892
893 for (id = 0; id < IB_UMAD_MAX_AGENTS; ++id)
894 if (file->agent[id])
895 ib_unregister_mad_agent(file->agent[id]);
896
897 up_read(&port->mutex);
898 down_write(&port->mutex);
899 }
874 900
875 up_write(&port->mutex); 901 up_write(&port->mutex);
876 902
@@ -913,7 +939,7 @@ static void ib_umad_add_one(struct ib_device *device)
913 939
914err: 940err:
915 while (--i >= s) 941 while (--i >= s)
916 ib_umad_kill_port(&umad_dev->port[i]); 942 ib_umad_kill_port(&umad_dev->port[i - s]);
917 943
918 kref_put(&umad_dev->ref, ib_umad_release_dev); 944 kref_put(&umad_dev->ref, ib_umad_release_dev);
919} 945}