2 * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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.
19 FILE_LICENCE ( GPL2_OR_LATER
);
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 #include <gpxe/ib_mi.h>
37 #include <gpxe/ib_sma.h>
45 /** List of Infiniband devices */
46 struct list_head ib_devices
= LIST_HEAD_INIT ( ib_devices
);
48 /** List of open Infiniband devices, in reverse order of opening */
49 static struct list_head open_ib_devices
= LIST_HEAD_INIT ( open_ib_devices
);
51 /***************************************************************************
55 ***************************************************************************
59 * Create completion queue
61 * @v ibdev Infiniband device
62 * @v num_cqes Number of completion queue entries
63 * @v op Completion queue operations
64 * @ret cq New completion queue
66 struct ib_completion_queue
*
67 ib_create_cq ( struct ib_device
*ibdev
, unsigned int num_cqes
,
68 struct ib_completion_queue_operations
*op
) {
69 struct ib_completion_queue
*cq
;
72 DBGC ( ibdev
, "IBDEV %p creating completion queue\n", ibdev
);
74 /* Allocate and initialise data structure */
75 cq
= zalloc ( sizeof ( *cq
) );
79 list_add ( &cq
->list
, &ibdev
->cqs
);
80 cq
->num_cqes
= num_cqes
;
81 INIT_LIST_HEAD ( &cq
->work_queues
);
84 /* Perform device-specific initialisation and get CQN */
85 if ( ( rc
= ibdev
->op
->create_cq ( ibdev
, cq
) ) != 0 ) {
86 DBGC ( ibdev
, "IBDEV %p could not initialise completion "
87 "queue: %s\n", ibdev
, strerror ( rc
) );
88 goto err_dev_create_cq
;
91 DBGC ( ibdev
, "IBDEV %p created %d-entry completion queue %p (%p) "
92 "with CQN %#lx\n", ibdev
, num_cqes
, cq
,
93 ib_cq_get_drvdata ( cq
), cq
->cqn
);
96 ibdev
->op
->destroy_cq ( ibdev
, cq
);
98 list_del ( &cq
->list
);
105 * Destroy completion queue
107 * @v ibdev Infiniband device
108 * @v cq Completion queue
110 void ib_destroy_cq ( struct ib_device
*ibdev
,
111 struct ib_completion_queue
*cq
) {
112 DBGC ( ibdev
, "IBDEV %p destroying completion queue %#lx\n",
114 assert ( list_empty ( &cq
->work_queues
) );
115 ibdev
->op
->destroy_cq ( ibdev
, cq
);
116 list_del ( &cq
->list
);
121 * Poll completion queue
123 * @v ibdev Infiniband device
124 * @v cq Completion queue
126 void ib_poll_cq ( struct ib_device
*ibdev
,
127 struct ib_completion_queue
*cq
) {
128 struct ib_work_queue
*wq
;
130 /* Poll completion queue */
131 ibdev
->op
->poll_cq ( ibdev
, cq
);
133 /* Refill receive work queues */
134 list_for_each_entry ( wq
, &cq
->work_queues
, list
) {
136 ib_refill_recv ( ibdev
, wq
->qp
);
140 /***************************************************************************
144 ***************************************************************************
150 * @v ibdev Infiniband device
151 * @v type Queue pair type
152 * @v num_send_wqes Number of send work queue entries
153 * @v send_cq Send completion queue
154 * @v num_recv_wqes Number of receive work queue entries
155 * @v recv_cq Receive completion queue
158 * The queue pair will be left in the INIT state; you must call
159 * ib_modify_qp() before it is ready to use for sending and receiving.
161 struct ib_queue_pair
* ib_create_qp ( struct ib_device
*ibdev
,
162 enum ib_queue_pair_type type
,
163 unsigned int num_send_wqes
,
164 struct ib_completion_queue
*send_cq
,
165 unsigned int num_recv_wqes
,
166 struct ib_completion_queue
*recv_cq
) {
167 struct ib_queue_pair
*qp
;
171 DBGC ( ibdev
, "IBDEV %p creating queue pair\n", ibdev
);
173 /* Allocate and initialise data structure */
174 total_size
= ( sizeof ( *qp
) +
175 ( num_send_wqes
* sizeof ( qp
->send
.iobufs
[0] ) ) +
176 ( num_recv_wqes
* sizeof ( qp
->recv
.iobufs
[0] ) ) );
177 qp
= zalloc ( total_size
);
181 list_add ( &qp
->list
, &ibdev
->qps
);
184 qp
->send
.is_send
= 1;
185 qp
->send
.cq
= send_cq
;
186 list_add ( &qp
->send
.list
, &send_cq
->work_queues
);
187 qp
->send
.psn
= ( random() & 0xffffffUL
);
188 qp
->send
.num_wqes
= num_send_wqes
;
189 qp
->send
.iobufs
= ( ( ( void * ) qp
) + sizeof ( *qp
) );
191 qp
->recv
.cq
= recv_cq
;
192 list_add ( &qp
->recv
.list
, &recv_cq
->work_queues
);
193 qp
->recv
.psn
= ( random() & 0xffffffUL
);
194 qp
->recv
.num_wqes
= num_recv_wqes
;
195 qp
->recv
.iobufs
= ( ( ( void * ) qp
) + sizeof ( *qp
) +
196 ( num_send_wqes
* sizeof ( qp
->send
.iobufs
[0] ) ));
197 INIT_LIST_HEAD ( &qp
->mgids
);
199 /* Perform device-specific initialisation and get QPN */
200 if ( ( rc
= ibdev
->op
->create_qp ( ibdev
, qp
) ) != 0 ) {
201 DBGC ( ibdev
, "IBDEV %p could not initialise queue pair: "
202 "%s\n", ibdev
, strerror ( rc
) );
203 goto err_dev_create_qp
;
205 DBGC ( ibdev
, "IBDEV %p created queue pair %p (%p) with QPN %#lx\n",
206 ibdev
, qp
, ib_qp_get_drvdata ( qp
), qp
->qpn
);
207 DBGC ( ibdev
, "IBDEV %p QPN %#lx has %d send entries at [%p,%p)\n",
208 ibdev
, qp
->qpn
, num_send_wqes
, qp
->send
.iobufs
,
210 DBGC ( ibdev
, "IBDEV %p QPN %#lx has %d receive entries at [%p,%p)\n",
211 ibdev
, qp
->qpn
, num_recv_wqes
, qp
->recv
.iobufs
,
212 ( ( ( void * ) qp
) + total_size
) );
214 /* Calculate externally-visible QPN */
217 qp
->ext_qpn
= IB_QPN_SMI
;
220 qp
->ext_qpn
= IB_QPN_GSI
;
223 qp
->ext_qpn
= qp
->qpn
;
226 if ( qp
->ext_qpn
!= qp
->qpn
) {
227 DBGC ( ibdev
, "IBDEV %p QPN %#lx has external QPN %#lx\n",
228 ibdev
, qp
->qpn
, qp
->ext_qpn
);
233 ibdev
->op
->destroy_qp ( ibdev
, qp
);
235 list_del ( &qp
->send
.list
);
236 list_del ( &qp
->recv
.list
);
237 list_del ( &qp
->list
);
246 * @v ibdev Infiniband device
248 * @v av New address vector, if applicable
249 * @ret rc Return status code
251 int ib_modify_qp ( struct ib_device
*ibdev
, struct ib_queue_pair
*qp
) {
254 DBGC ( ibdev
, "IBDEV %p modifying QPN %#lx\n", ibdev
, qp
->qpn
);
256 if ( ( rc
= ibdev
->op
->modify_qp ( ibdev
, qp
) ) != 0 ) {
257 DBGC ( ibdev
, "IBDEV %p could not modify QPN %#lx: %s\n",
258 ibdev
, qp
->qpn
, strerror ( rc
) );
268 * @v ibdev Infiniband device
271 void ib_destroy_qp ( struct ib_device
*ibdev
, struct ib_queue_pair
*qp
) {
272 struct io_buffer
*iobuf
;
275 DBGC ( ibdev
, "IBDEV %p destroying QPN %#lx\n",
278 assert ( list_empty ( &qp
->mgids
) );
280 /* Perform device-specific destruction */
281 ibdev
->op
->destroy_qp ( ibdev
, qp
);
283 /* Complete any remaining I/O buffers with errors */
284 for ( i
= 0 ; i
< qp
->send
.num_wqes
; i
++ ) {
285 if ( ( iobuf
= qp
->send
.iobufs
[i
] ) != NULL
)
286 ib_complete_send ( ibdev
, qp
, iobuf
, -ECANCELED
);
288 for ( i
= 0 ; i
< qp
->recv
.num_wqes
; i
++ ) {
289 if ( ( iobuf
= qp
->recv
.iobufs
[i
] ) != NULL
) {
290 ib_complete_recv ( ibdev
, qp
, NULL
, iobuf
,
295 /* Remove work queues from completion queue */
296 list_del ( &qp
->send
.list
);
297 list_del ( &qp
->recv
.list
);
300 list_del ( &qp
->list
);
305 * Find queue pair by QPN
307 * @v ibdev Infiniband device
308 * @v qpn Queue pair number
309 * @ret qp Queue pair, or NULL
311 struct ib_queue_pair
* ib_find_qp_qpn ( struct ib_device
*ibdev
,
312 unsigned long qpn
) {
313 struct ib_queue_pair
*qp
;
315 list_for_each_entry ( qp
, &ibdev
->qps
, list
) {
316 if ( ( qpn
== qp
->qpn
) || ( qpn
== qp
->ext_qpn
) )
323 * Find queue pair by multicast GID
325 * @v ibdev Infiniband device
326 * @v gid Multicast GID
327 * @ret qp Queue pair, or NULL
329 struct ib_queue_pair
* ib_find_qp_mgid ( struct ib_device
*ibdev
,
330 struct ib_gid
*gid
) {
331 struct ib_queue_pair
*qp
;
332 struct ib_multicast_gid
*mgid
;
334 list_for_each_entry ( qp
, &ibdev
->qps
, list
) {
335 list_for_each_entry ( mgid
, &qp
->mgids
, list
) {
336 if ( memcmp ( &mgid
->gid
, gid
,
337 sizeof ( mgid
->gid
) ) == 0 ) {
346 * Find work queue belonging to completion queue
348 * @v cq Completion queue
349 * @v qpn Queue pair number
350 * @v is_send Find send work queue (rather than receive)
351 * @ret wq Work queue, or NULL if not found
353 struct ib_work_queue
* ib_find_wq ( struct ib_completion_queue
*cq
,
354 unsigned long qpn
, int is_send
) {
355 struct ib_work_queue
*wq
;
357 list_for_each_entry ( wq
, &cq
->work_queues
, list
) {
358 if ( ( wq
->qp
->qpn
== qpn
) && ( wq
->is_send
== is_send
) )
365 * Post send work queue entry
367 * @v ibdev Infiniband device
369 * @v av Address vector
370 * @v iobuf I/O buffer
371 * @ret rc Return status code
373 int ib_post_send ( struct ib_device
*ibdev
, struct ib_queue_pair
*qp
,
374 struct ib_address_vector
*av
,
375 struct io_buffer
*iobuf
) {
376 struct ib_address_vector av_copy
;
379 /* Check queue fill level */
380 if ( qp
->send
.fill
>= qp
->send
.num_wqes
) {
381 DBGC ( ibdev
, "IBDEV %p QPN %#lx send queue full\n",
386 /* Use default address vector if none specified */
390 /* Make modifiable copy of address vector */
391 memcpy ( &av_copy
, av
, sizeof ( av_copy
) );
394 /* Fill in optional parameters in address vector */
398 av
->rate
= IB_RATE_2_5
;
400 /* Post to hardware */
401 if ( ( rc
= ibdev
->op
->post_send ( ibdev
, qp
, av
, iobuf
) ) != 0 ) {
402 DBGC ( ibdev
, "IBDEV %p QPN %#lx could not post send WQE: "
403 "%s\n", ibdev
, qp
->qpn
, strerror ( rc
) );
412 * Post receive work queue entry
414 * @v ibdev Infiniband device
416 * @v iobuf I/O buffer
417 * @ret rc Return status code
419 int ib_post_recv ( struct ib_device
*ibdev
, struct ib_queue_pair
*qp
,
420 struct io_buffer
*iobuf
) {
423 /* Check packet length */
424 if ( iob_tailroom ( iobuf
) < IB_MAX_PAYLOAD_SIZE
) {
425 DBGC ( ibdev
, "IBDEV %p QPN %#lx wrong RX buffer size (%zd)\n",
426 ibdev
, qp
->qpn
, iob_tailroom ( iobuf
) );
430 /* Check queue fill level */
431 if ( qp
->recv
.fill
>= qp
->recv
.num_wqes
) {
432 DBGC ( ibdev
, "IBDEV %p QPN %#lx receive queue full\n",
437 /* Post to hardware */
438 if ( ( rc
= ibdev
->op
->post_recv ( ibdev
, qp
, iobuf
) ) != 0 ) {
439 DBGC ( ibdev
, "IBDEV %p QPN %#lx could not post receive WQE: "
440 "%s\n", ibdev
, qp
->qpn
, strerror ( rc
) );
449 * Complete send work queue entry
451 * @v ibdev Infiniband device
453 * @v iobuf I/O buffer
454 * @v rc Completion status code
456 void ib_complete_send ( struct ib_device
*ibdev
, struct ib_queue_pair
*qp
,
457 struct io_buffer
*iobuf
, int rc
) {
459 if ( qp
->send
.cq
->op
->complete_send
) {
460 qp
->send
.cq
->op
->complete_send ( ibdev
, qp
, iobuf
, rc
);
468 * Complete receive work queue entry
470 * @v ibdev Infiniband device
472 * @v av Address vector
473 * @v iobuf I/O buffer
474 * @v rc Completion status code
476 void ib_complete_recv ( struct ib_device
*ibdev
, struct ib_queue_pair
*qp
,
477 struct ib_address_vector
*av
,
478 struct io_buffer
*iobuf
, int rc
) {
480 if ( qp
->recv
.cq
->op
->complete_recv
) {
481 qp
->recv
.cq
->op
->complete_recv ( ibdev
, qp
, av
, iobuf
, rc
);
489 * Refill receive work queue
491 * @v ibdev Infiniband device
494 void ib_refill_recv ( struct ib_device
*ibdev
, struct ib_queue_pair
*qp
) {
495 struct io_buffer
*iobuf
;
498 /* Keep filling while unfilled entries remain */
499 while ( qp
->recv
.fill
< qp
->recv
.num_wqes
) {
501 /* Allocate I/O buffer */
502 iobuf
= alloc_iob ( IB_MAX_PAYLOAD_SIZE
);
504 /* Non-fatal; we will refill on next attempt */
508 /* Post I/O buffer */
509 if ( ( rc
= ib_post_recv ( ibdev
, qp
, iobuf
) ) != 0 ) {
510 DBGC ( ibdev
, "IBDEV %p could not refill: %s\n",
511 ibdev
, strerror ( rc
) );
519 /***************************************************************************
523 ***************************************************************************
529 * @v ibdev Infiniband device
530 * @ret rc Return status code
532 int ib_open ( struct ib_device
*ibdev
) {
535 /* Increment device open request counter */
536 if ( ibdev
->open_count
++ > 0 ) {
537 /* Device was already open; do nothing */
541 /* Create subnet management interface */
542 ibdev
->smi
= ib_create_mi ( ibdev
, IB_QPT_SMI
);
543 if ( ! ibdev
->smi
) {
544 DBGC ( ibdev
, "IBDEV %p could not create SMI\n", ibdev
);
549 /* Create subnet management agent */
550 if ( ( rc
= ib_create_sma ( ibdev
, ibdev
->smi
) ) != 0 ) {
551 DBGC ( ibdev
, "IBDEV %p could not create SMA: %s\n",
552 ibdev
, strerror ( rc
) );
556 /* Create general services interface */
557 ibdev
->gsi
= ib_create_mi ( ibdev
, IB_QPT_GSI
);
558 if ( ! ibdev
->gsi
) {
559 DBGC ( ibdev
, "IBDEV %p could not create GSI\n", ibdev
);
565 if ( ( rc
= ibdev
->op
->open ( ibdev
) ) != 0 ) {
566 DBGC ( ibdev
, "IBDEV %p could not open: %s\n",
567 ibdev
, strerror ( rc
) );
571 /* Add to head of open devices list */
572 list_add ( &ibdev
->open_list
, &open_ib_devices
);
574 assert ( ibdev
->open_count
== 1 );
577 ibdev
->op
->close ( ibdev
);
579 ib_destroy_mi ( ibdev
, ibdev
->gsi
);
581 ib_destroy_sma ( ibdev
, ibdev
->smi
);
583 ib_destroy_mi ( ibdev
, ibdev
->smi
);
585 assert ( ibdev
->open_count
== 1 );
586 ibdev
->open_count
= 0;
593 * @v ibdev Infiniband device
595 void ib_close ( struct ib_device
*ibdev
) {
597 /* Decrement device open request counter */
600 /* Close device if this was the last remaining requested opening */
601 if ( ibdev
->open_count
== 0 ) {
602 list_del ( &ibdev
->open_list
);
603 ib_destroy_mi ( ibdev
, ibdev
->gsi
);
604 ib_destroy_sma ( ibdev
, ibdev
->smi
);
605 ib_destroy_mi ( ibdev
, ibdev
->smi
);
606 ibdev
->op
->close ( ibdev
);
610 /***************************************************************************
614 ***************************************************************************
618 * Attach to multicast group
620 * @v ibdev Infiniband device
622 * @v gid Multicast GID
623 * @ret rc Return status code
625 * Note that this function handles only the local device's attachment
626 * to the multicast GID; it does not issue the relevant MADs to join
627 * the multicast group on the subnet.
629 int ib_mcast_attach ( struct ib_device
*ibdev
, struct ib_queue_pair
*qp
,
630 struct ib_gid
*gid
) {
631 struct ib_multicast_gid
*mgid
;
634 /* Add to software multicast GID list */
635 mgid
= zalloc ( sizeof ( *mgid
) );
640 memcpy ( &mgid
->gid
, gid
, sizeof ( mgid
->gid
) );
641 list_add ( &mgid
->list
, &qp
->mgids
);
643 /* Add to hardware multicast GID list */
644 if ( ( rc
= ibdev
->op
->mcast_attach ( ibdev
, qp
, gid
) ) != 0 )
645 goto err_dev_mcast_attach
;
649 err_dev_mcast_attach
:
650 list_del ( &mgid
->list
);
657 * Detach from multicast group
659 * @v ibdev Infiniband device
661 * @v gid Multicast GID
663 void ib_mcast_detach ( struct ib_device
*ibdev
, struct ib_queue_pair
*qp
,
664 struct ib_gid
*gid
) {
665 struct ib_multicast_gid
*mgid
;
667 /* Remove from hardware multicast GID list */
668 ibdev
->op
->mcast_detach ( ibdev
, qp
, gid
);
670 /* Remove from software multicast GID list */
671 list_for_each_entry ( mgid
, &qp
->mgids
, list
) {
672 if ( memcmp ( &mgid
->gid
, gid
, sizeof ( mgid
->gid
) ) == 0 ) {
673 list_del ( &mgid
->list
);
680 /***************************************************************************
684 ***************************************************************************
688 * Get Infiniband HCA information
690 * @v ibdev Infiniband device
691 * @ret hca_guid HCA GUID
692 * @ret num_ports Number of ports
694 int ib_get_hca_info ( struct ib_device
*ibdev
,
695 struct ib_gid_half
*hca_guid
) {
696 struct ib_device
*tmp
;
699 /* Search for IB devices with the same physical device to
700 * identify port count and a suitable Node GUID.
702 for_each_ibdev ( tmp
) {
703 if ( tmp
->dev
!= ibdev
->dev
)
705 if ( num_ports
== 0 ) {
706 memcpy ( hca_guid
, &tmp
->gid
.u
.half
[1],
707 sizeof ( *hca_guid
) );
715 * Set port information
717 * @v ibdev Infiniband device
718 * @v mad Set port information MAD
720 int ib_set_port_info ( struct ib_device
*ibdev
, union ib_mad
*mad
) {
723 /* Adapters with embedded SMAs do not need to support this method */
724 if ( ! ibdev
->op
->set_port_info
) {
725 DBGC ( ibdev
, "IBDEV %p does not support setting port "
726 "information\n", ibdev
);
730 if ( ( rc
= ibdev
->op
->set_port_info ( ibdev
, mad
) ) != 0 ) {
731 DBGC ( ibdev
, "IBDEV %p could not set port information: %s\n",
732 ibdev
, strerror ( rc
) );
740 * Set partition key table
742 * @v ibdev Infiniband device
743 * @v mad Set partition key table MAD
745 int ib_set_pkey_table ( struct ib_device
*ibdev
, union ib_mad
*mad
) {
748 /* Adapters with embedded SMAs do not need to support this method */
749 if ( ! ibdev
->op
->set_pkey_table
) {
750 DBGC ( ibdev
, "IBDEV %p does not support setting partition "
751 "key table\n", ibdev
);
755 if ( ( rc
= ibdev
->op
->set_pkey_table ( ibdev
, mad
) ) != 0 ) {
756 DBGC ( ibdev
, "IBDEV %p could not set partition key table: "
757 "%s\n", ibdev
, strerror ( rc
) );
764 /***************************************************************************
768 ***************************************************************************
772 * Handle Infiniband link state change
774 * @v ibdev Infiniband device
776 void ib_link_state_changed ( struct ib_device
*ibdev
) {
778 /* Notify IPoIB of link state change */
779 ipoib_link_state_changed ( ibdev
);
785 * @v ibdev Infiniband device
787 void ib_poll_eq ( struct ib_device
*ibdev
) {
788 struct ib_completion_queue
*cq
;
790 /* Poll device's event queue */
791 ibdev
->op
->poll_eq ( ibdev
);
793 /* Poll all completion queues */
794 list_for_each_entry ( cq
, &ibdev
->cqs
, list
)
795 ib_poll_cq ( ibdev
, cq
);
799 * Single-step the Infiniband event queue
801 * @v process Infiniband event queue process
803 static void ib_step ( struct process
*process __unused
) {
804 struct ib_device
*ibdev
;
806 for_each_ibdev ( ibdev
)
807 ib_poll_eq ( ibdev
);
810 /** Infiniband event queue process */
811 struct process ib_process __permanent_process
= {
812 .list
= LIST_HEAD_INIT ( ib_process
.list
),
816 /***************************************************************************
818 * Infiniband device creation/destruction
820 ***************************************************************************
824 * Allocate Infiniband device
826 * @v priv_size Size of driver private data area
827 * @ret ibdev Infiniband device, or NULL
829 struct ib_device
* alloc_ibdev ( size_t priv_size
) {
830 struct ib_device
*ibdev
;
834 total_len
= ( sizeof ( *ibdev
) + priv_size
);
835 ibdev
= zalloc ( total_len
);
837 drv_priv
= ( ( ( void * ) ibdev
) + sizeof ( *ibdev
) );
838 ib_set_drvdata ( ibdev
, drv_priv
);
839 INIT_LIST_HEAD ( &ibdev
->cqs
);
840 INIT_LIST_HEAD ( &ibdev
->qps
);
841 ibdev
->lid
= IB_LID_NONE
;
842 ibdev
->pkey
= IB_PKEY_NONE
;
848 * Register Infiniband device
850 * @v ibdev Infiniband device
851 * @ret rc Return status code
853 int register_ibdev ( struct ib_device
*ibdev
) {
856 /* Add to device list */
858 list_add_tail ( &ibdev
->list
, &ib_devices
);
860 /* Add IPoIB device */
861 if ( ( rc
= ipoib_probe ( ibdev
) ) != 0 ) {
862 DBGC ( ibdev
, "IBDEV %p could not add IPoIB device: %s\n",
863 ibdev
, strerror ( rc
) );
864 goto err_ipoib_probe
;
867 DBGC ( ibdev
, "IBDEV %p registered (phys %s)\n", ibdev
,
872 list_del ( &ibdev
->list
);
878 * Unregister Infiniband device
880 * @v ibdev Infiniband device
882 void unregister_ibdev ( struct ib_device
*ibdev
) {
885 ipoib_remove ( ibdev
);
887 /* Remove from device list */
888 list_del ( &ibdev
->list
);
890 DBGC ( ibdev
, "IBDEV %p unregistered\n", ibdev
);
894 * Find Infiniband device by GID
897 * @ret ibdev Infiniband device, or NULL
899 struct ib_device
* find_ibdev ( struct ib_gid
*gid
) {
900 struct ib_device
*ibdev
;
902 for_each_ibdev ( ibdev
) {
903 if ( memcmp ( gid
, &ibdev
->gid
, sizeof ( *gid
) ) == 0 )
910 * Get most recently opened Infiniband device
912 * @ret ibdev Most recently opened Infiniband device, or NULL
914 struct ib_device
* last_opened_ibdev ( void ) {
915 struct ib_device
*ibdev
;
917 list_for_each_entry ( ibdev
, &open_ib_devices
, open_list
) {
918 assert ( ibdev
->open_count
!= 0 );