infiniband.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017  */
00018 
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020 
00021 #include <stdint.h>
00022 #include <stdlib.h>
00023 #include <stdio.h>
00024 #include <string.h>
00025 #include <unistd.h>
00026 #include <byteswap.h>
00027 #include <errno.h>
00028 #include <assert.h>
00029 #include <gpxe/list.h>
00030 #include <gpxe/errortab.h>
00031 #include <gpxe/if_arp.h>
00032 #include <gpxe/netdevice.h>
00033 #include <gpxe/iobuf.h>
00034 #include <gpxe/ipoib.h>
00035 #include <gpxe/process.h>
00036 #include <gpxe/infiniband.h>
00037 #include <gpxe/ib_mi.h>
00038 #include <gpxe/ib_sma.h>
00039 
00040 /** @file
00041  *
00042  * Infiniband protocol
00043  *
00044  */
00045 
00046 /** List of Infiniband devices */
00047 struct list_head ib_devices = LIST_HEAD_INIT ( ib_devices );
00048 
00049 /** List of open Infiniband devices, in reverse order of opening */
00050 static struct list_head open_ib_devices = LIST_HEAD_INIT ( open_ib_devices );
00051 
00052 /* Disambiguate the various possible EINPROGRESSes */
00053 #define EINPROGRESS_INIT ( EINPROGRESS | EUNIQ_01 )
00054 #define EINPROGRESS_ARMED ( EINPROGRESS | EUNIQ_02 )
00055 
00056 /** Human-readable message for the link statuses */
00057 struct errortab infiniband_errors[] __errortab = {
00058         { EINPROGRESS_INIT, "Initialising" },
00059         { EINPROGRESS_ARMED, "Armed" },
00060 };
00061 
00062 /***************************************************************************
00063  *
00064  * Completion queues
00065  *
00066  ***************************************************************************
00067  */
00068 
00069 /**
00070  * Create completion queue
00071  *
00072  * @v ibdev             Infiniband device
00073  * @v num_cqes          Number of completion queue entries
00074  * @v op                Completion queue operations
00075  * @ret cq              New completion queue
00076  */
00077 struct ib_completion_queue *
00078 ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
00079                struct ib_completion_queue_operations *op ) {
00080         struct ib_completion_queue *cq;
00081         int rc;
00082 
00083         DBGC ( ibdev, "IBDEV %p creating completion queue\n", ibdev );
00084 
00085         /* Allocate and initialise data structure */
00086         cq = zalloc ( sizeof ( *cq ) );
00087         if ( ! cq )
00088                 goto err_alloc_cq;
00089         cq->ibdev = ibdev;
00090         list_add ( &cq->list, &ibdev->cqs );
00091         cq->num_cqes = num_cqes;
00092         INIT_LIST_HEAD ( &cq->work_queues );
00093         cq->op = op;
00094 
00095         /* Perform device-specific initialisation and get CQN */
00096         if ( ( rc = ibdev->op->create_cq ( ibdev, cq ) ) != 0 ) {
00097                 DBGC ( ibdev, "IBDEV %p could not initialise completion "
00098                        "queue: %s\n", ibdev, strerror ( rc ) );
00099                 goto err_dev_create_cq;
00100         }
00101 
00102         DBGC ( ibdev, "IBDEV %p created %d-entry completion queue %p (%p) "
00103                "with CQN %#lx\n", ibdev, num_cqes, cq,
00104                ib_cq_get_drvdata ( cq ), cq->cqn );
00105         return cq;
00106 
00107         ibdev->op->destroy_cq ( ibdev, cq );
00108  err_dev_create_cq:
00109         list_del ( &cq->list );
00110         free ( cq );
00111  err_alloc_cq:
00112         return NULL;
00113 }
00114 
00115 /**
00116  * Destroy completion queue
00117  *
00118  * @v ibdev             Infiniband device
00119  * @v cq                Completion queue
00120  */
00121 void ib_destroy_cq ( struct ib_device *ibdev,
00122                      struct ib_completion_queue *cq ) {
00123         DBGC ( ibdev, "IBDEV %p destroying completion queue %#lx\n",
00124                ibdev, cq->cqn );
00125         assert ( list_empty ( &cq->work_queues ) );
00126         ibdev->op->destroy_cq ( ibdev, cq );
00127         list_del ( &cq->list );
00128         free ( cq );
00129 }
00130 
00131 /**
00132  * Poll completion queue
00133  *
00134  * @v ibdev             Infiniband device
00135  * @v cq                Completion queue
00136  */
00137 void ib_poll_cq ( struct ib_device *ibdev,
00138                   struct ib_completion_queue *cq ) {
00139         struct ib_work_queue *wq;
00140 
00141         /* Poll completion queue */
00142         ibdev->op->poll_cq ( ibdev, cq );
00143 
00144         /* Refill receive work queues */
00145         list_for_each_entry ( wq, &cq->work_queues, list ) {
00146                 if ( ! wq->is_send )
00147                         ib_refill_recv ( ibdev, wq->qp );
00148         }
00149 }
00150 
00151 /***************************************************************************
00152  *
00153  * Work queues
00154  *
00155  ***************************************************************************
00156  */
00157 
00158 /**
00159  * Create queue pair
00160  *
00161  * @v ibdev             Infiniband device
00162  * @v type              Queue pair type
00163  * @v num_send_wqes     Number of send work queue entries
00164  * @v send_cq           Send completion queue
00165  * @v num_recv_wqes     Number of receive work queue entries
00166  * @v recv_cq           Receive completion queue
00167  * @ret qp              Queue pair
00168  *
00169  * The queue pair will be left in the INIT state; you must call
00170  * ib_modify_qp() before it is ready to use for sending and receiving.
00171  */
00172 struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
00173                                       enum ib_queue_pair_type type,
00174                                       unsigned int num_send_wqes,
00175                                       struct ib_completion_queue *send_cq,
00176                                       unsigned int num_recv_wqes,
00177                                       struct ib_completion_queue *recv_cq ) {
00178         struct ib_queue_pair *qp;
00179         size_t total_size;
00180         int rc;
00181 
00182         DBGC ( ibdev, "IBDEV %p creating queue pair\n", ibdev );
00183 
00184         /* Allocate and initialise data structure */
00185         total_size = ( sizeof ( *qp ) +
00186                        ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ) +
00187                        ( num_recv_wqes * sizeof ( qp->recv.iobufs[0] ) ) );
00188         qp = zalloc ( total_size );
00189         if ( ! qp )
00190                 goto err_alloc_qp;
00191         qp->ibdev = ibdev;
00192         list_add ( &qp->list, &ibdev->qps );
00193         qp->type = type;
00194         qp->send.qp = qp;
00195         qp->send.is_send = 1;
00196         qp->send.cq = send_cq;
00197         list_add ( &qp->send.list, &send_cq->work_queues );
00198         qp->send.psn = ( random() & 0xffffffUL );
00199         qp->send.num_wqes = num_send_wqes;
00200         qp->send.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) );
00201         qp->recv.qp = qp;
00202         qp->recv.cq = recv_cq;
00203         list_add ( &qp->recv.list, &recv_cq->work_queues );
00204         qp->recv.psn = ( random() & 0xffffffUL );
00205         qp->recv.num_wqes = num_recv_wqes;
00206         qp->recv.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) +
00207                             ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ));
00208         INIT_LIST_HEAD ( &qp->mgids );
00209 
00210         /* Perform device-specific initialisation and get QPN */
00211         if ( ( rc = ibdev->op->create_qp ( ibdev, qp ) ) != 0 ) {
00212                 DBGC ( ibdev, "IBDEV %p could not initialise queue pair: "
00213                        "%s\n", ibdev, strerror ( rc ) );
00214                 goto err_dev_create_qp;
00215         }
00216         DBGC ( ibdev, "IBDEV %p created queue pair %p (%p) with QPN %#lx\n",
00217                ibdev, qp, ib_qp_get_drvdata ( qp ), qp->qpn );
00218         DBGC ( ibdev, "IBDEV %p QPN %#lx has %d send entries at [%p,%p)\n",
00219                ibdev, qp->qpn, num_send_wqes, qp->send.iobufs,
00220                qp->recv.iobufs );
00221         DBGC ( ibdev, "IBDEV %p QPN %#lx has %d receive entries at [%p,%p)\n",
00222                ibdev, qp->qpn, num_recv_wqes, qp->recv.iobufs,
00223                ( ( ( void * ) qp ) + total_size ) );
00224 
00225         /* Calculate externally-visible QPN */
00226         switch ( type ) {
00227         case IB_QPT_SMI:
00228                 qp->ext_qpn = IB_QPN_SMI;
00229                 break;
00230         case IB_QPT_GSI:
00231                 qp->ext_qpn = IB_QPN_GSI;
00232                 break;
00233         default:
00234                 qp->ext_qpn = qp->qpn;
00235                 break;
00236         }
00237         if ( qp->ext_qpn != qp->qpn ) {
00238                 DBGC ( ibdev, "IBDEV %p QPN %#lx has external QPN %#lx\n",
00239                        ibdev, qp->qpn, qp->ext_qpn );
00240         }
00241 
00242         return qp;
00243 
00244         ibdev->op->destroy_qp ( ibdev, qp );
00245  err_dev_create_qp:
00246         list_del ( &qp->send.list );
00247         list_del ( &qp->recv.list );
00248         list_del ( &qp->list );
00249         free ( qp );
00250  err_alloc_qp:
00251         return NULL;
00252 }
00253 
00254 /**
00255  * Modify queue pair
00256  *
00257  * @v ibdev             Infiniband device
00258  * @v qp                Queue pair
00259  * @v av                New address vector, if applicable
00260  * @ret rc              Return status code
00261  */
00262 int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
00263         int rc;
00264 
00265         DBGC ( ibdev, "IBDEV %p modifying QPN %#lx\n", ibdev, qp->qpn );
00266 
00267         if ( ( rc = ibdev->op->modify_qp ( ibdev, qp ) ) != 0 ) {
00268                 DBGC ( ibdev, "IBDEV %p could not modify QPN %#lx: %s\n",
00269                        ibdev, qp->qpn, strerror ( rc ) );
00270                 return rc;
00271         }
00272 
00273         return 0;
00274 }
00275 
00276 /**
00277  * Destroy queue pair
00278  *
00279  * @v ibdev             Infiniband device
00280  * @v qp                Queue pair
00281  */
00282 void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
00283         struct io_buffer *iobuf;
00284         unsigned int i;
00285 
00286         DBGC ( ibdev, "IBDEV %p destroying QPN %#lx\n",
00287                ibdev, qp->qpn );
00288 
00289         assert ( list_empty ( &qp->mgids ) );
00290 
00291         /* Perform device-specific destruction */
00292         ibdev->op->destroy_qp ( ibdev, qp );
00293 
00294         /* Complete any remaining I/O buffers with errors */
00295         for ( i = 0 ; i < qp->send.num_wqes ; i++ ) {
00296                 if ( ( iobuf = qp->send.iobufs[i] ) != NULL )
00297                         ib_complete_send ( ibdev, qp, iobuf, -ECANCELED );
00298         }
00299         for ( i = 0 ; i < qp->recv.num_wqes ; i++ ) {
00300                 if ( ( iobuf = qp->recv.iobufs[i] ) != NULL ) {
00301                         ib_complete_recv ( ibdev, qp, NULL, iobuf,
00302                                            -ECANCELED );
00303                 }
00304         }
00305 
00306         /* Remove work queues from completion queue */
00307         list_del ( &qp->send.list );
00308         list_del ( &qp->recv.list );
00309 
00310         /* Free QP */
00311         list_del ( &qp->list );
00312         free ( qp );
00313 }
00314 
00315 /**
00316  * Find queue pair by QPN
00317  *
00318  * @v ibdev             Infiniband device
00319  * @v qpn               Queue pair number
00320  * @ret qp              Queue pair, or NULL
00321  */
00322 struct ib_queue_pair * ib_find_qp_qpn ( struct ib_device *ibdev,
00323                                         unsigned long qpn ) {
00324         struct ib_queue_pair *qp;
00325 
00326         list_for_each_entry ( qp, &ibdev->qps, list ) {
00327                 if ( ( qpn == qp->qpn ) || ( qpn == qp->ext_qpn ) )
00328                         return qp;
00329         }
00330         return NULL;
00331 }
00332 
00333 /**
00334  * Find queue pair by multicast GID
00335  *
00336  * @v ibdev             Infiniband device
00337  * @v gid               Multicast GID
00338  * @ret qp              Queue pair, or NULL
00339  */
00340 struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev,
00341                                          struct ib_gid *gid ) {
00342         struct ib_queue_pair *qp;
00343         struct ib_multicast_gid *mgid;
00344 
00345         list_for_each_entry ( qp, &ibdev->qps, list ) {
00346                 list_for_each_entry ( mgid, &qp->mgids, list ) {
00347                         if ( memcmp ( &mgid->gid, gid,
00348                                       sizeof ( mgid->gid ) ) == 0 ) {
00349                                 return qp;
00350                         }
00351                 }
00352         }
00353         return NULL;
00354 }
00355 
00356 /**
00357  * Find work queue belonging to completion queue
00358  *
00359  * @v cq                Completion queue
00360  * @v qpn               Queue pair number
00361  * @v is_send           Find send work queue (rather than receive)
00362  * @ret wq              Work queue, or NULL if not found
00363  */
00364 struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq,
00365                                     unsigned long qpn, int is_send ) {
00366         struct ib_work_queue *wq;
00367 
00368         list_for_each_entry ( wq, &cq->work_queues, list ) {
00369                 if ( ( wq->qp->qpn == qpn ) && ( wq->is_send == is_send ) )
00370                         return wq;
00371         }
00372         return NULL;
00373 }
00374 
00375 /**
00376  * Post send work queue entry
00377  *
00378  * @v ibdev             Infiniband device
00379  * @v qp                Queue pair
00380  * @v av                Address vector
00381  * @v iobuf             I/O buffer
00382  * @ret rc              Return status code
00383  */
00384 int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
00385                    struct ib_address_vector *av,
00386                    struct io_buffer *iobuf ) {
00387         struct ib_address_vector av_copy;
00388         int rc;
00389 
00390         /* Check queue fill level */
00391         if ( qp->send.fill >= qp->send.num_wqes ) {
00392                 DBGC ( ibdev, "IBDEV %p QPN %#lx send queue full\n",
00393                        ibdev, qp->qpn );
00394                 return -ENOBUFS;
00395         }
00396 
00397         /* Use default address vector if none specified */
00398         if ( ! av )
00399                 av = &qp->av;
00400 
00401         /* Make modifiable copy of address vector */
00402         memcpy ( &av_copy, av, sizeof ( av_copy ) );
00403         av = &av_copy;
00404 
00405         /* Fill in optional parameters in address vector */
00406         if ( ! av->qkey )
00407                 av->qkey = qp->qkey;
00408         if ( ! av->rate )
00409                 av->rate = IB_RATE_2_5;
00410 
00411         /* Post to hardware */
00412         if ( ( rc = ibdev->op->post_send ( ibdev, qp, av, iobuf ) ) != 0 ) {
00413                 DBGC ( ibdev, "IBDEV %p QPN %#lx could not post send WQE: "
00414                        "%s\n", ibdev, qp->qpn, strerror ( rc ) );
00415                 return rc;
00416         }
00417 
00418         qp->send.fill++;
00419         return 0;
00420 }
00421 
00422 /**
00423  * Post receive work queue entry
00424  *
00425  * @v ibdev             Infiniband device
00426  * @v qp                Queue pair
00427  * @v iobuf             I/O buffer
00428  * @ret rc              Return status code
00429  */
00430 int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
00431                    struct io_buffer *iobuf ) {
00432         int rc;
00433 
00434         /* Check packet length */
00435         if ( iob_tailroom ( iobuf ) < IB_MAX_PAYLOAD_SIZE ) {
00436                 DBGC ( ibdev, "IBDEV %p QPN %#lx wrong RX buffer size (%zd)\n",
00437                        ibdev, qp->qpn, iob_tailroom ( iobuf ) );
00438                 return -EINVAL;
00439         }
00440 
00441         /* Check queue fill level */
00442         if ( qp->recv.fill >= qp->recv.num_wqes ) {
00443                 DBGC ( ibdev, "IBDEV %p QPN %#lx receive queue full\n",
00444                        ibdev, qp->qpn );
00445                 return -ENOBUFS;
00446         }
00447 
00448         /* Post to hardware */
00449         if ( ( rc = ibdev->op->post_recv ( ibdev, qp, iobuf ) ) != 0 ) {
00450                 DBGC ( ibdev, "IBDEV %p QPN %#lx could not post receive WQE: "
00451                        "%s\n", ibdev, qp->qpn, strerror ( rc ) );
00452                 return rc;
00453         }
00454 
00455         qp->recv.fill++;
00456         return 0;
00457 }
00458 
00459 /**
00460  * Complete send work queue entry
00461  *
00462  * @v ibdev             Infiniband device
00463  * @v qp                Queue pair
00464  * @v iobuf             I/O buffer
00465  * @v rc                Completion status code
00466  */
00467 void ib_complete_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
00468                         struct io_buffer *iobuf, int rc ) {
00469 
00470         if ( qp->send.cq->op->complete_send ) {
00471                 qp->send.cq->op->complete_send ( ibdev, qp, iobuf, rc );
00472         } else {
00473                 free_iob ( iobuf );
00474         }
00475         qp->send.fill--;
00476 }
00477 
00478 /**
00479  * Complete receive work queue entry
00480  *
00481  * @v ibdev             Infiniband device
00482  * @v qp                Queue pair
00483  * @v av                Address vector
00484  * @v iobuf             I/O buffer
00485  * @v rc                Completion status code
00486  */
00487 void ib_complete_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
00488                         struct ib_address_vector *av,
00489                         struct io_buffer *iobuf, int rc ) {
00490 
00491         if ( qp->recv.cq->op->complete_recv ) {
00492                 qp->recv.cq->op->complete_recv ( ibdev, qp, av, iobuf, rc );
00493         } else {
00494                 free_iob ( iobuf );
00495         }
00496         qp->recv.fill--;
00497 }
00498 
00499 /**
00500  * Refill receive work queue
00501  *
00502  * @v ibdev             Infiniband device
00503  * @v qp                Queue pair
00504  */
00505 void ib_refill_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
00506         struct io_buffer *iobuf;
00507         int rc;
00508 
00509         /* Keep filling while unfilled entries remain */
00510         while ( qp->recv.fill < qp->recv.num_wqes ) {
00511 
00512                 /* Allocate I/O buffer */
00513                 iobuf = alloc_iob ( IB_MAX_PAYLOAD_SIZE );
00514                 if ( ! iobuf ) {
00515                         /* Non-fatal; we will refill on next attempt */
00516                         return;
00517                 }
00518 
00519                 /* Post I/O buffer */
00520                 if ( ( rc = ib_post_recv ( ibdev, qp, iobuf ) ) != 0 ) {
00521                         DBGC ( ibdev, "IBDEV %p could not refill: %s\n",
00522                                ibdev, strerror ( rc ) );
00523                         free_iob ( iobuf );
00524                         /* Give up */
00525                         return;
00526                 }
00527         }
00528 }
00529 
00530 /***************************************************************************
00531  *
00532  * Link control
00533  *
00534  ***************************************************************************
00535  */
00536 
00537 /**
00538  * Open port
00539  *
00540  * @v ibdev             Infiniband device
00541  * @ret rc              Return status code
00542  */
00543 int ib_open ( struct ib_device *ibdev ) {
00544         int rc;
00545 
00546         /* Increment device open request counter */
00547         if ( ibdev->open_count++ > 0 ) {
00548                 /* Device was already open; do nothing */
00549                 return 0;
00550         }
00551 
00552         /* Create subnet management interface */
00553         ibdev->smi = ib_create_mi ( ibdev, IB_QPT_SMI );
00554         if ( ! ibdev->smi ) {
00555                 DBGC ( ibdev, "IBDEV %p could not create SMI\n", ibdev );
00556                 rc = -ENOMEM;
00557                 goto err_create_smi;
00558         }
00559 
00560         /* Create subnet management agent */
00561         if ( ( rc = ib_create_sma ( ibdev, ibdev->smi ) ) != 0 ) {
00562                 DBGC ( ibdev, "IBDEV %p could not create SMA: %s\n",
00563                        ibdev, strerror ( rc ) );
00564                 goto err_create_sma;
00565         }
00566 
00567         /* Create general services interface */
00568         ibdev->gsi = ib_create_mi ( ibdev, IB_QPT_GSI );
00569         if ( ! ibdev->gsi ) {
00570                 DBGC ( ibdev, "IBDEV %p could not create GSI\n", ibdev );
00571                 rc = -ENOMEM;
00572                 goto err_create_gsi;
00573         }
00574 
00575         /* Open device */
00576         if ( ( rc = ibdev->op->open ( ibdev ) ) != 0 ) {
00577                 DBGC ( ibdev, "IBDEV %p could not open: %s\n",
00578                        ibdev, strerror ( rc ) );
00579                 goto err_open;
00580         }
00581 
00582         /* Add to head of open devices list */
00583         list_add ( &ibdev->open_list, &open_ib_devices );
00584 
00585         assert ( ibdev->open_count == 1 );
00586         return 0;
00587 
00588         ibdev->op->close ( ibdev );
00589  err_open:
00590         ib_destroy_mi ( ibdev, ibdev->gsi );
00591  err_create_gsi:
00592         ib_destroy_sma ( ibdev, ibdev->smi );
00593  err_create_sma:
00594         ib_destroy_mi ( ibdev, ibdev->smi );
00595  err_create_smi:
00596         assert ( ibdev->open_count == 1 );
00597         ibdev->open_count = 0;
00598         return rc;
00599 }
00600 
00601 /**
00602  * Close port
00603  *
00604  * @v ibdev             Infiniband device
00605  */
00606 void ib_close ( struct ib_device *ibdev ) {
00607 
00608         /* Decrement device open request counter */
00609         ibdev->open_count--;
00610 
00611         /* Close device if this was the last remaining requested opening */
00612         if ( ibdev->open_count == 0 ) {
00613                 list_del ( &ibdev->open_list );
00614                 ib_destroy_mi ( ibdev, ibdev->gsi );
00615                 ib_destroy_sma ( ibdev, ibdev->smi );
00616                 ib_destroy_mi ( ibdev, ibdev->smi );
00617                 ibdev->op->close ( ibdev );
00618         }
00619 }
00620 
00621 /**
00622  * Get link state
00623  *
00624  * @v ibdev             Infiniband device
00625  * @ret rc              Link status code
00626  */
00627 int ib_link_rc ( struct ib_device *ibdev ) {
00628         switch ( ibdev->port_state ) {
00629         case IB_PORT_STATE_DOWN:        return -ENOTCONN;
00630         case IB_PORT_STATE_INIT:        return -EINPROGRESS_INIT;
00631         case IB_PORT_STATE_ARMED:       return -EINPROGRESS_ARMED;
00632         case IB_PORT_STATE_ACTIVE:      return 0;
00633         default:                        return -EINVAL;
00634         }
00635 }
00636 
00637 /***************************************************************************
00638  *
00639  * Multicast
00640  *
00641  ***************************************************************************
00642  */
00643 
00644 /**
00645  * Attach to multicast group
00646  *
00647  * @v ibdev             Infiniband device
00648  * @v qp                Queue pair
00649  * @v gid               Multicast GID
00650  * @ret rc              Return status code
00651  *
00652  * Note that this function handles only the local device's attachment
00653  * to the multicast GID; it does not issue the relevant MADs to join
00654  * the multicast group on the subnet.
00655  */
00656 int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
00657                       struct ib_gid *gid ) {
00658         struct ib_multicast_gid *mgid;
00659         int rc;
00660 
00661         /* Add to software multicast GID list */
00662         mgid = zalloc ( sizeof ( *mgid ) );
00663         if ( ! mgid ) {
00664                 rc = -ENOMEM;
00665                 goto err_alloc_mgid;
00666         }
00667         memcpy ( &mgid->gid, gid, sizeof ( mgid->gid ) );
00668         list_add ( &mgid->list, &qp->mgids );
00669 
00670         /* Add to hardware multicast GID list */
00671         if ( ( rc = ibdev->op->mcast_attach ( ibdev, qp, gid ) ) != 0 )
00672                 goto err_dev_mcast_attach;
00673 
00674         return 0;
00675 
00676  err_dev_mcast_attach:
00677         list_del ( &mgid->list );
00678         free ( mgid );
00679  err_alloc_mgid:
00680         return rc;
00681 }
00682 
00683 /**
00684  * Detach from multicast group
00685  *
00686  * @v ibdev             Infiniband device
00687  * @v qp                Queue pair
00688  * @v gid               Multicast GID
00689  */
00690 void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
00691                        struct ib_gid *gid ) {
00692         struct ib_multicast_gid *mgid;
00693 
00694         /* Remove from hardware multicast GID list */
00695         ibdev->op->mcast_detach ( ibdev, qp, gid );
00696 
00697         /* Remove from software multicast GID list */
00698         list_for_each_entry ( mgid, &qp->mgids, list ) {
00699                 if ( memcmp ( &mgid->gid, gid, sizeof ( mgid->gid ) ) == 0 ) {
00700                         list_del ( &mgid->list );
00701                         free ( mgid );
00702                         break;
00703                 }
00704         }
00705 }
00706 
00707 /***************************************************************************
00708  *
00709  * Miscellaneous
00710  *
00711  ***************************************************************************
00712  */
00713 
00714 /**
00715  * Get Infiniband HCA information
00716  *
00717  * @v ibdev             Infiniband device
00718  * @ret hca_guid        HCA GUID
00719  * @ret num_ports       Number of ports
00720  */
00721 int ib_get_hca_info ( struct ib_device *ibdev,
00722                       struct ib_gid_half *hca_guid ) {
00723         struct ib_device *tmp;
00724         int num_ports = 0;
00725 
00726         /* Search for IB devices with the same physical device to
00727          * identify port count and a suitable Node GUID.
00728          */
00729         for_each_ibdev ( tmp ) {
00730                 if ( tmp->dev != ibdev->dev )
00731                         continue;
00732                 if ( num_ports == 0 ) {
00733                         memcpy ( hca_guid, &tmp->gid.u.half[1],
00734                                  sizeof ( *hca_guid ) );
00735                 }
00736                 num_ports++;
00737         }
00738         return num_ports;
00739 }
00740 
00741 /**
00742  * Set port information
00743  *
00744  * @v ibdev             Infiniband device
00745  * @v mad               Set port information MAD
00746  */
00747 int ib_set_port_info ( struct ib_device *ibdev, union ib_mad *mad ) {
00748         int rc;
00749 
00750         /* Adapters with embedded SMAs do not need to support this method */
00751         if ( ! ibdev->op->set_port_info ) {
00752                 DBGC ( ibdev, "IBDEV %p does not support setting port "
00753                        "information\n", ibdev );
00754                 return -ENOTSUP;
00755         }
00756 
00757         if ( ( rc = ibdev->op->set_port_info ( ibdev, mad ) ) != 0 ) {
00758                 DBGC ( ibdev, "IBDEV %p could not set port information: %s\n",
00759                        ibdev, strerror ( rc ) );
00760                 return rc;
00761         }
00762 
00763         return 0;
00764 };
00765 
00766 /**
00767  * Set partition key table
00768  *
00769  * @v ibdev             Infiniband device
00770  * @v mad               Set partition key table MAD
00771  */
00772 int ib_set_pkey_table ( struct ib_device *ibdev, union ib_mad *mad ) {
00773         int rc;
00774 
00775         /* Adapters with embedded SMAs do not need to support this method */
00776         if ( ! ibdev->op->set_pkey_table ) {
00777                 DBGC ( ibdev, "IBDEV %p does not support setting partition "
00778                        "key table\n", ibdev );
00779                 return -ENOTSUP;
00780         }
00781 
00782         if ( ( rc = ibdev->op->set_pkey_table ( ibdev, mad ) ) != 0 ) {
00783                 DBGC ( ibdev, "IBDEV %p could not set partition key table: "
00784                        "%s\n", ibdev, strerror ( rc ) );
00785                 return rc;
00786         }
00787 
00788         return 0;
00789 };
00790 
00791 /***************************************************************************
00792  *
00793  * Event queues
00794  *
00795  ***************************************************************************
00796  */
00797 
00798 /**
00799  * Handle Infiniband link state change
00800  *
00801  * @v ibdev             Infiniband device
00802  */
00803 void ib_link_state_changed ( struct ib_device *ibdev ) {
00804 
00805         /* Notify IPoIB of link state change */
00806         ipoib_link_state_changed ( ibdev );
00807 }
00808 
00809 /**
00810  * Poll event queue
00811  *
00812  * @v ibdev             Infiniband device
00813  */
00814 void ib_poll_eq ( struct ib_device *ibdev ) {
00815         struct ib_completion_queue *cq;
00816 
00817         /* Poll device's event queue */
00818         ibdev->op->poll_eq ( ibdev );
00819 
00820         /* Poll all completion queues */
00821         list_for_each_entry ( cq, &ibdev->cqs, list )
00822                 ib_poll_cq ( ibdev, cq );
00823 }
00824 
00825 /**
00826  * Single-step the Infiniband event queue
00827  *
00828  * @v process           Infiniband event queue process
00829  */
00830 static void ib_step ( struct process *process __unused ) {
00831         struct ib_device *ibdev;
00832 
00833         for_each_ibdev ( ibdev )
00834                 ib_poll_eq ( ibdev );
00835 }
00836 
00837 /** Infiniband event queue process */
00838 struct process ib_process __permanent_process = {
00839         .list = LIST_HEAD_INIT ( ib_process.list ),
00840         .step = ib_step,
00841 };
00842 
00843 /***************************************************************************
00844  *
00845  * Infiniband device creation/destruction
00846  *
00847  ***************************************************************************
00848  */
00849 
00850 /**
00851  * Allocate Infiniband device
00852  *
00853  * @v priv_size         Size of driver private data area
00854  * @ret ibdev           Infiniband device, or NULL
00855  */
00856 struct ib_device * alloc_ibdev ( size_t priv_size ) {
00857         struct ib_device *ibdev;
00858         void *drv_priv;
00859         size_t total_len;
00860 
00861         total_len = ( sizeof ( *ibdev ) + priv_size );
00862         ibdev = zalloc ( total_len );
00863         if ( ibdev ) {
00864                 drv_priv = ( ( ( void * ) ibdev ) + sizeof ( *ibdev ) );
00865                 ib_set_drvdata ( ibdev, drv_priv );
00866                 INIT_LIST_HEAD ( &ibdev->cqs );
00867                 INIT_LIST_HEAD ( &ibdev->qps );
00868                 ibdev->port_state = IB_PORT_STATE_DOWN;
00869                 ibdev->lid = IB_LID_NONE;
00870                 ibdev->pkey = IB_PKEY_DEFAULT;
00871         }
00872         return ibdev;
00873 }
00874 
00875 /**
00876  * Register Infiniband device
00877  *
00878  * @v ibdev             Infiniband device
00879  * @ret rc              Return status code
00880  */
00881 int register_ibdev ( struct ib_device *ibdev ) {
00882         int rc;
00883 
00884         /* Add to device list */
00885         ibdev_get ( ibdev );
00886         list_add_tail ( &ibdev->list, &ib_devices );
00887 
00888         /* Add IPoIB device */
00889         if ( ( rc = ipoib_probe ( ibdev ) ) != 0 ) {
00890                 DBGC ( ibdev, "IBDEV %p could not add IPoIB device: %s\n",
00891                        ibdev, strerror ( rc ) );
00892                 goto err_ipoib_probe;
00893         }
00894 
00895         DBGC ( ibdev, "IBDEV %p registered (phys %s)\n", ibdev,
00896                ibdev->dev->name );
00897         return 0;
00898 
00899  err_ipoib_probe:
00900         list_del ( &ibdev->list );
00901         ibdev_put ( ibdev );
00902         return rc;
00903 }
00904 
00905 /**
00906  * Unregister Infiniband device
00907  *
00908  * @v ibdev             Infiniband device
00909  */
00910 void unregister_ibdev ( struct ib_device *ibdev ) {
00911 
00912         /* Close device */
00913         ipoib_remove ( ibdev );
00914 
00915         /* Remove from device list */
00916         list_del ( &ibdev->list );
00917         ibdev_put ( ibdev );
00918         DBGC ( ibdev, "IBDEV %p unregistered\n", ibdev );
00919 }
00920 
00921 /**
00922  * Find Infiniband device by GID
00923  *
00924  * @v gid               GID
00925  * @ret ibdev           Infiniband device, or NULL
00926  */
00927 struct ib_device * find_ibdev ( struct ib_gid *gid ) {
00928         struct ib_device *ibdev;
00929 
00930         for_each_ibdev ( ibdev ) {
00931                 if ( memcmp ( gid, &ibdev->gid, sizeof ( *gid ) ) == 0 )
00932                         return ibdev;
00933         }
00934         return NULL;
00935 }
00936 
00937 /**
00938  * Get most recently opened Infiniband device
00939  *
00940  * @ret ibdev           Most recently opened Infiniband device, or NULL
00941  */
00942 struct ib_device * last_opened_ibdev ( void ) {
00943         struct ib_device *ibdev;
00944 
00945         list_for_each_entry ( ibdev, &open_ib_devices, open_list ) {
00946                 assert ( ibdev->open_count != 0 );
00947                 return ibdev;
00948         }
00949 
00950         return NULL;
00951 }

Generated on Tue Apr 6 20:01:10 2010 for gPXE by  doxygen 1.5.7.1