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