[hermon] Randomise the high-order bits of queue pair numbers
authorMichael Brown <mcb30@etherboot.org>
Sun, 9 Aug 2009 19:38:35 +0000 (20:38 +0100)
committerMichael Brown <mcb30@etherboot.org>
Mon, 10 Aug 2009 21:19:39 +0000 (22:19 +0100)
The Infiniband Communication Manager will refuse to establish a
connection if it believes the connection is already established.
There is no immediately obvious way to ask it to tear down the
existing connection and replace it; to issue a DREP we would need to
know the local and remote communication IDs used for the previous
connection setup.

We can work around this by randomising the high-order bits of the
queue pair number; these have no significance to the hardware, but are
sufficient to convince the IB CM that this is a different connection.

src/drivers/infiniband/hermon.c
src/drivers/infiniband/hermon.h

index 6e2f323..0012904 100644 (file)
@@ -857,7 +857,8 @@ static int hermon_alloc_qpn ( struct ib_device *ibdev,
                               hermon );
                        return qpn_offset;
                }
                               hermon );
                        return qpn_offset;
                }
-               qp->qpn = ( hermon->qpn_base + qpn_offset );
+               qp->qpn = ( ( random() & HERMON_QPN_RANDOM_MASK ) |
+                           ( hermon->qpn_base + qpn_offset ) );
                return 0;
        default:
                DBGC ( hermon, "Hermon %p unsupported QP type %d\n",
                return 0;
        default:
                DBGC ( hermon, "Hermon %p unsupported QP type %d\n",
@@ -877,7 +878,8 @@ static void hermon_free_qpn ( struct ib_device *ibdev,
        struct hermon *hermon = ib_get_drvdata ( ibdev );
        int qpn_offset;
 
        struct hermon *hermon = ib_get_drvdata ( ibdev );
        int qpn_offset;
 
-       qpn_offset = ( qp->qpn - hermon->qpn_base );
+       qpn_offset = ( ( qp->qpn & ~HERMON_QPN_RANDOM_MASK )
+                      - hermon->qpn_base );
        if ( qpn_offset >= 0 )
                hermon_bitmask_free ( hermon->qp_inuse, qpn_offset, 1 );
 }
        if ( qpn_offset >= 0 )
                hermon_bitmask_free ( hermon->qp_inuse, qpn_offset, 1 );
 }
@@ -2529,8 +2531,7 @@ static int hermon_configure_special_qps ( struct hermon *hermon ) {
        int rc;
 
        /* Special QP block must be aligned on its own size */
        int rc;
 
        /* Special QP block must be aligned on its own size */
-       hermon->special_qpn_base = ( ( HERMON_QPN_BASE +
-                                      hermon->cap.reserved_qps +
+       hermon->special_qpn_base = ( ( hermon->cap.reserved_qps +
                                       HERMON_NUM_SPECIAL_QPS - 1 )
                                     & ~( HERMON_NUM_SPECIAL_QPS - 1 ) );
        hermon->qpn_base = ( hermon->special_qpn_base +
                                       HERMON_NUM_SPECIAL_QPS - 1 )
                                     & ~( HERMON_NUM_SPECIAL_QPS - 1 ) );
        hermon->qpn_base = ( hermon->special_qpn_base +
index c3d895c..f19fd35 100644 (file)
@@ -422,8 +422,8 @@ struct hermon_recv_work_queue {
  */
 #define HERMON_MAX_QPS         8
 
  */
 #define HERMON_MAX_QPS         8
 
-/** Base queue pair number */
-#define HERMON_QPN_BASE 0x550000
+/** Queue pair number randomisation mask */
+#define HERMON_QPN_RANDOM_MASK 0xfff000
 
 /** Hermon queue pair state */
 enum hermon_queue_pair_state {
 
 /** Hermon queue pair state */
 enum hermon_queue_pair_state {