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