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.
27 #include <gpxe/list.h>
28 #include <gpxe/if_arp.h>
29 #include <gpxe/netdevice.h>
30 #include <gpxe/iobuf.h>
31 #include <gpxe/ipoib.h>
32 #include <gpxe/infiniband.h>
41 * Create completion queue
43 * @v ibdev Infiniband device
44 * @v num_cqes Number of completion queue entries
45 * @ret cq New completion queue
47 struct ib_completion_queue * ib_create_cq ( struct ib_device *ibdev,
48 unsigned int num_cqes ) {
49 struct ib_completion_queue *cq;
52 DBGC ( ibdev, "IBDEV %p creating completion queue\n", ibdev );
54 /* Allocate and initialise data structure */
55 cq = zalloc ( sizeof ( *cq ) );
58 cq->num_cqes = num_cqes;
59 INIT_LIST_HEAD ( &cq->work_queues );
61 /* Perform device-specific initialisation and get CQN */
62 if ( ( rc = ibdev->op->create_cq ( ibdev, cq ) ) != 0 ) {
63 DBGC ( ibdev, "IBDEV %p could not initialise completion "
64 "queue: %s\n", ibdev, strerror ( rc ) );
69 DBGC ( ibdev, "IBDEV %p created %d-entry completion queue %p (%p) "
70 "with CQN %#lx\n", ibdev, num_cqes, cq,
71 ib_cq_get_drvdata ( cq ), cq->cqn );
76 * Destroy completion queue
78 * @v ibdev Infiniband device
79 * @v cq Completion queue
81 void ib_destroy_cq ( struct ib_device *ibdev,
82 struct ib_completion_queue *cq ) {
83 DBGC ( ibdev, "IBDEV %p destroying completion queue %#lx\n",
85 assert ( list_empty ( &cq->work_queues ) );
86 ibdev->op->destroy_cq ( ibdev, cq );
93 * @v ibdev Infiniband device
94 * @v num_send_wqes Number of send work queue entries
95 * @v send_cq Send completion queue
96 * @v num_recv_wqes Number of receive work queue entries
97 * @v recv_cq Receive completion queue
101 struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
102 unsigned int num_send_wqes,
103 struct ib_completion_queue *send_cq,
104 unsigned int num_recv_wqes,
105 struct ib_completion_queue *recv_cq,
106 unsigned long qkey ) {
107 struct ib_queue_pair *qp;
111 DBGC ( ibdev, "IBDEV %p creating queue pair\n", ibdev );
113 /* Allocate and initialise data structure */
114 total_size = ( sizeof ( *qp ) +
115 ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ) +
116 ( num_recv_wqes * sizeof ( qp->recv.iobufs[0] ) ) );
117 qp = zalloc ( total_size );
122 qp->send.is_send = 1;
123 qp->send.cq = send_cq;
124 list_add ( &qp->send.list, &send_cq->work_queues );
125 qp->send.num_wqes = num_send_wqes;
126 qp->send.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) );
128 qp->recv.cq = recv_cq;
129 list_add ( &qp->recv.list, &recv_cq->work_queues );
130 qp->recv.num_wqes = num_recv_wqes;
131 qp->recv.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) +
132 ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ));
134 /* Perform device-specific initialisation and get QPN */
135 if ( ( rc = ibdev->op->create_qp ( ibdev, qp ) ) != 0 ) {
136 DBGC ( ibdev, "IBDEV %p could not initialise queue pair: "
137 "%s\n", ibdev, strerror ( rc ) );
138 list_del ( &qp->send.list );
139 list_del ( &qp->recv.list );
144 DBGC ( ibdev, "IBDEV %p created queue pair %p (%p) with QPN %#lx\n",
145 ibdev, qp, ib_qp_get_drvdata ( qp ), qp->qpn );
146 DBGC ( ibdev, "IBDEV %p QPN %#lx has %d send entries at [%p,%p)\n",
147 ibdev, qp->qpn, num_send_wqes, qp->send.iobufs,
149 DBGC ( ibdev, "IBDEV %p QPN %#lx has %d receive entries at [%p,%p)\n",
150 ibdev, qp->qpn, num_recv_wqes, qp->recv.iobufs,
151 ( ( ( void * ) qp ) + total_size ) );
158 * @v ibdev Infiniband device
161 void ib_destroy_qp ( struct ib_device *ibdev,
162 struct ib_queue_pair *qp ) {
163 DBGC ( ibdev, "IBDEV %p destroying queue pair %#lx\n",
165 ibdev->op->destroy_qp ( ibdev, qp );
166 list_del ( &qp->send.list );
167 list_del ( &qp->recv.list );
172 * Find work queue belonging to completion queue
174 * @v cq Completion queue
175 * @v qpn Queue pair number
176 * @v is_send Find send work queue (rather than receive)
177 * @ret wq Work queue, or NULL if not found
179 struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq,
180 unsigned long qpn, int is_send ) {
181 struct ib_work_queue *wq;
183 list_for_each_entry ( wq, &cq->work_queues, list ) {
184 if ( ( wq->qp->qpn == qpn ) && ( wq->is_send == is_send ) )
190 /***************************************************************************
192 * Management datagram operations
194 ***************************************************************************
198 * Get port information
200 * @v ibdev Infiniband device
201 * @v port_info Port information datagram to fill in
202 * @ret rc Return status code
204 static int ib_get_port_info ( struct ib_device *ibdev,
205 struct ib_mad_port_info *port_info ) {
206 struct ib_mad_hdr *hdr = &port_info->mad_hdr;
210 memset ( port_info, 0, sizeof ( *port_info ) );
211 hdr->base_version = IB_MGMT_BASE_VERSION;
212 hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
213 hdr->class_version = 1;
214 hdr->method = IB_MGMT_METHOD_GET;
215 hdr->attr_id = htons ( IB_SMP_ATTR_PORT_INFO );
216 hdr->attr_mod = htonl ( ibdev->port );
218 if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *port_info ) ) ) != 0 ) {
219 DBGC ( ibdev, "IBDEV %p could not get port info: %s\n",
220 ibdev, strerror ( rc ) );
227 * Get GUID information
229 * @v ibdev Infiniband device
230 * @v guid_info GUID information datagram to fill in
231 * @ret rc Return status code
233 static int ib_get_guid_info ( struct ib_device *ibdev,
234 struct ib_mad_guid_info *guid_info ) {
235 struct ib_mad_hdr *hdr = &guid_info->mad_hdr;
239 memset ( guid_info, 0, sizeof ( *guid_info ) );
240 hdr->base_version = IB_MGMT_BASE_VERSION;
241 hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
242 hdr->class_version = 1;
243 hdr->method = IB_MGMT_METHOD_GET;
244 hdr->attr_id = htons ( IB_SMP_ATTR_GUID_INFO );
246 if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *guid_info ) ) ) != 0 ) {
247 DBGC ( ibdev, "IBDEV %p could not get GUID info: %s\n",
248 ibdev, strerror ( rc ) );
255 * Get partition key table
257 * @v ibdev Infiniband device
258 * @v guid_info Partition key table datagram to fill in
259 * @ret rc Return status code
261 static int ib_get_pkey_table ( struct ib_device *ibdev,
262 struct ib_mad_pkey_table *pkey_table ) {
263 struct ib_mad_hdr *hdr = &pkey_table->mad_hdr;
267 memset ( pkey_table, 0, sizeof ( *pkey_table ) );
268 hdr->base_version = IB_MGMT_BASE_VERSION;
269 hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
270 hdr->class_version = 1;
271 hdr->method = IB_MGMT_METHOD_GET;
272 hdr->attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE );
274 if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *pkey_table ) ) ) != 0 ) {
275 DBGC ( ibdev, "IBDEV %p could not get pkey table: %s\n",
276 ibdev, strerror ( rc ) );
285 * @v ibdev Infiniband device
286 * @ret rc Return status code
288 * This function shouldn't really exist. Unfortunately, IB links take
289 * a long time to come up, and we can't get various key parameters
290 * e.g. our own IPoIB MAC address without information from the subnet
291 * manager). We should eventually make link-up an asynchronous event.
293 static int ib_wait_for_link ( struct ib_device *ibdev ) {
294 struct ib_mad_port_info port_info;
295 unsigned int retries;
298 printf ( "Waiting for Infiniband link-up..." );
299 for ( retries = 20 ; retries ; retries-- ) {
300 if ( ( rc = ib_get_port_info ( ibdev, &port_info ) ) != 0 )
302 if ( ( ( port_info.port_state__link_speed_supported ) & 0xf )
310 printf ( "failed\n" );
317 * @v ibdev Infiniband device
318 * @ret rc Return status code
320 static int ib_get_mad_params ( struct ib_device *ibdev ) {
322 /* This union exists just to save stack space */
323 struct ib_mad_port_info port_info;
324 struct ib_mad_guid_info guid_info;
325 struct ib_mad_pkey_table pkey_table;
329 /* Port info gives us the first half of the port GID and the SM LID */
330 if ( ( rc = ib_get_port_info ( ibdev, &u.port_info ) ) != 0 )
332 memcpy ( &ibdev->port_gid.u.bytes[0], u.port_info.gid_prefix, 8 );
333 ibdev->sm_lid = ntohs ( u.port_info.mastersm_lid );
335 /* GUID info gives us the second half of the port GID */
336 if ( ( rc = ib_get_guid_info ( ibdev, &u.guid_info ) ) != 0 )
338 memcpy ( &ibdev->port_gid.u.bytes[8], u.guid_info.gid_local, 8 );
340 /* Get partition key */
341 if ( ( rc = ib_get_pkey_table ( ibdev, &u.pkey_table ) ) != 0 )
343 ibdev->pkey = ntohs ( u.pkey_table.pkey[0][0] );
345 DBGC ( ibdev, "IBDEV %p port GID is %08lx:%08lx:%08lx:%08lx\n",
346 ibdev, htonl ( ibdev->port_gid.u.dwords[0] ),
347 htonl ( ibdev->port_gid.u.dwords[1] ),
348 htonl ( ibdev->port_gid.u.dwords[2] ),
349 htonl ( ibdev->port_gid.u.dwords[3] ) );
354 /***************************************************************************
356 * Infiniband device creation/destruction
358 ***************************************************************************
362 * Allocate Infiniband device
364 * @v priv_size Size of driver private data area
365 * @ret ibdev Infiniband device, or NULL
367 struct ib_device * alloc_ibdev ( size_t priv_size ) {
368 struct ib_device *ibdev;
372 total_len = ( sizeof ( *ibdev ) + priv_size );
373 ibdev = zalloc ( total_len );
375 drv_priv = ( ( ( void * ) ibdev ) + sizeof ( *ibdev ) );
376 ib_set_drvdata ( ibdev, drv_priv );
382 * Register Infiniband device
384 * @v ibdev Infiniband device
385 * @ret rc Return status code
387 int register_ibdev ( struct ib_device *ibdev ) {
391 if ( ( rc = ib_open ( ibdev ) ) != 0 )
395 if ( ( rc = ib_wait_for_link ( ibdev ) ) != 0 )
396 goto err_wait_for_link;
398 /* Get MAD parameters */
399 if ( ( rc = ib_get_mad_params ( ibdev ) ) != 0 )
400 goto err_get_mad_params;
402 /* Add IPoIB device */
403 if ( ( rc = ipoib_probe ( ibdev ) ) != 0 ) {
404 DBGC ( ibdev, "IBDEV %p could not add IPoIB device: %s\n",
405 ibdev, strerror ( rc ) );
406 goto err_ipoib_probe;
420 * Unregister Infiniband device
422 * @v ibdev Infiniband device
424 void unregister_ibdev ( struct ib_device *ibdev ) {
425 ipoib_remove ( ibdev );
430 * Free Infiniband device
432 * @v ibdev Infiniband device
434 void free_ibdev ( struct ib_device *ibdev ) {