diff options
Diffstat (limited to 'gpxe/src/net/infiniband.c')
-rw-r--r-- | gpxe/src/net/infiniband.c | 951 |
1 files changed, 0 insertions, 951 deletions
diff --git a/gpxe/src/net/infiniband.c b/gpxe/src/net/infiniband.c deleted file mode 100644 index d7813249..00000000 --- a/gpxe/src/net/infiniband.c +++ /dev/null @@ -1,951 +0,0 @@ -/* - * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include <stdint.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <byteswap.h> -#include <errno.h> -#include <assert.h> -#include <gpxe/list.h> -#include <gpxe/errortab.h> -#include <gpxe/if_arp.h> -#include <gpxe/netdevice.h> -#include <gpxe/iobuf.h> -#include <gpxe/ipoib.h> -#include <gpxe/process.h> -#include <gpxe/infiniband.h> -#include <gpxe/ib_mi.h> -#include <gpxe/ib_sma.h> - -/** @file - * - * Infiniband protocol - * - */ - -/** List of Infiniband devices */ -struct list_head ib_devices = LIST_HEAD_INIT ( ib_devices ); - -/** List of open Infiniband devices, in reverse order of opening */ -static struct list_head open_ib_devices = LIST_HEAD_INIT ( open_ib_devices ); - -/* Disambiguate the various possible EINPROGRESSes */ -#define EINPROGRESS_INIT ( EINPROGRESS | EUNIQ_01 ) -#define EINPROGRESS_ARMED ( EINPROGRESS | EUNIQ_02 ) - -/** Human-readable message for the link statuses */ -struct errortab infiniband_errors[] __errortab = { - { EINPROGRESS_INIT, "Initialising" }, - { EINPROGRESS_ARMED, "Armed" }, -}; - -/*************************************************************************** - * - * Completion queues - * - *************************************************************************** - */ - -/** - * Create completion queue - * - * @v ibdev Infiniband device - * @v num_cqes Number of completion queue entries - * @v op Completion queue operations - * @ret cq New completion queue - */ -struct ib_completion_queue * -ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes, - struct ib_completion_queue_operations *op ) { - struct ib_completion_queue *cq; - int rc; - - DBGC ( ibdev, "IBDEV %p creating completion queue\n", ibdev ); - - /* Allocate and initialise data structure */ - cq = zalloc ( sizeof ( *cq ) ); - if ( ! cq ) - goto err_alloc_cq; - cq->ibdev = ibdev; - list_add ( &cq->list, &ibdev->cqs ); - cq->num_cqes = num_cqes; - INIT_LIST_HEAD ( &cq->work_queues ); - cq->op = op; - - /* Perform device-specific initialisation and get CQN */ - if ( ( rc = ibdev->op->create_cq ( ibdev, cq ) ) != 0 ) { - DBGC ( ibdev, "IBDEV %p could not initialise completion " - "queue: %s\n", ibdev, strerror ( rc ) ); - goto err_dev_create_cq; - } - - DBGC ( ibdev, "IBDEV %p created %d-entry completion queue %p (%p) " - "with CQN %#lx\n", ibdev, num_cqes, cq, - ib_cq_get_drvdata ( cq ), cq->cqn ); - return cq; - - ibdev->op->destroy_cq ( ibdev, cq ); - err_dev_create_cq: - list_del ( &cq->list ); - free ( cq ); - err_alloc_cq: - return NULL; -} - -/** - * Destroy completion queue - * - * @v ibdev Infiniband device - * @v cq Completion queue - */ -void ib_destroy_cq ( struct ib_device *ibdev, - struct ib_completion_queue *cq ) { - DBGC ( ibdev, "IBDEV %p destroying completion queue %#lx\n", - ibdev, cq->cqn ); - assert ( list_empty ( &cq->work_queues ) ); - ibdev->op->destroy_cq ( ibdev, cq ); - list_del ( &cq->list ); - free ( cq ); -} - -/** - * Poll completion queue - * - * @v ibdev Infiniband device - * @v cq Completion queue - */ -void ib_poll_cq ( struct ib_device *ibdev, - struct ib_completion_queue *cq ) { - struct ib_work_queue *wq; - - /* Poll completion queue */ - ibdev->op->poll_cq ( ibdev, cq ); - - /* Refill receive work queues */ - list_for_each_entry ( wq, &cq->work_queues, list ) { - if ( ! wq->is_send ) - ib_refill_recv ( ibdev, wq->qp ); - } -} - -/*************************************************************************** - * - * Work queues - * - *************************************************************************** - */ - -/** - * Create queue pair - * - * @v ibdev Infiniband device - * @v type Queue pair type - * @v num_send_wqes Number of send work queue entries - * @v send_cq Send completion queue - * @v num_recv_wqes Number of receive work queue entries - * @v recv_cq Receive completion queue - * @ret qp Queue pair - * - * The queue pair will be left in the INIT state; you must call - * ib_modify_qp() before it is ready to use for sending and receiving. - */ -struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev, - enum ib_queue_pair_type type, - unsigned int num_send_wqes, - struct ib_completion_queue *send_cq, - unsigned int num_recv_wqes, - struct ib_completion_queue *recv_cq ) { - struct ib_queue_pair *qp; - size_t total_size; - int rc; - - DBGC ( ibdev, "IBDEV %p creating queue pair\n", ibdev ); - - /* Allocate and initialise data structure */ - total_size = ( sizeof ( *qp ) + - ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ) + - ( num_recv_wqes * sizeof ( qp->recv.iobufs[0] ) ) ); - qp = zalloc ( total_size ); - if ( ! qp ) - goto err_alloc_qp; - qp->ibdev = ibdev; - list_add ( &qp->list, &ibdev->qps ); - qp->type = type; - qp->send.qp = qp; - qp->send.is_send = 1; - qp->send.cq = send_cq; - list_add ( &qp->send.list, &send_cq->work_queues ); - qp->send.psn = ( random() & 0xffffffUL ); - qp->send.num_wqes = num_send_wqes; - qp->send.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) ); - qp->recv.qp = qp; - qp->recv.cq = recv_cq; - list_add ( &qp->recv.list, &recv_cq->work_queues ); - qp->recv.psn = ( random() & 0xffffffUL ); - qp->recv.num_wqes = num_recv_wqes; - qp->recv.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) + - ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) )); - INIT_LIST_HEAD ( &qp->mgids ); - - /* Perform device-specific initialisation and get QPN */ - if ( ( rc = ibdev->op->create_qp ( ibdev, qp ) ) != 0 ) { - DBGC ( ibdev, "IBDEV %p could not initialise queue pair: " - "%s\n", ibdev, strerror ( rc ) ); - goto err_dev_create_qp; - } - DBGC ( ibdev, "IBDEV %p created queue pair %p (%p) with QPN %#lx\n", - ibdev, qp, ib_qp_get_drvdata ( qp ), qp->qpn ); - DBGC ( ibdev, "IBDEV %p QPN %#lx has %d send entries at [%p,%p)\n", - ibdev, qp->qpn, num_send_wqes, qp->send.iobufs, - qp->recv.iobufs ); - DBGC ( ibdev, "IBDEV %p QPN %#lx has %d receive entries at [%p,%p)\n", - ibdev, qp->qpn, num_recv_wqes, qp->recv.iobufs, - ( ( ( void * ) qp ) + total_size ) ); - - /* Calculate externally-visible QPN */ - switch ( type ) { - case IB_QPT_SMI: - qp->ext_qpn = IB_QPN_SMI; - break; - case IB_QPT_GSI: - qp->ext_qpn = IB_QPN_GSI; - break; - default: - qp->ext_qpn = qp->qpn; - break; - } - if ( qp->ext_qpn != qp->qpn ) { - DBGC ( ibdev, "IBDEV %p QPN %#lx has external QPN %#lx\n", - ibdev, qp->qpn, qp->ext_qpn ); - } - - return qp; - - ibdev->op->destroy_qp ( ibdev, qp ); - err_dev_create_qp: - list_del ( &qp->send.list ); - list_del ( &qp->recv.list ); - list_del ( &qp->list ); - free ( qp ); - err_alloc_qp: - return NULL; -} - -/** - * Modify queue pair - * - * @v ibdev Infiniband device - * @v qp Queue pair - * @v av New address vector, if applicable - * @ret rc Return status code - */ -int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) { - int rc; - - DBGC ( ibdev, "IBDEV %p modifying QPN %#lx\n", ibdev, qp->qpn ); - - if ( ( rc = ibdev->op->modify_qp ( ibdev, qp ) ) != 0 ) { - DBGC ( ibdev, "IBDEV %p could not modify QPN %#lx: %s\n", - ibdev, qp->qpn, strerror ( rc ) ); - return rc; - } - - return 0; -} - -/** - * Destroy queue pair - * - * @v ibdev Infiniband device - * @v qp Queue pair - */ -void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) { - struct io_buffer *iobuf; - unsigned int i; - - DBGC ( ibdev, "IBDEV %p destroying QPN %#lx\n", - ibdev, qp->qpn ); - - assert ( list_empty ( &qp->mgids ) ); - - /* Perform device-specific destruction */ - ibdev->op->destroy_qp ( ibdev, qp ); - - /* Complete any remaining I/O buffers with errors */ - for ( i = 0 ; i < qp->send.num_wqes ; i++ ) { - if ( ( iobuf = qp->send.iobufs[i] ) != NULL ) - ib_complete_send ( ibdev, qp, iobuf, -ECANCELED ); - } - for ( i = 0 ; i < qp->recv.num_wqes ; i++ ) { - if ( ( iobuf = qp->recv.iobufs[i] ) != NULL ) { - ib_complete_recv ( ibdev, qp, NULL, iobuf, - -ECANCELED ); - } - } - - /* Remove work queues from completion queue */ - list_del ( &qp->send.list ); - list_del ( &qp->recv.list ); - - /* Free QP */ - list_del ( &qp->list ); - free ( qp ); -} - -/** - * Find queue pair by QPN - * - * @v ibdev Infiniband device - * @v qpn Queue pair number - * @ret qp Queue pair, or NULL - */ -struct ib_queue_pair * ib_find_qp_qpn ( struct ib_device *ibdev, - unsigned long qpn ) { - struct ib_queue_pair *qp; - - list_for_each_entry ( qp, &ibdev->qps, list ) { - if ( ( qpn == qp->qpn ) || ( qpn == qp->ext_qpn ) ) - return qp; - } - return NULL; -} - -/** - * Find queue pair by multicast GID - * - * @v ibdev Infiniband device - * @v gid Multicast GID - * @ret qp Queue pair, or NULL - */ -struct ib_queue_pair * ib_find_qp_mgid ( struct ib_device *ibdev, - struct ib_gid *gid ) { - struct ib_queue_pair *qp; - struct ib_multicast_gid *mgid; - - list_for_each_entry ( qp, &ibdev->qps, list ) { - list_for_each_entry ( mgid, &qp->mgids, list ) { - if ( memcmp ( &mgid->gid, gid, - sizeof ( mgid->gid ) ) == 0 ) { - return qp; - } - } - } - return NULL; -} - -/** - * Find work queue belonging to completion queue - * - * @v cq Completion queue - * @v qpn Queue pair number - * @v is_send Find send work queue (rather than receive) - * @ret wq Work queue, or NULL if not found - */ -struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq, - unsigned long qpn, int is_send ) { - struct ib_work_queue *wq; - - list_for_each_entry ( wq, &cq->work_queues, list ) { - if ( ( wq->qp->qpn == qpn ) && ( wq->is_send == is_send ) ) - return wq; - } - return NULL; -} - -/** - * Post send work queue entry - * - * @v ibdev Infiniband device - * @v qp Queue pair - * @v av Address vector - * @v iobuf I/O buffer - * @ret rc Return status code - */ -int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp, - struct ib_address_vector *av, - struct io_buffer *iobuf ) { - struct ib_address_vector av_copy; - int rc; - - /* Check queue fill level */ - if ( qp->send.fill >= qp->send.num_wqes ) { - DBGC ( ibdev, "IBDEV %p QPN %#lx send queue full\n", - ibdev, qp->qpn ); - return -ENOBUFS; - } - - /* Use default address vector if none specified */ - if ( ! av ) - av = &qp->av; - - /* Make modifiable copy of address vector */ - memcpy ( &av_copy, av, sizeof ( av_copy ) ); - av = &av_copy; - - /* Fill in optional parameters in address vector */ - if ( ! av->qkey ) - av->qkey = qp->qkey; - if ( ! av->rate ) - av->rate = IB_RATE_2_5; - - /* Post to hardware */ - if ( ( rc = ibdev->op->post_send ( ibdev, qp, av, iobuf ) ) != 0 ) { - DBGC ( ibdev, "IBDEV %p QPN %#lx could not post send WQE: " - "%s\n", ibdev, qp->qpn, strerror ( rc ) ); - return rc; - } - - qp->send.fill++; - return 0; -} - -/** - * Post receive work queue entry - * - * @v ibdev Infiniband device - * @v qp Queue pair - * @v iobuf I/O buffer - * @ret rc Return status code - */ -int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp, - struct io_buffer *iobuf ) { - int rc; - - /* Check packet length */ - if ( iob_tailroom ( iobuf ) < IB_MAX_PAYLOAD_SIZE ) { - DBGC ( ibdev, "IBDEV %p QPN %#lx wrong RX buffer size (%zd)\n", - ibdev, qp->qpn, iob_tailroom ( iobuf ) ); - return -EINVAL; - } - - /* Check queue fill level */ - if ( qp->recv.fill >= qp->recv.num_wqes ) { - DBGC ( ibdev, "IBDEV %p QPN %#lx receive queue full\n", - ibdev, qp->qpn ); - return -ENOBUFS; - } - - /* Post to hardware */ - if ( ( rc = ibdev->op->post_recv ( ibdev, qp, iobuf ) ) != 0 ) { - DBGC ( ibdev, "IBDEV %p QPN %#lx could not post receive WQE: " - "%s\n", ibdev, qp->qpn, strerror ( rc ) ); - return rc; - } - - qp->recv.fill++; - return 0; -} - -/** - * Complete send work queue entry - * - * @v ibdev Infiniband device - * @v qp Queue pair - * @v iobuf I/O buffer - * @v rc Completion status code - */ -void ib_complete_send ( struct ib_device *ibdev, struct ib_queue_pair *qp, - struct io_buffer *iobuf, int rc ) { - - if ( qp->send.cq->op->complete_send ) { - qp->send.cq->op->complete_send ( ibdev, qp, iobuf, rc ); - } else { - free_iob ( iobuf ); - } - qp->send.fill--; -} - -/** - * Complete receive work queue entry - * - * @v ibdev Infiniband device - * @v qp Queue pair - * @v av Address vector - * @v iobuf I/O buffer - * @v rc Completion status code - */ -void ib_complete_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp, - struct ib_address_vector *av, - struct io_buffer *iobuf, int rc ) { - - if ( qp->recv.cq->op->complete_recv ) { - qp->recv.cq->op->complete_recv ( ibdev, qp, av, iobuf, rc ); - } else { - free_iob ( iobuf ); - } - qp->recv.fill--; -} - -/** - * Refill receive work queue - * - * @v ibdev Infiniband device - * @v qp Queue pair - */ -void ib_refill_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp ) { - struct io_buffer *iobuf; - int rc; - - /* Keep filling while unfilled entries remain */ - while ( qp->recv.fill < qp->recv.num_wqes ) { - - /* Allocate I/O buffer */ - iobuf = alloc_iob ( IB_MAX_PAYLOAD_SIZE ); - if ( ! iobuf ) { - /* Non-fatal; we will refill on next attempt */ - return; - } - - /* Post I/O buffer */ - if ( ( rc = ib_post_recv ( ibdev, qp, iobuf ) ) != 0 ) { - DBGC ( ibdev, "IBDEV %p could not refill: %s\n", - ibdev, strerror ( rc ) ); - free_iob ( iobuf ); - /* Give up */ - return; - } - } -} - -/*************************************************************************** - * - * Link control - * - *************************************************************************** - */ - -/** - * Open port - * - * @v ibdev Infiniband device - * @ret rc Return status code - */ -int ib_open ( struct ib_device *ibdev ) { - int rc; - - /* Increment device open request counter */ - if ( ibdev->open_count++ > 0 ) { - /* Device was already open; do nothing */ - return 0; - } - - /* Create subnet management interface */ - ibdev->smi = ib_create_mi ( ibdev, IB_QPT_SMI ); - if ( ! ibdev->smi ) { - DBGC ( ibdev, "IBDEV %p could not create SMI\n", ibdev ); - rc = -ENOMEM; - goto err_create_smi; - } - - /* Create subnet management agent */ - if ( ( rc = ib_create_sma ( ibdev, ibdev->smi ) ) != 0 ) { - DBGC ( ibdev, "IBDEV %p could not create SMA: %s\n", - ibdev, strerror ( rc ) ); - goto err_create_sma; - } - - /* Create general services interface */ - ibdev->gsi = ib_create_mi ( ibdev, IB_QPT_GSI ); - if ( ! ibdev->gsi ) { - DBGC ( ibdev, "IBDEV %p could not create GSI\n", ibdev ); - rc = -ENOMEM; - goto err_create_gsi; - } - - /* Open device */ - if ( ( rc = ibdev->op->open ( ibdev ) ) != 0 ) { - DBGC ( ibdev, "IBDEV %p could not open: %s\n", - ibdev, strerror ( rc ) ); - goto err_open; - } - - /* Add to head of open devices list */ - list_add ( &ibdev->open_list, &open_ib_devices ); - - assert ( ibdev->open_count == 1 ); - return 0; - - ibdev->op->close ( ibdev ); - err_open: - ib_destroy_mi ( ibdev, ibdev->gsi ); - err_create_gsi: - ib_destroy_sma ( ibdev, ibdev->smi ); - err_create_sma: - ib_destroy_mi ( ibdev, ibdev->smi ); - err_create_smi: - assert ( ibdev->open_count == 1 ); - ibdev->open_count = 0; - return rc; -} - -/** - * Close port - * - * @v ibdev Infiniband device - */ -void ib_close ( struct ib_device *ibdev ) { - - /* Decrement device open request counter */ - ibdev->open_count--; - - /* Close device if this was the last remaining requested opening */ - if ( ibdev->open_count == 0 ) { - list_del ( &ibdev->open_list ); - ib_destroy_mi ( ibdev, ibdev->gsi ); - ib_destroy_sma ( ibdev, ibdev->smi ); - ib_destroy_mi ( ibdev, ibdev->smi ); - ibdev->op->close ( ibdev ); - } -} - -/** - * Get link state - * - * @v ibdev Infiniband device - * @ret rc Link status code - */ -int ib_link_rc ( struct ib_device *ibdev ) { - switch ( ibdev->port_state ) { - case IB_PORT_STATE_DOWN: return -ENOTCONN; - case IB_PORT_STATE_INIT: return -EINPROGRESS_INIT; - case IB_PORT_STATE_ARMED: return -EINPROGRESS_ARMED; - case IB_PORT_STATE_ACTIVE: return 0; - default: return -EINVAL; - } -} - -/*************************************************************************** - * - * Multicast - * - *************************************************************************** - */ - -/** - * Attach to multicast group - * - * @v ibdev Infiniband device - * @v qp Queue pair - * @v gid Multicast GID - * @ret rc Return status code - * - * Note that this function handles only the local device's attachment - * to the multicast GID; it does not issue the relevant MADs to join - * the multicast group on the subnet. - */ -int ib_mcast_attach ( struct ib_device *ibdev, struct ib_queue_pair *qp, - struct ib_gid *gid ) { - struct ib_multicast_gid *mgid; - int rc; - - /* Add to software multicast GID list */ - mgid = zalloc ( sizeof ( *mgid ) ); - if ( ! mgid ) { - rc = -ENOMEM; - goto err_alloc_mgid; - } - memcpy ( &mgid->gid, gid, sizeof ( mgid->gid ) ); - list_add ( &mgid->list, &qp->mgids ); - - /* Add to hardware multicast GID list */ - if ( ( rc = ibdev->op->mcast_attach ( ibdev, qp, gid ) ) != 0 ) - goto err_dev_mcast_attach; - - return 0; - - err_dev_mcast_attach: - list_del ( &mgid->list ); - free ( mgid ); - err_alloc_mgid: - return rc; -} - -/** - * Detach from multicast group - * - * @v ibdev Infiniband device - * @v qp Queue pair - * @v gid Multicast GID - */ -void ib_mcast_detach ( struct ib_device *ibdev, struct ib_queue_pair *qp, - struct ib_gid *gid ) { - struct ib_multicast_gid *mgid; - - /* Remove from hardware multicast GID list */ - ibdev->op->mcast_detach ( ibdev, qp, gid ); - - /* Remove from software multicast GID list */ - list_for_each_entry ( mgid, &qp->mgids, list ) { - if ( memcmp ( &mgid->gid, gid, sizeof ( mgid->gid ) ) == 0 ) { - list_del ( &mgid->list ); - free ( mgid ); - break; - } - } -} - -/*************************************************************************** - * - * Miscellaneous - * - *************************************************************************** - */ - -/** - * Get Infiniband HCA information - * - * @v ibdev Infiniband device - * @ret hca_guid HCA GUID - * @ret num_ports Number of ports - */ -int ib_get_hca_info ( struct ib_device *ibdev, - struct ib_gid_half *hca_guid ) { - struct ib_device *tmp; - int num_ports = 0; - - /* Search for IB devices with the same physical device to - * identify port count and a suitable Node GUID. - */ - for_each_ibdev ( tmp ) { - if ( tmp->dev != ibdev->dev ) - continue; - if ( num_ports == 0 ) { - memcpy ( hca_guid, &tmp->gid.u.half[1], - sizeof ( *hca_guid ) ); - } - num_ports++; - } - return num_ports; -} - -/** - * Set port information - * - * @v ibdev Infiniband device - * @v mad Set port information MAD - */ -int ib_set_port_info ( struct ib_device *ibdev, union ib_mad *mad ) { - int rc; - - /* Adapters with embedded SMAs do not need to support this method */ - if ( ! ibdev->op->set_port_info ) { - DBGC ( ibdev, "IBDEV %p does not support setting port " - "information\n", ibdev ); - return -ENOTSUP; - } - - if ( ( rc = ibdev->op->set_port_info ( ibdev, mad ) ) != 0 ) { - DBGC ( ibdev, "IBDEV %p could not set port information: %s\n", - ibdev, strerror ( rc ) ); - return rc; - } - - return 0; -}; - -/** - * Set partition key table - * - * @v ibdev Infiniband device - * @v mad Set partition key table MAD - */ -int ib_set_pkey_table ( struct ib_device *ibdev, union ib_mad *mad ) { - int rc; - - /* Adapters with embedded SMAs do not need to support this method */ - if ( ! ibdev->op->set_pkey_table ) { - DBGC ( ibdev, "IBDEV %p does not support setting partition " - "key table\n", ibdev ); - return -ENOTSUP; - } - - if ( ( rc = ibdev->op->set_pkey_table ( ibdev, mad ) ) != 0 ) { - DBGC ( ibdev, "IBDEV %p could not set partition key table: " - "%s\n", ibdev, strerror ( rc ) ); - return rc; - } - - return 0; -}; - -/*************************************************************************** - * - * Event queues - * - *************************************************************************** - */ - -/** - * Handle Infiniband link state change - * - * @v ibdev Infiniband device - */ -void ib_link_state_changed ( struct ib_device *ibdev ) { - - /* Notify IPoIB of link state change */ - ipoib_link_state_changed ( ibdev ); -} - -/** - * Poll event queue - * - * @v ibdev Infiniband device - */ -void ib_poll_eq ( struct ib_device *ibdev ) { - struct ib_completion_queue *cq; - - /* Poll device's event queue */ - ibdev->op->poll_eq ( ibdev ); - - /* Poll all completion queues */ - list_for_each_entry ( cq, &ibdev->cqs, list ) - ib_poll_cq ( ibdev, cq ); -} - -/** - * Single-step the Infiniband event queue - * - * @v process Infiniband event queue process - */ -static void ib_step ( struct process *process __unused ) { - struct ib_device *ibdev; - - for_each_ibdev ( ibdev ) - ib_poll_eq ( ibdev ); -} - -/** Infiniband event queue process */ -struct process ib_process __permanent_process = { - .list = LIST_HEAD_INIT ( ib_process.list ), - .step = ib_step, -}; - -/*************************************************************************** - * - * Infiniband device creation/destruction - * - *************************************************************************** - */ - -/** - * Allocate Infiniband device - * - * @v priv_size Size of driver private data area - * @ret ibdev Infiniband device, or NULL - */ -struct ib_device * alloc_ibdev ( size_t priv_size ) { - struct ib_device *ibdev; - void *drv_priv; - size_t total_len; - - total_len = ( sizeof ( *ibdev ) + priv_size ); - ibdev = zalloc ( total_len ); - if ( ibdev ) { - drv_priv = ( ( ( void * ) ibdev ) + sizeof ( *ibdev ) ); - ib_set_drvdata ( ibdev, drv_priv ); - INIT_LIST_HEAD ( &ibdev->cqs ); - INIT_LIST_HEAD ( &ibdev->qps ); - ibdev->port_state = IB_PORT_STATE_DOWN; - ibdev->lid = IB_LID_NONE; - ibdev->pkey = IB_PKEY_DEFAULT; - } - return ibdev; -} - -/** - * Register Infiniband device - * - * @v ibdev Infiniband device - * @ret rc Return status code - */ -int register_ibdev ( struct ib_device *ibdev ) { - int rc; - - /* Add to device list */ - ibdev_get ( ibdev ); - list_add_tail ( &ibdev->list, &ib_devices ); - - /* Add IPoIB device */ - if ( ( rc = ipoib_probe ( ibdev ) ) != 0 ) { - DBGC ( ibdev, "IBDEV %p could not add IPoIB device: %s\n", - ibdev, strerror ( rc ) ); - goto err_ipoib_probe; - } - - DBGC ( ibdev, "IBDEV %p registered (phys %s)\n", ibdev, - ibdev->dev->name ); - return 0; - - err_ipoib_probe: - list_del ( &ibdev->list ); - ibdev_put ( ibdev ); - return rc; -} - -/** - * Unregister Infiniband device - * - * @v ibdev Infiniband device - */ -void unregister_ibdev ( struct ib_device *ibdev ) { - - /* Close device */ - ipoib_remove ( ibdev ); - - /* Remove from device list */ - list_del ( &ibdev->list ); - ibdev_put ( ibdev ); - DBGC ( ibdev, "IBDEV %p unregistered\n", ibdev ); -} - -/** - * Find Infiniband device by GID - * - * @v gid GID - * @ret ibdev Infiniband device, or NULL - */ -struct ib_device * find_ibdev ( struct ib_gid *gid ) { - struct ib_device *ibdev; - - for_each_ibdev ( ibdev ) { - if ( memcmp ( gid, &ibdev->gid, sizeof ( *gid ) ) == 0 ) - return ibdev; - } - return NULL; -} - -/** - * Get most recently opened Infiniband device - * - * @ret ibdev Most recently opened Infiniband device, or NULL - */ -struct ib_device * last_opened_ibdev ( void ) { - struct ib_device *ibdev; - - list_for_each_entry ( ibdev, &open_ib_devices, open_list ) { - assert ( ibdev->open_count != 0 ); - return ibdev; - } - - return NULL; -} |