[infiniband] Pass address vector in receive completions
authorMichael Brown <mcb30@etherboot.org>
Thu, 6 Nov 2008 21:20:30 +0000 (21:20 +0000)
committerMichael Brown <mcb30@etherboot.org>
Tue, 11 Nov 2008 05:31:07 +0000 (05:31 +0000)
Receive completion handlers now get passed an address vector
containing the information extracted from the packet headers
(including the GRH, if present), and only the payload remains in the
I/O buffer.

This breaks the symmetry between transmit and receive completions, so
remove the ib_completer_t type and use an ib_completion_queue_operations
structure instead.

Rename the "destination QPN" and "destination LID" fields in struct
ib_address_vector to reflect its new dual usage.

Since the ib_completion structure now contains only an IB status code,
("syndrome") replace it with a generic gPXE integer status code.

src/drivers/infiniband/arbel.c
src/drivers/infiniband/hermon.c
src/drivers/net/ipoib.c
src/include/gpxe/infiniband.h
src/net/infiniband.c

index 2649a4a..8a31ad8 100644 (file)
@@ -1006,7 +1006,7 @@ static int arbel_post_send ( struct ib_device *ibdev,
                     ud_address_vector.pd, ARBEL_GLOBAL_PD,
                     ud_address_vector.port_number, ibdev->port );
        MLX_FILL_2 ( &wqe->ud, 1,
-                    ud_address_vector.rlid, av->dlid,
+                    ud_address_vector.rlid, av->lid,
                     ud_address_vector.g, av->gid_present );
        MLX_FILL_2 ( &wqe->ud, 2,
                     ud_address_vector.max_stat_rate,
@@ -1015,7 +1015,7 @@ static int arbel_post_send ( struct ib_device *ibdev,
        MLX_FILL_1 ( &wqe->ud, 3, ud_address_vector.sl, av->sl );
        gid = ( av->gid_present ? &av->gid : &arbel_no_gid );
        memcpy ( &wqe->ud.u.dwords[4], gid, sizeof ( *gid ) );
-       MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->dest_qp );
+       MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->qpn );
        MLX_FILL_1 ( &wqe->ud, 9, q_key, av->qkey );
        MLX_FILL_1 ( &wqe->data[0], 0, byte_count, iob_len ( iobuf ) );
        MLX_FILL_1 ( &wqe->data[0], 1, l_key, arbel->reserved_lkey );
