[infiniband] Implement SMA as an instance of a GMA
[people/sha0/gpxe.git] / src / net / infiniband.c
1 /*
2  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 FILE_LICENCE ( GPL2_OR_LATER );
20
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <byteswap.h>
27 #include <errno.h>
28 #include <assert.h>
29 #include <gpxe/list.h>
30 #include <gpxe/if_arp.h>
31 #include <gpxe/netdevice.h>
32 #include <gpxe/iobuf.h>
33 #include <gpxe/ipoib.h>
34 #include <gpxe/process.h>
35 #include <gpxe/infiniband.h>
36
37 /** @file
38  *
39  * Infiniband protocol
40  *
41  */
42
43 /** List of Infiniband devices */
44 struct list_head ib_devices = LIST_HEAD_INIT ( ib_devices );
45
46 /***************************************************************************
47  *
48  * Completion queues
49  *
50  ***************************************************************************
51  */
52
53 /**
54  * Create completion queue
55  *
56  * @v ibdev             Infiniband device
57  * @v num_cqes          Number of completion queue entries
58  * @v op                Completion queue operations
59  * @ret cq              New completion queue
60  */
61 struct ib_completion_queue *
62 ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
63                struct ib_completion_queue_operations *op ) {
64         struct ib_completion_queue *cq;
65         int rc;
66
67         DBGC ( ibdev, "IBDEV %p creating completion queue\n", ibdev );
68
69         /* Allocate and initialise data structure */
70         cq = zalloc ( sizeof ( *cq ) );
71         if ( ! cq )
72                 goto err_alloc_cq;
73         cq->ibdev = ibdev;
74         list_add ( &cq->list, &ibdev->cqs );
75         cq->num_cqes = num_cqes;
76         INIT_LIST_HEAD ( &cq->work_queues );
77         cq->op = op;
78
79         /* Perform device-specific initialisation and get CQN */
80         if ( ( rc = ibdev->op->create_cq ( ibdev, cq ) ) != 0 ) {
81                 DBGC ( ibdev, "IBDEV %p could not initialise completion "
82                        "queue: %s\n", ibdev, strerror ( rc ) );
83                 goto err_dev_create_cq;
84         }
85
86         DBGC ( ibdev, "IBDEV %p created %d-entry completion queue %p (%p) "
87                "with CQN %#lx\n", ibdev, num_cqes, cq,
88                ib_cq_get_drvdata ( cq ), cq->cqn );
89         return cq;
90
91         ibdev->op->destroy_cq ( ibdev, cq );
92  err_dev_create_cq:
93         list_del ( &cq->list );
94         free ( cq );
95  err_alloc_cq:
96         return NULL;
97 }
98
99 /**
100  * Destroy completion queue
101  *
102  * @v ibdev             Infiniband device
103  * @v cq                Completion queue
104  */
105 void ib_destroy_cq ( struct ib_device *ibdev,
106                      struct ib_completion_queue *cq ) {
107         DBGC ( ibdev, "IBDEV %p destroying completion queue %#lx\n",
108                ibdev, cq->cqn );
109         assert ( list_empty ( &cq->work_queues ) );
110         ibdev->op->destroy_cq ( ibdev, cq );
111         list_del ( &cq->list );
112         free ( cq );
113 }
114
115 /**
116  * Poll completion queue
117  *
118  * @v ibdev             Infiniband device
119  * @v cq                Completion queue
120  */
121 void ib_poll_cq ( struct ib_device *ibdev,
122                   struct ib_completion_queue *cq ) {
123         struct ib_work_queue *wq;
124
125         /* Poll completion queue */
126         ibdev->op->poll_cq ( ibdev, cq );
127
128         /* Refill receive work queues */
129         list_for_each_entry ( wq, &cq->work_queues, list ) {
130                 if ( ! wq->is_send )
131                         ib_refill_recv ( ibdev, wq->qp );
132         }
133 }
134
135 /***************************************************************************
136  *
137  * Work queues
138  *
139  ***************************************************************************
140  */
141
142 /**
143  * Create queue pair
144  *
145  * @v ibdev             Infiniband device
146  * @v num_send_wqes     Number of send work queue entries
147  * @v send_cq           Send completion queue
148  * @v num_recv_wqes     Number of receive work queue entries
149  * @v recv_cq           Receive completion queue
150  * @v qkey              Queue key
151  * @ret qp              Queue pair
152  */
153 struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
154                                       unsigned int num_send_wqes,
155                                       struct ib_completion_queue *send_cq,
156                                       unsigned int num_recv_wqes,
157                                       struct ib_completion_queue *recv_cq,
158                                       unsigned long qkey ) {
159         struct ib_queue_pair *qp;
160         size_t total_size;
161         int rc;
162
163         DBGC ( ibdev, "IBDEV %p creating queue pair\n", ibdev );
164
165         /* Allocate and initialise data structure */
166         total_size = ( sizeof ( *qp ) +
167                        ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ) +
168                        ( num_recv_wqes * sizeof ( qp->recv.iobufs[0] ) ) );
169         qp = zalloc ( total_size );
170         if ( ! qp )
171                 goto err_alloc_qp;
172         qp->ibdev = ibdev;
173         list_add ( &qp->list, &ibdev->qps );
174         qp->qkey = qkey;
175         qp->send.qp = qp;
176         qp->send.is_send = 1;
177         qp->send.cq = send_cq;
178         list_add ( &qp->send.list, &send_cq->work_queues );
179         qp->send.num_wqes = num_send_wqes;
180         qp->send.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) );
181         qp->recv.qp = qp;
182         qp->recv.cq = recv_cq;
183         list_add ( &qp->recv.list, &recv_cq->work_queues );
184         qp->recv.num_wqes = num_recv_wqes;
185         qp->recv.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) +
186                             ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ));
187         INIT_LIST_HEAD ( &qp->mgids );
188
189         /* Perform device-specific initialisation and get QPN */
190         if ( ( rc = ibdev->op->create_qp ( ibdev, qp ) ) != 0 ) {
191                 DBGC ( ibdev, "IBDEV %p could not initialise queue pair: "
192                        "%s\n", ibdev, strerror ( rc ) );
193                 goto err_dev_create_qp;
194         }
195
196         DBGC ( ibdev, "IBDEV %p created queue pair %p (%p) with QPN %#lx\n",
197                ibdev, qp, ib_qp_get_drvdata ( qp ), qp->qpn );
198         DBGC ( ibdev, "IBDEV %p QPN %#lx has %d send entries at [%p,%p)\n",
199                ibdev, qp->qpn, num_send_wqes, qp->send.iobufs,
200                qp->recv.iobufs );
201         DBGC ( ibdev, "IBDEV %p QPN %#lx has %d receive entries at [%p,%p)\n",
202                ibdev, qp->qpn, num_recv_wqes, qp->recv.iobufs,
203                ( ( ( void * ) qp ) + total_size ) );
204         return qp;
205
206         ibdev->op->destroy_qp ( ibdev, qp );
207  err_dev_create_qp:
208         list_del ( &qp->send.list );
209         list_del ( &qp->recv.list );
210         list_del ( &qp->list );
211         free ( qp );
212  err_alloc_qp:
213         return NULL;
214 }
215
216 /**
217  * Modify queue pair
218  *
219  * @v ibdev             Infiniband device
220  * @v qp                Queue pair
221  * @v mod_list          Modification list
222  * @v qkey              New queue key, if applicable
223  * @ret rc              Return status code
224  */
225 int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp,
226                    unsigned long mod_list, unsigned long qkey ) {
227         int rc;
228
229         DBGC ( ibdev, "IBDEV %p modifying QPN %#lx\n", ibdev, qp->qpn );
230
231         if ( mod_list & IB_MODIFY_QKEY )
232                 qp->qkey = qkey;
233
234         if ( ( rc = ibdev->op->modify_qp ( ibdev, qp, mod_list ) ) != 0 ) {
235                 DBGC ( ibdev, "IBDEV %p could not modify QPN %#lx: %s\n",
236                        ibdev, qp->qpn, strerror ( rc ) );
237                 return rc;
238         }
239
240         return 0;
241 }
242
243 /**
244  * Destroy queue pair
245  *
246  * @v ibdev             Infiniband device
247  * @v qp                Queue pair
248  */
249 void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
250         struct io_buffer *iobuf;
251         unsigned int i;
252
253         DBGC ( ibdev, "IBDEV %p destroying QPN %#lx\n",
254                ibdev, qp->qpn );
255
256         assert ( list_empty ( &qp->mgids ) );
257
258         /* Perform device-specific destruction */
259         ibdev->op->destroy_qp ( ibdev, qp );
260
261         /* Complete any remaining I/O buffers with errors */
262         for ( i = 0 ; i < qp->send.num_wqes ; i++ ) {
263                 if ( ( iobuf = qp->send.iobufs[i] ) != NULL )
264                         ib_complete_send ( ibdev, qp, iobuf, -ECANCELED );
265         }
266         for ( i = 0 ; i < qp->recv.num_wqes ; i++ ) {
267                 if ( ( iobuf = qp->recv.iobufs[i] ) != NULL ) {
268                         ib_complete_recv ( ibdev, qp, NULL, iobuf,
269                                            -ECANCELED );
270                 }
271         }
272
273         /* Remove work queues from completion queue */
274         list_del ( &qp->send.list );
275         list_del ( &qp->recv.list );
276
277         /* Free QP */
278         list_del ( &qp->list );
279         free ( qp );
280 }
281
282 /**
283  * Find queue pair by QPN
284  *
285  * @v ibdev             Infiniband device
286  * @v qpn               Queue pair number
287  * @ret qp              Queue pair, or NULL
288  */
289 struct ib_queue_pair * ib_find_qp_qpn ( struct ib_device *ibdev,
290                                         unsigned long qpn ) {
291         struct ib_queue_pair *qp;
292
293         list_for_each_entry ( qp, &ibdev->qps, list ) {
294                 if ( qp->qpn == qpn )
295                         return qp;
296         }
297         return NULL;
298 }
299
300 /**
301  * Find queue pair by multicast GID
302  *
303  * @v ibdev             Infiniband device
304  * @v gid               Multicast GID
305  * @ret qp              Queue pair, or NULL
306  */
307 struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev,
308                                          struct ib_gid *gid ) {
309         struct ib_queue_pair *qp;
310         struct ib_multicast_gid *mgid;
311
312         list_for_each_entry ( qp, &ibdev->qps, list ) {
313                 list_for_each_entry ( mgid, &qp->mgids, list ) {
314                         if ( memcmp ( &mgid->gid, gid,
315                                       sizeof ( mgid->gid ) ) == 0 ) {
316                                 return qp;
317                         }
318                 }
319         }
320         return NULL;
321 }
322
323 /**
324  * Find work queue belonging to completion queue
325  *
326  * @v cq                Completion queue
327  * @v qpn               Queue pair number
328  * @v is_send           Find send work queue (rather than receive)
329  * @ret wq              Work queue, or NULL if not found
330  */
331 struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq,
332                                     unsigned long qpn, int is_send ) {
333         struct ib_work_queue *wq;
334
335         list_for_each_entry ( wq, &cq->work_queues, list ) {
336                 if ( ( wq->qp->qpn == qpn ) && ( wq->is_send == is_send ) )
337                         return wq;
338         }
339         return NULL;
340 }
341
342 /**
343  * Post send work queue entry
344  *
345  * @v ibdev             Infiniband device
346  * @v qp                Queue pair
347  * @v av                Address vector
348  * @v iobuf             I/O buffer
349  * @ret rc              Return status code
350  */
351 int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
352                    struct ib_address_vector *av,
353                    struct io_buffer *iobuf ) {
354         int rc;
355
356         /* Check queue fill level */
357         if ( qp->send.fill >= qp->send.num_wqes ) {
358                 DBGC ( ibdev, "IBDEV %p QPN %#lx send queue full\n",
359                        ibdev, qp->qpn );
360                 return -ENOBUFS;
361         }
362
363         /* Fill in optional parameters in address vector */
364         if ( ! av->qkey )
365                 av->qkey = qp->qkey;
366         if ( ! av->rate )
367                 av->rate = IB_RATE_2_5;
368
369         /* Post to hardware */
370         if ( ( rc = ibdev->op->post_send ( ibdev, qp, av, iobuf ) ) != 0 ) {
371                 DBGC ( ibdev, "IBDEV %p QPN %#lx could not post send WQE: "
372                        "%s\n", ibdev, qp->qpn, strerror ( rc ) );
373                 return rc;
374         }
375
376         qp->send.fill++;
377         return 0;
378 }
379
380 /**
381  * Post receive work queue entry
382  *
383  * @v ibdev             Infiniband device
384  * @v qp                Queue pair
385  * @v iobuf             I/O buffer
386  * @ret rc              Return status code
387  */
388 int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
389                    struct io_buffer *iobuf ) {
390         int rc;
391
392         /* Check packet length */
393         if ( iob_tailroom ( iobuf ) < IB_MAX_PAYLOAD_SIZE ) {
394                 DBGC ( ibdev, "IBDEV %p QPN %#lx wrong RX buffer size (%zd)\n",
395                        ibdev, qp->qpn, iob_tailroom ( iobuf ) );
396                 return -EINVAL;
397         }
398
399         /* Check queue fill level */
400         if ( qp->recv.fill >= qp->recv.num_wqes ) {
401                 DBGC ( ibdev, "IBDEV %p QPN %#lx receive queue full\n",
402                        ibdev, qp->qpn );
403                 return -ENOBUFS;
404         }
405
406         /* Post to hardware */
407         if ( ( rc = ibdev->op->post_recv ( ibdev, qp, iobuf ) ) != 0 ) {
408                 DBGC ( ibdev, "IBDEV %p QPN %#lx could not post receive WQE: "
409                        "%s\n", ibdev, qp->qpn, strerror ( rc ) );
410                 return rc;
411         }
412
413         qp->recv.fill++;
414         return 0;
415 }
416
417 /**
418  * Complete send work queue entry
419  *
420  * @v ibdev             Infiniband device
421  * @v qp                Queue pair
422  * @v iobuf             I/O buffer
423  * @v rc                Completion status code
424  */
425 void ib_complete_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
426                         struct io_buffer *iobuf, int rc ) {
427         qp->send.cq->op->complete_send ( ibdev, qp, iobuf, rc );
428         qp->send.fill--;
429 }
430
431 /**
432  * Complete receive work queue entry
433  *
434  * @v ibdev             Infiniband device
435  * @v qp                Queue pair
436  * @v av                Address vector
437  * @v iobuf             I/O buffer
438  * @v rc                Completion status code
439  */
440 void ib_complete_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
441                         struct ib_address_vector *av,
442                         struct io_buffer *iobuf, int rc ) {
443         qp->recv.cq->op->complete_recv ( ibdev, qp, av, iobuf, rc );
444         qp->recv.fill--;
445 }
446
447 /**
448  * Refill receive work queue
449  *
450  * @v ibdev             Infiniband device
451  * @v qp                Queue pair
452  */
453 void ib_refill_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
454         struct io_buffer *iobuf;
455         int rc;
456
457         /* Keep filling while unfilled entries remain */
458         while ( qp->recv.fill < qp->recv.num_wqes ) {
459
460                 /* Allocate I/O buffer */
461                 iobuf = alloc_iob ( IB_MAX_PAYLOAD_SIZE );
462                 if ( ! iobuf ) {
463                         /* Non-fatal; we will refill on next attempt */
464                         return;
465                 }
466
467                 /* Post I/O buffer */
468                 if ( ( rc = ib_post_recv ( ibdev, qp, iobuf ) ) != 0 ) {
469                         DBGC ( ibdev, "IBDEV %p could not refill: %s\n",
470                                ibdev, strerror ( rc ) );
471                         free_iob ( iobuf );
472                         /* Give up */
473                         return;
474                 }
475         }
476 }
477
478 /***************************************************************************
479  *
480  * Link control
481  *
482  ***************************************************************************
483  */
484
485 /**
486  * Open port
487  *
488  * @v ibdev             Infiniband device
489  * @ret rc              Return status code
490  */
491 int ib_open ( struct ib_device *ibdev ) {
492         int rc;
493
494         /* Increment device open request counter */
495         if ( ibdev->open_count++ > 0 ) {
496                 /* Device was already open; do nothing */
497                 return 0;
498         }
499
500         /* Open device */
501         if ( ( rc = ibdev->op->open ( ibdev ) ) != 0 ) {
502                 DBGC ( ibdev, "IBDEV %p could not open: %s\n",
503                        ibdev, strerror ( rc ) );
504                 goto err_open;
505         }
506
507         /* Create general management agent */
508         if ( ( rc = ib_create_gma ( &ibdev->gma, ibdev, IB_QKEY_GMA ) ) != 0 ){
509                 DBGC ( ibdev, "IBDEV %p could not create GMA: %s\n",
510                        ibdev, strerror ( rc ) );
511                 goto err_create_gma;
512         }
513
514         assert ( ibdev->open_count == 1 );
515         return 0;
516
517         ib_destroy_gma ( &ibdev->gma );
518  err_create_gma:
519         ibdev->op->close ( ibdev );
520  err_open:
521         assert ( ibdev->open_count == 1 );
522         ibdev->open_count = 0;
523         return rc;
524 }
525
526 /**
527  * Close port
528  *
529  * @v ibdev             Infiniband device
530  */
531 void ib_close ( struct ib_device *ibdev ) {
532
533         /* Decrement device open request counter */
534         ibdev->open_count--;
535
536         /* Close device if this was the last remaining requested opening */
537         if ( ibdev->open_count == 0 ) {
538                 ib_destroy_gma ( &ibdev->gma );
539                 ibdev->op->close ( ibdev );
540         }
541 }
542
543 /***************************************************************************
544  *
545  * Multicast
546  *
547  ***************************************************************************
548  */
549
550 /**
551  * Attach to multicast group
552  *
553  * @v ibdev             Infiniband device
554  * @v qp                Queue pair
555  * @v gid               Multicast GID
556  * @ret rc              Return status code
557  *
558  * Note that this function handles only the local device's attachment
559  * to the multicast GID; it does not issue the relevant MADs to join
560  * the multicast group on the subnet.
561  */
562 int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
563                       struct ib_gid *gid ) {
564         struct ib_multicast_gid *mgid;
565         int rc;
566
567         /* Add to software multicast GID list */
568         mgid = zalloc ( sizeof ( *mgid ) );
569         if ( ! mgid ) {
570                 rc = -ENOMEM;
571                 goto err_alloc_mgid;
572         }
573         memcpy ( &mgid->gid, gid, sizeof ( mgid->gid ) );
574         list_add ( &mgid->list, &qp->mgids );
575
576         /* Add to hardware multicast GID list */
577         if ( ( rc = ibdev->op->mcast_attach ( ibdev, qp, gid ) ) != 0 )
578                 goto err_dev_mcast_attach;
579
580         return 0;
581
582  err_dev_mcast_attach:
583         list_del ( &mgid->list );
584         free ( mgid );
585  err_alloc_mgid:
586         return rc;
587 }
588
589 /**
590  * Detach from multicast group
591  *
592  * @v ibdev             Infiniband device
593  * @v qp                Queue pair
594  * @v gid               Multicast GID
595  */
596 void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
597                        struct ib_gid *gid ) {
598         struct ib_multicast_gid *mgid;
599
600         /* Remove from hardware multicast GID list */
601         ibdev->op->mcast_detach ( ibdev, qp, gid );
602
603         /* Remove from software multicast GID list */
604         list_for_each_entry ( mgid, &qp->mgids, list ) {
605                 if ( memcmp ( &mgid->gid, gid, sizeof ( mgid->gid ) ) == 0 ) {
606                         list_del ( &mgid->list );
607                         free ( mgid );
608                         break;
609                 }
610         }
611 }
612
613 /***************************************************************************
614  *
615  * Miscellaneous
616  *
617  ***************************************************************************
618  */
619
620 /**
621  * Get Infiniband HCA information
622  *
623  * @v ibdev             Infiniband device
624  * @ret hca_guid        HCA GUID
625  * @ret num_ports       Number of ports
626  */
627 int ib_get_hca_info ( struct ib_device *ibdev,
628                       struct ib_gid_half *hca_guid ) {
629         struct ib_device *tmp;
630         int num_ports = 0;
631
632         /* Search for IB devices with the same physical device to
633          * identify port count and a suitable Node GUID.
634          */
635         for_each_ibdev ( tmp ) {
636                 if ( tmp->dev != ibdev->dev )
637                         continue;
638                 if ( num_ports == 0 ) {
639                         memcpy ( hca_guid, &tmp->gid.u.half[1],
640                                  sizeof ( *hca_guid ) );
641                 }
642                 num_ports++;
643         }
644         return num_ports;
645 }
646
647 /** Set port information
648  *
649  * @v ibdev             Infiniband device
650  * @v port_info         New port information
651  */
652 int ib_set_port_info ( struct ib_device *ibdev,
653                        const struct ib_port_info *port_info ) {
654         int rc;
655
656         /* Adapters with embedded SMAs do not need to support this method */
657         if ( ! ibdev->op->set_port_info ) {
658                 DBGC ( ibdev, "IBDEV %p does not support setting port "
659                        "information\n", ibdev );
660                 return -ENOTSUP;
661         }
662
663         if ( ( rc = ibdev->op->set_port_info ( ibdev, port_info ) ) != 0 ) {
664                 DBGC ( ibdev, "IBDEV %p could not set port information: %s\n",
665                        ibdev, strerror ( rc ) );
666                 return rc;
667         }
668
669         return 0;
670 };
671
672 /***************************************************************************
673  *
674  * Event queues
675  *
676  ***************************************************************************
677  */
678
679 /**
680  * Handle Infiniband link state change
681  *
682  * @v ibdev             Infiniband device
683  */
684 void ib_link_state_changed ( struct ib_device *ibdev ) {
685
686         /* Notify IPoIB of link state change */
687         ipoib_link_state_changed ( ibdev );
688 }
689
690 /**
691  * Poll event queue
692  *
693  * @v ibdev             Infiniband device
694  */
695 void ib_poll_eq ( struct ib_device *ibdev ) {
696         struct ib_completion_queue *cq;
697
698         /* Poll device's event queue */
699         ibdev->op->poll_eq ( ibdev );
700
701         /* Poll all completion queues */
702         list_for_each_entry ( cq, &ibdev->cqs, list )
703                 ib_poll_cq ( ibdev, cq );
704 }
705
706 /**
707  * Single-step the Infiniband event queue
708  *
709  * @v process           Infiniband event queue process
710  */
711 static void ib_step ( struct process *process __unused ) {
712         struct ib_device *ibdev;
713
714         for_each_ibdev ( ibdev )
715                 ib_poll_eq ( ibdev );
716 }
717
718 /** Infiniband event queue process */
719 struct process ib_process __permanent_process = {
720         .step = ib_step,
721 };
722
723 /***************************************************************************
724  *
725  * Infiniband device creation/destruction
726  *
727  ***************************************************************************
728  */
729
730 /**
731  * Allocate Infiniband device
732  *
733  * @v priv_size         Size of driver private data area
734  * @ret ibdev           Infiniband device, or NULL
735  */
736 struct ib_device * alloc_ibdev ( size_t priv_size ) {
737         struct ib_device *ibdev;
738         void *drv_priv;
739         size_t total_len;
740
741         total_len = ( sizeof ( *ibdev ) + priv_size );
742         ibdev = zalloc ( total_len );
743         if ( ibdev ) {
744                 drv_priv = ( ( ( void * ) ibdev ) + sizeof ( *ibdev ) );
745                 ib_set_drvdata ( ibdev, drv_priv );
746                 INIT_LIST_HEAD ( &ibdev->cqs );
747                 INIT_LIST_HEAD ( &ibdev->qps );
748                 ibdev->lid = IB_LID_NONE;
749                 ibdev->pkey = IB_PKEY_NONE;
750         }
751         return ibdev;
752 }
753
754 /**
755  * Register Infiniband device
756  *
757  * @v ibdev             Infiniband device
758  * @ret rc              Return status code
759  */
760 int register_ibdev ( struct ib_device *ibdev ) {
761         int rc;
762
763         /* Add to device list */
764         ibdev_get ( ibdev );
765         list_add_tail ( &ibdev->list, &ib_devices );
766
767         /* Add IPoIB device */
768         if ( ( rc = ipoib_probe ( ibdev ) ) != 0 ) {
769                 DBGC ( ibdev, "IBDEV %p could not add IPoIB device: %s\n",
770                        ibdev, strerror ( rc ) );
771                 goto err_ipoib_probe;
772         }
773
774         DBGC ( ibdev, "IBDEV %p registered (phys %s)\n", ibdev,
775                ibdev->dev->name );
776         return 0;
777
778  err_ipoib_probe:
779         list_del ( &ibdev->list );
780         ibdev_put ( ibdev );
781         return rc;
782 }
783
784 /**
785  * Unregister Infiniband device
786  *
787  * @v ibdev             Infiniband device
788  */
789 void unregister_ibdev ( struct ib_device *ibdev ) {
790
791         /* Close device */
792         ipoib_remove ( ibdev );
793
794         /* Remove from device list */
795         list_del ( &ibdev->list );
796         ibdev_put ( ibdev );
797         DBGC ( ibdev, "IBDEV %p unregistered\n", ibdev );
798 }