[infiniband] Create a general management agent
[people/lynusvaz/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         /* Post to hardware */
364         if ( ( rc = ibdev->op->post_send ( ibdev, qp, av, iobuf ) ) != 0 ) {
365                 DBGC ( ibdev, "IBDEV %p QPN %#lx could not post send WQE: "
366                        "%s\n", ibdev, qp->qpn, strerror ( rc ) );
367                 return rc;
368         }
369
370         qp->send.fill++;
371         return 0;
372 }
373
374 /**
375  * Post receive work queue entry
376  *
377  * @v ibdev             Infiniband device
378  * @v qp                Queue pair
379  * @v iobuf             I/O buffer
380  * @ret rc              Return status code
381  */
382 int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
383                    struct io_buffer *iobuf ) {
384         int rc;
385
386         /* Check packet length */
387         if ( iob_tailroom ( iobuf ) < IB_MAX_PAYLOAD_SIZE ) {
388                 DBGC ( ibdev, "IBDEV %p QPN %#lx wrong RX buffer size (%zd)\n",
389                        ibdev, qp->qpn, iob_tailroom ( iobuf ) );
390                 return -EINVAL;
391         }
392
393         /* Check queue fill level */
394         if ( qp->recv.fill >= qp->recv.num_wqes ) {
395                 DBGC ( ibdev, "IBDEV %p QPN %#lx receive queue full\n",
396                        ibdev, qp->qpn );
397                 return -ENOBUFS;
398         }
399
400         /* Post to hardware */
401         if ( ( rc = ibdev->op->post_recv ( ibdev, qp, iobuf ) ) != 0 ) {
402                 DBGC ( ibdev, "IBDEV %p QPN %#lx could not post receive WQE: "
403                        "%s\n", ibdev, qp->qpn, strerror ( rc ) );
404                 return rc;
405         }
406
407         qp->recv.fill++;
408         return 0;
409 }
410
411 /**
412  * Complete send work queue entry
413  *
414  * @v ibdev             Infiniband device
415  * @v qp                Queue pair
416  * @v iobuf             I/O buffer
417  * @v rc                Completion status code
418  */
419 void ib_complete_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
420                         struct io_buffer *iobuf, int rc ) {
421         qp->send.cq->op->complete_send ( ibdev, qp, iobuf, rc );
422         qp->send.fill--;
423 }
424
425 /**
426  * Complete receive work queue entry
427  *
428  * @v ibdev             Infiniband device
429  * @v qp                Queue pair
430  * @v av                Address vector
431  * @v iobuf             I/O buffer
432  * @v rc                Completion status code
433  */
434 void ib_complete_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
435                         struct ib_address_vector *av,
436                         struct io_buffer *iobuf, int rc ) {
437         qp->recv.cq->op->complete_recv ( ibdev, qp, av, iobuf, rc );
438         qp->recv.fill--;
439 }
440
441 /**
442  * Refill receive work queue
443  *
444  * @v ibdev             Infiniband device
445  * @v qp                Queue pair
446  */
447 void ib_refill_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
448         struct io_buffer *iobuf;
449         int rc;
450
451         /* Keep filling while unfilled entries remain */
452         while ( qp->recv.fill < qp->recv.num_wqes ) {
453
454                 /* Allocate I/O buffer */
455                 iobuf = alloc_iob ( IB_MAX_PAYLOAD_SIZE );
456                 if ( ! iobuf ) {
457                         /* Non-fatal; we will refill on next attempt */
458                         return;
459                 }
460
461                 /* Post I/O buffer */
462                 if ( ( rc = ib_post_recv ( ibdev, qp, iobuf ) ) != 0 ) {
463                         DBGC ( ibdev, "IBDEV %p could not refill: %s\n",
464                                ibdev, strerror ( rc ) );
465                         free_iob ( iobuf );
466                         /* Give up */
467                         return;
468                 }
469         }
470 }
471
472 /***************************************************************************
473  *
474  * Link control
475  *
476  ***************************************************************************
477  */
478
479 /**
480  * Open port
481  *
482  * @v ibdev             Infiniband device
483  * @ret rc              Return status code
484  */
485 int ib_open ( struct ib_device *ibdev ) {
486         int rc;
487
488         /* Increment device open request counter */
489         if ( ibdev->open_count++ > 0 ) {
490                 /* Device was already open; do nothing */
491                 return 0;
492         }
493
494         /* Open device */
495         if ( ( rc = ibdev->op->open ( ibdev ) ) != 0 ) {
496                 DBGC ( ibdev, "IBDEV %p could not open: %s\n",
497                        ibdev, strerror ( rc ) );
498                 goto err_open;
499         }
500
501         /* Create general management agent */
502         if ( ( rc = ib_create_gma ( &ibdev->gma, ibdev, IB_QKEY_GMA ) ) != 0 ){
503                 DBGC ( ibdev, "IBDEV %p could not create GMA: %s\n",
504                        ibdev, strerror ( rc ) );
505                 goto err_create_gma;
506         }
507
508         assert ( ibdev->open_count == 1 );
509         return 0;
510
511         ib_destroy_gma ( &ibdev->gma );
512  err_create_gma:
513         ibdev->op->close ( ibdev );
514  err_open:
515         assert ( ibdev->open_count == 1 );
516         ibdev->open_count = 0;
517         return rc;
518 }
519
520 /**
521  * Close port
522  *
523  * @v ibdev             Infiniband device
524  */
525 void ib_close ( struct ib_device *ibdev ) {
526
527         /* Decrement device open request counter */
528         ibdev->open_count--;
529
530         /* Close device if this was the last remaining requested opening */
531         if ( ibdev->open_count == 0 ) {
532                 ib_destroy_gma ( &ibdev->gma );
533                 ibdev->op->close ( ibdev );
534         }
535 }
536
537 /***************************************************************************
538  *
539  * Multicast
540  *
541  ***************************************************************************
542  */
543
544 /**
545  * Attach to multicast group
546  *
547  * @v ibdev             Infiniband device
548  * @v qp                Queue pair
549  * @v gid               Multicast GID
550  * @ret rc              Return status code
551  */
552 int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
553                       struct ib_gid *gid ) {
554         struct ib_multicast_gid *mgid;
555         int rc;
556
557         /* Add to software multicast GID list */
558         mgid = zalloc ( sizeof ( *mgid ) );
559         if ( ! mgid ) {
560                 rc = -ENOMEM;
561                 goto err_alloc_mgid;
562         }
563         memcpy ( &mgid->gid, gid, sizeof ( mgid->gid ) );
564         list_add ( &mgid->list, &qp->mgids );
565
566         /* Add to hardware multicast GID list */
567         if ( ( rc = ibdev->op->mcast_attach ( ibdev, qp, gid ) ) != 0 )
568                 goto err_dev_mcast_attach;
569
570         return 0;
571
572  err_dev_mcast_attach:
573         list_del ( &mgid->list );
574         free ( mgid );
575  err_alloc_mgid:
576         return rc;
577 }
578
579 /**
580  * Detach from multicast group
581  *
582  * @v ibdev             Infiniband device
583  * @v qp                Queue pair
584  * @v gid               Multicast GID
585  */
586 void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
587                        struct ib_gid *gid ) {
588         struct ib_multicast_gid *mgid;
589
590         /* Remove from hardware multicast GID list */
591         ibdev->op->mcast_detach ( ibdev, qp, gid );
592
593         /* Remove from software multicast GID list */
594         list_for_each_entry ( mgid, &qp->mgids, list ) {
595                 if ( memcmp ( &mgid->gid, gid, sizeof ( mgid->gid ) ) == 0 ) {
596                         list_del ( &mgid->list );
597                         free ( mgid );
598                         break;
599                 }
600         }
601 }
602
603 /***************************************************************************
604  *
605  * Miscellaneous
606  *
607  ***************************************************************************
608  */
609
610 /**
611  * Get Infiniband HCA information
612  *
613  * @v ibdev             Infiniband device
614  * @ret hca_guid        HCA GUID
615  * @ret num_ports       Number of ports
616  */
617 int ib_get_hca_info ( struct ib_device *ibdev,
618                       struct ib_gid_half *hca_guid ) {
619         struct ib_device *tmp;
620         int num_ports = 0;
621
622         /* Search for IB devices with the same physical device to
623          * identify port count and a suitable Node GUID.
624          */
625         for_each_ibdev ( tmp ) {
626                 if ( tmp->dev != ibdev->dev )
627                         continue;
628                 if ( num_ports == 0 ) {
629                         memcpy ( hca_guid, &tmp->gid.u.half[1],
630                                  sizeof ( *hca_guid ) );
631                 }
632                 num_ports++;
633         }
634         return num_ports;
635 }
636
637 /***************************************************************************
638  *
639  * Event queues
640  *
641  ***************************************************************************
642  */
643
644 /**
645  * Handle Infiniband link state change
646  *
647  * @v ibdev             Infiniband device
648  */
649 void ib_link_state_changed ( struct ib_device *ibdev ) {
650
651         /* Notify IPoIB of link state change */
652         ipoib_link_state_changed ( ibdev );
653 }
654
655 /**
656  * Poll event queue
657  *
658  * @v ibdev             Infiniband device
659  */
660 void ib_poll_eq ( struct ib_device *ibdev ) {
661         struct ib_completion_queue *cq;
662
663         /* Poll device's event queue */
664         ibdev->op->poll_eq ( ibdev );
665
666         /* Poll all completion queues */
667         list_for_each_entry ( cq, &ibdev->cqs, list )
668                 ib_poll_cq ( ibdev, cq );
669 }
670
671 /**
672  * Single-step the Infiniband event queue
673  *
674  * @v process           Infiniband event queue process
675  */
676 static void ib_step ( struct process *process __unused ) {
677         struct ib_device *ibdev;
678
679         for_each_ibdev ( ibdev )
680                 ib_poll_eq ( ibdev );
681 }
682
683 /** Infiniband event queue process */
684 struct process ib_process __permanent_process = {
685         .step = ib_step,
686 };
687
688 /***************************************************************************
689  *
690  * Infiniband device creation/destruction
691  *
692  ***************************************************************************
693  */
694
695 /**
696  * Allocate Infiniband device
697  *
698  * @v priv_size         Size of driver private data area
699  * @ret ibdev           Infiniband device, or NULL
700  */
701 struct ib_device * alloc_ibdev ( size_t priv_size ) {
702         struct ib_device *ibdev;
703         void *drv_priv;
704         size_t total_len;
705
706         total_len = ( sizeof ( *ibdev ) + priv_size );
707         ibdev = zalloc ( total_len );
708         if ( ibdev ) {
709                 drv_priv = ( ( ( void * ) ibdev ) + sizeof ( *ibdev ) );
710                 ib_set_drvdata ( ibdev, drv_priv );
711                 INIT_LIST_HEAD ( &ibdev->cqs );
712                 INIT_LIST_HEAD ( &ibdev->qps );
713                 ibdev->lid = IB_LID_NONE;
714                 ibdev->pkey = IB_PKEY_NONE;
715         }
716         return ibdev;
717 }
718
719 /**
720  * Register Infiniband device
721  *
722  * @v ibdev             Infiniband device
723  * @ret rc              Return status code
724  */
725 int register_ibdev ( struct ib_device *ibdev ) {
726         int rc;
727
728         /* Add to device list */
729         ibdev_get ( ibdev );
730         list_add_tail ( &ibdev->list, &ib_devices );
731
732         /* Add IPoIB device */
733         if ( ( rc = ipoib_probe ( ibdev ) ) != 0 ) {
734                 DBGC ( ibdev, "IBDEV %p could not add IPoIB device: %s\n",
735                        ibdev, strerror ( rc ) );
736                 goto err_ipoib_probe;
737         }
738
739         DBGC ( ibdev, "IBDEV %p registered (phys %s)\n", ibdev,
740                ibdev->dev->name );
741         return 0;
742
743  err_ipoib_probe:
744         list_del ( &ibdev->list );
745         ibdev_put ( ibdev );
746         return rc;
747 }
748
749 /**
750  * Unregister Infiniband device
751  *
752  * @v ibdev             Infiniband device
753  */
754 void unregister_ibdev ( struct ib_device *ibdev ) {
755
756         /* Close device */
757         ipoib_remove ( ibdev );
758
759         /* Remove from device list */
760         list_del ( &ibdev->list );
761         ibdev_put ( ibdev );
762         DBGC ( ibdev, "IBDEV %p unregistered\n", ibdev );
763 }