[Infiniband] Move event-queue process from driver to Infiniband core
authorMichael Brown <mcb30@etherboot.org>
Mon, 21 Apr 2008 12:23:11 +0000 (13:23 +0100)
committerMichael Brown <mcb30@etherboot.org>
Mon, 21 Apr 2008 12:23:11 +0000 (13:23 +0100)
src/drivers/infiniband/arbel.c
src/drivers/infiniband/hermon.c
src/drivers/infiniband/hermon.h
src/include/gpxe/infiniband.h
src/net/infiniband.c

index 462638e..2409e28 100644 (file)
@@ -835,6 +835,27 @@ static int arbel_create_qp ( struct ib_device *ibdev,
        return rc;
 }
 
+/**
+ * Modify queue pair
+ *
+ * @v ibdev            Infiniband device
+ * @v qp               Queue pair
+ * @v mod_list         Modification list
+ * @ret rc             Return status code
+ */
+static int arbel_modify_qp ( struct ib_device *ibdev,
+                            struct ib_queue_pair *qp,
+                            unsigned long mod_list ) {
+       struct arbel *arbel = ib_get_drvdata ( ibdev );
+
+       /* TODO */
+       ( void ) arbel;
+       ( void ) qp;
+       ( void ) mod_list;
+
+       return -ENOTSUP;
+}
+
 /**
  * Destroy queue pair
  *
@@ -1202,6 +1223,25 @@ static void arbel_poll_cq ( struct ib_device *ibdev,
        }
 }
 
+/***************************************************************************
+ *
+ * Event queues
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Poll event queue
+ *
+ * @v ibdev            Infiniband device
+ */
+static void arbel_poll_eq ( struct ib_device *ibdev ) {
+       struct arbel *arbel = ib_get_drvdata ( ibdev );
+
+       /* TODO */
+       ( void ) arbel;
+}
+
 /***************************************************************************
  *
  * Infiniband link-layer operations
@@ -1399,10 +1439,12 @@ static struct ib_device_operations arbel_ib_operations = {
        .create_cq      = arbel_create_cq,
        .destroy_cq     = arbel_destroy_cq,
        .create_qp      = arbel_create_qp,
+       .modify_qp      = arbel_modify_qp,
        .destroy_qp     = arbel_destroy_qp,
        .post_send      = arbel_post_send,
        .post_recv      = arbel_post_recv,
        .poll_cq        = arbel_poll_cq,
+       .poll_eq        = arbel_poll_eq,
        .open           = arbel_open,
        .close          = arbel_close,
        .mcast_attach   = arbel_mcast_attach,
@@ -1938,7 +1980,7 @@ static int arbel_probe ( struct pci_device *pci,
        i = ( ARBEL_NUM_PORTS - 1 );
  err_alloc_ibdev:
        for ( ; i >= 0 ; i-- )
-               free_ibdev ( arbel->ibdev[i] );
+               ibdev_put ( arbel->ibdev[i] );
        free ( arbel );
  err_alloc_arbel:
        return rc;
@@ -1962,7 +2004,7 @@ static void arbel_remove ( struct pci_device *pci ) {
        free_dma ( arbel->mailbox_out, ARBEL_MBOX_SIZE );
        free_dma ( arbel->mailbox_in, ARBEL_MBOX_SIZE );
        for ( i = ( ARBEL_NUM_PORTS - 1 ) ; i >= 0 ; i-- )
-               free_ibdev ( arbel->ibdev[i] );
+               ibdev_put ( arbel->ibdev[i] );
        free ( arbel );
 }
 
index 7d1b30a..c198556 100644 (file)
@@ -30,7 +30,6 @@
 #include <gpxe/umalloc.h>
 #include <gpxe/iobuf.h>
 #include <gpxe/netdevice.h>
-#include <gpxe/process.h>
 #include <gpxe/infiniband.h>
 #include "hermon.h"
 
@@ -1226,215 +1225,6 @@ 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
- *
- ***************************************************************************
- */
-
-/**
- * Attach to multicast group
- *
- * @v ibdev            Infiniband device
- * @v qp               Queue pair
- * @v gid              Multicast GID
- * @ret rc             Return status code
- */
-static int hermon_mcast_attach ( struct ib_device *ibdev,
-                                struct ib_queue_pair *qp,
-                                struct ib_gid *gid ) {
-       struct hermon *hermon = ib_get_drvdata ( ibdev );
-       struct hermonprm_mgm_hash hash;
-       struct hermonprm_mcg_entry mcg;
-       unsigned int index;
-       int rc;
-
-       /* Generate hash table index */
-       if ( ( rc = hermon_cmd_mgid_hash ( hermon, gid, &hash ) ) != 0 ) {
-               DBGC ( hermon, "Hermon %p could not hash GID: %s\n",
-                      hermon, strerror ( rc ) );
-               return rc;
-       }
-       index = MLX_GET ( &hash, hash );
-
-       /* Check for existing hash table entry */
-       if ( ( rc = hermon_cmd_read_mcg ( hermon, index, &mcg ) ) != 0 ) {
-               DBGC ( hermon, "Hermon %p could not read MCG %#x: %s\n",
-                      hermon, index, strerror ( rc ) );
-               return rc;
-       }
-       if ( MLX_GET ( &mcg, hdr.members_count ) != 0 ) {
-               /* FIXME: this implementation allows only a single QP
-                * per multicast group, and doesn't handle hash
-                * collisions.  Sufficient for IPoIB but may need to
-                * be extended in future.
-                */
-               DBGC ( hermon, "Hermon %p MGID index %#x already in use\n",
-                      hermon, index );
-               return -EBUSY;
-       }
-
-       /* Update hash table entry */
-       MLX_FILL_1 ( &mcg, 1, hdr.members_count, 1 );
-       MLX_FILL_1 ( &mcg, 8, qp[0].qpn, qp->qpn );
-       memcpy ( &mcg.u.dwords[4], gid, sizeof ( *gid ) );
-       if ( ( rc = hermon_cmd_write_mcg ( hermon, index, &mcg ) ) != 0 ) {
-               DBGC ( hermon, "Hermon %p could not write MCG %#x: %s\n",
-                      hermon, index, strerror ( rc ) );
-               return rc;
-       }
-
-       return 0;
-}
-
-/**
- * Detach from multicast group
- *
- * @v ibdev            Infiniband device
- * @v qp               Queue pair
- * @v gid              Multicast GID
- */
-static void hermon_mcast_detach ( struct ib_device *ibdev,
-                                 struct ib_queue_pair *qp __unused,
-                                 struct ib_gid *gid ) {
-       struct hermon *hermon = ib_get_drvdata ( ibdev );
-       struct hermonprm_mgm_hash hash;
-       struct hermonprm_mcg_entry mcg;
-       unsigned int index;
-       int rc;
-
-       /* Generate hash table index */
-       if ( ( rc = hermon_cmd_mgid_hash ( hermon, gid, &hash ) ) != 0 ) {
-               DBGC ( hermon, "Hermon %p could not hash GID: %s\n",
-                      hermon, strerror ( rc ) );
-               return;
-       }
-       index = MLX_GET ( &hash, hash );
-
-       /* Clear hash table entry */
-       memset ( &mcg, 0, sizeof ( mcg ) );
-       if ( ( rc = hermon_cmd_write_mcg ( hermon, index, &mcg ) ) != 0 ) {
-               DBGC ( hermon, "Hermon %p could not write MCG %#x: %s\n",
-                      hermon, index, strerror ( rc ) );
-               return;
-       }
-}
-
-/***************************************************************************
- *
- * MAD operations
- *
- ***************************************************************************
- */
-
-/**
- * Issue management datagram
- *
- * @v ibdev            Infiniband device
- * @v mad              Management datagram
- * @v len              Length of management datagram
- * @ret rc             Return status code
- */
-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;
-
-       /* Copy in request packet */
-       memset ( &mad_ifc, 0, sizeof ( mad_ifc ) );
-       assert ( len <= sizeof ( mad_ifc.mad ) );
-       memcpy ( &mad_ifc.mad, mad, len );
-
-       /* 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;
-       }
-
-       /* 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,
-       .modify_qp      = hermon_modify_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,
-};
-
 /***************************************************************************
  *
  * Event queues
@@ -1597,9 +1387,10 @@ static void hermon_event_port_state_change ( struct hermon *hermon,
 /**
  * Poll event queue
  *
- * @v hermon           Hermon device
+ * @v ibdev            Infiniband device
  */
