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

1.1     ! root        1: /*
        !             2:  * Copyright (C) 2009 Fen Systems Ltd <[email protected]>.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms, with or without
        !             6:  * modification, are permitted provided that the following conditions
        !             7:  * are met:
        !             8:  *
        !             9:  *   Redistributions of source code must retain the above copyright
        !            10:  *   notice, this list of conditions and the following disclaimer.
        !            11:  *
        !            12:  *   Redistributions in binary form must reproduce the above copyright
        !            13:  *   notice, this list of conditions and the following disclaimer in
        !            14:  *   the documentation and/or other materials provided with the
        !            15:  *   distribution.
        !            16:  *
        !            17:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
        !            18:  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
        !            19:  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
        !            20:  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
        !            21:  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
        !            22:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            23:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        !            24:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            25:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
        !            26:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            27:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
        !            28:  * OF THE POSSIBILITY OF SUCH DAMAGE.
        !            29:  */
        !            30: 
        !            31: FILE_LICENCE ( BSD2 );
        !            32: 
        !            33: #include <stdlib.h>
        !            34: #include <string.h>
        !            35: #include <errno.h>
        !            36: #include <ipxe/iobuf.h>
        !            37: #include <ipxe/xfer.h>
        !            38: #include <ipxe/process.h>
        !            39: #include <ipxe/infiniband.h>
        !            40: #include <ipxe/ib_cm.h>
        !            41: #include <ipxe/ib_cmrc.h>
        !            42: 
        !            43: /**
        !            44:  * @file
        !            45:  *
        !            46:  * Infiniband Communication-managed Reliable Connections
        !            47:  *
        !            48:  */
        !            49: 
        !            50: /** CMRC number of send WQEs
        !            51:  *
        !            52:  * This is a policy decision.
        !            53:  */
        !            54: #define IB_CMRC_NUM_SEND_WQES 4
        !            55: 
        !            56: /** CMRC number of receive WQEs
        !            57:  *
        !            58:  * This is a policy decision.
        !            59:  */
        !            60: #define IB_CMRC_NUM_RECV_WQES 2
        !            61: 
        !            62: /** CMRC number of completion queue entries
        !            63:  *
        !            64:  * This is a policy decision
        !            65:  */
        !            66: #define IB_CMRC_NUM_CQES 8
        !            67: 
        !            68: /** An Infiniband Communication-Managed Reliable Connection */
        !            69: struct ib_cmrc_connection {
        !            70:        /** Reference count */
        !            71:        struct refcnt refcnt;
        !            72:        /** Data transfer interface */
        !            73:        struct interface xfer;
        !            74:        /** Infiniband device */
        !            75:        struct ib_device *ibdev;
        !            76:        /** Completion queue */
        !            77:        struct ib_completion_queue *cq;
        !            78:        /** Queue pair */
        !            79:        struct ib_queue_pair *qp;
        !            80:        /** Connection */
        !            81:        struct ib_connection *conn;
        !            82:        /** Destination GID */
        !            83:        union ib_gid dgid;
        !            84:        /** Service ID */
        !            85:        union ib_guid service_id;
        !            86:        /** QP is connected */
        !            87:        int connected;
        !            88:        /** Shutdown process */
        !            89:        struct process shutdown;
        !            90: };
        !            91: 
        !            92: /**
        !            93:  * Shut down CMRC connection gracefully
        !            94:  *
        !            95:  * @v process          Process
        !            96:  *
        !            97:  * The Infiniband data structures are not reference-counted or
        !            98:  * guarded.  It is therefore unsafe to shut them down while we may be
        !            99:  * in the middle of a callback from the Infiniband stack (e.g. in a
        !           100:  * receive completion handler).
        !           101:  *
        !           102:  * This shutdown process will run some time after the call to
        !           103:  * ib_cmrc_close(), after control has returned out of the Infiniband
        !           104:  * core, and will shut down the Infiniband interfaces cleanly.
        !           105:  *
        !           106:  * The shutdown process holds an implicit reference on the CMRC
        !           107:  * connection, ensuring that the structure is not freed before the
        !           108:  * shutdown process has run.
        !           109:  */
        !           110: static void ib_cmrc_shutdown ( struct process *process ) {
        !           111:        struct ib_cmrc_connection *cmrc =
        !           112:                container_of ( process, struct ib_cmrc_connection, shutdown );
        !           113: 
        !           114:        DBGC ( cmrc, "CMRC %p shutting down\n", cmrc );
        !           115: 
        !           116:        /* Shut down Infiniband interface */
        !           117:        ib_destroy_conn ( cmrc->ibdev, cmrc->qp, cmrc->conn );
        !           118:        ib_destroy_qp ( cmrc->ibdev, cmrc->qp );
        !           119:        ib_destroy_cq ( cmrc->ibdev, cmrc->cq );
        !           120:        ib_close ( cmrc->ibdev );
        !           121: 
        !           122:        /* Remove process from run queue */
        !           123:        process_del ( &cmrc->shutdown );
        !           124: 
        !           125:        /* Drop the remaining reference */
        !           126:        ref_put ( &cmrc->refcnt );
        !           127: }
        !           128: 
        !           129: /**
        !           130:  * Close CMRC connection
        !           131:  *
        !           132:  * @v cmrc             Communication-Managed Reliable Connection
        !           133:  * @v rc               Reason for close
        !           134:  */
        !           135: static void ib_cmrc_close ( struct ib_cmrc_connection *cmrc, int rc ) {
        !           136: 
        !           137:        /* Close data transfer interface */
        !           138:        intf_shutdown ( &cmrc->xfer, rc );
        !           139: 
        !           140:        /* Schedule shutdown process */
        !           141:        process_add ( &cmrc->shutdown );
        !           142: }
        !           143: 
        !           144: /**
        !           145:  * Handle change of CMRC connection status
        !           146:  *
        !           147:  * @v ibdev            Infiniband device
        !           148:  * @v qp               Queue pair
        !           149:  * @v conn             Connection
        !           150:  * @v rc_cm            Connection status code
        !           151:  * @v private_data     Private data, if available
        !           152:  * @v private_data_len Length of private data
        !           153:  */
        !           154: static void ib_cmrc_changed ( struct ib_device *ibdev __unused,
        !           155:                              struct ib_queue_pair *qp,
        !           156:                              struct ib_connection *conn __unused, int rc_cm,
        !           157:                              void *private_data, size_t private_data_len ) {
        !           158:        struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
        !           159:        int rc_xfer;
        !           160: 
        !           161:        /* Record connection status */
        !           162:        if ( rc_cm == 0 ) {
        !           163:                DBGC ( cmrc, "CMRC %p connected\n", cmrc );
        !           164:                cmrc->connected = 1;
        !           165:        } else {
        !           166:                DBGC ( cmrc, "CMRC %p disconnected: %s\n",
        !           167:                       cmrc, strerror ( rc_cm ) );
        !           168:                cmrc->connected = 0;
        !           169:        }
        !           170: 
        !           171:        /* Pass up any private data */
        !           172:        DBGC2 ( cmrc, "CMRC %p received private data:\n", cmrc );
        !           173:        DBGC2_HDA ( cmrc, 0, private_data, private_data_len );
        !           174:        if ( private_data &&
        !           175:             ( rc_xfer = xfer_deliver_raw ( &cmrc->xfer, private_data,
        !           176:                                            private_data_len ) ) != 0 ) {
        !           177:                DBGC ( cmrc, "CMRC %p could not deliver private data: %s\n",
        !           178:                       cmrc, strerror ( rc_xfer ) );
        !           179:                ib_cmrc_close ( cmrc, rc_xfer );
        !           180:                return;
        !           181:        }
        !           182: 
        !           183:        /* If we are disconnected, close the upper connection */
        !           184:        if ( rc_cm != 0 ) {
        !           185:                ib_cmrc_close ( cmrc, rc_cm );
        !           186:                return;
        !           187:        }
        !           188: }
        !           189: 
        !           190: /** CMRC connection operations */
        !           191: static struct ib_connection_operations ib_cmrc_conn_op = {
        !           192:        .changed = ib_cmrc_changed,
        !           193: };
        !           194: 
        !           195: /**
        !           196:  * Handle CMRC send completion
        !           197:  *
        !           198:  * @v ibdev            Infiniband device
        !           199:  * @v qp               Queue pair
        !           200:  * @v iobuf            I/O buffer
        !           201:  * @v rc               Completion status code
        !           202:  */
        !           203: static void ib_cmrc_complete_send ( struct ib_device *ibdev __unused,
        !           204:                                    struct ib_queue_pair *qp,
        !           205:                                    struct io_buffer *iobuf, int rc ) {
        !           206:        struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
        !           207: 
        !           208:        /* Free the completed I/O buffer */
        !           209:        free_iob ( iobuf );
        !           210: 
        !           211:        /* Close the connection on any send errors */
        !           212:        if ( rc != 0 ) {
        !           213:                DBGC ( cmrc, "CMRC %p send error: %s\n",
        !           214:                       cmrc, strerror ( rc ) );
        !           215:                ib_cmrc_close ( cmrc, rc );
        !           216:                return;
        !           217:        }
        !           218: }
        !           219: 
        !           220: /**
        !           221:  * Handle CMRC receive completion
        !           222:  *
        !           223:  * @v ibdev            Infiniband device
        !           224:  * @v qp               Queue pair
        !           225:  * @v av               Address vector, or NULL
        !           226:  * @v iobuf            I/O buffer
        !           227:  * @v rc               Completion status code
        !           228:  */
        !           229: static void ib_cmrc_complete_recv ( struct ib_device *ibdev __unused,
        !           230:                                    struct ib_queue_pair *qp,
        !           231:                                    struct ib_address_vector *av __unused,
        !           232:                                    struct io_buffer *iobuf, int rc ) {
        !           233:        struct ib_cmrc_connection *cmrc = ib_qp_get_ownerdata ( qp );
        !           234: 
        !           235:        /* Close the connection on any receive errors */
        !           236:        if ( rc != 0 ) {
        !           237:                DBGC ( cmrc, "CMRC %p receive error: %s\n",
        !           238:                       cmrc, strerror ( rc ) );
        !           239:                free_iob ( iobuf );
        !           240:                ib_cmrc_close ( cmrc, rc );
        !           241:                return;
        !           242:        }
        !           243: 
        !           244:        DBGC2 ( cmrc, "CMRC %p received:\n", cmrc );
        !           245:        DBGC2_HDA ( cmrc, 0, iobuf->data, iob_len ( iobuf ) );
        !           246: 
        !           247:        /* Pass up data */
        !           248:        if ( ( rc = xfer_deliver_iob ( &cmrc->xfer, iobuf ) ) != 0 ) {
        !           249:                DBGC ( cmrc, "CMRC %p could not deliver data: %s\n",
        !           250:                       cmrc, strerror ( rc ) );
        !           251:                ib_cmrc_close ( cmrc, rc );
        !           252:                return;
        !           253:        }
        !           254: }
        !           255: 
        !           256: /** Infiniband CMRC completion operations */
        !           257: static struct ib_completion_queue_operations ib_cmrc_completion_ops = {
        !           258:        .complete_send = ib_cmrc_complete_send,
        !           259:        .complete_recv = ib_cmrc_complete_recv,
        !           260: };
        !           261: 
        !           262: /**
        !           263:  * Send data via CMRC
        !           264:  *
        !           265:  * @v cmrc             CMRC connection
        !           266:  * @v iobuf            Datagram I/O buffer
        !           267:  * @v meta             Data transfer metadata
        !           268:  * @ret rc             Return status code
        !           269:  */
        !           270: static int ib_cmrc_xfer_deliver ( struct ib_cmrc_connection *cmrc,
        !           271:                                  struct io_buffer *iobuf,
        !           272:                                  struct xfer_metadata *meta __unused ) {
        !           273:        int rc;
        !           274: 
        !           275:        /* If no connection has yet been attempted, send this datagram
        !           276:         * as the CM REQ private data.  Otherwise, send it via the QP.
        !           277:         */
        !           278:        if ( ! cmrc->connected ) {
        !           279: 
        !           280:                /* Abort if we have already sent a CM connection request */
        !           281:                if ( cmrc->conn ) {
        !           282:                        DBGC ( cmrc, "CMRC %p attempt to send before "
        !           283:                               "connection is complete\n", cmrc );
        !           284:                        rc = -EIO;
        !           285:                        goto out;
        !           286:                }
        !           287: 
        !           288:                /* Send via CM connection request */
        !           289:                cmrc->conn = ib_create_conn ( cmrc->ibdev, cmrc->qp,
        !           290:                                              &cmrc->dgid, &cmrc->service_id,
        !           291:                                              iobuf->data, iob_len ( iobuf ),
        !           292:                                              &ib_cmrc_conn_op );
        !           293:                if ( ! cmrc->conn ) {
        !           294:                        DBGC ( cmrc, "CMRC %p could not connect\n", cmrc );
        !           295:                        rc = -ENOMEM;
        !           296:                        goto out;
        !           297:                }
        !           298: 
        !           299:        } else {
        !           300: 
        !           301:                /* Send via QP */
        !           302:                if ( ( rc = ib_post_send ( cmrc->ibdev, cmrc->qp, NULL,
        !           303:                                           iob_disown ( iobuf ) ) ) != 0 ) {
        !           304:                        DBGC ( cmrc, "CMRC %p could not send: %s\n",
        !           305:                               cmrc, strerror ( rc ) );
        !           306:                        goto out;
        !           307:                }
        !           308: 
        !           309:        }
        !           310:        return 0;
        !           311: 
        !           312:  out:
        !           313:        /* Free the I/O buffer if necessary */
        !           314:        free_iob ( iobuf );
        !           315: 
        !           316:        /* Close the connection on any errors */
        !           317:        if ( rc != 0 )
        !           318:                ib_cmrc_close ( cmrc, rc );
        !           319: 
        !           320:        return rc;
        !           321: }
        !           322: 
        !           323: /**
        !           324:  * Check CMRC flow control window
        !           325:  *
        !           326:  * @v cmrc             CMRC connection
        !           327:  * @ret len            Length of window
        !           328:  */
        !           329: static size_t ib_cmrc_xfer_window ( struct ib_cmrc_connection *cmrc ) {
        !           330: 
        !           331:        /* We indicate a window only when we are successfully
        !           332:         * connected.
        !           333:         */
        !           334:        return ( cmrc->connected ? IB_MAX_PAYLOAD_SIZE : 0 );
        !           335: }
        !           336: 
        !           337: /**
        !           338:  * Identify device underlying CMRC connection
        !           339:  *
        !           340:  * @v cmrc             CMRC connection
        !           341:  * @ret device         Underlying device
        !           342:  */
        !           343: static struct device *
        !           344: ib_cmrc_identify_device ( struct ib_cmrc_connection *cmrc ) {
        !           345:        return cmrc->ibdev->dev;
        !           346: }
        !           347: 
        !           348: /** CMRC data transfer interface operations */
        !           349: static struct interface_operation ib_cmrc_xfer_operations[] = {
        !           350:        INTF_OP ( xfer_deliver, struct ib_cmrc_connection *,
        !           351:                  ib_cmrc_xfer_deliver ),
        !           352:        INTF_OP ( xfer_window, struct ib_cmrc_connection *,
        !           353:                  ib_cmrc_xfer_window ),
        !           354:        INTF_OP ( intf_close, struct ib_cmrc_connection *, ib_cmrc_close ),
        !           355:        INTF_OP ( identify_device, struct ib_cmrc_connection *,
        !           356:                  ib_cmrc_identify_device ),
        !           357: };
        !           358: 
        !           359: /** CMRC data transfer interface descriptor */
        !           360: static struct interface_descriptor ib_cmrc_xfer_desc =
        !           361:        INTF_DESC ( struct ib_cmrc_connection, xfer, ib_cmrc_xfer_operations );
        !           362: 
        !           363: /**
        !           364:  * Open CMRC connection
        !           365:  *
        !           366:  * @v xfer             Data transfer interface
        !           367:  * @v ibdev            Infiniband device
        !           368:  * @v dgid             Destination GID
        !           369:  * @v service_id       Service ID
        !           370:  * @ret rc             Returns status code
        !           371:  */
        !           372: int ib_cmrc_open ( struct interface *xfer, struct ib_device *ibdev,
        !           373:                   union ib_gid *dgid, union ib_guid *service_id ) {
        !           374:        struct ib_cmrc_connection *cmrc;
        !           375:        int rc;
        !           376: 
        !           377:        /* Allocate and initialise structure */
        !           378:        cmrc = zalloc ( sizeof ( *cmrc ) );
        !           379:        if ( ! cmrc ) {
        !           380:                rc = -ENOMEM;
        !           381:                goto err_alloc;
        !           382:        }
        !           383:        ref_init ( &cmrc->refcnt, NULL );
        !           384:        intf_init ( &cmrc->xfer, &ib_cmrc_xfer_desc, &cmrc->refcnt );
        !           385:        cmrc->ibdev = ibdev;
        !           386:        memcpy ( &cmrc->dgid, dgid, sizeof ( cmrc->dgid ) );
        !           387:        memcpy ( &cmrc->service_id, service_id, sizeof ( cmrc->service_id ) );
        !           388:        process_init_stopped ( &cmrc->shutdown, ib_cmrc_shutdown,
        !           389:                               &cmrc->refcnt );
        !           390: 
        !           391:        /* Open Infiniband device */
        !           392:        if ( ( rc = ib_open ( ibdev ) ) != 0 ) {
        !           393:                DBGC ( cmrc, "CMRC %p could not open device: %s\n",
        !           394:                       cmrc, strerror ( rc ) );
        !           395:                goto err_open;
        !           396:        }
        !           397: 
        !           398:        /* Create completion queue */
        !           399:        cmrc->cq = ib_create_cq ( ibdev, IB_CMRC_NUM_CQES,
        !           400:                                  &ib_cmrc_completion_ops );
        !           401:        if ( ! cmrc->cq ) {
        !           402:                DBGC ( cmrc, "CMRC %p could not create completion queue\n",
        !           403:                       cmrc );
        !           404:                rc = -ENOMEM;
        !           405:                goto err_create_cq;
        !           406:        }
        !           407: 
        !           408:        /* Create queue pair */
        !           409:        cmrc->qp = ib_create_qp ( ibdev, IB_QPT_RC, IB_CMRC_NUM_SEND_WQES,
        !           410:                                  cmrc->cq, IB_CMRC_NUM_RECV_WQES, cmrc->cq );
        !           411:        if ( ! cmrc->qp ) {
        !           412:                DBGC ( cmrc, "CMRC %p could not create queue pair\n", cmrc );
        !           413:                rc = -ENOMEM;
        !           414:                goto err_create_qp;
        !           415:        }
        !           416:        ib_qp_set_ownerdata ( cmrc->qp, cmrc );
        !           417:        DBGC ( cmrc, "CMRC %p using QPN %lx\n", cmrc, cmrc->qp->qpn );
        !           418: 
        !           419:        /* Attach to parent interface, transfer reference (implicitly)
        !           420:         * to our shutdown process, and return.
        !           421:         */
        !           422:        intf_plug_plug ( &cmrc->xfer, xfer );
        !           423:        return 0;
        !           424: 
        !           425:        ib_destroy_qp ( ibdev, cmrc->qp );
        !           426:  err_create_qp:
        !           427:        ib_destroy_cq ( ibdev, cmrc->cq );
        !           428:  err_create_cq:
        !           429:        ib_close ( ibdev );
        !           430:  err_open:
        !           431:        ref_put ( &cmrc->refcnt );
        !           432:  err_alloc:
        !           433:        return rc;
        !           434: }

unix.superglobalmegacorp.com

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