[infiniband] Maintain queue fill level as a property of a work queue
[people/mcb30/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 #include <stdint.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <byteswap.h>
25 #include <errno.h>
26 #include <assert.h>
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/process.h>
33 #include <gpxe/infiniband.h>
34
35 /** @file
36  *
37  * Infiniband protocol
38  *
39  */
40
41 /** List of Infiniband devices */
42 struct list_head ib_devices = LIST_HEAD_INIT ( ib_devices );
43
44 /**
45  * Create completion queue
46  *
47  * @v ibdev             Infiniband device
48  * @v num_cqes          Number of completion queue entries
49  * @v complete_send     Send completion handler
50  * @v complete_recv     Receive completion handler
51  * @ret cq              New completion queue
52  */
53 struct ib_completion_queue *
54 ib_create_cq ( struct ib_device *ibdev, unsigned int num_cqes,
55                ib_completer_t complete_send, ib_completer_t complete_recv ) {
56         struct ib_completion_queue *cq;
57         int rc;
58
59         DBGC ( ibdev, "IBDEV %p creating completion queue\n", ibdev );
60
61         /* Allocate and initialise data structure */
62         cq = zalloc ( sizeof ( *cq ) );
63         if ( ! cq )
64                 return NULL;
65         cq->num_cqes = num_cqes;
66         INIT_LIST_HEAD ( &cq->work_queues );
67         cq->complete_send = complete_send;
68         cq->complete_recv = complete_recv;
69
70         /* Perform device-specific initialisation and get CQN */
71         if ( ( rc = ibdev->op->create_cq ( ibdev, cq ) ) != 0 ) {
72                 DBGC ( ibdev, "IBDEV %p could not initialise completion "
73                        "queue: %s\n", ibdev, strerror ( rc ) );
74                 free ( cq );
75                 return NULL;
76         }
77
78         DBGC ( ibdev, "IBDEV %p created %d-entry completion queue %p (%p) "
79                "with CQN %#lx\n", ibdev, num_cqes, cq,
80                ib_cq_get_drvdata ( cq ), cq->cqn );
81         return cq;
82 }
83
84 /**
85  * Destroy completion queue
86  *
87  * @v ibdev             Infiniband device
88  * @v cq                Completion queue
89  */
90 void ib_destroy_cq ( struct ib_device *ibdev,
91                      struct ib_completion_queue *cq ) {
92         DBGC ( ibdev, "IBDEV %p destroying completion queue %#lx\n",
93                ibdev, cq->cqn );
94         assert ( list_empty ( &cq->work_queues ) );
95         ibdev->op->destroy_cq ( ibdev, cq );
96         free ( cq );
97 }
98
99 /**
100  * Create queue pair
101  *
102  * @v ibdev             Infiniband device
103  * @v num_send_wqes     Number of send work queue entries
104  * @v send_cq           Send completion queue
105  * @v num_recv_wqes     Number of receive work queue entries
106  * @v recv_cq           Receive completion queue
107  * @v qkey              Queue key
108  * @ret qp              Queue pair
109  */
110 struct ib_queue_pair * ib_create_qp ( struct ib_device *ibdev,
111                                       unsigned int num_send_wqes,
112                                       struct ib_completion_queue *send_cq,
113                                       unsigned int num_recv_wqes,
114                                       struct ib_completion_queue *recv_cq,
115                                       unsigned long qkey ) {
116         struct ib_queue_pair *qp;
117         size_t total_size;
118         int rc;
119
120         DBGC ( ibdev, "IBDEV %p creating queue pair\n", ibdev );
121
122         /* Allocate and initialise data structure */
123         total_size = ( sizeof ( *qp ) +
124                        ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ) +
125                        ( num_recv_wqes * sizeof ( qp->recv.iobufs[0] ) ) );
126         qp = zalloc ( total_size );
127         if ( ! qp )
128                 return NULL;
129         qp->qkey = qkey;
130         qp->send.qp = qp;
131         qp->send.is_send = 1;
132         qp->send.cq = send_cq;
133         list_add ( &qp->send.list, &send_cq->work_queues );
134         qp->send.num_wqes = num_send_wqes;
135         qp->send.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) );
136         qp->recv.qp = qp;
137         qp->recv.cq = recv_cq;
138         list_add ( &qp->recv.list, &recv_cq->work_queues );
139         qp->recv.num_wqes = num_recv_wqes;
140         qp->recv.iobufs = ( ( ( void * ) qp ) + sizeof ( *qp ) +
141                             ( num_send_wqes * sizeof ( qp->send.iobufs[0] ) ));
142
143         /* Perform device-specific initialisation and get QPN */
144         if ( ( rc = ibdev->op->create_qp ( ibdev, qp ) ) != 0 ) {
145                 DBGC ( ibdev, "IBDEV %p could not initialise queue pair: "
146                        "%s\n", ibdev, strerror ( rc ) );
147                 list_del ( &qp->send.list );
148                 list_del ( &qp->recv.list );
149                 free ( qp );
150                 return NULL;
151         }
152
153         DBGC ( ibdev, "IBDEV %p created queue pair %p (%p) with QPN %#lx\n",
154                ibdev, qp, ib_qp_get_drvdata ( qp ), qp->qpn );
155         DBGC ( ibdev, "IBDEV %p QPN %#lx has %d send entries at [%p,%p)\n",
156                ibdev, qp->qpn, num_send_wqes, qp->send.iobufs,
157                qp->recv.iobufs );
158         DBGC ( ibdev, "IBDEV %p QPN %#lx has %d receive entries at [%p,%p)\n",
159                ibdev, qp->qpn, num_recv_wqes, qp->recv.iobufs,
160                ( ( ( void * ) qp ) + total_size ) );
161         return qp;
162 }
163
164 /**
165  * Modify queue pair
166  *
167  * @v ibdev             Infiniband device
168  * @v qp                Queue pair
169  * @v mod_list          Modification list
170  * @v qkey              New queue key, if applicable
171  * @ret rc              Return status code
172  */
173 int ib_modify_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp,
174                    unsigned long mod_list, unsigned long qkey ) {
175         int rc;
176
177         DBGC ( ibdev, "IBDEV %p modifying QPN %#lx\n", ibdev, qp->qpn );
178
179         if ( mod_list & IB_MODIFY_QKEY )
180                 qp->qkey = qkey;
181
182         if ( ( rc = ibdev->op->modify_qp ( ibdev, qp, mod_list ) ) != 0 ) {
183                 DBGC ( ibdev, "IBDEV %p could not modify QPN %#lx: %s\n",
184                        ibdev, qp->qpn, strerror ( rc ) );
185                 return rc;
186         }
187
188         return 0;
189 }
190
191 /**
192  * Destroy queue pair
193  *
194  * @v ibdev             Infiniband device
195  * @v qp                Queue pair
196  */
197 void ib_destroy_qp ( struct ib_device *ibdev, struct ib_queue_pair *qp ) {
198         struct ib_completion completion = {
199                 .syndrome = IB_SYN_LOCAL_QP,
200         };
201         struct io_buffer *iobuf;
202         unsigned int i;
203
204         DBGC ( ibdev, "IBDEV %p destroying QPN %#lx\n",
205                ibdev, qp->qpn );
206
207         /* Perform device-specific destruction */
208         ibdev->op->destroy_qp ( ibdev, qp );
209
210         /* Complete any remaining I/O buffers with errors */
211         for ( i = 0 ; i < qp->send.num_wqes ; i++ ) {
212                 if ( ( iobuf = qp->send.iobufs[i] ) != NULL )
213                         ib_complete_send ( ibdev, qp, &completion, iobuf );
214         }
215         for ( i = 0 ; i < qp->recv.num_wqes ; i++ ) {
216                 if ( ( iobuf = qp->recv.iobufs[i] ) != NULL )
217                         ib_complete_recv ( ibdev, qp, &completion, iobuf );
218         }
219
220         /* Remove work queues from completion queue */
221         list_del ( &qp->send.list );
222         list_del ( &qp->recv.list );
223
224         /* Free QP */
225         free ( qp );
226 }
227
228 /**
229  * Find work queue belonging to completion queue
230  *
231  * @v cq                Completion queue
232  * @v qpn               Queue pair number
233  * @v is_send           Find send work queue (rather than receive)
234  * @ret wq              Work queue, or NULL if not found
235  */
236 struct ib_work_queue * ib_find_wq ( struct ib_completion_queue *cq,
237                                     unsigned long qpn, int is_send ) {
238         struct ib_work_queue *wq;
239
240         list_for_each_entry ( wq, &cq->work_queues, list ) {
241                 if ( ( wq->qp->qpn == qpn ) && ( wq->is_send == is_send ) )
242                         return wq;
243         }
244         return NULL;
245 }
246
247 /**
248  * Post send work queue entry
249  *
250  * @v ibdev             Infiniband device
251  * @v qp                Queue pair
252  * @v av                Address vector
253  * @v iobuf             I/O buffer
254  * @ret rc              Return status code
255  */
256 int ib_post_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
257                    struct ib_address_vector *av, struct io_buffer *iobuf ) {
258         int rc;
259
260         /* Check queue fill level */
261         if ( qp->send.fill >= qp->send.num_wqes ) {
262                 DBGC ( ibdev, "IBDEV %p QPN %#lx send queue full\n",
263                        ibdev, qp->qpn );
264                 return -ENOBUFS;
265         }
266
267         /* Post to hardware */
268         if ( ( rc = ibdev->op->post_send ( ibdev, qp, av, iobuf ) ) != 0 ) {
269                 DBGC ( ibdev, "IBDEV %p QPN %#lx could not post send WQE: "
270                        "%s\n", ibdev, qp->qpn, strerror ( rc ) );
271                 return rc;
272         }
273
274         qp->send.fill++;
275         return 0;
276 }
277
278 /**
279  * Post receive work queue entry
280  *
281  * @v ibdev             Infiniband device
282  * @v qp                Queue pair
283  * @v iobuf             I/O buffer
284  * @ret rc              Return status code
285  */
286 int ib_post_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
287                    struct io_buffer *iobuf ) {
288         int rc;
289
290         /* Check queue fill level */
291         if ( qp->recv.fill >= qp->recv.num_wqes ) {
292                 DBGC ( ibdev, "IBDEV %p QPN %#lx receive queue full\n",
293                        ibdev, qp->qpn );
294                 return -ENOBUFS;
295         }
296
297         /* Post to hardware */
298         if ( ( rc = ibdev->op->post_recv ( ibdev, qp, iobuf ) ) != 0 ) {
299                 DBGC ( ibdev, "IBDEV %p QPN %#lx could not post receive WQE: "
300                        "%s\n", ibdev, qp->qpn, strerror ( rc ) );
301                 return rc;
302         }
303
304         qp->recv.fill++;
305         return 0;
306 }
307
308 /**
309  * Complete send work queue entry
310  *
311  * @v ibdev             Infiniband device
312  * @v qp                Queue pair
313  * @v completion        Completion
314  * @v iobuf             I/O buffer
315  */
316 void ib_complete_send ( struct ib_device *ibdev, struct ib_queue_pair *qp,
317                         struct ib_completion *completion,
318                         struct io_buffer *iobuf ) {
319         qp->send.cq->complete_send ( ibdev, qp, completion, iobuf );
320         qp->send.fill--;
321 }
322
323 /**
324  * Complete receive work queue entry
325  *
326  * @v ibdev             Infiniband device
327  * @v qp                Queue pair
328  * @v completion        Completion
329  * @v iobuf             I/O buffer
330  */
331 void ib_complete_recv ( struct ib_device *ibdev, struct ib_queue_pair *qp,
332                         struct ib_completion *completion,
333                         struct io_buffer *iobuf ) {
334         qp->recv.cq->complete_recv ( ibdev, qp, completion, iobuf );
335         qp->recv.fill--;
336 }
337
338 /***************************************************************************
339  *
340  * Management datagram operations
341  *
342  ***************************************************************************
343  */
344
345 /**
346  * Get port information
347  *
348  * @v ibdev             Infiniband device
349  * @v port_info         Port information datagram to fill in
350  * @ret rc              Return status code
351  */
352 static int ib_get_port_info ( struct ib_device *ibdev,
353                               struct ib_mad_port_info *port_info ) {
354         struct ib_mad_hdr *hdr = &port_info->mad_hdr;
355         int rc;
356
357         /* Construct MAD */
358         memset ( port_info, 0, sizeof ( *port_info ) );
359         hdr->base_version = IB_MGMT_BASE_VERSION;
360         hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
361         hdr->class_version = 1;
362         hdr->method = IB_MGMT_METHOD_GET;
363         hdr->attr_id = htons ( IB_SMP_ATTR_PORT_INFO );
364         hdr->attr_mod = htonl ( ibdev->port );
365
366         if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *port_info ) ) ) != 0 ) {
367                 DBGC ( ibdev, "IBDEV %p could not get port info: %s\n",
368                        ibdev, strerror ( rc ) );
369                 return rc;
370         }
371         return 0;
372 }
373
374 /**
375  * Get GUID information
376  *
377  * @v ibdev             Infiniband device
378  * @v guid_info         GUID information datagram to fill in
379  * @ret rc              Return status code
380  */
381 static int ib_get_guid_info ( struct ib_device *ibdev,
382                               struct ib_mad_guid_info *guid_info ) {
383         struct ib_mad_hdr *hdr = &guid_info->mad_hdr;
384         int rc;
385
386         /* Construct MAD */
387         memset ( guid_info, 0, sizeof ( *guid_info ) );
388         hdr->base_version = IB_MGMT_BASE_VERSION;
389         hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
390         hdr->class_version = 1;
391         hdr->method = IB_MGMT_METHOD_GET;
392         hdr->attr_id = htons ( IB_SMP_ATTR_GUID_INFO );
393
394         if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *guid_info ) ) ) != 0 ) {
395                 DBGC ( ibdev, "IBDEV %p could not get GUID info: %s\n",
396                        ibdev, strerror ( rc ) );
397                 return rc;
398         }
399         return 0;
400 }
401
402 /**
403  * Get partition key table
404  *
405  * @v ibdev             Infiniband device
406  * @v guid_info         Partition key table datagram to fill in
407  * @ret rc              Return status code
408  */
409 static int ib_get_pkey_table ( struct ib_device *ibdev,
410                                struct ib_mad_pkey_table *pkey_table ) {
411         struct ib_mad_hdr *hdr = &pkey_table->mad_hdr;
412         int rc;
413
414         /* Construct MAD */
415         memset ( pkey_table, 0, sizeof ( *pkey_table ) );
416         hdr->base_version = IB_MGMT_BASE_VERSION;
417         hdr->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED;
418         hdr->class_version = 1;
419         hdr->method = IB_MGMT_METHOD_GET;
420         hdr->attr_id = htons ( IB_SMP_ATTR_PKEY_TABLE );
421
422         if ( ( rc = ib_mad ( ibdev, hdr, sizeof ( *pkey_table ) ) ) != 0 ) {
423                 DBGC ( ibdev, "IBDEV %p could not get pkey table: %s\n",
424                        ibdev, strerror ( rc ) );
425                 return rc;
426         }
427         return 0;
428 }
429
430 /**
431  * Get MAD parameters
432  *
433  * @v ibdev             Infiniband device
434  * @ret rc              Return status code
435  */
436 static int ib_get_mad_params ( struct ib_device *ibdev ) {
437         union {
438                 /* This union exists just to save stack space */
439                 struct ib_mad_port_info port_info;
440                 struct ib_mad_guid_info guid_info;
441                 struct ib_mad_pkey_table pkey_table;
442         } u;
443         int rc;
444
445         /* Port info gives us the link state, the first half of the
446          * port GID and the SM LID.
447          */
448         if ( ( rc = ib_get_port_info ( ibdev, &u.port_info ) ) != 0 )
449                 return rc;
450         ibdev->link_up = ( ( u.port_info.port_state__link_speed_supported
451                              & 0xf ) == 4 );
452         memcpy ( &ibdev->port_gid.u.bytes[0], u.port_info.gid_prefix, 8 );
453         ibdev->sm_lid = ntohs ( u.port_info.mastersm_lid );
454
455         /* GUID info gives us the second half of the port GID */
456         if ( ( rc = ib_get_guid_info ( ibdev, &u.guid_info ) ) != 0 )
457                 return rc;
458         memcpy ( &ibdev->port_gid.u.bytes[8], u.guid_info.gid_local, 8 );
459
460         /* Get partition key */
461         if ( ( rc = ib_get_pkey_table ( ibdev, &u.pkey_table ) ) != 0 )
462                 return rc;
463         ibdev->pkey = ntohs ( u.pkey_table.pkey[0][0] );
464
465         DBGC ( ibdev, "IBDEV %p port GID is %08lx:%08lx:%08lx:%08lx\n",
466                ibdev, htonl ( ibdev->port_gid.u.dwords[0] ),
467                htonl ( ibdev->port_gid.u.dwords[1] ),
468                htonl ( ibdev->port_gid.u.dwords[2] ),
469                htonl ( ibdev->port_gid.u.dwords[3] ) );
470
471         return 0;
472 }
473
474 /***************************************************************************
475  *
476  * Event queues
477  *
478  ***************************************************************************
479  */
480
481 /**
482  * Handle Infiniband link state change
483  *
484  * @v ibdev             Infiniband device
485  */
486 void ib_link_state_changed ( struct ib_device *ibdev ) {
487         int rc;
488
489         /* Update MAD parameters */
490         if ( ( rc = ib_get_mad_params ( ibdev ) ) != 0 ) {
491                 DBGC ( ibdev, "IBDEV %p could not update MAD parameters: %s\n",
492                        ibdev, strerror ( rc ) );
493                 return;
494         }
495
496         /* Notify IPoIB of link state change */
497         ipoib_link_state_changed ( ibdev );
498 }
499
500 /**
501  * Single-step the Infiniband event queue
502  *
503  * @v process           Infiniband event queue process
504  */
505 static void ib_step ( struct process *process __unused ) {
506         struct ib_device *ibdev;
507
508         list_for_each_entry ( ibdev, &ib_devices, list ) {
509                 ibdev->op->poll_eq ( ibdev );
510         }
511 }
512
513 /** Infiniband event queue process */
514 struct process ib_process __permanent_process = {
515         .step = ib_step,
516 };
517
518 /***************************************************************************
519  *
520  * Infiniband device creation/destruction
521  *
522  ***************************************************************************
523  */
524
525 /**
526  * Allocate Infiniband device
527  *
528  * @v priv_size         Size of driver private data area
529  * @ret ibdev           Infiniband device, or NULL
530  */
531 struct ib_device * alloc_ibdev ( size_t priv_size ) {
532         struct ib_device *ibdev;
533         void *drv_priv;
534         size_t total_len;
535
536         total_len = ( sizeof ( *ibdev ) + priv_size );
537         ibdev = zalloc ( total_len );
538         if ( ibdev ) {
539                 drv_priv = ( ( ( void * ) ibdev ) + sizeof ( *ibdev ) );
540                 ib_set_drvdata ( ibdev, drv_priv );
541         }
542         return ibdev;
543 }
544
545 /**
546  * Register Infiniband device
547  *
548  * @v ibdev             Infiniband device
549  * @ret rc              Return status code
550  */
551 int register_ibdev ( struct ib_device *ibdev ) {
552         int rc;
553
554         /* Add to device list */
555         ibdev_get ( ibdev );
556         list_add_tail ( &ibdev->list, &ib_devices );
557
558         /* Open link */
559         if ( ( rc = ib_open ( ibdev ) ) != 0 )
560                 goto err_open;
561
562         /* Get MAD parameters */
563         if ( ( rc = ib_get_mad_params ( ibdev ) ) != 0 )
564                 goto err_get_mad_params;
565
566         /* Add IPoIB device */
567         if ( ( rc = ipoib_probe ( ibdev ) ) != 0 ) {
568                 DBGC ( ibdev, "IBDEV %p could not add IPoIB device: %s\n",
569                        ibdev, strerror ( rc ) );
570                 goto err_ipoib_probe;
571         }
572
573         DBGC ( ibdev, "IBDEV %p registered (phys %s)\n", ibdev,
574                ibdev->dev->name );
575         return 0;
576
577  err_ipoib_probe:
578  err_get_mad_params:
579         ib_close ( ibdev );
580  err_open:
581         list_del ( &ibdev->list );
582         ibdev_put ( ibdev );
583         return rc;
584 }
585
586 /**
587  * Unregister Infiniband device
588  *
589  * @v ibdev             Infiniband device
590  */
591 void unregister_ibdev ( struct ib_device *ibdev ) {
592
593         /* Close device */
594         ipoib_remove ( ibdev );
595         ib_close ( ibdev );
596
597         /* Remove from device list */
598         list_del ( &ibdev->list );
599         ibdev_put ( ibdev );
600         DBGC ( ibdev, "IBDEV %p unregistered\n", ibdev );
601 }