Annotation of qemu/roms/ipxe/src/net/infiniband.c, revision 1.1

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 );

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.