42ffbcec5bc79d5428c6db55c120edf30b95c787
[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 type              Queue pair type
147  * @v num_send_wqes     Number of send work queue entries
148  * @v send_cq           Send completion queue
149  * @v num_recv_wqes     Number of receive work queue entries
150  * @v recv_cq           Receive completion queue
151  * @v qkey              Queue key
152  * @ret qp              Queue pair
153  */
154 struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
155                                       enum ib_queue_pair_type type,
156                                       unsigned int num_send_wqes,
157                                       struct ib_completion_queue *send_cq,
158                                       unsigned int num_recv_wqes,
159                                       struct ib_completion_queue *recv_cq,
160                                       unsigned long qkey ) {
161         struct ib_queue_pair *qp;
162         size_t total_size;
163         int rc;
164
165         DBGC ( ibdev, "IBDEV %p creating queue pair\n", ibdev );
166
167         /* Allocate and initialise data structure */
168         total_size = ( sizeof ( *qp ) +
169                        ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ) +
170                        ( num_recv_wqes * sizeof ( qp->recv.iobufs[0] ) ) );
171         qp = zalloc ( total_size );
172         if ( ! qp )
173                 goto err_alloc_qp;
174         qp->ibdev = ibdev;
175         list_add ( &qp->list, &ibdev->qps );
176         qp->type = type;
177         qp->qkey = qkey;
178         qp->send.qp = qp;
179         qp->send.is_send = 1;
180         qp->send.cq = send_cq;
181         list_add ( &qp->send.list, &send_cq->work_queues );
182         qp->send.num_wqes = num_send_wqes;
183         qp->send.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) );
184         qp->recv.qp = qp;
185         qp->recv.cq = recv_cq;
186         list_add ( &qp->recv.list, &recv_cq->work_queues );
187         qp->recv.num_wqes = num_recv_wqes;
188         qp->recv.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) +
189                             ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ));
190         INIT_LIST_HEAD ( &qp->mgids );
191
192         /* Perform device-specific initialisation and get QPN */
193         if ( ( rc = ibdev->op->create_qp ( ibdev, qp ) ) != 0 ) {
194                 DBGC ( ibdev, "IBDEV %p could not initialise queue pair: "
195                        "%s\n", ibdev, strerror ( rc ) );
196                 goto err_dev_create_qp;
197         }
198
199         DBGC ( ibdev, "IBDEV %p created queue pair %p (%p) with QPN %#lx\n",
200                ibdev, qp, ib_qp_get_drvdata ( qp ), qp->qpn );
201         DBGC ( ibdev, "IBDEV %p QPN %#lx has %d send entries at [%p,%p)\n",
202                ibdev, qp->qpn, num_send_wqes, qp->send.iobufs,
203                qp->recv.iobufs );
204         DBGC ( ibdev, "IBDEV %p QPN %#lx has %d receive entries at [%p,%p)\n",
205                ibdev, qp->qpn, num_recv_wqes, qp->recv.iobufs,
206                ( ( ( void * ) qp ) + total_size ) );
207         return qp;
208
209         ibdev->op->destroy_qp ( ibdev, qp );
210  err_dev_create_qp:
211         list_del ( &qp->send.list );
212         list_del ( &qp->recv.list );
213         list_del ( &qp->list );
214         free ( qp );
215  err_alloc_qp:
216         return NULL;
217 }
218
219 /**
220  * Modify queue pair
221  *
222  * @v ibdev             Infiniband device
223  * @v qp                Queue pair
224  * @v mod_list          Modification list
225  * @v qkey              New queue key, if applicable
226  * @ret rc              Return status code
227  */
228 int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp,
229                    unsigned long mod_list, unsigned long qkey ) {
230         int rc;
231
232         DBGC ( ibdev, "IBDEV %p modifying QPN %#lx\n", ibdev, qp->qpn );
233
234         if ( mod_list & IB_MODIFY_QKEY )
235                 qp->qkey = qkey;
236
237         if ( ( rc = ibdev->op->modify_qp ( ibdev, qp, mod_list ) ) != 0 ) {
238                 DBGC ( ibdev, "IBDEV %p could not modify QPN %#lx: %s\n",
239                        ibdev, qp->qpn, strerror ( rc ) );
240                 return rc;
241         }
242
243         return 0;
244 }
245
246 /**
247  * Destroy queue pair
248  *
249  * @v ibdev             Infiniband device
250  * @v qp                Queue pair
251  */
252 void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
253         struct io_buffer *iobuf;
254         unsigned int i;
255
256         DBGC ( ibdev, "IBDEV %p destroying QPN %#lx\n",
257                ibdev, qp->qpn );
258
259         assert ( list_empty ( &qp->mgids ) );
260
261         /* Perform device-specific destruction */
262         ibdev->op->destroy_qp ( ibdev, qp );
263
264         /* Complete any remaining I/O buffers with errors */
265         for ( i = 0 ; i < qp->send.num_wqes ; i++ ) {
266                 if ( ( iobuf = qp->send.iobufs[i] ) != NULL )
267                         ib_complete_send ( ibdev, qp, iobuf, -ECANCELED );
268         }
269         for ( i = 0 ; i < qp->recv.num_wqes ; i++ ) {
270                 if ( ( iobuf = qp->recv.iobufs[i] ) != NULL ) {
271                         ib_complete_recv ( ibdev, qp, NULL, iobuf,
272                                            -ECANCELED );
273                 }
274         }
275
276         /* Remove work queues from completion queue */
277         list_del ( &qp->send.list );
278         list_del ( &qp->recv.list );
279
280         /* Free QP */
281         list_del ( &qp->list );
282         free ( qp );
283 }
284
285 /**
286  * Find queue pair by QPN
287  *
288  * @v ibdev             Infiniband device
289  * @v qpn               Queue pair number
290  * @ret qp              Queue pair, or NULL
291  */
292 struct ib_queue_pair * ib_find_qp_qpn ( struct ib_device *ibdev,
293                                         unsigned long qpn ) {
294         struct ib_queue_pair *qp;
295
296         list_for_each_entry ( qp, &ibdev->qps, list ) {
297                 if ( qp->qpn == qpn )
298                         return qp;
299         }
300         return NULL;
301 }
302
303 /**
304  * Find queue pair by multicast GID
305  *
306  * @v ibdev             Infiniband device
307  * @v gid               Multicast GID
308  * @ret qp              Queue pair, or NULL
309  */
310 struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev,
311                                          struct ib_gid *gid ) {
312         struct ib_queue_pair *qp;
313         struct ib_multicast_gid *mgid;
314
315         list_for_each_entry ( qp, &ibdev->qps, list ) {
316                 list_for_each_entry ( mgid, &qp->mgids, list ) {
317                         if ( memcmp ( &mgid->gid, gid,
318                                       sizeof ( mgid->gid ) ) == 0 ) {
319                                 return qp;
320                         }
321                 }
322         }
323         return NULL;
324 }
325
326 /**
327  * Find work queue belonging to completion queue
328  *
329  * @v cq                Completion queue
330  * @v qpn               Queue pair number
331  * @v is_send           Find send work queue (rather than receive)
332  * @ret wq              Work queue, or NULL if not found
333  */
334 struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq,
335                                     unsigned long qpn, int is_send ) {
336         struct ib_work_queue *wq;
337
338         list_for_each_entry ( wq, &cq->work_queues, list ) {
339                 if ( ( wq->qp->qpn == qpn ) && ( wq->is_send == is_send ) )
340                         return wq;
341         }
342         return NULL;
343 }
344
345 /**
346  * Post send work queue entry
347  *
348  * @v ibdev             Infiniband device
349  * @v qp                Queue pair
350  * @v av                Address vector
351  * @v iobuf             I/O buffer
352  * @ret rc              Return status code
353  */
354 int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
355                    struct ib_address_vector *av,
356                    struct io_buffer *iobuf ) {
357         int rc;
358
359         /* Check queue fill level */
360         if ( qp->send.fill >= qp->send.num_wqes ) {
361                 DBGC ( ibdev, "IBDEV %p QPN %#lx send queue full\n",
362                        ibdev, qp->qpn );
363                 return -ENOBUFS;
364         }
365
366         /* Fill in optional parameters in address vector */
367         if ( ! av->qkey )
368                 av->qkey = qp->qkey;
369         if ( ! av->rate )
370                 av->rate = IB_RATE_2_5;
371
372         /* Post to hardware */
373         if ( ( rc = ibdev->op->post_send ( ibdev, qp, av, iobuf ) ) != 0 ) {
374                 DBGC ( ibdev, "IBDEV %p QPN %#lx could not post send WQE: "
375                        "%s\n", ibdev, qp->qpn, strerror ( rc ) );
376                 return rc;
377         }
378
379         qp->send.fill++;
380         return 0;
381 }
382
383 /**
384  * Post receive work queue entry
385  *
386  * @v ibdev             Infiniband device
387  * @v qp                Queue pair
388  * @v iobuf             I/O buffer
389  * @ret rc              Return status code
390  */
391 int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
392                    struct io_buffer *iobuf ) {
393         int rc;
394
395         /* Check packet length */
396         if ( iob_tailroom ( iobuf ) < IB_MAX_PAYLOAD_SIZE ) {
397                 DBGC ( ibdev, "IBDEV %p QPN %#lx wrong RX buffer size (%zd)\n",
398                        ibdev, qp->qpn, iob_tailroom ( iobuf ) );
399                 return -EINVAL;
400         }
401
402         /* Check queue fill level */
403         if ( qp->recv.fill >= qp->recv.num_wqes ) {
404                 DBGC ( ibdev, "IBDEV %p QPN %#lx receive queue full\n",
405                        ibdev, qp->qpn );
406                 return -ENOBUFS;
407         }
408
409         /* Post to hardware */
410         if ( ( rc = ibdev->op->post_recv ( ibdev, qp, iobuf ) ) != 0 ) {
411                 DBGC ( ibdev, "IBDEV %p QPN %#lx could not post receive WQE: "
412                        "%s\n", ibdev, qp->qpn, strerror ( rc ) );
413                 return rc;
414         }
415
416         qp->recv.fill++;
417         return 0;
418 }
419
420 /**
421  * Complete send work queue entry
422  *
423  * @v ibdev             Infiniband device
424  * @v qp                Queue pair
425  * @v iobuf             I/O buffer
426  * @v rc                Completion status code
427  */
428 void ib_complete_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
429                         struct io_buffer *iobuf, int rc ) {
430
431         if ( qp->send.cq->op->complete_send ) {
432                 qp->send.cq->op->complete_send ( ibdev, qp, iobuf, rc );
433         } else {
434                 free_iob ( iobuf );
435         }
436         qp->send.fill--;
437 }
438
439 /**
440  * Complete receive work queue entry
441  *
442  * @v ibdev             Infiniband device
443  * @v qp                Queue pair
444  * @v av                Address vector
445  * @v iobuf             I/O buffer
446  * @v rc                Completion status code
447  */
448 void ib_complete_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
449                         struct ib_address_vector *av,
450                         struct io_buffer *iobuf, int rc ) {
451
452         if ( qp->recv.cq->op->complete_recv ) {
453                 qp->recv.cq->op->complete_recv ( ibdev, qp, av, iobuf, rc );
454         } else {
455                 free_iob ( iobuf );
456         }
457         qp->recv.fill--;
458 }
459
460 /**
461  * Refill receive work queue
462  *
463  * @v ibdev             Infiniband device
464  * @v qp                Queue pair
465  */
466 void ib_refill_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
467         struct io_buffer *iobuf;
468         int rc;
469
470         /* Keep filling while unfilled entries remain */
471         while ( qp->recv.fill < qp->recv.num_wqes ) {
472
473                 /* Allocate I/O buffer */
474                 iobuf = alloc_iob ( IB_MAX_PAYLOAD_SIZE );
475                 if ( ! iobuf ) {
476                         /* Non-fatal; we will refill on next attempt */
477                         return;
478                 }
479
480                 /* Post I/O buffer */
481                 if ( ( rc = ib_post_recv ( ibdev, qp, iobuf ) ) != 0 ) {
482                         DBGC ( ibdev, "IBDEV %p could not refill: %s\n",
483                                ibdev, strerror ( rc ) );
484                         free_iob ( iobuf );
485                         /* Give up */
486                         return;
487                 }
488         }
489 }
490
491 /***************************************************************************
492  *
493  * Link control
494  *
495  ***************************************************************************
496  */
497
498 /**
499  * Open port
500  *
501  * @v ibdev             Infiniband device
502  * @ret rc              Return status code
503  */
504 int ib_open ( struct ib_device *ibdev ) {
505         int rc;
506
507         /* Increment device open request counter */
508         if ( ibdev->open_count++ > 0 ) {
509                 /* Device was already open; do nothing */
510                 return 0;
511         }
512
513         /* Open device */
514         if ( ( rc = ibdev->op->open ( ibdev ) ) != 0 ) {
515                 DBGC ( ibdev, "IBDEV %p could not open: %s\n",
516                        ibdev, strerror ( rc ) );
517                 goto err_open;
518         }
519
520         /* Create general management agent */
521         if ( ( rc = ib_create_gma ( &ibdev->gma, ibdev, IB_QPT_GMA ) ) != 0 ) {
522                 DBGC ( ibdev, "IBDEV %p could not create GMA: %s\n",
523                        ibdev, strerror ( rc ) );
524                 goto err_create_gma;
525         }
526
527         assert ( ibdev->open_count == 1 );
528         return 0;
529
530         ib_destroy_gma ( &ibdev->gma );
531  err_create_gma:
532         ibdev->op->close ( ibdev );
533  err_open:
534         assert ( ibdev->open_count == 1 );
535         ibdev->open_count = 0;
536         return rc;
537 }
538
539 /**
540  * Close port
541  *
542  * @v ibdev             Infiniband device
543  */
544 void ib_close ( struct ib_device *ibdev ) {
545
546         /* Decrement device open request counter */
547         ibdev->open_count--;
548
549         /* Close device if this was the last remaining requested opening */
550         if ( ibdev->open_count == 0 ) {
551                 ib_destroy_gma ( &ibdev->gma );
552                 ibdev->op->close ( ibdev );
553         }
554 }
555
556 /***************************************************************************
557  *
558  * Multicast
559  *
560  ***************************************************************************
561  */
562
563 /**
564  * Attach to multicast group
565  *
566  * @v ibdev             Infiniband device
567  * @v qp                Queue pair
568  * @v gid               Multicast GID
569  * @ret rc              Return status code
570  *
571  * Note that this function handles only the local device's attachment
572  * to the multicast GID; it does not issue the relevant MADs to join
573  * the multicast group on the subnet.
574  */
575 int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
576                       struct ib_gid *gid ) {
577         struct ib_multicast_gid *mgid;
578         int rc;
579
580         /* Add to software multicast GID list */
581         mgid = zalloc ( sizeof ( *mgid ) );
582         if ( ! mgid ) {
583                 rc = -ENOMEM;
584                 goto err_alloc_mgid;
585         }
586         memcpy ( &mgid->gid, gid, sizeof ( mgid->gid ) );
587         list_add ( &mgid->list, &qp->mgids );
588
589         /* Add to hardware multicast GID list */
590         if ( ( rc = ibdev->op->mcast_attach ( ibdev, qp, gid ) ) != 0 )
591                 goto err_dev_mcast_attach;
592
593         return 0;
594
595  err_dev_mcast_attach:
596         list_del ( &mgid->list );
597         free ( mgid );
598  err_alloc_mgid:
599         return rc;
600 }
601
602 /**
603  * Detach from multicast group
604  *
605  * @v ibdev             Infiniband device
606  * @v qp                Queue pair
607  * @v gid               Multicast GID
608  */
609 void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp,
610                        struct ib_gid *gid ) {
611         struct ib_multicast_gid *mgid;
612
613         /* Remove from hardware multicast GID list */
614         ibdev->op->mcast_detach ( ibdev, qp, gid );
615
616         /* Remove from software multicast GID list */
617         list_for_each_entry ( mgid, &qp->mgids, list ) {
618                 if ( memcmp ( &mgid->gid, gid, sizeof ( mgid->gid ) ) == 0 ) {
619                         list_del ( &mgid->list );
620                         free ( mgid );
621                         break;
622                 }
623         }
624 }
625
626 /***************************************************************************
627  *
628  * Miscellaneous
629  *
630  ***************************************************************************
631  */
632
633 /**
634  * Get Infiniband HCA information
635  *
636  * @v ibdev             Infiniband device
637  * @ret hca_guid        HCA GUID
638  * @ret num_ports       Number of ports
639  */
640 int ib_get_hca_info ( struct ib_device *ibdev,
641                       struct ib_gid_half *hca_guid ) {
642         struct ib_device *tmp;
643         int num_ports = 0;
644
645         /* Search for IB devices with the same physical device to
646          * identify port count and a suitable Node GUID.
647          */
648         for_each_ibdev ( tmp ) {
649                 if ( tmp->dev != ibdev->dev )
650                         continue;
651                 if ( num_ports == 0 ) {
652                         memcpy ( hca_guid, &tmp->gid.u.half[1],
653                                  sizeof ( *hca_guid ) );
654                 }
655                 num_ports++;
656         }
657         return num_ports;
658 }
659
660 /** Set port information
661  *
662  * @v ibdev             Infiniband device
663  * @v port_info         New port information
664  */
665 int ib_set_port_info ( struct ib_device *ibdev,
666                        const struct ib_port_info *port_info ) {
667         int rc;
668
669         /* Adapters with embedded SMAs do not need to support this method */
670         if ( ! ibdev->op->set_port_info ) {
671                 DBGC ( ibdev, "IBDEV %p does not support setting port "
672                        "information\n", ibdev );
673                 return -ENOTSUP;
674         }
675
676         if ( ( rc = ibdev->op->set_port_info ( ibdev, port_info ) ) != 0 ) {
677                 DBGC ( ibdev, "IBDEV %p could not set port information: %s\n",
678                        ibdev, strerror ( rc ) );
679                 return rc;
680         }
681
682         return 0;
683 };
684
685 /***************************************************************************
686  *
687  * Event queues
688  *
689  ***************************************************************************
690  */
691
692 /**
693  * Handle Infiniband link state change
694  *
695  * @v ibdev             Infiniband device
696  */
697 void ib_link_state_changed ( struct ib_device *ibdev ) {
698
699         /* Notify IPoIB of link state change */
700         ipoib_link_state_changed ( ibdev );
701 }
702
703 /**
704  * Poll event queue
705  *
706  * @v ibdev             Infiniband device
707  */
708 void ib_poll_eq ( struct ib_device *ibdev ) {
709         struct ib_completion_queue *cq;
710
711         /* Poll device's event queue */
712         ibdev->op->poll_eq ( ibdev );
713
714         /* Poll all completion queues */
715         list_for_each_entry ( cq, &ibdev->cqs, list )
716                 ib_poll_cq ( ibdev, cq );
717 }
718
719 /**
720  * Single-step the Infiniband event queue
721  *
722  * @v process           Infiniband event queue process
723  */
724 static void ib_step ( struct process *process __unused ) {
725         struct ib_device *ibdev;
726
727         for_each_ibdev ( ibdev )
728                 ib_poll_eq ( ibdev );
729 }
730
731 /** Infiniband event queue process */
732 struct process ib_process __permanent_process = {
733         .step = ib_step,
734 };
735
736 /***************************************************************************
737  *
738  * Infiniband device creation/destruction
739  *
740  ***************************************************************************
741  */
742
743 /**
744  * Allocate Infiniband device
745  *
746  * @v priv_size         Size of driver private data area
747  * @ret ibdev           Infiniband device, or NULL
748  */
749 struct ib_device * alloc_ibdev ( size_t priv_size ) {
750         struct ib_device *ibdev;
751         void *drv_priv;
752         size_t total_len;
753
754         total_len = ( sizeof ( *ibdev ) + priv_size );
755         ibdev = zalloc ( total_len );
756         if ( ibdev ) {
757                 drv_priv = ( ( ( void * ) ibdev ) + sizeof ( *ibdev ) );
758                 ib_set_drvdata ( ibdev, drv_priv );
759                 INIT_LIST_HEAD ( &ibdev->cqs );
760                 INIT_LIST_HEAD ( &ibdev->qps );
761                 ibdev->lid = IB_LID_NONE;
762                 ibdev->pkey = IB_PKEY_NONE;
763         }
764         return ibdev;
765 }
766
767 /**
768  * Register Infiniband device
769  *
770  * @v ibdev             Infiniband device
771  * @ret rc              Return status code
772  */
773 int register_ibdev ( struct ib_device *ibdev ) {
774         int rc;
775
776         /* Add to device list */
777         ibdev_get ( ibdev );
778         list_add_tail ( &ibdev->list, &ib_devices );
779
780         /* Add IPoIB device */
781         if ( ( rc = ipoib_probe ( ibdev ) ) != 0 ) {
782                 DBGC ( ibdev, "IBDEV %p could not add IPoIB device: %s\n",
783                        ibdev, strerror ( rc ) );
784                 goto err_ipoib_probe;
785         }
786
787         DBGC ( ibdev, "IBDEV %p registered (phys %s)\n", ibdev,
788                ibdev->dev->name );
789         return 0;
790
791  err_ipoib_probe:
792         list_del ( &ibdev->list );
793         ibdev_put ( ibdev );
794         return rc;
795 }
796
797 /**
798  * Unregister Infiniband device
799  *
800  * @v ibdev             Infiniband device
801  */
802 void unregister_ibdev ( struct ib_device *ibdev ) {
803
804         /* Close device */
805         ipoib_remove ( ibdev );
806
807         /* Remove from device list */
808         list_del ( &ibdev->list );
809         ibdev_put ( ibdev );
810         DBGC ( ibdev, "IBDEV %p unregistered\n", ibdev );
811 }