-static void hermon_poll_eq ( struct hermon *hermon ) {
+static void hermon_poll_eq ( struct ib_device *ibdev ) {
+       struct hermon *hermon = ib_get_drvdata ( ibdev );
        struct hermon_event_queue *hermon_eq = &hermon->eq;
        union hermonprm_event_entry *eqe;
        union hermonprm_doorbell_register db_reg;
@@ -1644,18 +1435,216 @@ static void hermon_poll_eq ( struct hermon *hermon ) {
        }
 }
 
+/***************************************************************************
+ *
+ * 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;
+}
+
 /**
- * Event queue poll processor
+ * Close Infiniband link
  *
- * @v process          Hermon event queue process
+ * @v ibdev            Infiniband device
  */
-static void hermon_step ( struct process *process ) {
-       struct hermon *hermon =
-               container_of ( process, struct hermon, event_process );
+static void hermon_close ( struct ib_device *ibdev ) {
+       struct hermon *hermon = ib_get_drvdata ( ibdev );
+       int rc;
 
-       hermon_poll_eq ( hermon );
+       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
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Attach to multicast group
+ *
+ * @v ibdev            Infiniband device
+ * @v qp               Queue pair
+ * @v gid              Multicast GID
+ * @ret rc             Return status code
+ */
+static int hermon_mcast_attach ( struct ib_device *ibdev,
+                                struct ib_queue_pair *qp,
+                                struct ib_gid *gid ) {
+       struct hermon *hermon = ib_get_drvdata ( ibdev );
+       struct hermonprm_mgm_hash hash;
+       struct hermonprm_mcg_entry mcg;
+       unsigned int index;
+       int rc;
+
+       /* Generate hash table index */
+       if ( ( rc = hermon_cmd_mgid_hash ( hermon, gid, &hash ) ) != 0 ) {
+               DBGC ( hermon, "Hermon %p could not hash GID: %s\n",
+                      hermon, strerror ( rc ) );
+               return rc;
+       }
+       index = MLX_GET ( &hash, hash );
+
+       /* Check for existing hash table entry */
+       if ( ( rc = hermon_cmd_read_mcg ( hermon, index, &mcg ) ) != 0 ) {
+               DBGC ( hermon, "Hermon %p could not read MCG %#x: %s\n",
+                      hermon, index, strerror ( rc ) );
+               return rc;
+       }
+       if ( MLX_GET ( &mcg, hdr.members_count ) != 0 ) {
+               /* FIXME: this implementation allows only a single QP
+                * per multicast group, and doesn't handle hash
+                * collisions.  Sufficient for IPoIB but may need to
+                * be extended in future.
+                */
+               DBGC ( hermon, "Hermon %p MGID index %#x already in use\n",
+                      hermon, index );
+               return -EBUSY;
+       }
+
+       /* Update hash table entry */
+       MLX_FILL_1 ( &mcg, 1, hdr.members_count, 1 );
+       MLX_FILL_1 ( &mcg, 8, qp[0].qpn, qp->qpn );
+       memcpy ( &mcg.u.dwords[4], gid, sizeof ( *gid ) );
+       if ( ( rc = hermon_cmd_write_mcg ( hermon, index, &mcg ) ) != 0 ) {
+               DBGC ( hermon, "Hermon %p could not write MCG %#x: %s\n",
+                      hermon, index, strerror ( rc ) );
+               return rc;
+       }
+
+       return 0;
+}
+
+/**
+ * Detach from multicast group
+ *
+ * @v ibdev            Infiniband device
+ * @v qp               Queue pair
+ * @v gid              Multicast GID
+ */
+static void hermon_mcast_detach ( struct ib_device *ibdev,
+                                 struct ib_queue_pair *qp __unused,
+                                 struct ib_gid *gid ) {
+       struct hermon *hermon = ib_get_drvdata ( ibdev );
+       struct hermonprm_mgm_hash hash;
+       struct hermonprm_mcg_entry mcg;
+       unsigned int index;
+       int rc;
+
+       /* Generate hash table index */
+       if ( ( rc = hermon_cmd_mgid_hash ( hermon, gid, &hash ) ) != 0 ) {
+               DBGC ( hermon, "Hermon %p could not hash GID: %s\n",
+                      hermon, strerror ( rc ) );
+               return;
+       }
+       index = MLX_GET ( &hash, hash );
+
+       /* Clear hash table entry */
+       memset ( &mcg, 0, sizeof ( mcg ) );
+       if ( ( rc = hermon_cmd_write_mcg ( hermon, index, &mcg ) ) != 0 ) {
+               DBGC ( hermon, "Hermon %p could not write MCG %#x: %s\n",
+                      hermon, index, strerror ( rc ) );
+               return;
+       }
+}
+
+/***************************************************************************
+ *
+ * MAD operations
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Issue management datagram
+ *
+ * @v ibdev            Infiniband device
+ * @v mad              Management datagram
+ * @v len              Length of management datagram
+ * @ret rc             Return status code
+ */
+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;
+
+       /* Copy in request packet */
+       memset ( &mad_ifc, 0, sizeof ( mad_ifc ) );
+       assert ( len <= sizeof ( mad_ifc.mad ) );
+       memcpy ( &mad_ifc.mad, mad, len );
+
+       /* 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;
+       }
+
+       /* 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,
+       .modify_qp      = hermon_modify_qp,
+       .destroy_qp     = hermon_destroy_qp,
+       .post_send      = hermon_post_send,
+       .post_recv      = hermon_post_recv,
+       .poll_cq        = hermon_poll_cq,
+       .poll_eq        = hermon_poll_eq,
+       .open           = hermon_open,
+       .close          = hermon_close,
+       .mcast_attach   = hermon_mcast_attach,
+       .mcast_detach   = hermon_mcast_detach,
+       .mad            = hermon_mad,
+};
+
 /***************************************************************************
  *
  * Firmware control
@@ -2168,7 +2157,6 @@ static int hermon_probe ( struct pci_device *pci,
                goto err_alloc_hermon;
        }
        pci_set_drvdata ( pci, hermon );
-       process_init ( &hermon->event_process, hermon_step, NULL );
 
        /* Allocate Infiniband devices */
        for ( i = 0 ; i < HERMON_NUM_PORTS ; i++ ) {
@@ -2270,8 +2258,7 @@ static int hermon_probe ( struct pci_device *pci,
        i = ( HERMON_NUM_PORTS - 1 );
  err_alloc_ibdev:
        for ( ; i >= 0 ; i-- )
-               free_ibdev ( hermon->ibdev[i] );
-       process_del ( &hermon->event_process );
+               ibdev_put ( hermon->ibdev[i] );
        free ( hermon );
  err_alloc_hermon:
        return rc;
@@ -2296,8 +2283,7 @@ static void hermon_remove ( struct pci_device *pci ) {
        free_dma ( hermon->mailbox_out, HERMON_MBOX_SIZE );
        free_dma ( hermon->mailbox_in, HERMON_MBOX_SIZE );
        for ( i = ( HERMON_NUM_PORTS - 1 ) ; i >= 0 ; i-- )
-               free_ibdev ( hermon->ibdev[i] );
-       process_del ( &hermon->event_process );
+               ibdev_put ( hermon->ibdev[i] );
        free ( hermon );
 }
 
index 45d7a1c..1ae2778 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <stdint.h>
 #include <gpxe/uaccess.h>
-#include <gpxe/process.h>
 #include "mlx_bitops.h"
 #include "MT25408_PRM.h"
 
@@ -465,8 +464,6 @@ struct hermon {
 
        /** Event queue */
        struct hermon_event_queue eq;
-       /** Event queue process */
-       struct process event_process;
 
        /** Completion queue in-use bitmask */
        hermon_bitmask_t cq_inuse[ HERMON_BITMASK_SIZE ( HERMON_MAX_CQS ) ];
index 8fc928c..f9e6534 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <stdint.h>
+#include <gpxe/refcnt.h>
 #include <gpxe/device.h>
 
 /** Subnet administrator QPN */
@@ -254,6 +255,12 @@ struct ib_device_operations {
                             struct ib_completion_queue *cq,
                             ib_completer_t complete_send,
                             ib_completer_t complete_recv );
+       /**
+        * Poll event queue
+        *
+        * @v ibdev             Infiniband device
+        */
+       void ( * poll_eq ) ( struct ib_device *ibdev );
        /**
         * Open port
         *
@@ -300,6 +307,10 @@ struct ib_device_operations {
 
 /** An Infiniband device */
 struct ib_device {
+       /** Reference counter */
+       struct refcnt refcnt;
+       /** List of Infiniband devices */
+       struct list_head list;
        /** Underlying device */
        struct device *dev;
        /** Infiniband operations */
@@ -337,7 +348,6 @@ extern struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq,
 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 );
-extern void free_ibdev ( struct ib_device *ibdev );
 extern void ib_link_state_changed ( struct ib_device *ibdev );
 
 /**
@@ -444,6 +454,28 @@ ib_mad ( struct ib_device *ibdev, struct ib_mad_hdr *mad, size_t len ) {
        return ibdev->op->mad ( ibdev, mad, len );
 }
 
+/**
+ * Get reference to Infiniband device
+ *
+ * @v ibdev            Infiniband device
+ * @ret ibdev          Infiniband device
+ */
+static inline __attribute__ (( always_inline )) struct ib_device *
+ibdev_get ( struct ib_device *ibdev ) {
+       ref_get ( &ibdev->refcnt );
+       return ibdev;
+}
+
+/**
+ * Drop reference to Infiniband device
+ *
+ * @v ibdev            Infiniband device
+ */
+static inline __attribute__ (( always_inline )) void
+ibdev_put ( struct ib_device *ibdev ) {
+       ref_put ( &ibdev->refcnt );
+}
+
 /**
  * Set Infiniband work queue driver-private data
  *
index e5c79e9..ab76742 100644 (file)
@@ -29,6 +29,7 @@
 #include <gpxe/netdevice.h>
 #include <gpxe/iobuf.h>
 #include <gpxe/ipoib.h>
+#include <gpxe/process.h>
 #include <gpxe/infiniband.h>
 
 /** @file
@@ -37,6 +38,9 @@
  *
  */
 
+/** List of Infiniband devices */
+struct list_head ib_devices = LIST_HEAD_INIT ( ib_devices );
+
 /**
  * Create completion queue
  *
@@ -349,6 +353,50 @@ static int ib_get_mad_params ( struct ib_device *ibdev ) {
        return 0;
 }
 
+/***************************************************************************
+ *
+ * Event queues
+ *
+ ***************************************************************************
+ */
+
+/**
+ * Handle Infiniband link state change
+ *
+ * @v ibdev            Infiniband device
+ */
+void ib_link_state_changed ( struct ib_device *ibdev ) {
+       int rc;
+
+       /* Update MAD parameters */
+       if ( ( rc = ib_get_mad_params ( ibdev ) ) != 0 ) {
+               DBGC ( ibdev, "IBDEV %p could not update MAD parameters: %s\n",
+                      ibdev, strerror ( rc ) );
+               return;
+       }
+
+       /* Notify IPoIB of link state change */
+       ipoib_link_state_changed ( ibdev );
+}
+
+/**
+ * Single-step the Infiniband event queue
+ *
+ * @v process          Infiniband event queue process
+ */
+static void ib_step ( struct process *process __unused ) {
+       struct ib_device *ibdev;
+
+       list_for_each_entry ( ibdev, &ib_devices, list ) {
+               ibdev->op->poll_eq ( ibdev );
+       }
+}
+
+/** Infiniband event queue process */
+struct process ib_process __permanent_process = {
+       .step = ib_step,
+};
+
 /***************************************************************************
  *
  * Infiniband device creation/destruction
@@ -385,6 +433,10 @@ struct ib_device * alloc_ibdev ( size_t priv_size ) {
 int register_ibdev ( struct ib_device *ibdev ) {
        int rc;
 
+       /* Add to device list */
+       ibdev_get ( ibdev );
+       list_add_tail ( &ibdev->list, &ib_devices );
+
        /* Open link */
        if ( ( rc = ib_open ( ibdev ) ) != 0 )
                goto err_open;
@@ -400,12 +452,16 @@ int register_ibdev ( struct ib_device *ibdev ) {
                goto err_ipoib_probe;
        }
 
+       DBGC ( ibdev, "IBDEV %p registered (phys %s)\n", ibdev,
+              ibdev->dev->name );
        return 0;
 
  err_ipoib_probe:
  err_get_mad_params:
        ib_close ( ibdev );
  err_open:
+       list_del ( &ibdev->list );
+       ibdev_put ( ibdev );
        return rc;
 }
 
@@ -415,34 +471,13 @@ int register_ibdev ( struct ib_device *ibdev ) {
  * @v ibdev            Infiniband device
  */
 void unregister_ibdev ( struct ib_device *ibdev ) {
+
+       /* Close device */
        ipoib_remove ( ibdev );
        ib_close ( ibdev );
-}
-
-/**
- * Free Infiniband device
- *
- * @v ibdev            Infiniband device
- */
-void free_ibdev ( struct ib_device *ibdev ) {
-       free ( ibdev );
-}
-
-/**
- * Handle Infiniband link state change
- *
- * @v ibdev            Infiniband device
- */
-void ib_link_state_changed ( struct ib_device *ibdev ) {
-       int rc;
 
-       /* Update MAD parameters */
-       if ( ( rc = ib_get_mad_params ( ibdev ) ) != 0 ) {
-               DBGC ( ibdev, "IBDEV %p could not update MAD parameters: %s\n",
-                      ibdev, strerror ( rc ) );
-               return;
-       }
-
-       /* Notify IPoIB of link state change */
-       ipoib_link_state_changed ( ibdev );
+       /* Remove from device list */
+       list_del ( &ibdev->list );
+       ibdev_put ( ibdev );
+       DBGC ( ibdev, "IBDEV %p unregistered\n", ibdev );
 }