[infiniband] Report IB link status as IPoIB netdevice status
[people/peper/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/errortab.h>
28 #include <gpxe/if_arp.h>
29 #include <gpxe/iobuf.h>
30 #include <gpxe/netdevice.h>
31 #include <gpxe/infiniband.h>
32 #include <gpxe/ib_pathrec.h>
33 #include <gpxe/ib_mcast.h>
34 #include <gpxe/ipoib.h>
35
36 /** @file
37  *
38  * IP over Infiniband
39  */
40
41 /** Number of IPoIB send work queue entries */
42 #define IPOIB_NUM_SEND_WQES 2
43
44 /** Number of IPoIB receive work queue entries */
45 #define IPOIB_NUM_RECV_WQES 4
46
47 /** Number of IPoIB completion entries */
48 #define IPOIB_NUM_CQES 8
49
50 /** An IPoIB device */
51 struct ipoib_device {
52         /** Network device */
53         struct net_device *netdev;
54         /** Underlying Infiniband device */
55         struct ib_device *ibdev;
56         /** Completion queue */
57         struct ib_completion_queue *cq;
58         /** Queue pair */
59         struct ib_queue_pair *qp;
60         /** Broadcast MAC */
61         struct ipoib_mac broadcast;
62         /** Joined to IPv4 broadcast multicast group
63          *
64          * This flag indicates whether or not we have initiated the
65          * join to the IPv4 broadcast multicast group.
66          */
67         int broadcast_joined;
68         /** IPv4 broadcast multicast group membership */
69         struct ib_mc_membership broadcast_membership;
70 };
71
72 /** Broadcast IPoIB address */
73 static struct ipoib_mac ipoib_broadcast = {
74         .qpn = htonl ( IB_QPN_BROADCAST ),
75         .gid.u.bytes =  { 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00,
76                           0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff },
77 };
78
79 /** Link status for "broadcast join in progress" */
80 #define EINPROGRESS_JOINING ( EINPROGRESS | EUNIQ_01 )
81
82 /** Human-readable message for the link status */
83 struct errortab ipoib_errors[] __errortab = {
84         { EINPROGRESS_JOINING, "Joining" },
85 };
86
87 /****************************************************************************
88  *
89  * IPoIB peer cache
90  *
91  ****************************************************************************
92  */
93
94 /**
95  * IPoIB peer address
96  *
97  * The IPoIB link-layer header is only four bytes long and so does not
98  * have sufficient room to store IPoIB MAC address(es).  We therefore
99  * maintain a cache of MAC addresses identified by a single-byte key,
100  * and abuse the spare two bytes within the link-layer header to
101  * communicate these MAC addresses between the link-layer code and the
102  * netdevice driver.
103  */
104 struct ipoib_peer {
105         /** Key */
106         uint8_t key;
107         /** MAC address */
108         struct ipoib_mac mac;
109 };
110
111 /** Number of IPoIB peer cache entries
112  *
113  * Must be a power of two.
114  */
115 #define IPOIB_NUM_CACHED_PEERS 4
116
117 /** IPoIB peer address cache */
118 static struct ipoib_peer ipoib_peer_cache[IPOIB_NUM_CACHED_PEERS];
119
120 /** Oldest IPoIB peer cache entry index */
121 static unsigned int ipoib_peer_cache_idx = 1;
122
123 /**
124  * Look up cached peer by key
125  *
126  * @v key               Peer cache key
127  * @ret peer            Peer cache entry, or NULL
128  */
129 static struct ipoib_peer * ipoib_lookup_peer_by_key ( unsigned int key ) {
130         struct ipoib_peer *peer;
131         unsigned int i;
132
133         for ( i = 0 ; i < IPOIB_NUM_CACHED_PEERS ; i++ ) {
134                 peer = &ipoib_peer_cache[i];
135                 if ( peer->key == key )
136                         return peer;
137         }
138
139         if ( key != 0 ) {
140                 DBG ( "IPoIB warning: peer cache lost track of key %x while "
141                       "still in use\n", key );
142         }
143         return NULL;
144 }
145
146 /**
147  * Store GID and QPN in peer cache
148  *
149  * @v gid               Peer GID
150  * @v qpn               Peer QPN
151  * @ret peer            Peer cache entry
152  */
153 static struct ipoib_peer * ipoib_cache_peer ( const struct ipoib_mac *mac ) {
154         struct ipoib_peer *peer;
155         unsigned int key;
156         unsigned int i;
157
158         /* Look for existing cache entry */
159         for ( i = 0 ; i < IPOIB_NUM_CACHED_PEERS ; i++ ) {
160                 peer = &ipoib_peer_cache[i];
161                 if ( memcmp ( &peer->mac, mac, sizeof ( peer->mac ) ) == 0 )
162                         return peer;
163         }
164
165         /* No entry found: create a new one */
166         key = ipoib_peer_cache_idx++;
167         peer = &ipoib_peer_cache[ key % IPOIB_NUM_CACHED_PEERS ];
168         if ( peer->key )
169                 DBG ( "IPoIB peer %x evicted from cache\n", peer->key );
170
171         memset ( peer, 0, sizeof ( *peer ) );
172         peer->key = key;
173         memcpy ( &peer->mac, mac, sizeof ( peer->mac ) );
174         DBG ( "IPoIB peer %x has MAC %s\n",
175               peer->key, ipoib_ntoa ( &peer->mac ) );
176         return peer;
177 }
178
179 /****************************************************************************
180  *
181  * IPoIB link layer
182  *
183  ****************************************************************************
184  */
185
186 /**
187  * Add IPoIB link-layer header
188  *
189  * @v netdev            Network device
190  * @v iobuf             I/O buffer
191  * @v ll_dest           Link-layer destination address
192  * @v ll_source         Source link-layer address
193  * @v net_proto         Network-layer protocol, in network-byte order
194  * @ret rc              Return status code
195  */
196 static int ipoib_push ( struct net_device *netdev __unused,
197                         struct io_buffer *iobuf, const void *ll_dest,
198                         const void *ll_source __unused, uint16_t net_proto ) {
199         struct ipoib_hdr *ipoib_hdr =
200                 iob_push ( iobuf, sizeof ( *ipoib_hdr ) );
201         const struct ipoib_mac *dest_mac = ll_dest;
202         const struct ipoib_mac *src_mac = ll_source;
203         struct ipoib_peer *dest;
204         struct ipoib_peer *src;
205
206         /* Add link-layer addresses to cache */
207         dest = ipoib_cache_peer ( dest_mac );
208         src = ipoib_cache_peer ( src_mac );
209
210         /* Build IPoIB header */
211         ipoib_hdr->proto = net_proto;
212         ipoib_hdr->u.peer.dest = dest->key;
213         ipoib_hdr->u.peer.src = src->key;
214
215         return 0;
216 }
217
218 /**
219  * Remove IPoIB link-layer header
220  *
221  * @v netdev            Network device
222  * @v iobuf             I/O buffer
223  * @ret ll_dest         Link-layer destination address
224  * @ret ll_source       Source link-layer address
225  * @ret net_proto       Network-layer protocol, in network-byte order
226  * @ret rc              Return status code
227  */
228 static int ipoib_pull ( struct net_device *netdev,
229                         struct io_buffer *iobuf, const void **ll_dest,
230                         const void **ll_source, uint16_t *net_proto ) {
231         struct ipoib_device *ipoib = netdev->priv;
232         struct ipoib_hdr *ipoib_hdr = iobuf->data;
233         struct ipoib_peer *dest;
234         struct ipoib_peer *source;
235
236         /* Sanity check */
237         if ( iob_len ( iobuf ) < sizeof ( *ipoib_hdr ) ) {
238                 DBG ( "IPoIB packet too short for link-layer header\n" );
239                 DBG_HD ( iobuf->data, iob_len ( iobuf ) );
240                 return -EINVAL;
241         }
242
243         /* Strip off IPoIB header */
244         iob_pull ( iobuf, sizeof ( *ipoib_hdr ) );
245
246         /* Identify source and destination addresses, and clear
247          * reserved word in IPoIB header
248          */
249         dest = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.dest );
250         source = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.src );
251         ipoib_hdr->u.reserved = 0;
252
253         /* Fill in required fields */
254         *ll_dest = ( dest ? &dest->mac : &ipoib->broadcast );
255         *ll_source = ( source ? &source->mac : &ipoib->broadcast );
256         *net_proto = ipoib_hdr->proto;
257
258         return 0;
259 }
260
261 /**
262  * Initialise IPoIB link-layer address
263  *
264  * @v hw_addr           Hardware address
265  * @v ll_addr           Link-layer address
266  */
267 static void ipoib_init_addr ( const void *hw_addr, void *ll_addr ) {
268         const struct ib_gid_half *guid = hw_addr;
269         struct ipoib_mac *mac = ll_addr;
270
271         memset ( mac, 0, sizeof ( *mac ) );
272         memcpy ( &mac->gid.u.half[1], guid, sizeof ( mac->gid.u.half[1] ) );
273 }
274
275 /**
276  * Transcribe IPoIB link-layer address
277  *
278  * @v ll_addr   Link-layer address
279  * @ret string  Link-layer address in human-readable format
280  */
281 const char * ipoib_ntoa ( const void *ll_addr ) {
282         static char buf[45];
283         const struct ipoib_mac *mac = ll_addr;
284
285         snprintf ( buf, sizeof ( buf ), "%08x:%08x:%08x:%08x:%08x",
286                    htonl ( mac->qpn ), htonl ( mac->gid.u.dwords[0] ),
287                    htonl ( mac->gid.u.dwords[1] ),
288                    htonl ( mac->gid.u.dwords[2] ),
289                    htonl ( mac->gid.u.dwords[3] ) );
290         return buf;
291 }
292
293 /**
294  * Hash multicast address
295  *
296  * @v af                Address family
297  * @v net_addr          Network-layer address
298  * @v ll_addr           Link-layer address to fill in
299  * @ret rc              Return status code
300  */
301 static int ipoib_mc_hash ( unsigned int af __unused,
302                            const void *net_addr __unused,
303                            void *ll_addr __unused ) {
304
305         return -ENOTSUP;
306 }
307
308 /**
309  * Generate Mellanox Ethernet-compatible compressed link-layer address
310  *
311  * @v ll_addr           Link-layer address
312  * @v eth_addr          Ethernet-compatible address to fill in
313  */
314 static int ipoib_mlx_eth_addr ( const struct ib_gid_half *guid,
315                                 uint8_t *eth_addr ) {
316         eth_addr[0] = ( ( guid->u.bytes[3] == 2 ) ? 0x00 : 0x02 );
317         eth_addr[1] = guid->u.bytes[1];
318         eth_addr[2] = guid->u.bytes[2];
319         eth_addr[3] = guid->u.bytes[5];
320         eth_addr[4] = guid->u.bytes[6];
321         eth_addr[5] = guid->u.bytes[7];
322         return 0;
323 }
324
325 /** An IPoIB Ethernet-compatible compressed link-layer address generator */
326 struct ipoib_eth_addr_handler {
327         /** GUID byte 1 */
328         uint8_t byte1;
329         /** GUID byte 2 */
330         uint8_t byte2;
331         /** Handler */
332         int ( * eth_addr ) ( const struct ib_gid_half *guid,
333                              uint8_t *eth_addr );
334 };
335
336 /** IPoIB Ethernet-compatible compressed link-layer address generators */
337 static struct ipoib_eth_addr_handler ipoib_eth_addr_handlers[] = {
338         { 0x02, 0xc9, ipoib_mlx_eth_addr },
339 };
340
341 /**
342  * Generate Ethernet-compatible compressed link-layer address
343  *
344  * @v ll_addr           Link-layer address
345  * @v eth_addr          Ethernet-compatible address to fill in
346  */
347 static int ipoib_eth_addr ( const void *ll_addr, void *eth_addr ) {
348         const struct ipoib_mac *ipoib_addr = ll_addr;
349         const struct ib_gid_half *guid = &ipoib_addr->gid.u.half[1];
350         struct ipoib_eth_addr_handler *handler;
351         unsigned int i;
352
353         for ( i = 0 ; i < ( sizeof ( ipoib_eth_addr_handlers ) /
354                             sizeof ( ipoib_eth_addr_handlers[0] ) ) ; i++ ) {
355                 handler = &ipoib_eth_addr_handlers[i];
356                 if ( ( handler->byte1 == guid->u.bytes[1] ) &&
357                      ( handler->byte2 == guid->u.bytes[2] ) ) {
358                         return handler->eth_addr ( guid, eth_addr );
359                 }
360         }
361         return -ENOTSUP;
362 }
363
364 /** IPoIB protocol */
365 struct ll_protocol ipoib_protocol __ll_protocol = {
366         .name           = "IPoIB",
367         .ll_proto       = htons ( ARPHRD_INFINIBAND ),
368         .hw_addr_len    = sizeof ( struct ib_gid_half ),
369         .ll_addr_len    = IPOIB_ALEN,
370         .ll_header_len  = IPOIB_HLEN,
371         .push           = ipoib_push,
372         .pull           = ipoib_pull,
373         .init_addr      = ipoib_init_addr,
374         .ntoa           = ipoib_ntoa,
375         .mc_hash        = ipoib_mc_hash,
376         .eth_addr       = ipoib_eth_addr,
377 };
378
379 /**
380  * Allocate IPoIB device
381  *
382  * @v priv_size         Size of driver private data
383  * @ret netdev          Network device, or NULL
384  */
385 struct net_device * alloc_ipoibdev ( size_t priv_size ) {
386         struct net_device *netdev;
387
388         netdev = alloc_netdev ( priv_size );
389         if ( netdev ) {
390                 netdev->ll_protocol = &ipoib_protocol;
391                 netdev->ll_broadcast = ( uint8_t * ) &ipoib_broadcast;
392                 netdev->max_pkt_len = IB_MAX_PAYLOAD_SIZE;
393         }
394         return netdev;
395 }
396
397 /****************************************************************************
398  *
399  * IPoIB network device
400  *
401  ****************************************************************************
402  */
403
404 /**
405  * Transmit packet via IPoIB network device
406  *
407  * @v netdev            Network device
408  * @v iobuf             I/O buffer
409  * @ret rc              Return status code
410  */
411 static int ipoib_transmit ( struct net_device *netdev,
412                             struct io_buffer *iobuf ) {
413         struct ipoib_device *ipoib = netdev->priv;
414         struct ib_device *ibdev = ipoib->ibdev;
415         struct ipoib_hdr *ipoib_hdr;
416         struct ipoib_peer *dest;
417         struct ib_address_vector av;
418         int rc;
419
420         /* Sanity check */
421         if ( iob_len ( iobuf ) < sizeof ( *ipoib_hdr ) ) {
422                 DBGC ( ipoib, "IPoIB %p buffer too short\n", ipoib );
423                 return -EINVAL;
424         }
425         ipoib_hdr = iobuf->data;
426
427         /* Attempting transmission while link is down will put the
428          * queue pair into an error state, so don't try it.
429          */
430         if ( ! ib_link_ok ( ibdev ) )
431                 return -ENETUNREACH;
432
433         /* Identify destination address */
434         dest = ipoib_lookup_peer_by_key ( ipoib_hdr->u.peer.dest );
435         if ( ! dest )
436                 return -ENXIO;
437         ipoib_hdr->u.reserved = 0;
438
439         /* Construct address vector */
440         memset ( &av, 0, sizeof ( av ) );
441         av.qpn = ntohl ( dest->mac.qpn );
442         av.gid_present = 1;
443         memcpy ( &av.gid, &dest->mac.gid, sizeof ( av.gid ) );
444         if ( ( rc = ib_resolve_path ( ibdev, &av ) ) != 0 ) {
445                 /* Path not resolved yet */
446                 return rc;
447         }
448
449         return ib_post_send ( ibdev, ipoib->qp, &av, iobuf );
450 }
451
452 /**
453  * Handle IPoIB send completion
454  *
455  * @v ibdev             Infiniband device
456  * @v qp                Queue pair
457  * @v iobuf             I/O buffer
458  * @v rc                Completion status code
459  */
460 static void ipoib_complete_send ( struct ib_device *ibdev __unused,
461                                   struct ib_queue_pair *qp,
462                                   struct io_buffer *iobuf, int rc ) {
463         struct ipoib_device *ipoib = ib_qp_get_ownerdata ( qp );
464
465         netdev_tx_complete_err ( ipoib->netdev, iobuf, rc );
466 }
467
468 /**
469  * Handle IPoIB receive completion
470  *
471  * @v ibdev             Infiniband device
472  * @v qp                Queue pair
473  * @v av                Address vector, or NULL
474  * @v iobuf             I/O buffer
475  * @v rc                Completion status code
476  */
477 static void ipoib_complete_recv ( struct ib_device *ibdev __unused,
478                                   struct ib_queue_pair *qp,
479                                   struct ib_address_vector *av,
480                                   struct io_buffer *iobuf, int rc ) {
481         struct ipoib_device *ipoib = ib_qp_get_ownerdata ( qp );
482         struct net_device *netdev = ipoib->netdev;
483         struct ipoib_hdr *ipoib_hdr;
484         struct ipoib_mac ll_src;
485         struct ipoib_peer *src;
486
487         if ( rc != 0 ) {
488                 netdev_rx_err ( netdev, iobuf, rc );
489                 return;
490         }
491
492         /* Sanity check */
493         if ( iob_len ( iobuf ) < sizeof ( struct ipoib_hdr ) ) {
494                 DBGC ( ipoib, "IPoIB %p received packet too short to "
495                        "contain IPoIB header\n", ipoib );
496                 DBGC_HD ( ipoib, iobuf->data, iob_len ( iobuf ) );
497                 netdev_rx_err ( netdev, iobuf, -EIO );
498                 return;
499         }
500         ipoib_hdr = iobuf->data;
501
502         /* Parse source address */
503         if ( av->gid_present ) {
504                 ll_src.qpn = htonl ( av->qpn );
505                 memcpy ( &ll_src.gid, &av->gid, sizeof ( ll_src.gid ) );
506                 src = ipoib_cache_peer ( &ll_src );
507                 ipoib_hdr->u.peer.src = src->key;
508         }
509
510         /* Hand off to network layer */
511         netdev_rx ( netdev, iobuf );
512 }
513
514 /** IPoIB completion operations */
515 static struct ib_completion_queue_operations ipoib_cq_op = {
516         .complete_send = ipoib_complete_send,
517         .complete_recv = ipoib_complete_recv,
518 };
519
520 /**
521  * Poll IPoIB network device
522  *
523  * @v netdev            Network device
524  */
525 static void ipoib_poll ( struct net_device *netdev ) {
526         struct ipoib_device *ipoib = netdev->priv;
527         struct ib_device *ibdev = ipoib->ibdev;
528
529         ib_poll_eq ( ibdev );
530 }
531
532 /**
533  * Enable/disable interrupts on IPoIB network device
534  *
535  * @v netdev            Network device
536  * @v enable            Interrupts should be enabled
537  */
538 static void ipoib_irq ( struct net_device *netdev __unused,
539                         int enable __unused ) {
540         /* No implementation */
541 }
542
543 /**
544  * Handle IPv4 broadcast multicast group join completion
545  *
546  * @v ibdev             Infiniband device
547  * @v qp                Queue pair
548  * @v membership        Multicast group membership
549  * @v rc                Status code
550  * @v mad               Response MAD (or NULL on error)
551  */
552 void ipoib_join_complete ( struct ib_device *ibdev __unused,
553                            struct ib_queue_pair *qp __unused,
554                            struct ib_mc_membership *membership, int rc,
555                            union ib_mad *mad __unused ) {
556         struct ipoib_device *ipoib = container_of ( membership,
557                                    struct ipoib_device, broadcast_membership );
558
559         /* Record join status as link status */
560         netdev_link_err ( ipoib->netdev, rc );
561 }
562
563 /**
564  * Join IPv4 broadcast multicast group
565  *
566  * @v ipoib             IPoIB device
567  * @ret rc              Return status code
568  */
569 static int ipoib_join_broadcast_group ( struct ipoib_device *ipoib ) {
570         int rc;
571
572         if ( ( rc = ib_mcast_join ( ipoib->ibdev, ipoib->qp,
573                                     &ipoib->broadcast_membership,
574                                     &ipoib->broadcast.gid,
575                                     ipoib_join_complete ) ) != 0 ) {
576                 DBGC ( ipoib, "IPoIB %p could not join broadcast group: %s\n",
577                        ipoib, strerror ( rc ) );
578                 return rc;
579         }
580         ipoib->broadcast_joined = 1;
581
582         return 0;
583 }
584
585 /**
586  * Leave IPv4 broadcast multicast group
587  *
588  * @v ipoib             IPoIB device
589  */
590 static void ipoib_leave_broadcast_group ( struct ipoib_device *ipoib ) {
591
592         if ( ipoib->broadcast_joined ) {
593                 ib_mcast_leave ( ipoib->ibdev, ipoib->qp,
594                                  &ipoib->broadcast_membership );
595                 ipoib->broadcast_joined = 0;
596         }
597 }
598
599 /**
600  * Open IPoIB network device
601  *
602  * @v netdev            Network device
603  * @ret rc              Return status code
604  */
605 static int ipoib_open ( struct net_device *netdev ) {
606         struct ipoib_device *ipoib = netdev->priv;
607         struct ib_device *ibdev = ipoib->ibdev;
608         struct ipoib_mac *mac = ( ( struct ipoib_mac * ) netdev->ll_addr );
609         int rc;
610
611         /* Open IB device */
612         if ( ( rc = ib_open ( ibdev ) ) != 0 ) {
613                 DBGC ( ipoib, "IPoIB %p could not open device: %s\n",
614                        ipoib, strerror ( rc ) );
615                 goto err_ib_open;
616         }
617
618         /* Allocate completion queue */
619         ipoib->cq = ib_create_cq ( ibdev, IPOIB_NUM_CQES, &ipoib_cq_op );
620         if ( ! ipoib->cq ) {
621                 DBGC ( ipoib, "IPoIB %p could not allocate completion queue\n",
622                        ipoib );
623                 rc = -ENOMEM;
624                 goto err_create_cq;
625         }
626
627         /* Allocate queue pair */
628         ipoib->qp = ib_create_qp ( ibdev, IB_QPT_UD,
629                                    IPOIB_NUM_SEND_WQES, ipoib->cq,
630                                    IPOIB_NUM_RECV_WQES, ipoib->cq );
631         if ( ! ipoib->qp ) {
632                 DBGC ( ipoib, "IPoIB %p could not allocate queue pair\n",
633                        ipoib );
634                 rc = -ENOMEM;
635                 goto err_create_qp;
636         }
637         ib_qp_set_ownerdata ( ipoib->qp, ipoib );
638
639         /* Update MAC address with QPN */
640         mac->qpn = htonl ( ipoib->qp->qpn );
641
642         /* Fill receive rings */
643         ib_refill_recv ( ibdev, ipoib->qp );
644
645         /* Fake a link status change to join the broadcast group */
646         ipoib_link_state_changed ( ibdev );
647
648         return 0;
649
650         ib_destroy_qp ( ibdev, ipoib->qp );
651  err_create_qp:
652         ib_destroy_cq ( ibdev, ipoib->cq );
653  err_create_cq:
654         ib_close ( ibdev );
655  err_ib_open:
656         return rc;
657 }
658
659 /**
660  * Close IPoIB network device
661  *
662  * @v netdev            Network device
663  */
664 static void ipoib_close ( struct net_device *netdev ) {
665         struct ipoib_device *ipoib = netdev->priv;
666         struct ib_device *ibdev = ipoib->ibdev;
667         struct ipoib_mac *mac = ( ( struct ipoib_mac * ) netdev->ll_addr );
668
669         /* Leave broadcast group */
670         ipoib_leave_broadcast_group ( ipoib );
671
672         /* Remove QPN from MAC address */
673         mac->qpn = 0;
674
675         /* Tear down the queues */
676         ib_destroy_qp ( ibdev, ipoib->qp );
677         ib_destroy_cq ( ibdev, ipoib->cq );
678
679         /* Close IB device */
680         ib_close ( ibdev );
681 }
682
683 /** IPoIB network device operations */
684 static struct net_device_operations ipoib_operations = {
685         .open           = ipoib_open,
686         .close          = ipoib_close,
687         .transmit       = ipoib_transmit,
688         .poll           = ipoib_poll,
689         .irq            = ipoib_irq,
690 };
691
692 /**
693  * Handle link status change
694  *
695  * @v ibdev             Infiniband device
696  */
697 void ipoib_link_state_changed ( struct ib_device *ibdev ) {
698         struct net_device *netdev = ib_get_ownerdata ( ibdev );
699         struct ipoib_device *ipoib = netdev->priv;
700         struct ipoib_mac *mac = ( ( struct ipoib_mac * ) netdev->ll_addr );
701         int rc;
702
703         /* Leave existing broadcast group */
704         ipoib_leave_broadcast_group ( ipoib );
705
706         /* Update MAC address based on potentially-new GID prefix */
707         memcpy ( &mac->gid.u.half[0], &ibdev->gid.u.half[0],
708                  sizeof ( mac->gid.u.half[0] ) );
709
710         /* Update broadcast GID based on potentially-new partition key */
711         ipoib->broadcast.gid.u.words[2] = htons ( ibdev->pkey );
712
713         /* Set net device link state to reflect Infiniband link state */
714         rc = ib_link_rc ( ibdev );
715         netdev_link_err ( netdev, ( rc ? rc : -EINPROGRESS_JOINING ) );
716
717         /* Join new broadcast group */
718         if ( ib_link_ok ( ibdev ) &&
719              ( ( rc = ipoib_join_broadcast_group ( ipoib ) ) != 0 ) ) {
720                 DBGC ( ipoib, "IPoIB %p could not rejoin broadcast group: "
721                        "%s\n", ipoib, strerror ( rc ) );
722                 netdev_link_err ( netdev, rc );
723                 return;
724         }
725 }
726
727 /**
728  * Probe IPoIB device
729  *
730  * @v ibdev             Infiniband device
731  * @ret rc              Return status code
732  */
733 int ipoib_probe ( struct ib_device *ibdev ) {
734         struct net_device *netdev;
735         struct ipoib_device *ipoib;
736         int rc;
737
738         /* Allocate network device */
739         netdev = alloc_ipoibdev ( sizeof ( *ipoib ) );
740         if ( ! netdev )
741                 return -ENOMEM;
742         netdev_init ( netdev, &ipoib_operations );
743         ipoib = netdev->priv;
744         ib_set_ownerdata ( ibdev, netdev );
745         netdev->dev = ibdev->dev;
746         memset ( ipoib, 0, sizeof ( *ipoib ) );
747         ipoib->netdev = netdev;
748         ipoib->ibdev = ibdev;
749
750         /* Extract hardware address */
751         memcpy ( netdev->hw_addr, &ibdev->gid.u.half[1],
752                  sizeof ( ibdev->gid.u.half[1] ) );
753
754         /* Set default broadcast address */
755         memcpy ( &ipoib->broadcast, &ipoib_broadcast,
756                  sizeof ( ipoib->broadcast ) );
757         netdev->ll_broadcast = ( ( uint8_t * ) &ipoib->broadcast );
758
759         /* Register network device */
760         if ( ( rc = register_netdev ( netdev ) ) != 0 )
761                 goto err_register_netdev;
762
763         return 0;
764
765  err_register_netdev:
766         netdev_nullify ( netdev );
767         netdev_put ( netdev );
768         return rc;
769 }
770
771 /**
772  * Remove IPoIB device
773  *
774  * @v ibdev             Infiniband device
775  */
776 void ipoib_remove ( struct ib_device *ibdev ) {
777         struct net_device *netdev = ib_get_ownerdata ( ibdev );
778
779         unregister_netdev ( netdev );
780         netdev_nullify ( netdev );
781         netdev_put ( netdev );
782 }