|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2007 Michael Brown <[email protected]>. ! 3: * ! 4: * This program is free software; you can redistribute it and/or ! 5: * modify it under the terms of the GNU General Public License as ! 6: * published by the Free Software Foundation; either version 2 of the ! 7: * License, or any later version. ! 8: * ! 9: * This program is distributed in the hope that it will be useful, but ! 10: * WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 12: * General Public License for more details. ! 13: * ! 14: * You should have received a copy of the GNU General Public License ! 15: * along with this program; if not, write to the Free Software ! 16: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 17: */ ! 18: ! 19: FILE_LICENCE ( GPL2_OR_LATER ); ! 20: ! 21: #include <stdint.h> ! 22: #include <stdlib.h> ! 23: #include <stdio.h> ! 24: #include <string.h> ! 25: #include <unistd.h> ! 26: #include <byteswap.h> ! 27: #include <errno.h> ! 28: #include <assert.h> ! 29: #include <ipxe/list.h> ! 30: #include <ipxe/errortab.h> ! 31: #include <ipxe/if_arp.h> ! 32: #include <ipxe/netdevice.h> ! 33: #include <ipxe/iobuf.h> ! 34: #include <ipxe/process.h> ! 35: #include <ipxe/infiniband.h> ! 36: #include <ipxe/ib_mi.h> ! 37: #include <ipxe/ib_sma.h> ! 38: ! 39: /** @file ! 40: * ! 41: * Infiniband protocol ! 42: * ! 43: */ ! 44: ! 45: /** List of Infiniband devices */ ! 46: struct list_head ib_devices = LIST_HEAD_INIT ( ib_devices ); ! 47: ! 48: /** List of open Infiniband devices, in reverse order of opening */ ! 49: static struct list_head open_ib_devices = LIST_HEAD_INIT ( open_ib_devices ); ! 50: ! 51: /* Disambiguate the various possible EINPROGRESSes */ ! 52: #define EINPROGRESS_INIT __einfo_error ( EINFO_EINPROGRESS_INIT ) ! 53: #define EINFO_EINPROGRESS_INIT __einfo_uniqify \ ! 54: ( EINFO_EINPROGRESS, 0x01, "Initialising" ) ! 55: #define EINPROGRESS_ARMED __einfo_error ( EINFO_EINPROGRESS_ARMED ) ! 56: #define EINFO_EINPROGRESS_ARMED __einfo_uniqify \ ! 57: ( EINFO_EINPROGRESS, 0x02, "Armed" ) ! 58: ! 59: /** Human-readable message for the link statuses */ ! 60: struct errortab infiniband_errors[] __errortab = { ! 61: __einfo_errortab ( EINFO_EINPROGRESS_INIT ), ! 62: __einfo_errortab ( EINFO_EINPROGRESS_ARMED ), ! 63: }; ! 64: ! 65: /*************************************************************************** ! 66: * ! 67: * Completion queues ! 68: * ! 69: *************************************************************************** ! 70: */ ! 71: ! 72: /** ! 73: * Create completion queue ! 74: * ! 75: * @v ibdev Infiniband device ! 76: * @v num_cqes Number of completion queue entries ! 77: * @v op Completion queue operations ! 78: * @ret cq New completion queue ! 79: */ ! 80: struct ib_completion_queue * ! 81: ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes, ! 82: struct ib_completion_queue_operations *op ) { ! 83: struct ib_completion_queue *cq; ! 84: int rc; ! 85: ! 86: DBGC ( ibdev, "IBDEV %p creating completion queue\n", ibdev ); ! 87: ! 88: /* Allocate and initialise data structure */ ! 89: cq = zalloc ( sizeof ( *cq ) ); ! 90: if ( ! cq ) ! 91: goto err_alloc_cq; ! 92: cq->ibdev = ibdev; ! 93: list_add ( &cq->list, &ibdev->cqs ); ! 94: cq->num_cqes = num_cqes; ! 95: INIT_LIST_HEAD ( &cq->work_queues ); ! 96: cq->op = op; ! 97: ! 98: /* Perform device-specific initialisation and get CQN */ ! 99: if ( ( rc = ibdev->op->create_cq ( ibdev, cq ) ) != 0 ) { ! 100: DBGC ( ibdev, "IBDEV %p could not initialise completion " ! 101: "queue: %s\n", ibdev, strerror ( rc ) ); ! 102: goto err_dev_create_cq; ! 103: } ! 104: ! 105: DBGC ( ibdev, "IBDEV %p created %d-entry completion queue %p (%p) " ! 106: "with CQN %#lx\n", ibdev, num_cqes, cq, ! 107: ib_cq_get_drvdata ( cq ), cq->cqn ); ! 108: return cq; ! 109: ! 110: ibdev->op->destroy_cq ( ibdev, cq ); ! 111: err_dev_create_cq: ! 112: list_del ( &cq->list ); ! 113: free ( cq ); ! 114: err_alloc_cq: ! 115: return NULL; ! 116: } ! 117: ! 118: /** ! 119: * Destroy completion queue ! 120: * ! 121: * @v ibdev Infiniband device ! 122: * @v cq Completion queue ! 123: */ ! 124: void ib_destroy_cq ( struct ib_device *ibdev, ! 125: struct ib_completion_queue *cq ) { ! 126: DBGC ( ibdev, "IBDEV %p destroying completion queue %#lx\n", ! 127: ibdev, cq->cqn ); ! 128: assert ( list_empty ( &cq->work_queues ) ); ! 129: ibdev->op->destroy_cq ( ibdev, cq ); ! 130: list_del ( &cq->list ); ! 131: free ( cq ); ! 132: } ! 133: ! 134: /** ! 135: * Poll completion queue ! 136: * ! 137: * @v ibdev Infiniband device ! 138: * @v cq Completion queue ! 139: */ ! 140: void ib_poll_cq ( struct ib_device *ibdev, ! 141: struct ib_completion_queue *cq ) { ! 142: struct ib_work_queue *wq; ! 143: ! 144: /* Poll completion queue */ ! 145: ibdev->op->poll_cq ( ibdev, cq ); ! 146: ! 147: /* Refill receive work queues */ ! 148: list_for_each_entry ( wq, &cq->work_queues, list ) { ! 149: if ( ! wq->is_send ) ! 150: ib_refill_recv ( ibdev, wq->qp ); ! 151: } ! 152: } ! 153: ! 154: /*************************************************************************** ! 155: * ! 156: * Work queues ! 157: * ! 158: *************************************************************************** ! 159: */ ! 160: ! 161: /** ! 162: * Create queue pair ! 163: * ! 164: * @v ibdev Infiniband device ! 165: * @v type Queue pair type ! 166: * @v num_send_wqes Number of send work queue entries ! 167: * @v send_cq Send completion queue ! 168: * @v num_recv_wqes Number of receive work queue entries ! 169: * @v recv_cq Receive completion queue ! 170: * @ret qp Queue pair ! 171: * ! 172: * The queue pair will be left in the INIT state; you must call ! 173: * ib_modify_qp() before it is ready to use for sending and receiving. ! 174: */ ! 175: struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev, ! 176: enum ib_queue_pair_type type, ! 177: unsigned int num_send_wqes, ! 178: struct ib_completion_queue *send_cq, ! 179: unsigned int num_recv_wqes, ! 180: struct ib_completion_queue *recv_cq ) { ! 181: struct ib_queue_pair *qp; ! 182: size_t total_size; ! 183: int rc; ! 184: ! 185: DBGC ( ibdev, "IBDEV %p creating queue pair\n", ibdev ); ! 186: ! 187: /* Allocate and initialise data structure */ ! 188: total_size = ( sizeof ( *qp ) + ! 189: ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ) + ! 190: ( num_recv_wqes * sizeof ( qp->recv.iobufs[0] ) ) ); ! 191: qp = zalloc ( total_size ); ! 192: if ( ! qp ) ! 193: goto err_alloc_qp; ! 194: qp->ibdev = ibdev; ! 195: list_add ( &qp->list, &ibdev->qps ); ! 196: qp->type = type; ! 197: qp->send.qp = qp; ! 198: qp->send.is_send = 1; ! 199: qp->send.cq = send_cq; ! 200: list_add ( &qp->send.list, &send_cq->work_queues ); ! 201: qp->send.psn = ( random() & 0xffffffUL ); ! 202: qp->send.num_wqes = num_send_wqes; ! 203: qp->send.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) ); ! 204: qp->recv.qp = qp; ! 205: qp->recv.cq = recv_cq; ! 206: list_add ( &qp->recv.list, &recv_cq->work_queues ); ! 207: qp->recv.psn = ( random() & 0xffffffUL ); ! 208: qp->recv.num_wqes = num_recv_wqes; ! 209: qp->recv.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) + ! 210: ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) )); ! 211: INIT_LIST_HEAD ( &qp->mgids ); ! 212: ! 213: /* Perform device-specific initialisation and get QPN */ ! 214: if ( ( rc = ibdev->op->create_qp ( ibdev, qp ) ) != 0 ) { ! 215: DBGC ( ibdev, "IBDEV %p could not initialise queue pair: " ! 216: "%s\n", ibdev, strerror ( rc ) ); ! 217: goto err_dev_create_qp; ! 218: } ! 219: DBGC ( ibdev, "IBDEV %p created queue pair %p (%p) with QPN %#lx\n", ! 220: ibdev, qp, ib_qp_get_drvdata ( qp ), qp->qpn ); ! 221: DBGC ( ibdev, "IBDEV %p QPN %#lx has %d send entries at [%p,%p)\n", ! 222: ibdev, qp->qpn, num_send_wqes, qp->send.iobufs, ! 223: qp->recv.iobufs ); ! 224: DBGC ( ibdev, "IBDEV %p QPN %#lx has %d receive entries at [%p,%p)\n", ! 225: ibdev, qp->qpn, num_recv_wqes, qp->recv.iobufs, ! 226: ( ( ( void * ) qp ) + total_size ) ); ! 227: ! 228: /* Calculate externally-visible QPN */ ! 229: switch ( type ) { ! 230: case IB_QPT_SMI: ! 231: qp->ext_qpn = IB_QPN_SMI; ! 232: break; ! 233: case IB_QPT_GSI: ! 234: qp->ext_qpn = IB_QPN_GSI; ! 235: break; ! 236: default: ! 237: qp->ext_qpn = qp->qpn; ! 238: break; ! 239: } ! 240: if ( qp->ext_qpn != qp->qpn ) { ! 241: DBGC ( ibdev, "IBDEV %p QPN %#lx has external QPN %#lx\n", ! 242: ibdev, qp->qpn, qp->ext_qpn ); ! 243: } ! 244: ! 245: return qp; ! 246: ! 247: ibdev->op->destroy_qp ( ibdev, qp ); ! 248: err_dev_create_qp: ! 249: list_del ( &qp->send.list ); ! 250: list_del ( &qp->recv.list ); ! 251: list_del ( &qp->list ); ! 252: free ( qp ); ! 253: err_alloc_qp: ! 254: return NULL; ! 255: } ! 256: ! 257: /** ! 258: * Modify queue pair ! 259: * ! 260: * @v ibdev Infiniband device ! 261: * @v qp Queue pair ! 262: * @v av New address vector, if applicable ! 263: * @ret rc Return status code ! 264: */ ! 265: int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) { ! 266: int rc; ! 267: ! 268: DBGC ( ibdev, "IBDEV %p modifying QPN %#lx\n", ibdev, qp->qpn ); ! 269: ! 270: if ( ( rc = ibdev->op->modify_qp ( ibdev, qp ) ) != 0 ) { ! 271: DBGC ( ibdev, "IBDEV %p could not modify QPN %#lx: %s\n", ! 272: ibdev, qp->qpn, strerror ( rc ) ); ! 273: return rc; ! 274: } ! 275: ! 276: return 0; ! 277: } ! 278: ! 279: /** ! 280: * Destroy queue pair ! 281: * ! 282: * @v ibdev Infiniband device ! 283: * @v qp Queue pair ! 284: */ ! 285: void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) { ! 286: struct io_buffer *iobuf; ! 287: unsigned int i; ! 288: ! 289: DBGC ( ibdev, "IBDEV %p destroying QPN %#lx\n", ! 290: ibdev, qp->qpn ); ! 291: ! 292: assert ( list_empty ( &qp->mgids ) ); ! 293: ! 294: /* Perform device-specific destruction */ ! 295: ibdev->op->destroy_qp ( ibdev, qp ); ! 296: ! 297: /* Complete any remaining I/O buffers with errors */ ! 298: for ( i = 0 ; i < qp->send.num_wqes ; i++ ) { ! 299: if ( ( iobuf = qp->send.iobufs[i] ) != NULL ) ! 300: ib_complete_send ( ibdev, qp, iobuf, -ECANCELED ); ! 301: } ! 302: for ( i = 0 ; i < qp->recv.num_wqes ; i++ ) { ! 303: if ( ( iobuf = qp->recv.iobufs[i] ) != NULL ) { ! 304: ib_complete_recv ( ibdev, qp, NULL, iobuf, ! 305: -ECANCELED ); ! 306: } ! 307: } ! 308: ! 309: /* Remove work queues from completion queue */ ! 310: list_del ( &qp->send.list ); ! 311: list_del ( &qp->recv.list ); ! 312: ! 313: /* Free QP */ ! 314: list_del ( &qp->list ); ! 315: free ( qp ); ! 316: } ! 317: ! 318: /** ! 319: * Find queue pair by QPN ! 320: * ! 321: * @v ibdev Infiniband device ! 322: * @v qpn Queue pair number ! 323: * @ret qp Queue pair, or NULL ! 324: */ ! 325: struct ib_queue_pair * ib_find_qp_qpn ( struct ib_device *ibdev, ! 326: unsigned long qpn ) { ! 327: struct ib_queue_pair *qp; ! 328: ! 329: list_for_each_entry ( qp, &ibdev->qps, list ) { ! 330: if ( ( qpn == qp->qpn ) || ( qpn == qp->ext_qpn ) ) ! 331: return qp; ! 332: } ! 333: return NULL; ! 334: } ! 335: ! 336: /** ! 337: * Find queue pair by multicast GID ! 338: * ! 339: * @v ibdev Infiniband device ! 340: * @v gid Multicast GID ! 341: * @ret qp Queue pair, or NULL ! 342: */ ! 343: struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev, ! 344: union ib_gid *gid ) { ! 345: struct ib_queue_pair *qp; ! 346: struct ib_multicast_gid *mgid; ! 347: ! 348: list_for_each_entry ( qp, &ibdev->qps, list ) { ! 349: list_for_each_entry ( mgid, &qp->mgids, list ) { ! 350: if ( memcmp ( &mgid->gid, gid, ! 351: sizeof ( mgid->gid ) ) == 0 ) { ! 352: return qp; ! 353: } ! 354: } ! 355: } ! 356: return NULL; ! 357: } ! 358: ! 359: /** ! 360: * Find work queue belonging to completion queue ! 361: * ! 362: * @v cq Completion queue ! 363: * @v qpn Queue pair number ! 364: * @v is_send Find send work queue (rather than receive) ! 365: * @ret wq Work queue, or NULL if not found ! 366: */ ! 367: struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq, ! 368: unsigned long qpn, int is_send ) { ! 369: struct ib_work_queue *wq; ! 370: ! 371: list_for_each_entry ( wq, &cq->work_queues, list ) { ! 372: if ( ( wq->qp->qpn == qpn ) && ( wq->is_send == is_send ) ) ! 373: return wq; ! 374: } ! 375: return NULL; ! 376: } ! 377: ! 378: /** ! 379: * Post send work queue entry ! 380: * ! 381: * @v ibdev Infiniband device ! 382: * @v qp Queue pair ! 383: * @v av Address vector ! 384: * @v iobuf I/O buffer ! 385: * @ret rc Return status code ! 386: */ ! 387: int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp, ! 388: struct ib_address_vector *av, ! 389: struct io_buffer *iobuf ) { ! 390: struct ib_address_vector av_copy; ! 391: int rc; ! 392: ! 393: /* Check queue fill level */ ! 394: if ( qp->send.fill >= qp->send.num_wqes ) { ! 395: DBGC ( ibdev, "IBDEV %p QPN %#lx send queue full\n", ! 396: ibdev, qp->qpn ); ! 397: return -ENOBUFS; ! 398: } ! 399: ! 400: /* Use default address vector if none specified */ ! 401: if ( ! av ) ! 402: av = &qp->av; ! 403: ! 404: /* Make modifiable copy of address vector */ ! 405: memcpy ( &av_copy, av, sizeof ( av_copy ) ); ! 406: av = &av_copy; ! 407: ! 408: /* Fill in optional parameters in address vector */ ! 409: if ( ! av->qkey ) ! 410: av->qkey = qp->qkey; ! 411: if ( ! av->rate ) ! 412: av->rate = IB_RATE_2_5; ! 413: ! 414: /* Post to hardware */ ! 415: if ( ( rc = ibdev->op->post_send ( ibdev, qp, av, iobuf ) ) != 0 ) { ! 416: DBGC ( ibdev, "IBDEV %p QPN %#lx could not post send WQE: " ! 417: "%s\n", ibdev, qp->qpn, strerror ( rc ) ); ! 418: return rc; ! 419: } ! 420: ! 421: qp->send.fill++; ! 422: return 0; ! 423: } ! 424: ! 425: /** ! 426: * Post receive work queue entry ! 427: * ! 428: * @v ibdev Infiniband device ! 429: * @v qp Queue pair ! 430: * @v iobuf I/O buffer ! 431: * @ret rc Return status code ! 432: */ ! 433: int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp, ! 434: struct io_buffer *iobuf ) { ! 435: int rc; ! 436: ! 437: /* Check packet length */ ! 438: if ( iob_tailroom ( iobuf ) < IB_MAX_PAYLOAD_SIZE ) { ! 439: DBGC ( ibdev, "IBDEV %p QPN %#lx wrong RX buffer size (%zd)\n", ! 440: ibdev, qp->qpn, iob_tailroom ( iobuf ) ); ! 441: return -EINVAL; ! 442: } ! 443: ! 444: /* Check queue fill level */ ! 445: if ( qp->recv.fill >= qp->recv.num_wqes ) { ! 446: DBGC ( ibdev, "IBDEV %p QPN %#lx receive queue full\n", ! 447: ibdev, qp->qpn ); ! 448: return -ENOBUFS; ! 449: } ! 450: ! 451: /* Post to hardware */ ! 452: if ( ( rc = ibdev->op->post_recv ( ibdev, qp, iobuf ) ) != 0 ) { ! 453: DBGC ( ibdev, "IBDEV %p QPN %#lx could not post receive WQE: " ! 454: "%s\n", ibdev, qp->qpn, strerror ( rc ) ); ! 455: return rc; ! 456: } ! 457: ! 458: qp->recv.fill++; ! 459: return 0; ! 460: } ! 461: ! 462: /** ! 463: * Complete send work queue entry ! 464: * ! 465: * @v ibdev Infiniband device ! 466: * @v qp Queue pair ! 467: * @v iobuf I/O buffer ! 468: * @v rc Completion status code ! 469: */ ! 470: void ib_complete_send ( struct ib_device *ibdev, struct ib_queue_pair *qp, ! 471: struct io_buffer *iobuf, int rc ) { ! 472: ! 473: if ( qp->send.cq->op->complete_send ) { ! 474: qp->send.cq->op->complete_send ( ibdev, qp, iobuf, rc ); ! 475: } else { ! 476: free_iob ( iobuf ); ! 477: } ! 478: qp->send.fill--; ! 479: } ! 480: ! 481: /** ! 482: * Complete receive work queue entry ! 483: * ! 484: * @v ibdev Infiniband device ! 485: * @v qp Queue pair ! 486: * @v av Address vector, or NULL ! 487: * @v iobuf I/O buffer ! 488: * @v rc Completion status code ! 489: */ ! 490: void ib_complete_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp, ! 491: struct ib_address_vector *av, ! 492: struct io_buffer *iobuf, int rc ) { ! 493: ! 494: if ( qp->recv.cq->op->complete_recv ) { ! 495: qp->recv.cq->op->complete_recv ( ibdev, qp, av, iobuf, rc ); ! 496: } else { ! 497: free_iob ( iobuf ); ! 498: } ! 499: qp->recv.fill--; ! 500: } ! 501: ! 502: /** ! 503: * Refill receive work queue ! 504: * ! 505: * @v ibdev Infiniband device ! 506: * @v qp Queue pair ! 507: */ ! 508: void ib_refill_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp ) { ! 509: struct io_buffer *iobuf; ! 510: int rc; ! 511: ! 512: /* Keep filling while unfilled entries remain */ ! 513: while ( qp->recv.fill < qp->recv.num_wqes ) { ! 514: ! 515: /* Allocate I/O buffer */ ! 516: iobuf = alloc_iob ( IB_MAX_PAYLOAD_SIZE ); ! 517: if ( ! iobuf ) { ! 518: /* Non-fatal; we will refill on next attempt */ ! 519: return; ! 520: } ! 521: ! 522: /* Post I/O buffer */ ! 523: if ( ( rc = ib_post_recv ( ibdev, qp, iobuf ) ) != 0 ) { ! 524: DBGC ( ibdev, "IBDEV %p could not refill: %s\n", ! 525: ibdev, strerror ( rc ) ); ! 526: free_iob ( iobuf ); ! 527: /* Give up */ ! 528: return; ! 529: } ! 530: } ! 531: } ! 532: ! 533: /*************************************************************************** ! 534: * ! 535: * Link control ! 536: * ! 537: *************************************************************************** ! 538: */ ! 539: ! 540: /** ! 541: * Get link state ! 542: * ! 543: * @v ibdev Infiniband device ! 544: * @ret rc Link status code ! 545: */ ! 546: int ib_link_rc ( struct ib_device *ibdev ) { ! 547: switch ( ibdev->port_state ) { ! 548: case IB_PORT_STATE_DOWN: return -ENOTCONN; ! 549: case IB_PORT_STATE_INIT: return -EINPROGRESS_INIT; ! 550: case IB_PORT_STATE_ARMED: return -EINPROGRESS_ARMED; ! 551: case IB_PORT_STATE_ACTIVE: return 0; ! 552: default: return -EINVAL; ! 553: } ! 554: } ! 555: ! 556: /** ! 557: * Textual representation of Infiniband link state ! 558: * ! 559: * @v ibdev Infiniband device ! 560: * @ret link_text Link state text ! 561: */ ! 562: static const char * ib_link_state_text ( struct ib_device *ibdev ) { ! 563: switch ( ibdev->port_state ) { ! 564: case IB_PORT_STATE_DOWN: return "DOWN"; ! 565: case IB_PORT_STATE_INIT: return "INIT"; ! 566: case IB_PORT_STATE_ARMED: return "ARMED"; ! 567: case IB_PORT_STATE_ACTIVE: return "ACTIVE"; ! 568: default: return "UNKNOWN"; ! 569: } ! 570: } ! 571: ! 572: /** ! 573: * Notify drivers of Infiniband device or link state change ! 574: * ! 575: * @v ibdev Infiniband device ! 576: */ ! 577: static void ib_notify ( struct ib_device *ibdev ) { ! 578: struct ib_driver *driver; ! 579: ! 580: for_each_table_entry ( driver, IB_DRIVERS ) ! 581: driver->notify ( ibdev ); ! 582: } ! 583: ! 584: /** ! 585: * Notify of Infiniband link state change ! 586: * ! 587: * @v ibdev Infiniband device ! 588: */ ! 589: void ib_link_state_changed ( struct ib_device *ibdev ) { ! 590: ! 591: DBGC ( ibdev, "IBDEV %p link state is %s\n", ! 592: ibdev, ib_link_state_text ( ibdev ) ); ! 593: ! 594: /* Notify drivers of link state change */ ! 595: ib_notify ( ibdev ); ! 596: } ! 597: ! 598: /** ! 599: * Open port ! 600: * ! 601: * @v ibdev Infiniband device ! 602: * @ret rc Return status code ! 603: */ ! 604: int ib_open ( struct ib_device *ibdev ) { ! 605: int rc; ! 606: ! 607: /* Increment device open request counter */ ! 608: if ( ibdev->open_count++ > 0 ) { ! 609: /* Device was already open; do nothing */ ! 610: return 0; ! 611: } ! 612: ! 613: /* Create subnet management interface */ ! 614: ibdev->smi = ib_create_mi ( ibdev, IB_QPT_SMI ); ! 615: if ( ! ibdev->smi ) { ! 616: DBGC ( ibdev, "IBDEV %p could not create SMI\n", ibdev ); ! 617: rc = -ENOMEM; ! 618: goto err_create_smi; ! 619: } ! 620: ! 621: /* Create subnet management agent */ ! 622: if ( ( rc = ib_create_sma ( ibdev, ibdev->smi ) ) != 0 ) { ! 623: DBGC ( ibdev, "IBDEV %p could not create SMA: %s\n", ! 624: ibdev, strerror ( rc ) ); ! 625: goto err_create_sma; ! 626: } ! 627: ! 628: /* Create general services interface */ ! 629: ibdev->gsi = ib_create_mi ( ibdev, IB_QPT_GSI ); ! 630: if ( ! ibdev->gsi ) { ! 631: DBGC ( ibdev, "IBDEV %p could not create GSI\n", ibdev ); ! 632: rc = -ENOMEM; ! 633: goto err_create_gsi; ! 634: } ! 635: ! 636: /* Open device */ ! 637: if ( ( rc = ibdev->op->open ( ibdev ) ) != 0 ) { ! 638: DBGC ( ibdev, "IBDEV %p could not open: %s\n", ! 639: ibdev, strerror ( rc ) ); ! 640: goto err_open; ! 641: } ! 642: ! 643: /* Add to head of open devices list */ ! 644: list_add ( &ibdev->open_list, &open_ib_devices ); ! 645: ! 646: /* Notify drivers of device state change */ ! 647: ib_notify ( ibdev ); ! 648: ! 649: assert ( ibdev->open_count == 1 ); ! 650: return 0; ! 651: ! 652: ibdev->op->close ( ibdev ); ! 653: err_open: ! 654: ib_destroy_mi ( ibdev, ibdev->gsi ); ! 655: err_create_gsi: ! 656: ib_destroy_sma ( ibdev, ibdev->smi ); ! 657: err_create_sma: ! 658: ib_destroy_mi ( ibdev, ibdev->smi ); ! 659: err_create_smi: ! 660: assert ( ibdev->open_count == 1 ); ! 661: ibdev->open_count = 0; ! 662: return rc; ! 663: } ! 664: ! 665: /** ! 666: * Close port ! 667: * ! 668: * @v ibdev Infiniband device ! 669: */ ! 670: void ib_close ( struct ib_device *ibdev ) { ! 671: ! 672: /* Decrement device open request counter */ ! 673: ibdev->open_count--; ! 674: ! 675: /* Close device if this was the last remaining requested opening */ ! 676: if ( ibdev->open_count == 0 ) { ! 677: ib_notify ( ibdev ); ! 678: list_del ( &ibdev->open_list ); ! 679: ib_destroy_mi ( ibdev, ibdev->gsi ); ! 680: ib_destroy_sma ( ibdev, ibdev->smi ); ! 681: ib_destroy_mi ( ibdev, ibdev->smi ); ! 682: ibdev->op->close ( ibdev ); ! 683: } ! 684: } ! 685: ! 686: /*************************************************************************** ! 687: * ! 688: * Multicast ! 689: * ! 690: *************************************************************************** ! 691: */ ! 692: ! 693: /** ! 694: * Attach to multicast group ! 695: * ! 696: * @v ibdev Infiniband device ! 697: * @v qp Queue pair ! 698: * @v gid Multicast GID ! 699: * @ret rc Return status code ! 700: * ! 701: * Note that this function handles only the local device's attachment ! 702: * to the multicast GID; it does not issue the relevant MADs to join ! 703: * the multicast group on the subnet. ! 704: */ ! 705: int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp, ! 706: union ib_gid *gid ) { ! 707: struct ib_multicast_gid *mgid; ! 708: int rc; ! 709: ! 710: /* Add to software multicast GID list */ ! 711: mgid = zalloc ( sizeof ( *mgid ) ); ! 712: if ( ! mgid ) { ! 713: rc = -ENOMEM; ! 714: goto err_alloc_mgid; ! 715: } ! 716: memcpy ( &mgid->gid, gid, sizeof ( mgid->gid ) ); ! 717: list_add ( &mgid->list, &qp->mgids ); ! 718: ! 719: /* Add to hardware multicast GID list */ ! 720: if ( ( rc = ibdev->op->mcast_attach ( ibdev, qp, gid ) ) != 0 ) ! 721: goto err_dev_mcast_attach; ! 722: ! 723: return 0; ! 724: ! 725: err_dev_mcast_attach: ! 726: list_del ( &mgid->list ); ! 727: free ( mgid ); ! 728: err_alloc_mgid: ! 729: return rc; ! 730: } ! 731: ! 732: /** ! 733: * Detach from multicast group ! 734: * ! 735: * @v ibdev Infiniband device ! 736: * @v qp Queue pair ! 737: * @v gid Multicast GID ! 738: */ ! 739: void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp, ! 740: union ib_gid *gid ) { ! 741: struct ib_multicast_gid *mgid; ! 742: ! 743: /* Remove from hardware multicast GID list */ ! 744: ibdev->op->mcast_detach ( ibdev, qp, gid ); ! 745: ! 746: /* Remove from software multicast GID list */ ! 747: list_for_each_entry ( mgid, &qp->mgids, list ) { ! 748: if ( memcmp ( &mgid->gid, gid, sizeof ( mgid->gid ) ) == 0 ) { ! 749: list_del ( &mgid->list ); ! 750: free ( mgid ); ! 751: break; ! 752: } ! 753: } ! 754: } ! 755: ! 756: /*************************************************************************** ! 757: * ! 758: * Miscellaneous ! 759: * ! 760: *************************************************************************** ! 761: */ ! 762: ! 763: /** ! 764: * Count Infiniband HCA ports ! 765: * ! 766: * @v ibdev Infiniband device ! 767: * @ret num_ports Number of ports ! 768: */ ! 769: int ib_count_ports ( struct ib_device *ibdev ) { ! 770: struct ib_device *tmp; ! 771: int num_ports = 0; ! 772: ! 773: /* Search for IB devices with the same physical device to ! 774: * identify port count. ! 775: */ ! 776: for_each_ibdev ( tmp ) { ! 777: if ( tmp->dev == ibdev->dev ) ! 778: num_ports++; ! 779: } ! 780: return num_ports; ! 781: } ! 782: ! 783: /** ! 784: * Set port information ! 785: * ! 786: * @v ibdev Infiniband device ! 787: * @v mad Set port information MAD ! 788: */ ! 789: int ib_set_port_info ( struct ib_device *ibdev, union ib_mad *mad ) { ! 790: int rc; ! 791: ! 792: /* Adapters with embedded SMAs do not need to support this method */ ! 793: if ( ! ibdev->op->set_port_info ) { ! 794: DBGC ( ibdev, "IBDEV %p does not support setting port " ! 795: "information\n", ibdev ); ! 796: return -ENOTSUP; ! 797: } ! 798: ! 799: if ( ( rc = ibdev->op->set_port_info ( ibdev, mad ) ) != 0 ) { ! 800: DBGC ( ibdev, "IBDEV %p could not set port information: %s\n", ! 801: ibdev, strerror ( rc ) ); ! 802: return rc; ! 803: } ! 804: ! 805: return 0; ! 806: }; ! 807: ! 808: /** ! 809: * Set partition key table ! 810: * ! 811: * @v ibdev Infiniband device ! 812: * @v mad Set partition key table MAD ! 813: */ ! 814: int ib_set_pkey_table ( struct ib_device *ibdev, union ib_mad *mad ) { ! 815: int rc; ! 816: ! 817: /* Adapters with embedded SMAs do not need to support this method */ ! 818: if ( ! ibdev->op->set_pkey_table ) { ! 819: DBGC ( ibdev, "IBDEV %p does not support setting partition " ! 820: "key table\n", ibdev ); ! 821: return -ENOTSUP; ! 822: } ! 823: ! 824: if ( ( rc = ibdev->op->set_pkey_table ( ibdev, mad ) ) != 0 ) { ! 825: DBGC ( ibdev, "IBDEV %p could not set partition key table: " ! 826: "%s\n", ibdev, strerror ( rc ) ); ! 827: return rc; ! 828: } ! 829: ! 830: return 0; ! 831: }; ! 832: ! 833: /*************************************************************************** ! 834: * ! 835: * Event queues ! 836: * ! 837: *************************************************************************** ! 838: */ ! 839: ! 840: /** ! 841: * Poll event queue ! 842: * ! 843: * @v ibdev Infiniband device ! 844: */ ! 845: void ib_poll_eq ( struct ib_device *ibdev ) { ! 846: struct ib_completion_queue *cq; ! 847: ! 848: /* Poll device's event queue */ ! 849: ibdev->op->poll_eq ( ibdev ); ! 850: ! 851: /* Poll all completion queues */ ! 852: list_for_each_entry ( cq, &ibdev->cqs, list ) ! 853: ib_poll_cq ( ibdev, cq ); ! 854: } ! 855: ! 856: /** ! 857: * Single-step the Infiniband event queue ! 858: * ! 859: * @v process Infiniband event queue process ! 860: */ ! 861: static void ib_step ( struct process *process __unused ) { ! 862: struct ib_device *ibdev; ! 863: ! 864: for_each_ibdev ( ibdev ) ! 865: ib_poll_eq ( ibdev ); ! 866: } ! 867: ! 868: /** Infiniband event queue process */ ! 869: struct process ib_process __permanent_process = { ! 870: .list = LIST_HEAD_INIT ( ib_process.list ), ! 871: .step = ib_step, ! 872: }; ! 873: ! 874: /*************************************************************************** ! 875: * ! 876: * Infiniband device creation/destruction ! 877: * ! 878: *************************************************************************** ! 879: */ ! 880: ! 881: /** ! 882: * Allocate Infiniband device ! 883: * ! 884: * @v priv_size Size of driver private data area ! 885: * @ret ibdev Infiniband device, or NULL ! 886: */ ! 887: struct ib_device * alloc_ibdev ( size_t priv_size ) { ! 888: struct ib_device *ibdev; ! 889: void *drv_priv; ! 890: size_t total_len; ! 891: ! 892: total_len = ( sizeof ( *ibdev ) + priv_size ); ! 893: ibdev = zalloc ( total_len ); ! 894: if ( ibdev ) { ! 895: drv_priv = ( ( ( void * ) ibdev ) + sizeof ( *ibdev ) ); ! 896: ib_set_drvdata ( ibdev, drv_priv ); ! 897: INIT_LIST_HEAD ( &ibdev->list ); ! 898: INIT_LIST_HEAD ( &ibdev->open_list ); ! 899: INIT_LIST_HEAD ( &ibdev->cqs ); ! 900: INIT_LIST_HEAD ( &ibdev->qps ); ! 901: ibdev->port_state = IB_PORT_STATE_DOWN; ! 902: ibdev->lid = IB_LID_NONE; ! 903: ibdev->pkey = IB_PKEY_DEFAULT; ! 904: } ! 905: return ibdev; ! 906: } ! 907: ! 908: /** ! 909: * Register Infiniband device ! 910: * ! 911: * @v ibdev Infiniband device ! 912: * @ret rc Return status code ! 913: */ ! 914: int register_ibdev ( struct ib_device *ibdev ) { ! 915: struct ib_driver *driver; ! 916: int rc; ! 917: ! 918: /* Add to device list */ ! 919: ibdev_get ( ibdev ); ! 920: list_add_tail ( &ibdev->list, &ib_devices ); ! 921: DBGC ( ibdev, "IBDEV %p registered (phys %s)\n", ibdev, ! 922: ibdev->dev->name ); ! 923: ! 924: /* Probe device */ ! 925: for_each_table_entry ( driver, IB_DRIVERS ) { ! 926: if ( ( rc = driver->probe ( ibdev ) ) != 0 ) { ! 927: DBGC ( ibdev, "IBDEV %p could not add %s device: %s\n", ! 928: ibdev, driver->name, strerror ( rc ) ); ! 929: goto err_probe; ! 930: } ! 931: } ! 932: ! 933: return 0; ! 934: ! 935: err_probe: ! 936: for_each_table_entry_continue_reverse ( driver, IB_DRIVERS ) ! 937: driver->remove ( ibdev ); ! 938: list_del ( &ibdev->list ); ! 939: ibdev_put ( ibdev ); ! 940: return rc; ! 941: } ! 942: ! 943: /** ! 944: * Unregister Infiniband device ! 945: * ! 946: * @v ibdev Infiniband device ! 947: */ ! 948: void unregister_ibdev ( struct ib_device *ibdev ) { ! 949: struct ib_driver *driver; ! 950: ! 951: /* Remove device */ ! 952: for_each_table_entry_reverse ( driver, IB_DRIVERS ) ! 953: driver->remove ( ibdev ); ! 954: ! 955: /* Remove from device list */ ! 956: list_del ( &ibdev->list ); ! 957: ibdev_put ( ibdev ); ! 958: DBGC ( ibdev, "IBDEV %p unregistered\n", ibdev ); ! 959: } ! 960: ! 961: /** ! 962: * Find Infiniband device by GID ! 963: * ! 964: * @v gid GID ! 965: * @ret ibdev Infiniband device, or NULL ! 966: */ ! 967: struct ib_device * find_ibdev ( union ib_gid *gid ) { ! 968: struct ib_device *ibdev; ! 969: ! 970: for_each_ibdev ( ibdev ) { ! 971: if ( memcmp ( gid, &ibdev->gid, sizeof ( *gid ) ) == 0 ) ! 972: return ibdev; ! 973: } ! 974: return NULL; ! 975: } ! 976: ! 977: /** ! 978: * Get most recently opened Infiniband device ! 979: * ! 980: * @ret ibdev Most recently opened Infiniband device, or NULL ! 981: */ ! 982: struct ib_device * last_opened_ibdev ( void ) { ! 983: struct ib_device *ibdev; ! 984: ! 985: ibdev = list_first_entry ( &open_ib_devices, struct ib_device, ! 986: open_list ); ! 987: if ( ! ibdev ) ! 988: return NULL; ! 989: ! 990: assert ( ibdev->open_count != 0 ); ! 991: return ibdev; ! 992: } ! 993: ! 994: /* Drag in IPoIB */ ! 995: REQUIRE_OBJECT ( ipoib );
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.