dd04a43c5100208ea68b577941ff13c3dea5b71c
[people/oremanj/gpxe.git] / src / drivers / net / ipoib.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 <stdio.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <byteswap.h>
26 #include <errno.h>
27 #include <gpxe/if_arp.h>
28 #include <gpxe/iobuf.h>
29 #include <gpxe/netdevice.h>
30 #include <gpxe/infiniband.h>
31 #include <gpxe/ib_qset.h>
32 #include <gpxe/ib_pathrec.h>
33 #include <gpxe/ipoib.h>
34
35 /** @file
36  *
37  * IP over Infiniband
38  */
39
40 /** Number of IPoIB data send work queue entries */
41 #define IPOIB_DATA_NUM_SEND_WQES 2
42
43 /** Number of IPoIB data receive work queue entries */
44 #define IPOIB_DATA_NUM_RECV_WQES 4
45
46 /** Number of IPoIB data completion entries */
47 #define IPOIB_DATA_NUM_CQES 8
48
49 /** Number of IPoIB metadata send work queue entries */
50 #define IPOIB_META_NUM_SEND_WQES 2
51
52 /** Number of IPoIB metadata receive work queue entries */
53 #define IPOIB_META_NUM_RECV_WQES 2
54
55 /** Number of IPoIB metadata completion entries */
56 #define IPOIB_META_NUM_CQES 8
57
58 /** An IPoIB device */
59 struct ipoib_device {
60         /** Network device */
61         struct net_device *netdev;
62         /** Underlying Infiniband device */
63         struct ib_device *ibdev;
64         /** Data queue set */
65         struct ib_queue_set data;
66         /** Data queue set */
67         struct ib_queue_set meta;
68         /** Broadcast GID */
69         struct ib_gid broadcast_gid;
70         /** Broadcast LID */
71         unsigned int broadcast_lid;
72         /** Data queue key */
73         unsigned long data_qkey;
74         /** Attached to multicast group
75          *
76          * This flag indicates whether or not we have attached our
77          * data queue pair to the broadcast multicast GID.
78          */
79         int broadcast_attached;
80 };
81
82 /** TID half used to identify multicast member record replies */
83 #define IPOIB_TID_MC_MEMBER_REC 0x22222222UL
84
85 /** IPoIB metadata TID */
86 static uint32_t ipoib_meta_tid = 0;
87
88 /** Broadcast QPN used in IPoIB MAC addresses
89  *
90  * This is a guaranteed invalid real QPN
91  */
92 #define IPOIB_BROADCAST_QPN 0xffffffffUL
93
94 /** Broadcast IPoIB address */
95 static struct ipoib_mac ipoib_broadcast = {
96         .qpn = ntohl ( IPOIB_BROADCAST_QPN ),
97         .gid.u.bytes =  { 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00,
98                           0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff },
99 };
100
101 /****************************************************************************
102  *
103  * IPoIB peer cache
104  *
105  ****************************************************************************
106  */
107
108 /**
109  * IPoIB peer address
110  *
111  * This serves a similar role to the ARP cache for Ethernet.  (ARP
112  * *is* used on IPoIB; we have two caches to maintain.)
113  */
114 struct ipoib_peer {
115         /** Key */
116         uint8_t key;
117         /** MAC address */
118         struct ipoib_mac mac;
119 };
120
121 /** Number of IPoIB peer cache entries
122  *
123  * Must be a power of two.
124  */
125 #define IPOIB_NUM_CACHED_PEERS 4
126
127 /** IPoIB peer address cache */
128 static struct ipoib_peer ipoib_peer_cache[IPOIB_NUM_CACHED_PEERS];
129
130 /** Oldest IPoIB peer cache entry index */
131 static unsigned int ipoib_peer_cache_idx = 1;
132
133 /**
134  * Look up cached peer by key
135  *
136  * @v key               Peer cache key
137  * @ret peer            Peer cache entry, or NULL
138  */
139 static struct ipoib_peer * ipoib_lookup_peer_by_key ( unsigned int key ) {
140         struct ipoib_peer *peer;
141         unsigned int i;
142
143         for ( i = 0 ; i < IPOIB_NUM_CACHED_PEERS ; i++ ) {
144                 peer = &ipoib_peer_cache[i];
145                 if ( peer->key == key )
146                         return peer;
147         }
148
149         if ( key != 0 ) {
150                 DBG ( "IPoIB warning: peer cache lost track of key %x while "
151                       "still in use\n", key );
152         }
153         return NULL;
154 }
155
156 /**
157  * Look up cached peer by GID
158  *
159  * @v gid               Peer GID
160  * @ret peer            Peer cache entry, or NULL
161  */
162 static struct ipoib_peer *
163 ipoib_lookup_peer_by_gid ( const struct ib_gid *gid ) {
164         struct ipoib_peer *peer;
165         unsigned int i;
166
167         for ( i = 0 ; i < IPOIB_NUM_CACHED_PEERS ; i++ ) {
168                 peer = &ipoib_peer_cache[i];
169                 if ( memcmp ( &peer->mac.gid, gid,
170                               sizeof ( peer->mac.gid) ) == 0 ) {
171                         return peer;
172                 }
173         }
174
175         return NULL;
176 }
177
178 /**
179  * Store GID and QPN in peer cache
180  *
181  * @v gid               Peer GID
182  * @v qpn               Peer QPN
183  * @ret peer            Peer cache entry
184  */
185 static struct ipoib_peer *
186 ipoib_cache_peer ( const struct ib_gid *gid, unsigned long qpn ) {
187         struct ipoib_peer *peer;
188         unsigned int key;
189
190         /* Look for existing cache entry */
191         peer = ipoib_lookup_peer_by_gid ( gid );
192         if ( peer ) {
193                 assert ( peer->mac.qpn = ntohl ( qpn ) );
194                 return peer;
195         }
196
197         /* No entry found: create a new one */
198         key = ipoib_peer_cache_idx++;
199         peer = &ipoib_peer_cache[ key % IPOIB_NUM_CACHED_PEERS ];
200         if ( peer->key )
201                 DBG ( "IPoIB peer %x evicted from cache\n", peer->key );
202
203         memset ( peer, 0, sizeof ( *peer ) );
204         peer->key = key;
205         peer->mac.qpn = htonl ( qpn );
206         memcpy ( &peer->mac.gid, gid, sizeof ( peer->mac.gid ) );
207         DBG ( "IPoIB peer %x has GID %08x:%08x:%08x:%08x and QPN %lx\n",
208               peer->key, htonl ( gid->u.dwords[0] ),
209               htonl ( gid->u.dwords[1] ), htonl ( gid->u.dwords[2] ),
210               htonl ( gid->u.dwords[3] ), qpn );
211         return peer;
212 }
213
214 /****************************************************************************
215  *
216  * IPoIB link layer
217  *
218  ****************************************************************************
219  */
220
221 /**
222  * Add IPoIB link-layer header
223  *
224  * @v netdev            Network device
225  * @v iobuf             I/O buffer
226  * @v ll_dest           Link-layer destination address
227  * @v ll_source         Source link-layer address
228  * @v net_proto         Network-layer protocol, in network-byte order
229  * @ret rc              Return status code
230  */
231 static int ipoib_push ( struct net_device *netdev __unused,
232                         struct io_buffer *iobuf, const void *ll_dest,
233                         const void *ll_source __unused, uint16_t net_proto ) {
234         struct ipoib_hdr *ipoib_hdr =
235                 iob_push ( iobuf, sizeof ( *ipoib_hdr ) );
236         const struct ipoib_mac *dest_mac = ll_dest;
237         const struct ipoib_mac *src_mac = ll_source;
238         struct ipoib_peer *dest;
239         struct ipoib_peer *src;
240
241         /* Add link-layer addresses to cache */
242         dest = ipoib_cache_peer ( &dest_mac->gid, ntohl ( dest_mac->qpn ) );
243         src = ipoib_cache_peer ( &src_mac->gid, ntohl ( src_mac->qpn ) );
244
245         /* Build IPoIB header */
246         ipoib_hdr->proto = net_proto;
247         ipoib_hdr->u.peer.dest = dest->key;
248         ipoib_hdr->u.peer.src = src->key;
249
250         return 0;
251 }
252
253 /**
254  * Remove IPoIB link-layer header
255  *
256  * @v netdev            Network device
257  * @v iobuf             I/O buffer
258  * @ret ll_dest         Link-layer destination address
259  * @ret ll_source       Source link-layer address
260  * @ret net_proto       Network-layer protocol, in network-byte order
261  * @ret rc              Return status code
262  */
263 static int ipoib_pull ( struct net_device *netdev __unused,
264                         struct io_buffer *iobuf, const void **ll_dest,
265                         const void **ll_source, uint16_t *net_proto ) {
266         struct ipoib_hdr *ipoib_hdr = iobuf->data;
267         struct ipoib_peer *dest;
268         struct ipoib_peer *source;
269
270         /* Sanity check */
271         if ( iob_len ( iobuf ) < sizeof ( *ipoib_hdr ) ) {
272                 DBG ( "IPoIB packet too short for link-layer header\n" );
273                 DBG_HD ( iobuf->data, iob_len ( iobuf ) );
274                 return -EINVAL;
275         }
276
277         /* Strip off IPoIB header */
278         iob_pull ( iobuf, sizeof ( *ipoib_hdr ) );
279
280         /* Identify source and destination addresses, and clear
281          * reserved word in IPoIB header
282          */
283         dest = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.dest );
284         source = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.src );
285         ipoib_hdr->u.reserved = 0;
286
287         /* Fill in required fields */
288         *ll_dest = ( dest ? &dest->mac : &ipoib_broadcast );
289         *ll_source = ( source ? &source->mac : &ipoib_broadcast );
290         *net_proto = ipoib_hdr->proto;
291
292         return 0;
293 }
294
295 /**
296  * Transcribe IPoIB address
297  *
298  * @v ll_addr   Link-layer address
299  * @ret string  Link-layer address in human-readable format
300  */
301 const char * ipoib_ntoa ( const void *ll_addr ) {
302         static char buf[45];
303         const struct ipoib_mac *mac = ll_addr;
304
305         snprintf ( buf, sizeof ( buf ), "%08x:%08x:%08x:%08x:%08x",
306                    htonl ( mac->qpn ), htonl ( mac->gid.u.dwords[0] ),
307                    htonl ( mac->gid.u.dwords[1] ),
308                    htonl ( mac->gid.u.dwords[2] ),
309                    htonl ( mac->gid.u.dwords[3] ) );
310         return buf;
311 }
312
313 /**
314  * Hash multicast address
315  *
316  * @v af                Address family
317  * @v net_addr          Network-layer address
318  * @v ll_addr           Link-layer address to fill in
319  * @ret rc              Return status code
320  */
321 static int ipoib_mc_hash ( unsigned int af __unused,
322                            const void *net_addr __unused,
323                            void *ll_addr __unused ) {
324
325         return -ENOTSUP;
326 }
327
328 /** IPoIB protocol */
329 struct ll_protocol ipoib_protocol __ll_protocol = {
330         .name           = "IPoIB",
331         .ll_proto       = htons ( ARPHRD_INFINIBAND ),
332         .ll_addr_len    = IPOIB_ALEN,
333         .ll_header_len  = IPOIB_HLEN,
334         .push           = ipoib_push,
335         .pull           = ipoib_pull,
336         .ntoa           = ipoib_ntoa,
337         .mc_hash        = ipoib_mc_hash,
338 };
339
340 /****************************************************************************
341  *
342  * IPoIB network device
343  *
344  ****************************************************************************
345  */
346
347 /**
348  * Transmit multicast group membership request
349  *
350  * @v ipoib             IPoIB device
351  * @v gid               Multicast GID
352  * @v join              Join (rather than leave) group
353  * @ret rc              Return status code
354  */
355 static int ipoib_mc_member_record ( struct ipoib_device *ipoib,
356                                     struct ib_gid *gid, int join ) {
357         struct ib_device *ibdev = ipoib->ibdev;
358         struct io_buffer *iobuf;
359         struct ib_mad_sa *sa;
360         struct ib_address_vector av;
361         int rc;
362
363         /* Allocate I/O buffer */
364         iobuf = alloc_iob ( sizeof ( *sa ) );
365         if ( ! iobuf )
366                 return -ENOMEM;
367         iob_put ( iobuf, sizeof ( *sa ) );
368         sa = iobuf->data;
369         memset ( sa, 0, sizeof ( *sa ) );
370
371         /* Construct path record request */
372         sa->mad_hdr.base_version = IB_MGMT_BASE_VERSION;
373         sa->mad_hdr.mgmt_class = IB_MGMT_CLASS_SUBN_ADM;
374         sa->mad_hdr.class_version = 2;
375         sa->mad_hdr.method =
376                 ( join ? IB_MGMT_METHOD_SET : IB_MGMT_METHOD_DELETE );
377         sa->mad_hdr.attr_id = htons ( IB_SA_ATTR_MC_MEMBER_REC );
378         sa->mad_hdr.tid[0] = IPOIB_TID_MC_MEMBER_REC;
379         sa->mad_hdr.tid[1] = ipoib_meta_tid++;
380         sa->sa_hdr.comp_mask[1] =
381                 htonl ( IB_SA_MCMEMBER_REC_MGID | IB_SA_MCMEMBER_REC_PORT_GID |
382                         IB_SA_MCMEMBER_REC_JOIN_STATE );
383         sa->sa_data.mc_member_record.scope__join_state = 1;
384         memcpy ( &sa->sa_data.mc_member_record.mgid, gid,
385                  sizeof ( sa->sa_data.mc_member_record.mgid ) );
386         memcpy ( &sa->sa_data.mc_member_record.port_gid, &ibdev->gid,
387                  sizeof ( sa->sa_data.mc_member_record.port_gid ) );
388
389         /* Construct address vector */
390         memset ( &av, 0, sizeof ( av ) );
391         av.lid = ibdev->sm_lid;
392         av.sl = ibdev->sm_sl;
393         av.qpn = IB_QPN_GMA;
394         av.qkey = IB_QKEY_GMA;
395
396         /* Post send request */
397         if ( ( rc = ib_post_send ( ibdev, ipoib->meta.qp, &av,
398                                    iobuf ) ) != 0 ) {
399                 DBGC ( ipoib, "IPoIB %p could not send get path record: %s\n",
400                        ipoib, strerror ( rc ) );
401                 free_iob ( iobuf );
402                 return rc;
403         }
404
405         return 0;
406 }
407
408 /**
409  * Transmit packet via IPoIB network device
410  *
411  * @v netdev            Network device
412  * @v iobuf             I/O buffer
413  * @ret rc              Return status code
414  */
415 static int ipoib_transmit ( struct net_device *netdev,
416                             struct io_buffer *iobuf ) {
417         struct ipoib_device *ipoib = netdev->priv;
418         struct ib_device *ibdev = ipoib->ibdev;
419         struct ipoib_hdr *ipoib_hdr;
420         struct ipoib_peer *dest;
421         struct ib_address_vector av;
422         int rc;
423
424         /* Sanity check */
425         if ( iob_len ( iobuf ) < sizeof ( *ipoib_hdr ) ) {
426                 DBGC ( ipoib, "IPoIB %p buffer too short\n", ipoib );
427                 return -EINVAL;
428         }
429         ipoib_hdr = iobuf->data;
430
431         /* Attempting transmission while link is down will put the
432          * queue pair into an error state, so don't try it.
433          */
434         if ( ! ib_link_ok ( ibdev ) )
435                 return -ENETUNREACH;
436
437         /* Identify destination address */
438         dest = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.dest );
439         if ( ! dest )
440                 return -ENXIO;
441         ipoib_hdr->u.reserved = 0;
442
443         /* Construct address vector */
444         memset ( &av, 0, sizeof ( av ) );
445         av.qkey = ipoib->data_qkey;
446         av.gid_present = 1;
447         if ( dest->mac.qpn == htonl ( IPOIB_BROADCAST_QPN ) ) {
448                 /* Broadcast */
449                 av.qpn = IB_QPN_BROADCAST;
450                 av.lid = ipoib->broadcast_lid;
451                 memcpy ( &av.gid, &ipoib->broadcast_gid, sizeof ( av.gid ) );
452         } else {
453                 /* Unicast */
454                 av.qpn = ntohl ( dest->mac.qpn );
455                 memcpy ( &av.gid, &dest->mac.gid, sizeof ( av.gid ) );
456                 if ( ( rc = ib_resolve_path ( ibdev, &av ) ) != 0 ) {
457                         /* Path not resolved yet */
458                         return rc;
459                 }
460         }
461
462         return ib_post_send ( ibdev, ipoib->data.qp, &av, iobuf );
463 }
464
465 /**
466  * Handle IPoIB data send completion
467  *
468  * @v ibdev             Infiniband device
469  * @v qp                Queue pair
470  * @v iobuf             I/O buffer
471  * @v rc                Completion status code
472  */
473 static void ipoib_data_complete_send ( struct ib_device *ibdev __unused,
474                                        struct ib_queue_pair *qp,
475                                        struct io_buffer *iobuf, int rc ) {
476         struct ipoib_device *ipoib = ib_qp_get_ownerdata ( qp );
477
478         netdev_tx_complete_err ( ipoib->netdev, iobuf, rc );
479 }
480
481 /**
482  * Handle IPoIB data receive completion
483  *
484  * @v ibdev             Infiniband device
485  * @v qp                Queue pair
486  * @v av                Address vector, or NULL
487  * @v iobuf             I/O buffer
488  * @v rc                Completion status code
489  */
490 static void ipoib_data_complete_recv ( struct ib_device *ibdev __unused,
491                                        struct ib_queue_pair *qp,
492                                        struct ib_address_vector *av,
493                                        struct io_buffer *iobuf, int rc ) {
494         struct ipoib_device *ipoib = ib_qp_get_ownerdata ( qp );
495         struct net_device *netdev = ipoib->netdev;
496         struct ipoib_hdr *ipoib_hdr;
497         struct ipoib_peer *src;
498
499         if ( rc != 0 ) {
500                 netdev_rx_err ( netdev, iobuf, rc );
501                 return;
502         }
503
504         /* Sanity check */
505         if ( iob_len ( iobuf ) < sizeof ( struct ipoib_hdr ) ) {
506                 DBGC ( ipoib, "IPoIB %p received data packet too short to "
507                        "contain IPoIB header\n", ipoib );
508                 DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) );
509                 netdev_rx_err ( netdev, iobuf, -EIO );
510                 return;
511         }
512         ipoib_hdr = iobuf->data;
513
514         /* Parse source address */
515         if ( av->gid_present ) {
516                 src = ipoib_cache_peer ( &av->gid, av->qpn );
517                 ipoib_hdr->u.peer.src = src->key;
518         }
519
520         /* Hand off to network layer */
521         netdev_rx ( netdev, iobuf );
522 }
523
524 /** IPoIB data completion operations */
525 static struct ib_completion_queue_operations ipoib_data_cq_op = {
526         .complete_send = ipoib_data_complete_send,
527         .complete_recv = ipoib_data_complete_recv,
528 };
529
530 /**
531  * Handle IPoIB metadata send completion
532  *
533  * @v ibdev             Infiniband device
534  * @v qp                Queue pair
535  * @v iobuf             I/O buffer
536  * @v rc                Completion status code
537  */
538 static void ipoib_meta_complete_send ( struct ib_device *ibdev __unused,
539                                        struct ib_queue_pair *qp,
540                                        struct io_buffer *iobuf, int rc ) {
541         struct ipoib_device *ipoib = ib_qp_get_ownerdata ( qp );
542
543         if ( rc != 0 ) {
544                 DBGC ( ipoib, "IPoIB %p metadata TX completion error: %s\n",
545                        ipoib, strerror ( rc ) );
546         }
547         free_iob ( iobuf );
548 }
549
550 /**
551  * Handle received IPoIB multicast membership record
552  *
553  * @v ipoib             IPoIB device
554  * @v mc_member_record  Multicast membership record
555  */
556 static void ipoib_recv_mc_member_record ( struct ipoib_device *ipoib,
557                                struct ib_mc_member_record *mc_member_record ) {
558         int joined;
559         int rc;
560
561         /* Record parameters */
562         joined = ( mc_member_record->scope__join_state & 0x0f );
563         ipoib->data_qkey = ntohl ( mc_member_record->qkey );
564         ipoib->broadcast_lid = ntohs ( mc_member_record->mlid );
565         DBGC ( ipoib, "IPoIB %p %s broadcast group: qkey %lx mlid %x\n",
566                ipoib, ( joined ? "joined" : "left" ), ipoib->data_qkey,
567                ipoib->broadcast_lid );
568
569         /* Update data queue pair qkey */
570         if ( ( rc = ib_modify_qp ( ipoib->ibdev, ipoib->data.qp,
571                                    IB_MODIFY_QKEY, ipoib->data_qkey ) ) != 0 ){
572                 DBGC ( ipoib, "IPoIB %p could not update data qkey: %s\n",
573                        ipoib, strerror ( rc ) );
574                 return;
575         }
576 }
577
578 /**
579  * Handle IPoIB metadata receive completion
580  *
581  * @v ibdev             Infiniband device
582  * @v qp                Queue pair
583  * @v av                Address vector, or NULL
584  * @v iobuf             I/O buffer
585  * @v rc                Completion status code
586  */
587 static void
588 ipoib_meta_complete_recv ( struct ib_device *ibdev __unused,
589                            struct ib_queue_pair *qp,
590                            struct ib_address_vector *av __unused,
591                            struct io_buffer *iobuf, int rc ) {
592         struct ipoib_device *ipoib = ib_qp_get_ownerdata ( qp );
593         struct ib_mad_sa *sa;
594
595         if ( rc != 0 ) {
596                 DBGC ( ipoib, "IPoIB %p metadata RX completion error: %s\n",
597                        ipoib, strerror ( rc ) );
598                 goto done;
599         }
600
601         if ( iob_len ( iobuf ) < sizeof ( *sa ) ) {
602                 DBGC ( ipoib, "IPoIB %p received metadata packet too short "
603                        "to contain reply\n", ipoib );
604                 DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) );
605                 goto done;
606         }
607         sa = iobuf->data;
608
609         if ( sa->mad_hdr.status != 0 ) {
610                 DBGC ( ipoib, "IPoIB %p metadata RX err status %04x\n",
611                        ipoib, ntohs ( sa->mad_hdr.status ) );
612                 goto done;
613         }
614
615         switch ( sa->mad_hdr.tid[0] ) {
616         case IPOIB_TID_MC_MEMBER_REC:
617                 ipoib_recv_mc_member_record ( ipoib,
618                                               &sa->sa_data.mc_member_record );
619                 break;
620         default:
621                 DBGC ( ipoib, "IPoIB %p unwanted response:\n",
622                        ipoib );
623                 DBGC_HD ( ipoib, sa, sizeof ( *sa ) );
624                 break;
625         }
626
627  done:
628         free_iob ( iobuf );
629 }
630
631 /** IPoIB metadata completion operations */
632 static struct ib_completion_queue_operations ipoib_meta_cq_op = {
633         .complete_send = ipoib_meta_complete_send,
634         .complete_recv = ipoib_meta_complete_recv,
635 };
636
637 /**
638  * Poll IPoIB network device
639  *
640  * @v netdev            Network device
641  */
642 static void ipoib_poll ( struct net_device *netdev ) {
643         struct ipoib_device *ipoib = netdev->priv;
644         struct ib_device *ibdev = ipoib->ibdev;
645
646         ib_poll_eq ( ibdev );
647 }
648
649 /**
650  * Enable/disable interrupts on IPoIB network device
651  *
652  * @v netdev            Network device
653  * @v enable            Interrupts should be enabled
654  */
655 static void ipoib_irq ( struct net_device *netdev __unused,
656                         int enable __unused ) {
657         /* No implementation */
658 }
659
660 /**
661  * Join IPv4 broadcast multicast group
662  *
663  * @v ipoib             IPoIB device
664  * @ret rc              Return status code
665  */
666 static int ipoib_join_broadcast_group ( struct ipoib_device *ipoib ) {
667         int rc;
668
669         /* Sanity check */
670         if ( ! ipoib->data.qp )
671                 return 0;
672
673         /* Attach data queue to broadcast multicast GID */
674         assert ( ipoib->broadcast_attached == 0 );
675         if ( ( rc = ib_mcast_attach ( ipoib->ibdev, ipoib->data.qp,
676                                       &ipoib->broadcast_gid ) ) != 0 ){
677                 DBGC ( ipoib, "IPoIB %p could not attach to broadcast GID: "
678                        "%s\n", ipoib, strerror ( rc ) );
679                 return rc;
680         }
681         ipoib->broadcast_attached = 1;
682
683         /* Initiate broadcast group join */
684         if ( ( rc = ipoib_mc_member_record ( ipoib, &ipoib->broadcast_gid,
685                                              1 ) ) != 0 ) {
686                 DBGC ( ipoib, "IPoIB %p could not send broadcast join: %s\n",
687                        ipoib, strerror ( rc ) );
688                 return rc;
689         }
690
691         /* We will set link up on the network device when we receive
692          * the broadcast join response.
693          */
694
695         return 0;
696 }
697
698 /**
699  * Leave IPv4 broadcast multicast group
700  *
701  * @v ipoib             IPoIB device
702  */
703 static void ipoib_leave_broadcast_group ( struct ipoib_device *ipoib ) {
704
705         /* Detach data queue from broadcast multicast GID */
706         if ( ipoib->broadcast_attached ) {
707                 assert ( ipoib->data.qp != NULL );
708                 ib_mcast_detach ( ipoib->ibdev, ipoib->data.qp,
709                                   &ipoib->broadcast_gid );
710                 ipoib->broadcast_attached = 0;
711         }
712 }
713
714 /**
715  * Open IPoIB network device
716  *
717  * @v netdev            Network device
718  * @ret rc              Return status code
719  */
720 static int ipoib_open ( struct net_device *netdev ) {
721         struct ipoib_device *ipoib = netdev->priv;
722         struct ib_device *ibdev = ipoib->ibdev;
723         struct ipoib_mac *mac = ( ( struct ipoib_mac * ) netdev->ll_addr );
724         int rc;
725
726         /* Open IB device */
727         if ( ( rc = ib_open ( ibdev ) ) != 0 ) {
728                 DBGC ( ipoib, "IPoIB %p could not open device: %s\n",
729                        ipoib, strerror ( rc ) );
730                 goto err_ib_open;
731         }
732
733         /* Allocate metadata queue set */
734         if ( ( rc = ib_create_qset ( ibdev, &ipoib->meta,
735                                      IPOIB_META_NUM_CQES, &ipoib_meta_cq_op,
736                                      IPOIB_META_NUM_SEND_WQES,
737                                      IPOIB_META_NUM_RECV_WQES,
738                                      IB_QKEY_GMA ) ) != 0 ) {
739                 DBGC ( ipoib, "IPoIB %p could not allocate metadata QP: %s\n",
740                        ipoib, strerror ( rc ) );
741                 goto err_create_meta_qset;
742         }
743         ib_qp_set_ownerdata ( ipoib->meta.qp, ipoib );
744
745         /* Allocate data queue set */
746         if ( ( rc = ib_create_qset ( ibdev, &ipoib->data,
747                                      IPOIB_DATA_NUM_CQES, &ipoib_data_cq_op,
748                                      IPOIB_DATA_NUM_SEND_WQES,
749                                      IPOIB_DATA_NUM_RECV_WQES,
750                                      IB_QKEY_GMA ) ) != 0 ) {
751                 DBGC ( ipoib, "IPoIB %p could not allocate data QP: %s\n",
752                        ipoib, strerror ( rc ) );
753                 goto err_create_data_qset;
754         }
755         ib_qp_set_ownerdata ( ipoib->data.qp, ipoib );
756
757         /* Update MAC address with data QPN */
758         mac->qpn = htonl ( ipoib->data.qp->qpn );
759
760         /* Fill receive rings */
761         ib_refill_recv ( ibdev, ipoib->meta.qp );
762         ib_refill_recv ( ibdev, ipoib->data.qp );
763
764         /* Join broadcast group */
765         if ( ( rc = ipoib_join_broadcast_group ( ipoib ) ) != 0 ) {
766                 DBGC ( ipoib, "IPoIB %p could not join broadcast group: %s\n",
767                        ipoib, strerror ( rc ) );
768                 goto err_join_broadcast;
769         }
770
771         return 0;
772
773  err_join_broadcast:
774         ib_destroy_qset ( ibdev, &ipoib->data );
775  err_create_data_qset:
776         ib_destroy_qset ( ibdev, &ipoib->meta );
777  err_create_meta_qset:
778         ib_close ( ibdev );
779  err_ib_open:
780         return rc;
781 }
782
783 /**
784  * Close IPoIB network device
785  *
786  * @v netdev            Network device
787  */
788 static void ipoib_close ( struct net_device *netdev ) {
789         struct ipoib_device *ipoib = netdev->priv;
790         struct ipoib_mac *mac = ( ( struct ipoib_mac * ) netdev->ll_addr );
791
792         /* Leave broadcast group */
793         ipoib_leave_broadcast_group ( ipoib );
794
795         /* Remove data QPN from MAC address */
796         mac->qpn = 0;
797
798         /* Tear down the queues */
799         ib_destroy_qset ( ipoib->ibdev, &ipoib->data );
800         ib_destroy_qset ( ipoib->ibdev, &ipoib->meta );
801
802         /* Close IB device */
803         ib_close ( ipoib->ibdev );
804 }
805
806 /** IPoIB network device operations */
807 static struct net_device_operations ipoib_operations = {
808         .open           = ipoib_open,
809         .close          = ipoib_close,
810         .transmit       = ipoib_transmit,
811         .poll           = ipoib_poll,
812         .irq            = ipoib_irq,
813 };
814
815 /**
816  * Update IPoIB dynamic Infiniband parameters
817  *
818  * @v ipoib             IPoIB device
819  *
820  * The Infiniband port GID and partition key will change at runtime,
821  * when the link is established (or lost).  The MAC address is based
822  * on the port GID, and the broadcast GID is based on the partition
823  * key.  This function recalculates these IPoIB device parameters.
824  */
825 static void ipoib_set_ib_params ( struct ipoib_device *ipoib ) {
826         struct ib_device *ibdev = ipoib->ibdev;
827         struct net_device *netdev = ipoib->netdev;
828         struct ipoib_mac *mac;
829
830         /* Calculate GID portion of MAC address based on port GID */
831         mac = ( ( struct ipoib_mac * ) netdev->ll_addr );
832         memcpy ( &mac->gid, &ibdev->gid, sizeof ( mac->gid ) );
833
834         /* Calculate broadcast GID based on partition key */
835         memcpy ( &ipoib->broadcast_gid, &ipoib_broadcast.gid,
836                  sizeof ( ipoib->broadcast_gid ) );
837         ipoib->broadcast_gid.u.words[2] = htons ( ibdev->pkey );
838
839         /* Set net device link state to reflect Infiniband link state */
840         if ( ib_link_ok ( ibdev ) ) {
841                 netdev_link_up ( netdev );
842         } else {
843                 netdev_link_down ( netdev );
844         }
845 }
846
847 /**
848  * Handle link status change
849  *
850  * @v ibdev             Infiniband device
851  */
852 void ipoib_link_state_changed ( struct ib_device *ibdev ) {
853         struct net_device *netdev = ib_get_ownerdata ( ibdev );
854         struct ipoib_device *ipoib = netdev->priv;
855         int rc;
856
857         /* Leave existing broadcast group */
858         ipoib_leave_broadcast_group ( ipoib );
859
860         /* Update MAC address and broadcast GID based on new port GID
861          * and partition key.
862          */
863         ipoib_set_ib_params ( ipoib );
864
865         /* Join new broadcast group */
866         if ( ( rc = ipoib_join_broadcast_group ( ipoib ) ) != 0 ) {
867                 DBGC ( ipoib, "IPoIB %p could not rejoin broadcast group: "
868                        "%s\n", ipoib, strerror ( rc ) );
869                 return;
870         }
871 }
872
873 /**
874  * Probe IPoIB device
875  *
876  * @v ibdev             Infiniband device
877  * @ret rc              Return status code
878  */
879 int ipoib_probe ( struct ib_device *ibdev ) {
880         struct net_device *netdev;
881         struct ipoib_device *ipoib;
882         int rc;
883
884         /* Allocate network device */
885         netdev = alloc_ipoibdev ( sizeof ( *ipoib ) );
886         if ( ! netdev )
887                 return -ENOMEM;
888         netdev_init ( netdev, &ipoib_operations );
889         ipoib = netdev->priv;
890         ib_set_ownerdata ( ibdev, netdev );
891         netdev->dev = ibdev->dev;
892         memset ( ipoib, 0, sizeof ( *ipoib ) );
893         ipoib->netdev = netdev;
894         ipoib->ibdev = ibdev;
895
896         /* Calculate as much of the broadcast GID and the MAC address
897          * as we can.  We won't know either of these in full until we
898          * have link-up.
899          */
900         ipoib_set_ib_params ( ipoib );
901
902         /* Register network device */
903         if ( ( rc = register_netdev ( netdev ) ) != 0 )
904                 goto err_register_netdev;
905
906         return 0;
907
908  err_register_netdev:
909         netdev_nullify ( netdev );
910         netdev_put ( netdev );
911         return rc;
912 }
913
914 /**
915  * Remove IPoIB device
916  *
917  * @v ibdev             Infiniband device
918  */
919 void ipoib_remove ( struct ib_device *ibdev ) {
920         struct net_device *netdev = ib_get_ownerdata ( ibdev );
921
922         unregister_netdev ( netdev );
923         netdev_nullify ( netdev );
924         netdev_put ( netdev );
925 }
926
927 /**
928  * Allocate IPoIB device
929  *
930  * @v priv_size         Size of driver private data
931  * @ret netdev          Network device, or NULL
932  */
933 struct net_device * alloc_ipoibdev ( size_t priv_size ) {
934         struct net_device *netdev;
935
936         netdev = alloc_netdev ( priv_size );
937         if ( netdev ) {
938                 netdev->ll_protocol = &ipoib_protocol;
939                 netdev->ll_broadcast = ( uint8_t * ) &ipoib_broadcast;
940                 netdev->max_pkt_len = IB_MAX_PAYLOAD_SIZE;
941         }
942         return netdev;
943 }