[Infiniband] Add preliminary support for multi-port devices.
[people/sha0/gpxe.git] / src / drivers / infiniband / hermon.c
index f808a32..fecf398 100644 (file)
@@ -1,8 +1,6 @@
 /*
- * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
- *
- * Based in part upon the original driver by Mellanox Technologies
- * Ltd.  Portions may be Copyright (c) Mellanox Technologies Ltd.
+ * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
+ * Copyright (C) 2008 Mellanox Technologies Ltd.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -34,7 +32,6 @@
 #include <gpxe/iobuf.h>
 #include <gpxe/netdevice.h>
 #include <gpxe/infiniband.h>
-#include <gpxe/ipoib.h>
 #include "hermon.h"
 
 /**
@@ -44,9 +41,6 @@
  *
  */
 
-/* Port to use */
-#define PXE_IB_PORT 1
-
 /***************************************************************************
  *
  * Queue number allocation
@@ -392,12 +386,13 @@ hermon_cmd_2rst_qp ( struct hermon *hermon, unsigned long qpn ) {
 }
 
 static inline int
-hermon_cmd_mad_ifc ( struct hermon *hermon, union hermonprm_mad *mad ) {
+hermon_cmd_mad_ifc ( struct hermon *hermon, unsigned int port,
+                    union hermonprm_mad *mad ) {
        return hermon_cmd ( hermon,
                            HERMON_HCR_INOUT_CMD ( HERMON_HCR_MAD_IFC,
                                                   1, sizeof ( *mad ),
                                                   1, sizeof ( *mad ) ),
-                           0x03, mad, PXE_IB_PORT, mad );
+                           0x03, mad, port, mad );
 }
 
 static inline int
@@ -601,7 +596,7 @@ static void hermon_free_mtt ( struct hermon *hermon,
  */
 static int hermon_create_cq ( struct ib_device *ibdev,
                              struct ib_completion_queue *cq ) {
-       struct hermon *hermon = ibdev->dev_priv;
+       struct hermon *hermon = ib_get_drvdata ( ibdev );
        struct hermon_completion_queue *hermon_cq;
        struct hermonprm_completion_queue_context cqctx;
        int cqn_offset;
@@ -667,7 +662,7 @@ static int hermon_create_cq ( struct ib_device *ibdev,
        DBGC ( hermon, "Hermon %p CQN %#lx ring at [%p,%p)\n",
               hermon, cq->cqn, hermon_cq->cqe,
               ( ( ( void * ) hermon_cq->cqe ) + hermon_cq->cqe_size ) );
-       cq->dev_priv = hermon_cq;
+       ib_cq_set_drvdata ( cq, hermon_cq );
        return 0;
 
  err_sw2hw_cq:
@@ -690,8 +685,8 @@ static int hermon_create_cq ( struct ib_device *ibdev,
  */
 static void hermon_destroy_cq ( struct ib_device *ibdev,
                                struct ib_completion_queue *cq ) {
-       struct hermon *hermon = ibdev->dev_priv;
-       struct hermon_completion_queue *hermon_cq = cq->dev_priv;
+       struct hermon *hermon = ib_get_drvdata ( ibdev );
+       struct hermon_completion_queue *hermon_cq = ib_cq_get_drvdata ( cq );
        struct hermonprm_completion_queue_context cqctx;
        int cqn_offset;
        int rc;
@@ -715,7 +710,7 @@ static void hermon_destroy_cq ( struct ib_device *ibdev,
        cqn_offset = ( cq->cqn - hermon->cap.reserved_cqs );
        hermon_bitmask_free ( hermon->cq_inuse, cqn_offset, 1 );
 
-       cq->dev_priv = NULL;
+       ib_cq_set_drvdata ( cq, NULL );
 }
 
 /***************************************************************************
@@ -734,7 +729,7 @@ static void hermon_destroy_cq ( struct ib_device *ibdev,
  */
 static int hermon_create_qp ( struct ib_device *ibdev,
                              struct ib_queue_pair *qp ) {
-       struct hermon *hermon = ibdev->dev_priv;
+       struct hermon *hermon = ib_get_drvdata ( ibdev );
        struct hermon_queue_pair *hermon_qp;
        struct hermonprm_qp_ee_state_transitions qpctx;
        int qpn_offset;
@@ -787,7 +782,7 @@ static int hermon_create_qp ( struct ib_device *ibdev,
                goto err_alloc_mtt;
        }
 
-       /* Hand queue over to hardware */
+       /* Transition queue to INIT state */
        memset ( &qpctx, 0, sizeof ( qpctx ) );
        MLX_FILL_2 ( &qpctx, 2,
                     qpc_eec_data.pm_state, 0x03 /* Always 0x03 for UD */,
@@ -819,6 +814,7 @@ static int hermon_create_qp ( struct ib_device *ibdev,
                goto err_rst2init_qp;
        }
 
+       /* Transition queue to RTR state */
        memset ( &qpctx, 0, sizeof ( qpctx ) );
        MLX_FILL_2 ( &qpctx, 4,
                     qpc_eec_data.mtu, HERMON_MTU_2048,
@@ -826,7 +822,7 @@ static int hermon_create_qp ( struct ib_device *ibdev,
        MLX_FILL_1 ( &qpctx, 16,
                     qpc_eec_data.primary_address_path.sched_queue,
                     ( 0x83 /* default policy */ |
-                      ( ( PXE_IB_PORT - 1 ) << 6 ) ) );
+                      ( ( ibdev->port - 1 ) << 6 ) ) );
        if ( ( rc = hermon_cmd_init2rtr_qp ( hermon, qp->qpn,
                                             &qpctx ) ) != 0 ) {
                DBGC ( hermon, "Hermon %p INIT2RTR_QP failed: %s\n",
@@ -846,7 +842,7 @@ static int hermon_create_qp ( struct ib_device *ibdev,
        DBGC ( hermon, "Hermon %p QPN %#lx receive ring at [%p,%p)\n",
               hermon, qp->qpn, hermon_qp->recv.wqe,
               ( ((void *)hermon_qp->recv.wqe ) + hermon_qp->recv.wqe_size ) );
-       qp->dev_priv = hermon_qp;
+       ib_qp_set_drvdata ( qp, hermon_qp );
        return 0;
 
  err_rtr2rts_qp:
@@ -872,8 +868,8 @@ static int hermon_create_qp ( struct ib_device *ibdev,
  */
 static void hermon_destroy_qp ( struct ib_device *ibdev,
                                struct ib_queue_pair *qp ) {
-       struct hermon *hermon = ibdev->dev_priv;
-       struct hermon_queue_pair *hermon_qp = qp->dev_priv;
+       struct hermon *hermon = ib_get_drvdata ( ibdev );
+       struct hermon_queue_pair *hermon_qp = ib_qp_get_drvdata ( qp );
        int qpn_offset;
        int rc;
 
@@ -897,7 +893,7 @@ static void hermon_destroy_qp ( struct ib_device *ibdev,
                       hermon->cap.reserved_qps );
        hermon_bitmask_free ( hermon->qp_inuse, qpn_offset, 1 );
 
-       qp->dev_priv = NULL;
+       ib_qp_set_drvdata ( qp, NULL );
 }
 
 /***************************************************************************
@@ -925,8 +921,8 @@ static int hermon_post_send ( struct ib_device *ibdev,
                              struct ib_queue_pair *qp,
                              struct ib_address_vector *av,
                              struct io_buffer *iobuf ) {
-       struct hermon *hermon = ibdev->dev_priv;
-       struct hermon_queue_pair *hermon_qp = qp->dev_priv;
+       struct hermon *hermon = ib_get_drvdata ( ibdev );
+       struct hermon_queue_pair *hermon_qp = ib_qp_get_drvdata ( qp );
        struct ib_work_queue *wq = &qp->send;
        struct hermon_send_work_queue *hermon_send_wq = &hermon_qp->send;
        struct hermonprm_ud_send_wqe *wqe;
@@ -951,7 +947,7 @@ static int hermon_post_send ( struct ib_device *ibdev,
        MLX_FILL_1 ( &wqe->ctrl, 2, c, 0x03 /* generate completion */ );
        MLX_FILL_2 ( &wqe->ud, 0,
                     ud_address_vector.pd, HERMON_GLOBAL_PD,
-                    ud_address_vector.port_number, PXE_IB_PORT );
+                    ud_address_vector.port_number, ibdev->port );
        MLX_FILL_2 ( &wqe->ud, 1,
                     ud_address_vector.rlid, av->dlid,
                     ud_address_vector.g, av->gid_present );
@@ -1001,8 +997,8 @@ static int hermon_post_send ( struct ib_device *ibdev,
 static int hermon_post_recv ( struct ib_device *ibdev,
                              struct ib_queue_pair *qp,
                              struct io_buffer *iobuf ) {
-       struct hermon *hermon = ibdev->dev_priv;
-       struct hermon_queue_pair *hermon_qp = qp->dev_priv;
+       struct hermon *hermon = ib_get_drvdata ( ibdev );
+       struct hermon_queue_pair *hermon_qp = ib_qp_get_drvdata ( qp );
        struct ib_work_queue *wq = &qp->recv;
        struct hermon_recv_work_queue *hermon_recv_wq = &hermon_qp->recv;
        struct hermonprm_recv_wqe *wqe;
@@ -1049,7 +1045,7 @@ static int hermon_complete ( struct ib_device *ibdev,
                             union hermonprm_completion_entry *cqe,
                             ib_completer_t complete_send,
                             ib_completer_t complete_recv ) {
-       struct hermon *hermon = ibdev->dev_priv;
+       struct hermon *hermon = ib_get_drvdata ( ibdev );
        struct ib_completion completion;
        struct ib_work_queue *wq;
        struct ib_queue_pair *qp;
@@ -1086,7 +1082,7 @@ static int hermon_complete ( struct ib_device *ibdev,
                return -EIO;
        }
        qp = wq->qp;
-       hermon_qp = qp->dev_priv;
+       hermon_qp = ib_qp_get_drvdata ( qp );
 
        /* Identify I/O buffer */
        wqe_idx = ( MLX_GET ( &cqe->normal, wqe_counter ) &
@@ -1129,8 +1125,8 @@ static void hermon_poll_cq ( struct ib_device *ibdev,
                             struct ib_completion_queue *cq,
                             ib_completer_t complete_send,
                             ib_completer_t complete_recv ) {
-       struct hermon *hermon = ibdev->dev_priv;
-       struct hermon_completion_queue *hermon_cq = cq->dev_priv;
+       struct hermon *hermon = ib_get_drvdata ( ibdev );
+       struct hermon_completion_queue *hermon_cq = ib_cq_get_drvdata ( cq );
        union hermonprm_completion_entry *cqe;
        unsigned int cqe_idx_mask;
        int rc;
@@ -1164,6 +1160,58 @@ static void hermon_poll_cq ( struct ib_device *ibdev,
        }
 }
 
+/***************************************************************************
+ *
+ * Infiniband link-layer operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Initialise Infiniband link
+ *
+ * @v ibdev            Infiniband device
+ * @ret rc             Return status code
+ */
+static int hermon_open ( struct ib_device *ibdev ) {
+       struct hermon *hermon = ib_get_drvdata ( ibdev );
+       struct hermonprm_init_port init_port;
+       int rc;
+
+       memset ( &init_port, 0, sizeof ( init_port ) );
+       MLX_FILL_2 ( &init_port, 0,
+                    port_width_cap, 3,
+                    vl_cap, 1 );
+       MLX_FILL_2 ( &init_port, 1,
+                    mtu, HERMON_MTU_2048,
+                    max_gid, 1 );
+       MLX_FILL_1 ( &init_port, 2, max_pkey, 64 );
+       if ( ( rc = hermon_cmd_init_port ( hermon, ibdev->port,
+                                          &init_port ) ) != 0 ) {
+               DBGC ( hermon, "Hermon %p could not intialise port: %s\n",
+                      hermon, strerror ( rc ) );
+               return rc;
+       }
+
+       return 0;
+}
+
+/**
+ * Close Infiniband link
+ *
+ * @v ibdev            Infiniband device
+ */
+static void hermon_close ( struct ib_device *ibdev ) {
+       struct hermon *hermon = ib_get_drvdata ( ibdev );
+       int rc;
+
+       if ( ( rc = hermon_cmd_close_port ( hermon, ibdev->port ) ) != 0 ) {
+               DBGC ( hermon, "Hermon %p could not close port: %s\n",
+                      hermon, strerror ( rc ) );
+               /* Nothing we can do about this */
+       }
+}
+
 /***************************************************************************
  *
  * Multicast group operations
@@ -1182,7 +1230,7 @@ static void hermon_poll_cq ( struct ib_device *ibdev,
 static int hermon_mcast_attach ( struct ib_device *ibdev,
                                 struct ib_queue_pair *qp,
                                 struct ib_gid *gid ) {
-       struct hermon *hermon = ibdev->dev_priv;
+       struct hermon *hermon = ib_get_drvdata ( ibdev );
        struct hermonprm_mgm_hash hash;
        struct hermonprm_mcg_entry mcg;
        unsigned int index;
@@ -1236,7 +1284,7 @@ static int hermon_mcast_attach ( struct ib_device *ibdev,
 static void hermon_mcast_detach ( struct ib_device *ibdev,
                                  struct ib_queue_pair *qp __unused,
                                  struct ib_gid *gid ) {
-       struct hermon *hermon = ibdev->dev_priv;
+       struct hermon *hermon = ib_get_drvdata ( ibdev );
        struct hermonprm_mgm_hash hash;
        struct hermonprm_mcg_entry mcg;
        unsigned int index;
@@ -1259,216 +1307,67 @@ static void hermon_mcast_detach ( struct ib_device *ibdev,
        }
 }
 
-/** Hermon Infiniband operations */
-static struct ib_device_operations hermon_ib_operations = {
-       .create_cq      = hermon_create_cq,
-       .destroy_cq     = hermon_destroy_cq,
-       .create_qp      = hermon_create_qp,
-       .destroy_qp     = hermon_destroy_qp,
-       .post_send      = hermon_post_send,
-       .post_recv      = hermon_post_recv,
-       .poll_cq        = hermon_poll_cq,
-       .mcast_attach   = hermon_mcast_attach,
-       .mcast_detach   = hermon_mcast_detach,
-};
-
 /***************************************************************************
  *
- * MAD IFC operations
+ * MAD operations
  *
  ***************************************************************************
  */
 
-static int hermon_mad_ifc ( struct hermon *hermon,
-                           union hermonprm_mad *mad ) {
-       struct ib_mad_hdr *hdr = &mad->mad.mad_hdr;
-       int rc;
-
-       hdr->base_version = IB_MGMT_BASE_VERSION;
-       if ( ( rc = hermon_cmd_mad_ifc ( hermon, mad ) ) != 0 ) {
-               DBGC ( hermon, "Hermon %p could not issue MAD IFC: %s\n",
-                      hermon, strerror ( rc ) );
-               return rc;
-       }
-       if ( hdr->status != 0 ) {
-               DBGC ( hermon, "Hermon %p MAD IFC status %04x\n",
-                      hermon, ntohs ( hdr->status ) );
-               return -EIO;
-       }
-       return 0;
-}
-
-static int hermon_get_port_info ( struct hermon *hermon,
-                                 struct ib_mad_port_info *port_info ) {
-       union hermonprm_mad mad;
-       struct ib_mad_hdr *hdr = &mad.mad.mad_hdr;
-       int rc;
-
-       memset ( &mad, 0, sizeof ( mad ) );
-       hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
-       hdr->class_version = 1;
-       hdr->method = IB_MGMT_METHOD_GET;
-       hdr->attr_id = htons ( IB_SMP_ATTR_PORT_INFO );
-       hdr->attr_mod = htonl ( PXE_IB_PORT );
-       if ( ( rc = hermon_mad_ifc ( hermon, &mad ) ) != 0 ) {
-               DBGC ( hermon, "Hermon %p could not get port info: %s\n",
-                      hermon, strerror ( rc ) );
-               return rc;
-       }
-       memcpy ( port_info, &mad.mad.port_info, sizeof ( *port_info ) );
-       return 0;
-}
-
-static int hermon_get_guid_info ( struct hermon *hermon,
-                                 struct ib_mad_guid_info *guid_info ) {
-       union hermonprm_mad mad;
-       struct ib_mad_hdr *hdr = &mad.mad.mad_hdr;
-       int rc;
-
-       memset ( &mad, 0, sizeof ( mad ) );
-       hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
-       hdr->class_version = 1;
-       hdr->method = IB_MGMT_METHOD_GET;
-       hdr->attr_id = htons ( IB_SMP_ATTR_GUID_INFO );
-       if ( ( rc = hermon_mad_ifc ( hermon, &mad ) ) != 0 ) {
-               DBGC ( hermon, "Hermon %p could not get GUID info: %s\n",
-                      hermon, strerror ( rc ) );
-               return rc;
-       }
-       memcpy ( guid_info, &mad.mad.guid_info, sizeof ( *guid_info ) );
-       return 0;
-}
-
-static int hermon_get_pkey_table ( struct hermon *hermon,
-                                  struct ib_mad_pkey_table *pkey_table ) {
-       union hermonprm_mad mad;
-       struct ib_mad_hdr *hdr = &mad.mad.mad_hdr;
-       int rc;
-
-       memset ( &mad, 0, sizeof ( mad ) );
-       hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
-       hdr->class_version = 1;
-       hdr->method = IB_MGMT_METHOD_GET;
-       hdr->attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE );
-       if ( ( rc = hermon_mad_ifc ( hermon, &mad ) ) != 0 ) {
-               DBGC ( hermon, "Hermon %p could not get pkey table: %s\n",
-                      hermon, strerror ( rc ) );
-               return rc;
-       }
-       memcpy ( pkey_table, &mad.mad.pkey_table, sizeof ( *pkey_table ) );
-       return 0;
-}
-
-static int hermon_get_port_gid ( struct hermon *hermon,
-                                struct ib_gid *port_gid ) {
-       union {
-               /* This union exists just to save stack space */
-               struct ib_mad_port_info port_info;
-               struct ib_mad_guid_info guid_info;
-       } u;
-       int rc;
-
-       /* Port info gives us the first half of the port GID */
-       if ( ( rc = hermon_get_port_info ( hermon, &u.port_info ) ) != 0 )
-               return rc;
-       memcpy ( &port_gid->u.bytes[0], u.port_info.gid_prefix, 8 );
-
-       /* GUID info gives us the second half of the port GID */
-       if ( ( rc = hermon_get_guid_info ( hermon, &u.guid_info ) ) != 0 )
-               return rc;
-       memcpy ( &port_gid->u.bytes[8], u.guid_info.gid_local, 8 );
-
-       return 0;
-}
-
-static int hermon_get_sm_lid ( struct hermon *hermon,
-                              unsigned long *sm_lid ) {
-       struct ib_mad_port_info port_info;
-       int rc;
-
-       if ( ( rc = hermon_get_port_info ( hermon, &port_info ) ) != 0 )
-               return rc;
-       *sm_lid = ntohs ( port_info.mastersm_lid );
-       return 0;
-}
-
-static int hermon_get_pkey ( struct hermon *hermon, unsigned int *pkey ) {
-       struct ib_mad_pkey_table pkey_table;
-       int rc;
-
-       if ( ( rc = hermon_get_pkey_table ( hermon, &pkey_table ) ) != 0 )
-               return rc;
-       *pkey = ntohs ( pkey_table.pkey[0][0] );
-       return 0;
-}
-
-/**
- * Wait for link up
- *
- * @v hermon           Hermon device
- * @ret rc             Return status code
- *
- * This function shouldn't really exist.  Unfortunately, IB links take
- * a long time to come up, and we can't get various key parameters
- * e.g. our own IPoIB MAC address without information from the subnet
- * manager).  We should eventually make link-up an asynchronous event.
- */
-static int hermon_wait_for_link ( struct hermon *hermon ) {
-       struct ib_mad_port_info port_info;
-       unsigned int retries;
-       int rc;
-
-       printf ( "Waiting for Infiniband link-up..." );
-       for ( retries = 20 ; retries ; retries-- ) {
-               if ( ( rc = hermon_get_port_info ( hermon,
-                                                  &port_info ) ) != 0 )
-                       continue;
-               if ( ( ( port_info.port_state__link_speed_supported ) & 0xf )
-                    == 4 ) {
-                       printf ( "ok\n" );
-                       return 0;
-               }
-               printf ( "." );
-               sleep ( 1 );
-       }
-       printf ( "failed\n" );
-       return -ENODEV;
-};
-
 /**
- * Get MAD parameters
+ * Issue management datagram
  *
- * @v hermon           Hermon device
+ * @v ibdev            Infiniband device
+ * @v mad              Management datagram
+ * @v len              Length of management datagram
  * @ret rc             Return status code
  */
-static int hermon_get_mad_params ( struct ib_device *ibdev ) {
-       struct hermon *hermon = ibdev->dev_priv;
+static int hermon_mad ( struct ib_device *ibdev, struct ib_mad_hdr *mad,
+                       size_t len ) {
+       struct hermon *hermon = ib_get_drvdata ( ibdev );
+       union hermonprm_mad mad_ifc;
        int rc;
 
-       /* Get subnet manager LID */
-       if ( ( rc = hermon_get_sm_lid ( hermon, &ibdev->sm_lid ) ) != 0 ) {
-               DBGC ( hermon, "Hermon %p could not determine subnet manager "
-                      "LID: %s\n", hermon, strerror ( rc ) );
-               return rc;
-       }
+       /* Copy in request packet */
+       memset ( &mad_ifc, 0, sizeof ( mad_ifc ) );
+       assert ( len <= sizeof ( mad_ifc.mad ) );
+       memcpy ( &mad_ifc.mad, mad, len );
 
-       /* Get port GID */
-       if ( ( rc = hermon_get_port_gid ( hermon, &ibdev->port_gid ) ) != 0 ) {
-               DBGC ( hermon, "Hermon %p could not determine port GID: %s\n",
+       /* Issue MAD */
+       if ( ( rc = hermon_cmd_mad_ifc ( hermon, ibdev->port,
+                                        &mad_ifc ) ) != 0 ) {
+               DBGC ( hermon, "Hermon %p could not issue MAD IFC: %s\n",
                       hermon, strerror ( rc ) );
                return rc;
        }
 
-       /* Get partition key */
-       if ( ( rc = hermon_get_pkey ( hermon, &ibdev->pkey ) ) != 0 ) {
-               DBGC ( hermon, "Hermon %p could not determine partition key: "
-                      "%s\n", hermon, strerror ( rc ) );
-               return rc;
-       }
+       /* Copy out reply packet */
+       memcpy ( mad, &mad_ifc.mad, len );
 
+       if ( mad->status != 0 ) {
+               DBGC ( hermon, "Hermon %p MAD IFC status %04x\n",
+                      hermon, ntohs ( mad->status ) );
+               return -EIO;
+       }
        return 0;
 }
 
+/** Hermon Infiniband operations */
+static struct ib_device_operations hermon_ib_operations = {
+       .create_cq      = hermon_create_cq,
+       .destroy_cq     = hermon_destroy_cq,
+       .create_qp      = hermon_create_qp,
+       .destroy_qp     = hermon_destroy_qp,
+       .post_send      = hermon_post_send,
+       .post_recv      = hermon_post_recv,
+       .poll_cq        = hermon_poll_cq,
+       .open           = hermon_open,
+       .close          = hermon_close,
+       .mcast_attach   = hermon_mcast_attach,
+       .mcast_detach   = hermon_mcast_detach,
+       .mad            = hermon_mad,
+};
+
 /***************************************************************************
  *
  * Firmware control
@@ -1916,56 +1815,6 @@ static void hermon_free_icm ( struct hermon *hermon ) {
        hermon->icm = UNULL;
 }
 
-/***************************************************************************
- *
- * Infiniband link-layer operations
- *
- ***************************************************************************
- */
-
-/**
- * Initialise Infiniband link
- *
- * @v hermon           Hermon device
- * @ret rc             Return status code
- */
-static int hermon_init_port ( struct hermon *hermon ) {
-       struct hermonprm_init_port init_port;
-       int rc;
-
-       memset ( &init_port, 0, sizeof ( init_port ) );
-       MLX_FILL_2 ( &init_port, 0,
-                    port_width_cap, 3,
-                    vl_cap, 1 );
-       MLX_FILL_2 ( &init_port, 1,
-                    mtu, HERMON_MTU_2048,
-                    max_gid, 1 );
-       MLX_FILL_1 ( &init_port, 2, max_pkey, 64 );
-       if ( ( rc = hermon_cmd_init_port ( hermon, PXE_IB_PORT,
-                                          &init_port ) ) != 0 ) {
-               DBGC ( hermon, "Hermon %p could not intialise port: %s\n",
-                      hermon, strerror ( rc ) );
-               return rc;
-       }
-
-       return 0;
-}
-
-/**
- * Close Infiniband link
- *
- * @v hermon           Hermon device
- */
-static void hermon_close_port ( struct hermon *hermon ) {
-       int rc;
-
-       if ( ( rc = hermon_cmd_close_port ( hermon, PXE_IB_PORT ) ) != 0 ) {
-               DBGC ( hermon, "Hermon %p could not close port: %s\n",
-                      hermon, strerror ( rc ) );
-               /* Nothing we can do about this */
-       }
-}
-
 /***************************************************************************
  *
  * PCI interface
@@ -2018,22 +1867,33 @@ static int hermon_setup_mpt ( struct hermon *hermon ) {
  */
 static int hermon_probe ( struct pci_device *pci,
                          const struct pci_device_id *id __unused ) {
-       struct ib_device *ibdev;
        struct hermon *hermon;
+       struct ib_device *ibdev;
        struct hermonprm_init_hca init_hca;
+       int i;
        int rc;
 
-       /* Allocate Infiniband device */
-       ibdev = alloc_ibdev ( sizeof ( *hermon ) );
-       if ( ! ibdev ) {
+       /* Allocate Hermon device */
+       hermon = zalloc ( sizeof ( *hermon ) );
+       if ( ! hermon ) {
                rc = -ENOMEM;
-               goto err_ibdev;
+               goto err_alloc_hermon;
+       }
+       pci_set_drvdata ( pci, hermon );
+
+       /* Allocate Infiniband devices */
+       for ( i = 0 ; i < HERMON_NUM_PORTS ; i++ ) {
+               ibdev = alloc_ibdev ( 0 );
+               if ( ! ibdev ) {
+                       rc = -ENOMEM;
+                       goto err_alloc_ibdev;
+               }
+               hermon->ibdev[i] = ibdev;
+               ibdev->op = &hermon_ib_operations;
+               ibdev->dev = &pci->dev;
+               ibdev->port = ( HERMON_PORT_BASE + i );
+               ib_set_drvdata ( ibdev, hermon );
        }
-       ibdev->op = &hermon_ib_operations;
-       pci_set_drvdata ( pci, ibdev );
-       ibdev->dev = &pci->dev;
-       hermon = ibdev->dev_priv;
-       memset ( hermon, 0, sizeof ( *hermon ) );
 
        /* Fix up PCI device */
        adjust_pci_device ( pci );
@@ -2086,38 +1946,21 @@ static int hermon_probe ( struct pci_device *pci,
        if ( ( rc = hermon_setup_mpt ( hermon ) ) != 0 )
                goto err_setup_mpt;
 
-       /* Bring up IB layer */
-       if ( ( rc = hermon_init_port ( hermon ) ) != 0 )
-               goto err_init_port;
-
-       /* Wait for link */
-       if ( ( rc = hermon_wait_for_link ( hermon ) ) != 0 )
-               goto err_wait_for_link;
-
-       /* Get MAD parameters */
-       if ( ( rc = hermon_get_mad_params ( ibdev ) ) != 0 )
-               goto err_get_mad_params;
-
-       DBGC ( hermon, "Hermon %p port GID is %08lx:%08lx:%08lx:%08lx\n",
-              hermon, htonl ( ibdev->port_gid.u.dwords[0] ),
-              htonl ( ibdev->port_gid.u.dwords[1] ),
-              htonl ( ibdev->port_gid.u.dwords[2] ),
-              htonl ( ibdev->port_gid.u.dwords[3] ) );
-
-       /* Add IPoIB device */
-       if ( ( rc = ipoib_probe ( ibdev ) ) != 0 ) {
-               DBGC ( hermon, "Hermon %p could not add IPoIB device: %s\n",
-                      hermon, strerror ( rc ) );
-               goto err_ipoib_probe;
+       /* Register Infiniband devices */
+       for ( i = 0 ; i < HERMON_NUM_PORTS ; i++ ) {
+               if ( ( rc = register_ibdev ( hermon->ibdev[i] ) ) != 0 ) {
+                       DBGC ( hermon, "Hermon %p could not register IB "
+                              "device: %s\n", hermon, strerror ( rc ) );
+                       goto err_register_ibdev;
+               }
        }
 
        return 0;
 
- err_ipoib_probe:
- err_get_mad_params:
- err_wait_for_link:
-       hermon_close_port ( hermon );
- err_init_port:
+       i = ( HERMON_NUM_PORTS - 1 );
+ err_register_ibdev:
+       for ( ; i >= 0 ; i-- )
+               unregister_ibdev ( hermon->ibdev[i] );
  err_setup_mpt:
        hermon_cmd_close_hca ( hermon );
  err_init_hca:
@@ -2130,8 +1973,12 @@ static int hermon_probe ( struct pci_device *pci,
  err_mailbox_out:
        free_dma ( hermon->mailbox_in, HERMON_MBOX_SIZE );
  err_mailbox_in:
-       free_ibdev ( ibdev );
- err_ibdev:
+       i = ( HERMON_NUM_PORTS - 1 );
+ err_alloc_ibdev:
+       for ( ; i >= 0 ; i-- )
+               free_ibdev ( hermon->ibdev[i] );
+       free ( hermon );
+ err_alloc_hermon:
        return rc;
 }
 
@@ -2141,18 +1988,20 @@ static int hermon_probe ( struct pci_device *pci,
  * @v pci              PCI device
  */
 static void hermon_remove ( struct pci_device *pci ) {
-       struct ib_device *ibdev = pci_get_drvdata ( pci );
-       struct hermon *hermon = ibdev->dev_priv;
+       struct hermon *hermon = pci_get_drvdata ( pci );
+       int i;
 
-       ipoib_remove ( ibdev );
-       hermon_close_port ( hermon );
+       for ( i = ( HERMON_NUM_PORTS - 1 ) ; i >= 0 ; i-- )
+               unregister_ibdev ( hermon->ibdev[i] );
        hermon_cmd_close_hca ( hermon );
        hermon_free_icm ( hermon );
        hermon_stop_firmware ( hermon );
        hermon_stop_firmware ( hermon );
        free_dma ( hermon->mailbox_out, HERMON_MBOX_SIZE );
        free_dma ( hermon->mailbox_in, HERMON_MBOX_SIZE );
-       free_ibdev ( ibdev );
+       for ( i = ( HERMON_NUM_PORTS - 1 ) ; i >= 0 ; i-- )
+               free_ibdev ( hermon->ibdev[i] );
+       free ( hermon );
 }
 
 static struct pci_device_id hermon_nics[] = {