gpxe import
[grub-extras.git] / gpxe / src / net / infiniband.c
blobcd7deae2502ef8a0a5ee9bc40ef40d19dd6c197a
1 /*
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 );
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 #include <gpxe/ib_mi.h>
37 #include <gpxe/ib_sma.h>
39 /** @file
41 * Infiniband protocol
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 /***************************************************************************
53 * Completion queues
55 ***************************************************************************
58 /**
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;
70 int rc;
72 DBGC ( ibdev, "IBDEV %p creating completion queue\n", ibdev );
74 /* Allocate and initialise data structure */
75 cq = zalloc ( sizeof ( *cq ) );
76 if ( ! cq )
77 goto err_alloc_cq;
78 cq->ibdev = ibdev;
79 list_add ( &cq->list, &ibdev->cqs );
80 cq->num_cqes = num_cqes;
81 INIT_LIST_HEAD ( &cq->work_queues );
82 cq->op = op;
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 );
94 return cq;
96 ibdev->op->destroy_cq ( ibdev, cq );
97 err_dev_create_cq:
98 list_del ( &cq->list );
99 free ( cq );
100 err_alloc_cq:
101 return NULL;
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",
113 ibdev, cq->cqn );
114 assert ( list_empty ( &cq->work_queues ) );
115 ibdev->op->destroy_cq ( ibdev, cq );
116 list_del ( &cq->list );
117 free ( cq );
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 ) {
135 if ( ! wq->is_send )
136 ib_refill_recv ( ibdev, wq->qp );
140 /***************************************************************************
142 * Work queues
144 ***************************************************************************
148 * Create queue pair
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
156 * @ret qp Queue pair
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;
168 size_t total_size;
169 int rc;
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 );
178 if ( ! qp )
179 goto err_alloc_qp;
180 qp->ibdev = ibdev;
181 list_add ( &qp->list, &ibdev->qps );
182 qp->type = type;
183 qp->send.qp = qp;
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 ) );
190 qp->recv.qp = 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,
209 qp->recv.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 */
215 switch ( type ) {
216 case IB_QPT_SMI:
217 qp->ext_qpn = IB_QPN_SMI;
218 break;
219 case IB_QPT_GSI:
220 qp->ext_qpn = IB_QPN_GSI;
221 break;
222 default:
223 qp->ext_qpn = qp->qpn;
224 break;
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 );
231 return qp;
233 ibdev->op->destroy_qp ( ibdev, qp );
234 err_dev_create_qp:
235 list_del ( &qp->send.list );
236 list_del ( &qp->recv.list );
237 list_del ( &qp->list );
238 free ( qp );
239 err_alloc_qp:
240 return NULL;
244 * Modify queue pair
246 * @v ibdev Infiniband device
247 * @v qp Queue pair
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 ) {
252 int rc;
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 ) );
259 return rc;
262 return 0;
266 * Destroy queue pair
268 * @v ibdev Infiniband device
269 * @v qp Queue pair
271 void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
272 struct io_buffer *iobuf;
273 unsigned int i;
275 DBGC ( ibdev, "IBDEV %p destroying QPN %#lx\n",
276 ibdev, qp->qpn );
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,
291 -ECANCELED );
295 /* Remove work queues from completion queue */
296 list_del ( &qp->send.list );
297 list_del ( &qp->recv.list );
299 /* Free QP */
300 list_del ( &qp->list );
301 free ( qp );
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 ) )
317 return qp;
319 return NULL;
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 ) {
338 return qp;
342 return NULL;
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 ) )
359 return wq;
361 return NULL;
365 * Post send work queue entry
367 * @v ibdev Infiniband device
368 * @v qp Queue pair
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;
377 int rc;
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",
382 ibdev, qp->qpn );
383 return -ENOBUFS;
386 /* Use default address vector if none specified */
387 if ( ! av )
388 av = &qp->av;
390 /* Make modifiable copy of address vector */
391 memcpy ( &av_copy, av, sizeof ( av_copy ) );
392 av = &av_copy;
394 /* Fill in optional parameters in address vector */
395 if ( ! av->qkey )
396 av->qkey = qp->qkey;
397 if ( ! av->rate )
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 ) );
404 return rc;
407 qp->send.fill++;
408 return 0;
412 * Post receive work queue entry
414 * @v ibdev Infiniband device
415 * @v qp Queue pair
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 ) {
421 int rc;
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 ) );
427 return -EINVAL;
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",
433 ibdev, qp->qpn );
434 return -ENOBUFS;
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 ) );
441 return rc;
444 qp->recv.fill++;
445 return 0;
449 * Complete send work queue entry
451 * @v ibdev Infiniband device
452 * @v qp Queue pair
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 );
461 } else {
462 free_iob ( iobuf );
464 qp->send.fill--;
468 * Complete receive work queue entry
470 * @v ibdev Infiniband device
471 * @v qp Queue pair
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 );
482 } else {
483 free_iob ( iobuf );
485 qp->recv.fill--;
489 * Refill receive work queue
491 * @v ibdev Infiniband device
492 * @v qp Queue pair
494 void ib_refill_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
495 struct io_buffer *iobuf;
496 int rc;
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 );
503 if ( ! iobuf ) {
504 /* Non-fatal; we will refill on next attempt */
505 return;
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 ) );
512 free_iob ( iobuf );
513 /* Give up */
514 return;
519 /***************************************************************************
521 * Link control
523 ***************************************************************************
527 * Open port
529 * @v ibdev Infiniband device
530 * @ret rc Return status code
532 int ib_open ( struct ib_device *ibdev ) {
533 int rc;
535 /* Increment device open request counter */
536 if ( ibdev->open_count++ > 0 ) {
537 /* Device was already open; do nothing */
538 return 0;
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 );
545 rc = -ENOMEM;
546 goto err_create_smi;
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 ) );
553 goto err_create_sma;
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 );
560 rc = -ENOMEM;
561 goto err_create_gsi;
564 /* Open device */
565 if ( ( rc = ibdev->op->open ( ibdev ) ) != 0 ) {
566 DBGC ( ibdev, "IBDEV %p could not open: %s\n",
567 ibdev, strerror ( rc ) );
568 goto err_open;
571 /* Add to head of open devices list */
572 list_add ( &ibdev->open_list, &open_ib_devices );
574 assert ( ibdev->open_count == 1 );
575 return 0;
577 ibdev->op->close ( ibdev );
578 err_open:
579 ib_destroy_mi ( ibdev, ibdev->gsi );
580 err_create_gsi:
581 ib_destroy_sma ( ibdev, ibdev->smi );
582 err_create_sma:
583 ib_destroy_mi ( ibdev, ibdev->smi );
584 err_create_smi:
585 assert ( ibdev->open_count == 1 );
586 ibdev->open_count = 0;
587 return rc;
591 * Close port
593 * @v ibdev Infiniband device
595 void ib_close ( struct ib_device *ibdev ) {
597 /* Decrement device open request counter */
598 ibdev->open_count--;
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 /***************************************************************************
612 * Multicast
614 ***************************************************************************
618 * Attach to multicast group
620 * @v ibdev Infiniband device
621 * @v qp Queue pair
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;
632 int rc;
634 /* Add to software multicast GID list */
635 mgid = zalloc ( sizeof ( *mgid ) );
636 if ( ! mgid ) {
637 rc = -ENOMEM;
638 goto err_alloc_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;
647 return 0;
649 err_dev_mcast_attach:
650 list_del ( &mgid->list );
651 free ( mgid );
652 err_alloc_mgid:
653 return rc;
657 * Detach from multicast group
659 * @v ibdev Infiniband device
660 * @v qp Queue pair
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 );
674 free ( mgid );
675 break;
680 /***************************************************************************
682 * Miscellaneous
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;
697 int num_ports = 0;
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 )
704 continue;
705 if ( num_ports == 0 ) {
706 memcpy ( hca_guid, &tmp->gid.u.half[1],
707 sizeof ( *hca_guid ) );
709 num_ports++;
711 return num_ports;
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 ) {
721 int rc;
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 );
727 return -ENOTSUP;
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 ) );
733 return rc;
736 return 0;
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 ) {
746 int rc;
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 );
752 return -ENOTSUP;
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 ) );
758 return rc;
761 return 0;
764 /***************************************************************************
766 * Event queues
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 );
783 * Poll event queue
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 ),
813 .step = ib_step,
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;
831 void *drv_priv;
832 size_t total_len;
834 total_len = ( sizeof ( *ibdev ) + priv_size );
835 ibdev = zalloc ( total_len );
836 if ( ibdev ) {
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;
844 return ibdev;
848 * Register Infiniband device
850 * @v ibdev Infiniband device
851 * @ret rc Return status code
853 int register_ibdev ( struct ib_device *ibdev ) {
854 int rc;
856 /* Add to device list */
857 ibdev_get ( ibdev );
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,
868 ibdev->dev->name );
869 return 0;
871 err_ipoib_probe:
872 list_del ( &ibdev->list );
873 ibdev_put ( ibdev );
874 return rc;
878 * Unregister Infiniband device
880 * @v ibdev Infiniband device
882 void unregister_ibdev ( struct ib_device *ibdev ) {
884 /* Close device */
885 ipoib_remove ( ibdev );
887 /* Remove from device list */
888 list_del ( &ibdev->list );
889 ibdev_put ( ibdev );
890 DBGC ( ibdev, "IBDEV %p unregistered\n", ibdev );
894 * Find Infiniband device by GID
896 * @v gid 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 )
904 return ibdev;
906 return NULL;
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 );
919 return ibdev;
922 return NULL;