aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/core/user_mad.c102
1 files changed, 73 insertions, 29 deletions
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index d97ded25c4ff..aee29139368c 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -118,6 +118,8 @@ struct ib_umad_file {
118 wait_queue_head_t recv_wait; 118 wait_queue_head_t recv_wait;
119 struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS]; 119 struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS];
120 int agents_dead; 120 int agents_dead;
121 u8 use_pkey_index;
122 u8 already_used;
121}; 123};
122 124
123struct ib_umad_packet { 125struct ib_umad_packet {
@@ -147,6 +149,12 @@ static void ib_umad_release_dev(struct kref *ref)
147 kfree(dev); 149 kfree(dev);
148} 150}
149 151
152static int hdr_size(struct ib_umad_file *file)
153{
154 return file->use_pkey_index ? sizeof (struct ib_user_mad_hdr) :
155 sizeof (struct ib_user_mad_hdr_old);
156}
157
150/* caller must hold port->mutex at least for reading */ 158/* caller must hold port->mutex at least for reading */
151static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id) 159static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id)
152{ 160{
@@ -221,13 +229,13 @@ static void recv_handler(struct ib_mad_agent *agent,
221 packet->length = mad_recv_wc->mad_len; 229 packet->length = mad_recv_wc->mad_len;
222 packet->recv_wc = mad_recv_wc; 230 packet->recv_wc = mad_recv_wc;
223 231
224 packet->mad.hdr.status = 0; 232 packet->mad.hdr.status = 0;
225 packet->mad.hdr.length = sizeof (struct ib_user_mad) + 233 packet->mad.hdr.length = hdr_size(file) + mad_recv_wc->mad_len;
226 mad_recv_wc->mad_len; 234 packet->mad.hdr.qpn = cpu_to_be32(mad_recv_wc->wc->src_qp);
227 packet->mad.hdr.qpn = cpu_to_be32(mad_recv_wc->wc->src_qp); 235 packet->mad.hdr.lid = cpu_to_be16(mad_recv_wc->wc->slid);
228 packet->mad.hdr.lid = cpu_to_be16(mad_recv_wc->wc->slid); 236 packet->mad.hdr.sl = mad_recv_wc->wc->sl;
229 packet->mad.hdr.sl = mad_recv_wc->wc->sl; 237 packet->mad.hdr.path_bits = mad_recv_wc->wc->dlid_path_bits;
230 packet->mad.hdr.path_bits = mad_recv_wc->wc->dlid_path_bits; 238 packet->mad.hdr.pkey_index = mad_recv_wc->wc->pkey_index;
231 packet->mad.hdr.grh_present = !!(mad_recv_wc->wc->wc_flags & IB_WC_GRH); 239 packet->mad.hdr.grh_present = !!(mad_recv_wc->wc->wc_flags & IB_WC_GRH);
232 if (packet->mad.hdr.grh_present) { 240 if (packet->mad.hdr.grh_present) {
233 struct ib_ah_attr ah_attr; 241 struct ib_ah_attr ah_attr;
@@ -253,8 +261,8 @@ err1:
253 ib_free_recv_mad(mad_recv_wc); 261 ib_free_recv_mad(mad_recv_wc);
254} 262}
255 263
256static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet, 264static ssize_t copy_recv_mad(struct ib_umad_file *file, char __user *buf,
257 size_t count) 265 struct ib_umad_packet *packet, size_t count)
258{ 266{
259 struct ib_mad_recv_buf *recv_buf; 267 struct ib_mad_recv_buf *recv_buf;
260 int left, seg_payload, offset, max_seg_payload; 268 int left, seg_payload, offset, max_seg_payload;
@@ -262,15 +270,15 @@ static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet,
262 /* We need enough room to copy the first (or only) MAD segment. */ 270 /* We need enough room to copy the first (or only) MAD segment. */
263 recv_buf = &packet->recv_wc->recv_buf; 271 recv_buf = &packet->recv_wc->recv_buf;
264 if ((packet->length <= sizeof (*recv_buf->mad) && 272 if ((packet->length <= sizeof (*recv_buf->mad) &&
265 count < sizeof (packet->mad) + packet->length) || 273 count < hdr_size(file) + packet->length) ||
266 (packet->length > sizeof (*recv_buf->mad) && 274 (packet->length > sizeof (*recv_buf->mad) &&
267 count < sizeof (packet->mad) + sizeof (*recv_buf->mad))) 275 count < hdr_size(file) + sizeof (*recv_buf->mad)))
268 return -EINVAL; 276 return -EINVAL;
269 277
270 if (copy_to_user(buf, &packet->mad, sizeof (packet->mad))) 278 if (copy_to_user(buf, &packet->mad, hdr_size(file)))
271 return -EFAULT; 279 return -EFAULT;
272 280
273 buf += sizeof (packet->mad); 281 buf += hdr_size(file);
274 seg_payload = min_t(int, packet->length, sizeof (*recv_buf->mad)); 282 seg_payload = min_t(int, packet->length, sizeof (*recv_buf->mad));
275 if (copy_to_user(buf, recv_buf->mad, seg_payload)) 283 if (copy_to_user(buf, recv_buf->mad, seg_payload))
276 return -EFAULT; 284 return -EFAULT;
@@ -280,7 +288,7 @@ static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet,
280 * Multipacket RMPP MAD message. Copy remainder of message. 288 * Multipacket RMPP MAD message. Copy remainder of message.
281 * Note that last segment may have a shorter payload. 289 * Note that last segment may have a shorter payload.
282 */ 290 */
283 if (count < sizeof (packet->mad) + packet->length) { 291 if (count < hdr_size(file) + packet->length) {
284 /* 292 /*
285 * The buffer is too small, return the first RMPP segment, 293 * The buffer is too small, return the first RMPP segment,
286 * which includes the RMPP message length. 294 * which includes the RMPP message length.
@@ -300,18 +308,23 @@ static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet,
300 return -EFAULT; 308 return -EFAULT;
301 } 309 }
302 } 310 }
303 return sizeof (packet->mad) + packet->length; 311 return hdr_size(file) + packet->length;
304} 312}
305 313
306static ssize_t copy_send_mad(char __user *buf, struct ib_umad_packet *packet, 314static ssize_t copy_send_mad(struct ib_umad_file *file, char __user *buf,
307 size_t count) 315 struct ib_umad_packet *packet, size_t count)
308{ 316{
309 ssize_t size = sizeof (packet->mad) + packet->length; 317 ssize_t size = hdr_size(file) + packet->length;
310 318
311 if (count < size) 319 if (count < size)
312 return -EINVAL; 320 return -EINVAL;
313 321
314 if (copy_to_user(buf, &packet->mad, size)) 322 if (copy_to_user(buf, &packet->mad, hdr_size(file)))
323 return -EFAULT;
324
325 buf += hdr_size(file);
326
327 if (copy_to_user(buf, packet->mad.data, packet->length))
315 return -EFAULT; 328 return -EFAULT;
316 329
317 return size; 330 return size;
@@ -324,7 +337,7 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
324 struct ib_umad_packet *packet; 337 struct ib_umad_packet *packet;
325 ssize_t ret; 338 ssize_t ret;
326 339
327 if (count < sizeof (struct ib_user_mad)) 340 if (count < hdr_size(file))
328 return -EINVAL; 341 return -EINVAL;
329 342
330 spin_lock_irq(&file->recv_lock); 343 spin_lock_irq(&file->recv_lock);
@@ -348,9 +361,9 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf,
348 spin_unlock_irq(&file->recv_lock); 361 spin_unlock_irq(&file->recv_lock);
349 362
350 if (packet->recv_wc) 363 if (packet->recv_wc)
351 ret = copy_recv_mad(buf, packet, count); 364 ret = copy_recv_mad(file, buf, packet, count);
352 else 365 else
353 ret = copy_send_mad(buf, packet, count); 366 ret = copy_send_mad(file, buf, packet, count);
354 367
355 if (ret < 0) { 368 if (ret < 0) {
356 /* Requeue packet */ 369 /* Requeue packet */
@@ -442,15 +455,14 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
442 __be64 *tid; 455 __be64 *tid;
443 int ret, data_len, hdr_len, copy_offset, rmpp_active; 456 int ret, data_len, hdr_len, copy_offset, rmpp_active;
444 457
445 if (count < sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR) 458 if (count < hdr_size(file) + IB_MGMT_RMPP_HDR)
446 return -EINVAL; 459 return -EINVAL;
447 460
448 packet = kzalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL); 461 packet = kzalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL);
449 if (!packet) 462 if (!packet)
450 return -ENOMEM; 463 return -ENOMEM;
451 464
452 if (copy_from_user(&packet->mad, buf, 465 if (copy_from_user(&packet->mad, buf, hdr_size(file))) {
453 sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR)) {
454 ret = -EFAULT; 466 ret = -EFAULT;
455 goto err; 467 goto err;
456 } 468 }
@@ -461,6 +473,13 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
461 goto err; 473 goto err;
462 } 474 }
463 475
476 buf += hdr_size(file);
477
478 if (copy_from_user(packet->mad.data, buf, IB_MGMT_RMPP_HDR)) {
479 ret = -EFAULT;
480 goto err;
481 }
482
464 down_read(&file->port->mutex); 483 down_read(&file->port->mutex);
465 484
466 agent = __get_agent(file, packet->mad.hdr.id); 485 agent = __get_agent(file, packet->mad.hdr.id);
@@ -500,11 +519,11 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
500 IB_MGMT_RMPP_FLAG_ACTIVE; 519 IB_MGMT_RMPP_FLAG_ACTIVE;
501 } 520 }
502 521
503 data_len = count - sizeof (struct ib_user_mad) - hdr_len; 522 data_len = count - hdr_size(file) - hdr_len;
504 packet->msg = ib_create_send_mad(agent, 523 packet->msg = ib_create_send_mad(agent,
505 be32_to_cpu(packet->mad.hdr.qpn), 524 be32_to_cpu(packet->mad.hdr.qpn),
506 0, rmpp_active, hdr_len, 525 packet->mad.hdr.pkey_index, rmpp_active,
507 data_len, GFP_KERNEL); 526 hdr_len, data_len, GFP_KERNEL);
508 if (IS_ERR(packet->msg)) { 527 if (IS_ERR(packet->msg)) {
509 ret = PTR_ERR(packet->msg); 528 ret = PTR_ERR(packet->msg);
510 goto err_ah; 529 goto err_ah;
@@ -517,7 +536,6 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
517 536
518 /* Copy MAD header. Any RMPP header is already in place. */ 537 /* Copy MAD header. Any RMPP header is already in place. */
519 memcpy(packet->msg->mad, packet->mad.data, IB_MGMT_MAD_HDR); 538 memcpy(packet->msg->mad, packet->mad.data, IB_MGMT_MAD_HDR);
520 buf += sizeof (struct ib_user_mad);
521 539
522 if (!rmpp_active) { 540 if (!rmpp_active) {
523 if (copy_from_user(packet->msg->mad + copy_offset, 541 if (copy_from_user(packet->msg->mad + copy_offset,
@@ -646,6 +664,16 @@ found:
646 goto out; 664 goto out;
647 } 665 }
648 666
667 if (!file->already_used) {
668 file->already_used = 1;
669 if (!file->use_pkey_index) {
670 printk(KERN_WARNING "user_mad: process %s did not enable "
671 "P_Key index support.\n", current->comm);
672 printk(KERN_WARNING "user_mad: Documentation/infiniband/user_mad.txt "
673 "has info on the new ABI.\n");
674 }
675 }
676
649 file->agent[agent_id] = agent; 677 file->agent[agent_id] = agent;
650 ret = 0; 678 ret = 0;
651 679
@@ -682,6 +710,20 @@ out:
682 return ret; 710 return ret;
683} 711}
684 712
713static long ib_umad_enable_pkey(struct ib_umad_file *file)
714{
715 int ret = 0;
716
717 down_write(&file->port->mutex);
718 if (file->already_used)
719 ret = -EINVAL;
720 else
721 file->use_pkey_index = 1;
722 up_write(&file->port->mutex);
723
724 return ret;
725}
726
685static long ib_umad_ioctl(struct file *filp, unsigned int cmd, 727static long ib_umad_ioctl(struct file *filp, unsigned int cmd,
686 unsigned long arg) 728 unsigned long arg)
687{ 729{
@@ -690,6 +732,8 @@ static long ib_umad_ioctl(struct file *filp, unsigned int cmd,
690 return ib_umad_reg_agent(filp->private_data, arg); 732 return ib_umad_reg_agent(filp->private_data, arg);
691 case IB_USER_MAD_UNREGISTER_AGENT: 733 case IB_USER_MAD_UNREGISTER_AGENT:
692 return ib_umad_unreg_agent(filp->private_data, arg); 734 return ib_umad_unreg_agent(filp->private_data, arg);
735 case IB_USER_MAD_ENABLE_PKEY:
736 return ib_umad_enable_pkey(filp->private_data);
693 default: 737 default:
694 return -ENOIOCTLCMD; 738 return -ENOIOCTLCMD;
695 } 739 }