@@ -1112,7 +1112,6 @@ static int arbel_complete ( struct ib_device *ibdev,
                            struct ib_completion_queue *cq,
                            union arbelprm_completion_entry *cqe ) {
        struct arbel *arbel = ib_get_drvdata ( ibdev );
-       struct ib_completion completion;
        struct ib_work_queue *wq;
        struct ib_queue_pair *qp;
        struct arbel_queue_pair *arbel_qp;
@@ -1120,15 +1119,17 @@ static int arbel_complete ( struct ib_device *ibdev,
        struct arbel_recv_work_queue *arbel_recv_wq;
        struct arbelprm_recv_wqe *recv_wqe;
        struct io_buffer *iobuf;
+       struct ib_address_vector av;
+       struct ib_global_route_header *grh;
        unsigned int opcode;
        unsigned long qpn;
        int is_send;
        unsigned long wqe_adr;
        unsigned int wqe_idx;
+       size_t len;
        int rc = 0;
 
        /* Parse completion */
-       memset ( &completion, 0, sizeof ( completion ) );
        qpn = MLX_GET ( &cqe->normal, my_qpn );
        is_send = MLX_GET ( &cqe->normal, s );
        wqe_adr = ( MLX_GET ( &cqe->normal, wqe_adr ) << 6 );
@@ -1136,9 +1137,8 @@ static int arbel_complete ( struct ib_device *ibdev,
        if ( opcode >= ARBEL_OPCODE_RECV_ERROR ) {
                /* "s" field is not valid for error opcodes */
                is_send = ( opcode == ARBEL_OPCODE_SEND_ERROR );
-               completion.syndrome = MLX_GET ( &cqe->error, syndrome );
-               DBGC ( arbel, "Arbel %p CPN %lx syndrome %x vendor %lx\n",
-                      arbel, cq->cqn, completion.syndrome,
+               DBGC ( arbel, "Arbel %p CPN %lx syndrome %lx vendor %lx\n",
+                      arbel, cq->cqn, MLX_GET ( &cqe->error, syndrome ),
                       MLX_GET ( &cqe->error, vendor_code ) );
                rc = -EIO;
                /* Don't return immediately; propagate error to completer */
@@ -1176,9 +1176,12 @@ static int arbel_complete ( struct ib_device *ibdev,
        }
        wq->iobufs[wqe_idx] = NULL;
 
-       /* Fill in length for received packets */
-       if ( ! is_send ) {
-               completion.len = MLX_GET ( &cqe->normal, byte_cnt );
+       if ( is_send ) {
+               /* Hand off to completion handler */
+               ib_complete_send ( ibdev, qp, iobuf, rc );
+       } else {
+               /* Set received length */
+               len = MLX_GET ( &cqe->normal, byte_cnt );
                recv_wqe = &arbel_recv_wq->wqe[wqe_idx].recv;
                assert ( MLX_GET ( &recv_wqe->data[0], local_address_l ) ==
                         virt_to_bus ( iobuf->data ) );
@@ -1187,19 +1190,20 @@ static int arbel_complete ( struct ib_device *ibdev,
                MLX_FILL_1 ( &recv_wqe->data[0], 0, byte_count, 0 );
                MLX_FILL_1 ( &recv_wqe->data[0], 1,
                             l_key, ARBEL_INVALID_LKEY );
-               if ( completion.len > iob_tailroom ( iobuf ) ) {
-                       DBGC ( arbel, "Arbel %p CQN %lx QPN %lx IDX %x "
-                              "overlength received packet length %zd\n",
-                              arbel, cq->cqn, qpn, wqe_idx, completion.len );
-                       return -EIO;
-               }
-       }
-
-       /* Pass off to caller's completion handler */
-       if ( is_send ) {
-               ib_complete_send ( ibdev, qp, &completion, iobuf );
-       } else {
-               ib_complete_recv ( ibdev, qp, &completion, iobuf );
+               assert ( len <= iob_tailroom ( iobuf ) );
+               iob_put ( iobuf, len );
+               assert ( iob_len ( iobuf ) >= sizeof ( *grh ) );
+               grh = iobuf->data;
+               iob_pull ( iobuf, sizeof ( *grh ) );
+               /* Construct address vector */
+               memset ( &av, 0, sizeof ( av ) );
+               av.qpn = MLX_GET ( &cqe->normal, rqpn );
+               av.lid = MLX_GET ( &cqe->normal, rlid );
+               av.sl = MLX_GET ( &cqe->normal, sl );
+               av.gid_present = MLX_GET ( &cqe->normal, g );
+               memcpy ( &av.gid, &grh->sgid, sizeof ( av.gid ) );
+               /* Hand off to completion handler */
+               ib_complete_recv ( ibdev, qp, &av, iobuf, rc );
        }
 
        return rc;
index a890763..db7619a 100644 (file)
@@ -1015,7 +1015,7 @@ static int hermon_post_send ( struct ib_device *ibdev,
                     ud_address_vector.pd, HERMON_GLOBAL_PD,
                     ud_address_vector.port_number, ibdev->port );
        MLX_FILL_2 ( &wqe->ud, 1,
-                    ud_address_vector.rlid, av->dlid,
+                    ud_address_vector.rlid, av->lid,
                     ud_address_vector.g, av->gid_present );
        MLX_FILL_1 ( &wqe->ud, 2,
                     ud_address_vector.max_stat_rate,
@@ -1024,7 +1024,7 @@ static int hermon_post_send ( struct ib_device *ibdev,
        MLX_FILL_1 ( &wqe->ud, 3, ud_address_vector.sl, av->sl );
        gid = ( av->gid_present ? &av->gid : &hermon_no_gid );
        memcpy ( &wqe->ud.u.dwords[4], gid, sizeof ( *gid ) );
-       MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->dest_qp );
+       MLX_FILL_1 ( &wqe->ud, 8, destination_qp, av->qpn );
        MLX_FILL_1 ( &wqe->ud, 9, q_key, av->qkey );
        MLX_FILL_1 ( &wqe->data[0], 0, byte_count, iob_len ( iobuf ) );
        MLX_FILL_1 ( &wqe->data[0], 1, l_key, hermon->reserved_lkey );
@@ -1107,28 +1107,28 @@ static int hermon_complete ( struct ib_device *ibdev,
                             struct ib_completion_queue *cq,
                             union hermonprm_completion_entry *cqe ) {
        struct hermon *hermon = ib_get_drvdata ( ibdev );
-       struct ib_completion completion;
        struct ib_work_queue *wq;
        struct ib_queue_pair *qp;
        struct hermon_queue_pair *hermon_qp;
        struct io_buffer *iobuf;
+       struct ib_address_vector av;
+       struct ib_global_route_header *grh;
        unsigned int opcode;
        unsigned long qpn;
        int is_send;
        unsigned int wqe_idx;
+       size_t len;
        int rc = 0;
 
        /* Parse completion */
-       memset ( &completion, 0, sizeof ( completion ) );
        qpn = MLX_GET ( &cqe->normal, qpn );
        is_send = MLX_GET ( &cqe->normal, s_r );
        opcode = MLX_GET ( &cqe->normal, opcode );
        if ( opcode >= HERMON_OPCODE_RECV_ERROR ) {
                /* "s" field is not valid for error opcodes */
                is_send = ( opcode == HERMON_OPCODE_SEND_ERROR );
-               completion.syndrome = MLX_GET ( &cqe->error, syndrome );
-               DBGC ( hermon, "Hermon %p CQN %lx syndrome %x vendor %lx\n",
-                      hermon, cq->cqn, completion.syndrome,
+               DBGC ( hermon, "Hermon %p CQN %lx syndrome %lx vendor %lx\n",
+                      hermon, cq->cqn, MLX_GET ( &cqe->error, syndrome ),
                       MLX_GET ( &cqe->error, vendor_error_syndrome ) );
                rc = -EIO;
                /* Don't return immediately; propagate error to completer */
@@ -1155,22 +1155,26 @@ static int hermon_complete ( struct ib_device *ibdev,
        }
        wq->iobufs[wqe_idx] = NULL;
 
-       /* Fill in length for received packets */
-       if ( ! is_send ) {
-               completion.len = MLX_GET ( &cqe->normal, byte_cnt );
-               if ( completion.len > iob_tailroom ( iobuf ) ) {
-                       DBGC ( hermon, "Hermon %p CQN %lx QPN %lx IDX %x "
-                              "overlength received packet length %zd\n",
-                              hermon, cq->cqn, qpn, wqe_idx, completion.len );
-                       return -EIO;
-               }
-       }
-
-       /* Pass off to caller's completion handler */
        if ( is_send ) {
-               ib_complete_send ( ibdev, qp, &completion, iobuf );
+               /* Hand off to completion handler */
+               ib_complete_send ( ibdev, qp, iobuf, rc );
        } else {
-               ib_complete_recv ( ibdev, qp, &completion, iobuf );
+               /* Set received length */
+               len = MLX_GET ( &cqe->normal, byte_cnt );
+               assert ( len <= iob_tailroom ( iobuf ) );
+               iob_put ( iobuf, len );
+               assert ( iob_len ( iobuf ) >= sizeof ( *grh ) );
+               grh = iobuf->data;
+               iob_pull ( iobuf, sizeof ( *grh ) );
+               /* Construct address vector */
+               memset ( &av, 0, sizeof ( av ) );
+               av.qpn = MLX_GET ( &cqe->normal, srq_rqpn );
+               av.lid = MLX_GET ( &cqe->normal, slid_smac47_32 );
+               av.sl = MLX_GET ( &cqe->normal, sl );
+               av.gid_present = MLX_GET ( &cqe->normal, g );
+               memcpy ( &av.gid, &grh->sgid, sizeof ( av.gid ) );
+               /* Hand off to completion handler */
+               ib_complete_recv ( ibdev, qp, &av, iobuf, rc );
        }
 
        return rc;
index 5512300..aa68fe3 100644 (file)
@@ -277,20 +277,18 @@ static void ipoib_destroy_qset ( struct ipoib_device *ipoib,
  * @v ipoib            IPoIB device
  * @v qset             Queue set
  * @v num_cqes         Number of completion queue entries
+ * @v cq_op            Completion queue operations
  * @v num_send_wqes    Number of send work queue entries
- * @v complete_send    Send completion handler
  * @v num_recv_wqes    Number of receive work queue entries
- * @v complete_recv    Receive completion handler
  * @v qkey             Queue key
  * @ret rc             Return status code
  */
 static int ipoib_create_qset ( struct ipoib_device *ipoib,
                               struct ipoib_queue_set *qset,
                               unsigned int num_cqes,
+                              struct ib_completion_queue_operations *cq_op,
                               unsigned int num_send_wqes,
-                              ib_completer_t complete_send,
                               unsigned int num_recv_wqes,
-                              ib_completer_t complete_recv,
                               unsigned long qkey ) {
        struct ib_device *ibdev = ipoib->ibdev;
        int rc;
@@ -303,8 +301,7 @@ static int ipoib_create_qset ( struct ipoib_device *ipoib,
        qset->recv_max_fill = num_recv_wqes;
 
        /* Allocate completion queue */
-       qset->cq = ib_create_cq ( ibdev, num_cqes, complete_send,
-                                 complete_recv );
+       qset->cq = ib_create_cq ( ibdev, num_cqes, cq_op );
        if ( ! qset->cq ) {
                DBGC ( ipoib, "IPoIB %p could not allocate completion queue\n",
                       ipoib );
@@ -391,8 +388,8 @@ static int ipoib_get_path_record ( struct ipoib_device *ipoib,
 
        /* Construct address vector */
        memset ( &av, 0, sizeof ( av ) );
-       av.dlid = ibdev->sm_lid;
-       av.dest_qp = IB_SA_QPN;
+       av.lid = ibdev->sm_lid;
+       av.qpn = IB_SA_QPN;
        av.qkey = IB_GLOBAL_QKEY;
 
        /* Post send request */
@@ -451,8 +448,8 @@ static int ipoib_mc_member_record ( struct ipoib_device *ipoib,
 
        /* Construct address vector */
        memset ( &av, 0, sizeof ( av ) );
-       av.dlid = ibdev->sm_lid;
-       av.dest_qp = IB_SA_QPN;
+       av.lid = ibdev->sm_lid;
+       av.qpn = IB_SA_QPN;
        av.qkey = IB_GLOBAL_QKEY;
 
        /* Post send request */
@@ -503,8 +500,8 @@ static int ipoib_transmit ( struct net_device *netdev,
        av.gid_present = 1;
        if ( ipoib_pshdr->peer.qpn == htonl ( IPOIB_BROADCAST_QPN ) ) {
                /* Broadcast address */
-               av.dest_qp = IB_BROADCAST_QPN;
-               av.dlid = ipoib->broadcast_lid;
+               av.qpn = IB_BROADCAST_QPN;
+               av.lid = ipoib->broadcast_lid;
                gid = &ipoib->broadcast_gid;
        } else {
                /* Unicast - look in path cache */
@@ -516,8 +513,8 @@ static int ipoib_transmit ( struct net_device *netdev,
                        netdev_tx_complete ( netdev, iobuf );
                        return rc;
                }
-               av.dest_qp = ntohl ( ipoib_pshdr->peer.qpn );
-               av.dlid = path->dlid;
+               av.qpn = ntohl ( ipoib_pshdr->peer.qpn );
+               av.lid = path->dlid;
                av.rate = path->rate;
                av.sl = path->sl;
                gid = &ipoib_pshdr->peer.gid;
@@ -532,17 +529,15 @@ static int ipoib_transmit ( struct net_device *netdev,
  *
  * @v ibdev            Infiniband device
  * @v qp               Queue pair
- * @v completion       Completion
  * @v iobuf            I/O buffer
+ * @v rc               Completion status code
  */
 static void ipoib_data_complete_send ( struct ib_device *ibdev __unused,
                                       struct ib_queue_pair *qp,
-                                      struct ib_completion *completion,
-                                      struct io_buffer *iobuf ) {
+                                      struct io_buffer *iobuf, int rc ) {
        struct net_device *netdev = ib_qp_get_ownerdata ( qp );
 
-       netdev_tx_complete_err ( netdev, iobuf,
-                                ( completion->syndrome ? -EIO : 0 ) );
+       netdev_tx_complete_err ( netdev, iobuf, rc );
 }
 
 /**
@@ -550,32 +545,23 @@ static void ipoib_data_complete_send ( struct ib_device *ibdev __unused,
  *
  * @v ibdev            Infiniband device
  * @v qp               Queue pair
- * @v completion       Completion
+ * @v av               Address vector, or NULL
  * @v iobuf            I/O buffer
+ * @v rc               Completion status code
  */
 static void ipoib_data_complete_recv ( struct ib_device *ibdev __unused,
                                       struct ib_queue_pair *qp,
-                                      struct ib_completion *completion,
-                                      struct io_buffer *iobuf ) {
+                                      struct ib_address_vector *av __unused,
+                                      struct io_buffer *iobuf, int rc ) {
        struct net_device *netdev = ib_qp_get_ownerdata ( qp );
        struct ipoib_device *ipoib = netdev->priv;
        struct ipoib_pseudo_hdr *ipoib_pshdr;
 
-       if ( completion->syndrome ) {
-               netdev_rx_err ( netdev, iobuf, -EIO );
+       if ( rc != 0 ) {
+               netdev_rx_err ( netdev, iobuf, rc );
                return;
        }
 
-       iob_put ( iobuf, completion->len );
-       if ( iob_len ( iobuf ) < sizeof ( struct ib_global_route_header ) ) {
-               DBGC ( ipoib, "IPoIB %p received data packet too short to "
-                      "contain GRH\n", ipoib );
-               DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) );
-               netdev_rx_err ( netdev, iobuf, -EIO );
-               return;
-       }
-       iob_pull ( iobuf, sizeof ( struct ib_global_route_header ) );
-
        if ( iob_len ( iobuf ) < sizeof ( struct ipoib_real_hdr ) ) {
                DBGC ( ipoib, "IPoIB %p received data packet too short to "
                       "contain IPoIB header\n", ipoib );
@@ -590,24 +576,29 @@ static void ipoib_data_complete_recv ( struct ib_device *ibdev __unused,
        netdev_rx ( netdev, iobuf );
 }
 
+/** IPoIB data completion operations */
+static struct ib_completion_queue_operations ipoib_data_cq_op = {
+       .complete_send = ipoib_data_complete_send,
+       .complete_recv = ipoib_data_complete_recv,
+};
+
 /**
  * Handle IPoIB metadata send completion
  *
  * @v ibdev            Infiniband device
  * @v qp               Queue pair
- * @v completion       Completion
  * @v iobuf            I/O buffer
+ * @v rc               Completion status code
  */
 static void ipoib_meta_complete_send ( struct ib_device *ibdev __unused,
                                       struct ib_queue_pair *qp,
-                                      struct ib_completion *completion,
-                                      struct io_buffer *iobuf ) {
+                                      struct io_buffer *iobuf, int rc ) {
        struct net_device *netdev = ib_qp_get_ownerdata ( qp );
        struct ipoib_device *ipoib = netdev->priv;
 
-       if ( completion->syndrome ) {
-               DBGC ( ipoib, "IPoIB %p metadata TX completion error %x\n",
-                      ipoib, completion->syndrome );
+       if ( rc != 0 ) {
+               DBGC ( ipoib, "IPoIB %p metadata TX completion error: %s\n",
+                      ipoib, strerror ( rc ) );
        }
        free_iob ( iobuf );
 }
@@ -673,31 +664,25 @@ static void ipoib_recv_mc_member_record ( struct ipoib_device *ipoib,
  *
  * @v ibdev            Infiniband device
  * @v qp               Queue pair
- * @v completion       Completion
+ * @v av               Address vector, or NULL
  * @v iobuf            I/O buffer
+ * @v rc               Completion status code
  */
-static void ipoib_meta_complete_recv ( struct ib_device *ibdev __unused,
-                                      struct ib_queue_pair *qp,
-                                      struct ib_completion *completion,
-                                      struct io_buffer *iobuf ) {
+static void
+ipoib_meta_complete_recv ( struct ib_device *ibdev __unused,
+                          struct ib_queue_pair *qp,
+                          struct ib_address_vector *av __unused,
+                          struct io_buffer *iobuf, int rc ) {
        struct net_device *netdev = ib_qp_get_ownerdata ( qp );
        struct ipoib_device *ipoib = netdev->priv;
        union ib_mad *mad;
 
-       if ( completion->syndrome ) {
-               DBGC ( ipoib, "IPoIB %p metadata RX completion error %x\n",
-                      ipoib, completion->syndrome );
+       if ( rc != 0 ) {
+               DBGC ( ipoib, "IPoIB %p metadata RX completion error: %s\n",
+                      ipoib, strerror ( rc ) );
                goto done;
        }
 
-       iob_put ( iobuf, completion->len );
-       if ( iob_len ( iobuf ) < sizeof ( struct ib_global_route_header ) ) {
-               DBGC ( ipoib, "IPoIB %p received metadata packet too short "
-                      "to contain GRH\n", ipoib );
-               DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) );
-               goto done;
-       }
-       iob_pull ( iobuf, sizeof ( struct ib_global_route_header ) );
        if ( iob_len ( iobuf ) < sizeof ( *mad ) ) {
                DBGC ( ipoib, "IPoIB %p received metadata packet too short "
                       "to contain reply\n", ipoib );
@@ -730,6 +715,12 @@ static void ipoib_meta_complete_recv ( struct ib_device *ibdev __unused,
        free_iob ( iobuf );
 }
 
+/** IPoIB metadata completion operations */
+static struct ib_completion_queue_operations ipoib_meta_cq_op = {
+       .complete_send = ipoib_meta_complete_send,
+       .complete_recv = ipoib_meta_complete_recv,
+};
+
 /**
  * Refill IPoIB receive ring
  *
@@ -846,10 +837,9 @@ static int ipoib_open ( struct net_device *netdev ) {
        /* Allocate metadata queue set */
        if ( ( rc = ipoib_create_qset ( ipoib, &ipoib->meta,
                                        IPOIB_META_NUM_CQES,
+                                       &ipoib_meta_cq_op,
                                        IPOIB_META_NUM_SEND_WQES,
-                                       ipoib_meta_complete_send,
                                        IPOIB_META_NUM_RECV_WQES,
-                                       ipoib_meta_complete_recv,
                                        IB_GLOBAL_QKEY ) ) != 0 ) {
                DBGC ( ipoib, "IPoIB %p could not allocate metadata QP: %s\n",
                       ipoib, strerror ( rc ) );
@@ -859,10 +849,9 @@ static int ipoib_open ( struct net_device *netdev ) {
        /* Allocate data queue set */
        if ( ( rc = ipoib_create_qset ( ipoib, &ipoib->data,
                                        IPOIB_DATA_NUM_CQES,
+                                       &ipoib_data_cq_op,
                                        IPOIB_DATA_NUM_SEND_WQES,
-                                       ipoib_data_complete_send,
                                        IPOIB_DATA_NUM_RECV_WQES,
-                                       ipoib_data_complete_recv,
                                        IB_GLOBAL_QKEY ) ) != 0 ) {
                DBGC ( ipoib, "IPoIB %p could not allocate data QP: %s\n",
                       ipoib, strerror ( rc ) );
index 36adf23..ed0d1a6 100644 (file)
@@ -52,6 +52,7 @@ struct ib_global_route_header {
 
 struct ib_device;
 struct ib_queue_pair;
+struct ib_address_vector;
 struct ib_completion_queue;
 
 /** An Infiniband Work Queue */
@@ -103,37 +104,58 @@ enum ib_queue_pair_mods {
        IB_MODIFY_QKEY = 0x0001,
 };
 
-/** An Infiniband completion */
-struct ib_completion {
-       /** Syndrome
+/** An Infiniband Address Vector */
+struct ib_address_vector {
+       /** Queue Pair Number */
+       unsigned long qpn;
+       /** Queue key
         *
-        * If non-zero, then the completion is in error.
+        * Not specified for received packets.
         */
-       unsigned int syndrome;
-       /** Length */
-       size_t len;
+       unsigned long qkey;
+       /** Local ID */
+       unsigned int lid;
+       /** Rate
+        *
+        * Not specified for received packets.
+        */
+       unsigned int rate;
+       /** Service level */
+       unsigned int sl;
+       /** GID is present */
+       unsigned int gid_present;
+       /** GID, if present */
+       struct ib_gid gid;
 };
 
-/** Infiniband completion syndromes */
-enum ib_syndrome {
-       IB_SYN_NONE = 0,
-       IB_SYN_LOCAL_LENGTH = 1,
-       IB_SYN_LOCAL_QP = 2,
-       IB_SYN_LOCAL_PROT = 4,
+/** Infiniband completion queue operations */
+struct ib_completion_queue_operations {
+       /**
+        * Complete Send WQE
+        *
+        * @v ibdev             Infiniband device
+        * @v qp                Queue pair
+        * @v iobuf             I/O buffer
+        * @v rc                Completion status code
+        */
+       void ( * complete_send ) ( struct ib_device *ibdev,
+                                  struct ib_queue_pair *qp,
+                                  struct io_buffer *iobuf, int rc );
+       /**
+        * Complete Receive WQE
+        *
+        * @v ibdev             Infiniband device
+        * @v qp                Queue pair
+        * @v av                Address vector, or NULL
+        * @v iobuf             I/O buffer
+        * @v rc                Completion status code
+        */
+       void ( * complete_recv ) ( struct ib_device *ibdev,
+                                  struct ib_queue_pair *qp,
+                                  struct ib_address_vector *av,
+                                  struct io_buffer *iobuf, int rc );
 };
 
-/** An Infiniband completion handler
- *
- * @v ibdev            Infiniband device
- * @v qp               Queue pair
- * @v completion       Completion
- * @v iobuf            I/O buffer
- */
-typedef void ( * ib_completer_t ) ( struct ib_device *ibdev,
-                                   struct ib_queue_pair *qp,
-                                   struct ib_completion *completion,
-                                   struct io_buffer *iobuf );
-
 /** An Infiniband Completion Queue */
 struct ib_completion_queue {
        /** Completion queue number */
@@ -150,32 +172,12 @@ struct ib_completion_queue {
        unsigned long next_idx;
        /** List of work queues completing to this queue */
        struct list_head work_queues;
-       /** Send completion handler */
-       ib_completer_t complete_send;
-       /** Receive completion handler */
-       ib_completer_t complete_recv;
+       /** Completion queue operations */
+       struct ib_completion_queue_operations *op;
        /** Driver private data */
        void *drv_priv;
 };
 
-/** An Infiniband Address Vector */
-struct ib_address_vector {
-       /** Destination Queue Pair */
-       unsigned int dest_qp;
-       /** Queue key */
-       unsigned long qkey;
-       /** Destination Local ID */
-       unsigned int dlid;
-       /** Rate */
-       unsigned int rate;
-       /** Service level */
-       unsigned int sl;
-       /** GID is present */
-       unsigned int gid_present;
-       /** GID */
-       struct ib_gid gid;
-};
-
 struct ib_mad_hdr;
 
 /**
@@ -344,7 +346,7 @@ struct ib_device {
 
 extern struct ib_completion_queue *
 ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
-              ib_completer_t complete_send, ib_completer_t complete_recv );
+              struct ib_completion_queue_operations *op );
 extern void ib_destroy_cq ( struct ib_device *ibdev,
                            struct ib_completion_queue *cq );
 extern struct ib_queue_pair *
@@ -364,12 +366,11 @@ extern int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
                          struct io_buffer *iobuf );
 extern void ib_complete_send ( struct ib_device *ibdev,
                               struct ib_queue_pair *qp,
-                              struct ib_completion *completion,
-                              struct io_buffer *iobuf );
+                              struct io_buffer *iobuf, int rc );
 extern void ib_complete_recv ( struct ib_device *ibdev,
                               struct ib_queue_pair *qp,
-                              struct ib_completion *completion,
-                              struct io_buffer *iobuf );
+                              struct ib_address_vector *av,
+                              struct io_buffer *iobuf, int rc );
 extern struct ib_device * alloc_ibdev ( size_t priv_size );
 extern int register_ibdev ( struct ib_device *ibdev );
 extern void unregister_ibdev ( struct ib_device *ibdev );
index 2db8a0f..ba7842c 100644 (file)
@@ -46,13 +46,12 @@ struct list_head ib_devices = LIST_HEAD_INIT ( ib_devices );
  *
  * @v ibdev            Infiniband device
  * @v num_cqes         Number of completion queue entries
- * @v complete_send    Send completion handler
- * @v complete_recv    Receive completion handler
+ * @v op               Completion queue operations
  * @ret cq             New completion queue
  */
 struct ib_completion_queue *
 ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
-              ib_completer_t complete_send, ib_completer_t complete_recv ) {
+              struct ib_completion_queue_operations *op ) {
        struct ib_completion_queue *cq;
        int rc;
 
@@ -64,8 +63,7 @@ ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
                return NULL;
        cq->num_cqes = num_cqes;
        INIT_LIST_HEAD ( &cq->work_queues );
-       cq->complete_send = complete_send;
-       cq->complete_recv = complete_recv;
+       cq->op = op;
 
        /* Perform device-specific initialisation and get CQN */
        if ( ( rc = ibdev->op->create_cq ( ibdev, cq ) ) != 0 ) {
@@ -195,9 +193,6 @@ int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp,
  * @v qp               Queue pair
  */
 void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
-       struct ib_completion completion = {
-               .syndrome = IB_SYN_LOCAL_QP,
-       };
        struct io_buffer *iobuf;
        unsigned int i;
 
@@ -210,11 +205,13 @@ void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
        /* Complete any remaining I/O buffers with errors */
        for ( i = 0 ; i < qp->send.num_wqes ; i++ ) {
                if ( ( iobuf = qp->send.iobufs[i] ) != NULL )
-                       ib_complete_send ( ibdev, qp, &completion, iobuf );
+                       ib_complete_send ( ibdev, qp, iobuf, -ECANCELED );
        }
        for ( i = 0 ; i < qp->recv.num_wqes ; i++ ) {
-               if ( ( iobuf = qp->recv.iobufs[i] ) != NULL )
-                       ib_complete_recv ( ibdev, qp, &completion, iobuf );
+               if ( ( iobuf = qp->recv.iobufs[i] ) != NULL ) {
+                       ib_complete_recv ( ibdev, qp, NULL, iobuf,
+                                          -ECANCELED );
+               }
        }
 
        /* Remove work queues from completion queue */
@@ -254,7 +251,8 @@ struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq,
  * @ret rc             Return status code
  */
 int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
-                  struct ib_address_vector *av, struct io_buffer *iobuf ) {
+                  struct ib_address_vector *av,
+                  struct io_buffer *iobuf ) {
        int rc;
 
        /* Check queue fill level */
@@ -310,13 +308,12 @@ int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
  *
  * @v ibdev            Infiniband device
  * @v qp               Queue pair
- * @v completion       Completion
  * @v iobuf            I/O buffer
+ * @v rc               Completion status code
  */
 void ib_complete_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
-                       struct ib_completion *completion,
-                       struct io_buffer *iobuf ) {
-       qp->send.cq->complete_send ( ibdev, qp, completion, iobuf );
+                       struct io_buffer *iobuf, int rc ) {
+       qp->send.cq->op->complete_send ( ibdev, qp, iobuf, rc );
        qp->send.fill--;
 }
 
@@ -325,13 +322,14 @@ void ib_complete_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
  *
  * @v ibdev            Infiniband device
  * @v qp               Queue pair
- * @v completion       Completion
+ * @v av               Address vector
  * @v iobuf            I/O buffer
+ * @v rc               Completion status code
  */
 void ib_complete_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
-                       struct ib_completion *completion,
-                       struct io_buffer *iobuf ) {
-       qp->recv.cq->complete_recv ( ibdev, qp, completion, iobuf );
+                       struct ib_address_vector *av,
+                       struct io_buffer *iobuf, int rc ) {
+       qp->recv.cq->op->complete_recv ( ibdev, qp, av, iobuf, rc );
        qp->recv.fill--;
 }