]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/sfxge/sfxge_port.c
MFC: 278248
[FreeBSD/stable/10.git] / sys / dev / sfxge / sfxge_port.c
1 /*-
2  * Copyright (c) 2010-2011 Solarflare Communications, Inc.
3  * All rights reserved.
4  *
5  * This software was developed in part by Philip Paeps under contract for
6  * Solarflare Communications, Inc.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/types.h>
34 #include <sys/limits.h>
35 #include <net/ethernet.h>
36 #include <net/if_dl.h>
37
38 #include "common/efx.h"
39
40 #include "sfxge.h"
41
42 static int
43 sfxge_mac_stat_update(struct sfxge_softc *sc)
44 {
45         struct sfxge_port *port = &sc->port;
46         efsys_mem_t *esmp = &(port->mac_stats.dma_buf);
47         clock_t now;
48         unsigned int count;
49         int rc;
50
51         SFXGE_PORT_LOCK_ASSERT_OWNED(port);
52
53         if (port->init_state != SFXGE_PORT_STARTED) {
54                 rc = 0;
55                 goto out;
56         }
57
58         now = ticks;
59         if (now - port->mac_stats.update_time < hz) {
60                 rc = 0;
61                 goto out;
62         }
63
64         port->mac_stats.update_time = now;
65
66         /* If we're unlucky enough to read statistics wduring the DMA, wait
67          * up to 10ms for it to finish (typically takes <500us) */
68         for (count = 0; count < 100; ++count) {
69                 EFSYS_PROBE1(wait, unsigned int, count);
70
71                 /* Synchronize the DMA memory for reading */
72                 bus_dmamap_sync(esmp->esm_tag, esmp->esm_map,
73                     BUS_DMASYNC_POSTREAD);
74
75                 /* Try to update the cached counters */
76                 if ((rc = efx_mac_stats_update(sc->enp, esmp,
77                     port->mac_stats.decode_buf, NULL)) != EAGAIN)
78                         goto out;
79
80                 DELAY(100);
81         }
82
83         rc = ETIMEDOUT;
84 out:
85         return (rc);
86 }
87
88 static int
89 sfxge_mac_stat_handler(SYSCTL_HANDLER_ARGS)
90 {
91         struct sfxge_softc *sc = arg1;
92         unsigned int id = arg2;
93         int rc;
94
95         SFXGE_PORT_LOCK(&sc->port);
96         if ((rc = sfxge_mac_stat_update(sc)) != 0)
97                 goto out;
98
99         rc = SYSCTL_OUT(req,
100                         (uint64_t *)sc->port.mac_stats.decode_buf + id,
101                         sizeof(uint64_t));
102 out:
103         SFXGE_PORT_UNLOCK(&sc->port);
104         return (rc);
105 }
106
107 static void
108 sfxge_mac_stat_init(struct sfxge_softc *sc)
109 {
110         struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev);
111         struct sysctl_oid_list *stat_list;
112         unsigned int id;
113         const char *name;
114
115         stat_list = SYSCTL_CHILDREN(sc->stats_node);
116
117         /* Initialise the named stats */
118         for (id = 0; id < EFX_MAC_NSTATS; id++) {
119                 name = efx_mac_stat_name(sc->enp, id);
120                 SYSCTL_ADD_PROC(
121                         ctx, stat_list,
122                         OID_AUTO, name, CTLTYPE_U64|CTLFLAG_RD,
123                         sc, id, sfxge_mac_stat_handler, "Q",
124                         "");
125         }
126 }
127
128 #ifdef SFXGE_HAVE_PAUSE_MEDIAOPTS
129
130 static unsigned int
131 sfxge_port_wanted_fc(struct sfxge_softc *sc)
132 {
133         struct ifmedia_entry *ifm = sc->media.ifm_cur;
134
135         if (ifm->ifm_media == (IFM_ETHER | IFM_AUTO))
136                 return (EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE);
137         return (((ifm->ifm_media & IFM_ETH_RXPAUSE) ? EFX_FCNTL_RESPOND : 0) |
138                 ((ifm->ifm_media & IFM_ETH_TXPAUSE) ? EFX_FCNTL_GENERATE : 0));
139 }
140
141 static unsigned int
142 sfxge_port_link_fc_ifm(struct sfxge_softc *sc)
143 {
144         unsigned int wanted_fc, link_fc;
145
146         efx_mac_fcntl_get(sc->enp, &wanted_fc, &link_fc);
147         return ((link_fc & EFX_FCNTL_RESPOND) ? IFM_ETH_RXPAUSE : 0) |
148                 ((link_fc & EFX_FCNTL_GENERATE) ? IFM_ETH_TXPAUSE : 0);
149 }
150
151 #else /* !SFXGE_HAVE_PAUSE_MEDIAOPTS */
152
153 static unsigned int
154 sfxge_port_wanted_fc(struct sfxge_softc *sc)
155 {
156         return (sc->port.wanted_fc);
157 }
158
159 static unsigned int
160 sfxge_port_link_fc_ifm(struct sfxge_softc *sc)
161 {
162         return (0);
163 }
164
165 static int
166 sfxge_port_wanted_fc_handler(SYSCTL_HANDLER_ARGS)
167 {
168         struct sfxge_softc *sc;
169         struct sfxge_port *port;
170         unsigned int fcntl;
171         int error;
172
173         sc = arg1;
174         port = &sc->port;
175
176         SFXGE_PORT_LOCK(port);
177
178         if (req->newptr != NULL) {
179                 if ((error = SYSCTL_IN(req, &fcntl, sizeof(fcntl))) != 0)
180                         goto out;
181
182                 if (port->wanted_fc == fcntl)
183                         goto out;
184
185                 port->wanted_fc = fcntl;
186
187                 if (port->init_state != SFXGE_PORT_STARTED)
188                         goto out;
189
190                 error = efx_mac_fcntl_set(sc->enp, port->wanted_fc, B_TRUE);
191         } else {
192                 error = SYSCTL_OUT(req, &port->wanted_fc,
193                                    sizeof(port->wanted_fc));
194         }
195
196 out:
197         SFXGE_PORT_UNLOCK(port);
198
199         return (error);
200 }
201
202 static int
203 sfxge_port_link_fc_handler(SYSCTL_HANDLER_ARGS)
204 {
205         struct sfxge_softc *sc;
206         struct sfxge_port *port;
207         unsigned int wanted_fc, link_fc;
208         int error;
209
210         sc = arg1;
211         port = &sc->port;
212
213         SFXGE_PORT_LOCK(port);
214         if (port->init_state == SFXGE_PORT_STARTED && SFXGE_LINK_UP(sc))
215                 efx_mac_fcntl_get(sc->enp, &wanted_fc, &link_fc);
216         else
217                 link_fc = 0;
218         error = SYSCTL_OUT(req, &link_fc, sizeof(link_fc));
219         SFXGE_PORT_UNLOCK(port);
220
221         return (error);
222 }
223
224 #endif /* SFXGE_HAVE_PAUSE_MEDIAOPTS */
225
226 static const u_long sfxge_link_baudrate[EFX_LINK_NMODES] = {
227         [EFX_LINK_10HDX]        = IF_Mbps(10),
228         [EFX_LINK_10FDX]        = IF_Mbps(10),
229         [EFX_LINK_100HDX]       = IF_Mbps(100),
230         [EFX_LINK_100FDX]       = IF_Mbps(100),
231         [EFX_LINK_1000HDX]      = IF_Gbps(1),
232         [EFX_LINK_1000FDX]      = IF_Gbps(1),
233         [EFX_LINK_10000FDX]     = MIN(IF_Gbps(10ULL), ULONG_MAX),
234 };
235
236 void
237 sfxge_mac_link_update(struct sfxge_softc *sc, efx_link_mode_t mode)
238 {
239         struct sfxge_port *port;
240         int link_state;
241
242         port = &sc->port;
243
244         if (port->link_mode == mode)
245                 return;
246
247         port->link_mode = mode;
248
249         /* Push link state update to the OS */
250         link_state = (port->link_mode != EFX_LINK_DOWN ?
251                       LINK_STATE_UP : LINK_STATE_DOWN);
252         sc->ifnet->if_baudrate = sfxge_link_baudrate[port->link_mode];
253         if_link_state_change(sc->ifnet, link_state);
254 }
255
256 static void
257 sfxge_mac_poll_work(void *arg, int npending)
258 {
259         struct sfxge_softc *sc;
260         efx_nic_t *enp;
261         struct sfxge_port *port;
262         efx_link_mode_t mode;
263
264         sc = (struct sfxge_softc *)arg;
265         enp = sc->enp;
266         port = &sc->port;
267
268         SFXGE_PORT_LOCK(port);
269
270         if (port->init_state != SFXGE_PORT_STARTED)
271                 goto done;
272
273         /* This may sleep waiting for MCDI completion */
274         (void)efx_port_poll(enp, &mode);
275         sfxge_mac_link_update(sc, mode);
276
277 done:
278         SFXGE_PORT_UNLOCK(port);
279 }
280
281 static int
282 sfxge_mac_filter_set_locked(struct sfxge_softc *sc)
283 {
284         unsigned int bucket[EFX_MAC_HASH_BITS];
285         struct ifnet *ifp = sc->ifnet;
286         struct ifmultiaddr *ifma;
287         struct sockaddr_dl *sa;
288         efx_nic_t *enp = sc->enp;
289         unsigned int index;
290         int rc;
291
292         /* Set promisc-unicast and broadcast filter bits */
293         if ((rc = efx_mac_filter_set(enp, !!(ifp->if_flags & IFF_PROMISC),
294                                      B_TRUE)) != 0)
295                 return (rc);
296
297         /* Set multicast hash filter */
298         if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) {
299                 for (index = 0; index < EFX_MAC_HASH_BITS; index++)
300                         bucket[index] = 1;
301         } else {
302                 /* Broadcast frames also go through the multicast
303                  * filter, and the broadcast address hashes to
304                  * 0xff. */
305                 bucket[0xff] = 1;
306
307                 if_maddr_rlock(ifp);
308                 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
309                         if (ifma->ifma_addr->sa_family == AF_LINK) {
310                                 sa = (struct sockaddr_dl *)ifma->ifma_addr;
311                                 index = ether_crc32_le(LLADDR(sa), 6) & 0xff;
312                                 bucket[index] = 1;
313                         }
314                 }
315                 if_maddr_runlock(ifp);
316         }
317         return (efx_mac_hash_set(enp, bucket));
318 }
319
320 int
321 sfxge_mac_filter_set(struct sfxge_softc *sc)
322 {
323         struct sfxge_port *port = &sc->port;
324         int rc;
325
326         SFXGE_PORT_LOCK(port);
327         /*
328          * The function may be called without softc_lock held in the
329          * case of SIOCADDMULTI and SIOCDELMULTI ioctls. ioctl handler
330          * checks IFF_DRV_RUNNING flag which implies port started, but
331          * it is not guaranteed to remain. softc_lock shared lock can't
332          * be held in the case of these ioctls processing, since it
333          * results in failure where kernel complains that non-sleepable
334          * lock is held in sleeping thread. Both problems are repeatable
335          * on LAG with LACP proto bring up.
336          */
337         if (port->init_state == SFXGE_PORT_STARTED)
338                 rc = sfxge_mac_filter_set_locked(sc);
339         else
340                 rc = 0;
341         SFXGE_PORT_UNLOCK(port);
342         return (rc);
343 }
344
345 void
346 sfxge_port_stop(struct sfxge_softc *sc)
347 {
348         struct sfxge_port *port;
349         efx_nic_t *enp;
350
351         port = &sc->port;
352         enp = sc->enp;
353
354         SFXGE_PORT_LOCK(port);
355
356         KASSERT(port->init_state == SFXGE_PORT_STARTED,
357             ("port not started"));
358
359         port->init_state = SFXGE_PORT_INITIALIZED;
360
361         port->mac_stats.update_time = 0;
362
363         /* This may call MCDI */
364         (void)efx_mac_drain(enp, B_TRUE);
365
366         (void)efx_mac_stats_periodic(enp, &port->mac_stats.dma_buf, 0, B_FALSE);
367
368         port->link_mode = EFX_LINK_UNKNOWN;
369
370         /* Destroy the common code port object. */
371         efx_port_fini(sc->enp);
372
373         SFXGE_PORT_UNLOCK(port);
374 }
375
376 int
377 sfxge_port_start(struct sfxge_softc *sc)
378 {
379         uint8_t mac_addr[ETHER_ADDR_LEN];
380         struct ifnet *ifp = sc->ifnet;
381         struct sfxge_port *port;
382         efx_nic_t *enp;
383         size_t pdu;
384         int rc;
385
386         port = &sc->port;
387         enp = sc->enp;
388
389         SFXGE_PORT_LOCK(port);
390
391         KASSERT(port->init_state == SFXGE_PORT_INITIALIZED,
392             ("port not initialized"));
393
394         /* Initialize the port object in the common code. */
395         if ((rc = efx_port_init(sc->enp)) != 0)
396                 goto fail;
397
398         /* Set the SDU */
399         pdu = EFX_MAC_PDU(ifp->if_mtu);
400         if ((rc = efx_mac_pdu_set(enp, pdu)) != 0)
401                 goto fail2;
402
403         if ((rc = efx_mac_fcntl_set(enp, sfxge_port_wanted_fc(sc), B_TRUE))
404             != 0)
405                 goto fail2;
406
407         /* Set the unicast address */
408         if_addr_rlock(ifp);
409         bcopy(LLADDR((struct sockaddr_dl *)ifp->if_addr->ifa_addr),
410               mac_addr, sizeof(mac_addr));
411         if_addr_runlock(ifp);
412         if ((rc = efx_mac_addr_set(enp, mac_addr)) != 0)
413                 goto fail;
414
415         sfxge_mac_filter_set_locked(sc);
416
417         /* Update MAC stats by DMA every second */
418         if ((rc = efx_mac_stats_periodic(enp, &port->mac_stats.dma_buf,
419             1000, B_FALSE)) != 0)
420                 goto fail2;
421
422         if ((rc = efx_mac_drain(enp, B_FALSE)) != 0)
423                 goto fail3;
424
425         if ((rc = efx_phy_adv_cap_set(sc->enp, sc->media.ifm_cur->ifm_data))
426             != 0)
427                 goto fail4;
428
429         port->init_state = SFXGE_PORT_STARTED;
430
431         /* Single poll in case there were missing initial events */
432         SFXGE_PORT_UNLOCK(port);
433         sfxge_mac_poll_work(sc, 0);
434
435         return (0);
436
437 fail4:
438         (void)efx_mac_drain(enp, B_TRUE);
439 fail3:
440         (void)efx_mac_stats_periodic(enp, &port->mac_stats.dma_buf,
441             0, B_FALSE);
442 fail2:
443         efx_port_fini(sc->enp);
444 fail:
445         SFXGE_PORT_UNLOCK(port);
446
447         return (rc);
448 }
449
450 static int
451 sfxge_phy_stat_update(struct sfxge_softc *sc)
452 {
453         struct sfxge_port *port = &sc->port;
454         efsys_mem_t *esmp = &port->phy_stats.dma_buf;
455         clock_t now;
456         unsigned int count;
457         int rc;
458
459         SFXGE_PORT_LOCK_ASSERT_OWNED(port);
460
461         if (port->init_state != SFXGE_PORT_STARTED) {
462                 rc = 0;
463                 goto out;
464         }
465
466         now = ticks;
467         if (now - port->phy_stats.update_time < hz) {
468                 rc = 0;
469                 goto out;
470         }
471
472         port->phy_stats.update_time = now;
473
474         /* If we're unlucky enough to read statistics wduring the DMA, wait
475          * up to 10ms for it to finish (typically takes <500us) */
476         for (count = 0; count < 100; ++count) {
477                 EFSYS_PROBE1(wait, unsigned int, count);
478
479                 /* Synchronize the DMA memory for reading */
480                 bus_dmamap_sync(esmp->esm_tag, esmp->esm_map,
481                     BUS_DMASYNC_POSTREAD);
482
483                 /* Try to update the cached counters */
484                 if ((rc = efx_phy_stats_update(sc->enp, esmp,
485                     port->phy_stats.decode_buf)) != EAGAIN)
486                         goto out;
487
488                 DELAY(100);
489         }
490
491         rc = ETIMEDOUT;
492 out:
493         return (rc);
494 }
495
496 static int
497 sfxge_phy_stat_handler(SYSCTL_HANDLER_ARGS)
498 {
499         struct sfxge_softc *sc = arg1;
500         unsigned int id = arg2;
501         int rc;
502
503         SFXGE_PORT_LOCK(&sc->port);
504         if ((rc = sfxge_phy_stat_update(sc)) != 0)
505                 goto out;
506
507         rc = SYSCTL_OUT(req,
508                         (uint32_t *)sc->port.phy_stats.decode_buf + id,
509                         sizeof(uint32_t));
510 out:
511         SFXGE_PORT_UNLOCK(&sc->port);
512         return (rc);
513 }
514
515 static void
516 sfxge_phy_stat_init(struct sfxge_softc *sc)
517 {
518         struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev);
519         struct sysctl_oid_list *stat_list;
520         unsigned int id;
521         const char *name;
522         uint64_t stat_mask = efx_nic_cfg_get(sc->enp)->enc_phy_stat_mask;
523
524         stat_list = SYSCTL_CHILDREN(sc->stats_node);
525
526         /* Initialise the named stats */
527         for (id = 0; id < EFX_PHY_NSTATS; id++) {
528                 if (!(stat_mask & ((uint64_t)1 << id)))
529                         continue;
530                 name = efx_phy_stat_name(sc->enp, id);
531                 SYSCTL_ADD_PROC(
532                         ctx, stat_list,
533                         OID_AUTO, name, CTLTYPE_UINT|CTLFLAG_RD,
534                         sc, id, sfxge_phy_stat_handler,
535                         id == EFX_PHY_STAT_OUI ? "IX" : "IU",
536                         "");
537         }
538 }
539
540 void
541 sfxge_port_fini(struct sfxge_softc *sc)
542 {
543         struct sfxge_port *port;
544         efsys_mem_t *esmp;
545
546         port = &sc->port;
547         esmp = &port->mac_stats.dma_buf;
548
549         KASSERT(port->init_state == SFXGE_PORT_INITIALIZED,
550             ("Port not initialized"));
551
552         port->init_state = SFXGE_PORT_UNINITIALIZED;
553
554         port->link_mode = EFX_LINK_UNKNOWN;
555
556         /* Finish with PHY DMA memory */
557         sfxge_dma_free(&port->phy_stats.dma_buf);
558         free(port->phy_stats.decode_buf, M_SFXGE);
559
560         sfxge_dma_free(esmp);
561         free(port->mac_stats.decode_buf, M_SFXGE);
562
563         SFXGE_PORT_LOCK_DESTROY(port);
564
565         port->sc = NULL;
566 }
567
568 int
569 sfxge_port_init(struct sfxge_softc *sc)
570 {
571         struct sfxge_port *port;
572         struct sysctl_ctx_list *sysctl_ctx;
573         struct sysctl_oid *sysctl_tree;
574         efsys_mem_t *mac_stats_buf, *phy_stats_buf;
575         int rc;
576
577         port = &sc->port;
578         mac_stats_buf = &port->mac_stats.dma_buf;
579         phy_stats_buf = &port->phy_stats.dma_buf;
580
581         KASSERT(port->init_state == SFXGE_PORT_UNINITIALIZED,
582             ("Port already initialized"));
583
584         port->sc = sc;
585
586         SFXGE_PORT_LOCK_INIT(port, "sfxge_port");
587
588         port->phy_stats.decode_buf = malloc(EFX_PHY_NSTATS * sizeof(uint32_t),
589                                             M_SFXGE, M_WAITOK | M_ZERO);
590         if ((rc = sfxge_dma_alloc(sc, EFX_PHY_STATS_SIZE, phy_stats_buf)) != 0)
591                 goto fail;
592         sfxge_phy_stat_init(sc);
593
594         sysctl_ctx = device_get_sysctl_ctx(sc->dev);
595         sysctl_tree = device_get_sysctl_tree(sc->dev);
596
597 #ifndef SFXGE_HAVE_PAUSE_MEDIAOPTS
598         /* If flow control cannot be configured or reported through
599          * ifmedia, provide sysctls for it. */
600         port->wanted_fc = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
601         SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
602             "wanted_fc", CTLTYPE_UINT|CTLFLAG_RW, sc, 0,
603             sfxge_port_wanted_fc_handler, "IU", "wanted flow control mode");
604         SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
605             "link_fc", CTLTYPE_UINT|CTLFLAG_RD, sc, 0,
606             sfxge_port_link_fc_handler, "IU", "link flow control mode");
607 #endif
608
609         port->mac_stats.decode_buf = malloc(EFX_MAC_NSTATS * sizeof(uint64_t),
610                                             M_SFXGE, M_WAITOK | M_ZERO);
611         if ((rc = sfxge_dma_alloc(sc, EFX_MAC_STATS_SIZE, mac_stats_buf)) != 0)
612                 goto fail2;
613         sfxge_mac_stat_init(sc);
614
615         port->init_state = SFXGE_PORT_INITIALIZED;
616
617         return (0);
618
619 fail2:
620         free(port->mac_stats.decode_buf, M_SFXGE);
621         sfxge_dma_free(phy_stats_buf);
622 fail:
623         free(port->phy_stats.decode_buf, M_SFXGE);
624         SFXGE_PORT_LOCK_DESTROY(port);
625         port->sc = NULL;
626         return (rc);
627 }
628
629 static int sfxge_link_mode[EFX_PHY_MEDIA_NTYPES][EFX_LINK_NMODES] = {
630         [EFX_PHY_MEDIA_CX4] = {
631                 [EFX_LINK_10000FDX]     = IFM_ETHER | IFM_FDX | IFM_10G_CX4,
632         },
633         [EFX_PHY_MEDIA_KX4] = {
634                 [EFX_LINK_10000FDX]     = IFM_ETHER | IFM_FDX | IFM_10G_KX4,
635         },
636         [EFX_PHY_MEDIA_XFP] = {
637                 /* Don't know the module type, but assume SR for now. */
638                 [EFX_LINK_10000FDX]     = IFM_ETHER | IFM_FDX | IFM_10G_SR,
639         },
640         [EFX_PHY_MEDIA_SFP_PLUS] = {
641                 /* Don't know the module type, but assume SX/SR for now. */
642                 [EFX_LINK_1000FDX]      = IFM_ETHER | IFM_FDX | IFM_1000_SX,
643                 [EFX_LINK_10000FDX]     = IFM_ETHER | IFM_FDX | IFM_10G_SR,
644         },
645         [EFX_PHY_MEDIA_BASE_T] = {
646                 [EFX_LINK_10HDX]        = IFM_ETHER | IFM_HDX | IFM_10_T,
647                 [EFX_LINK_10FDX]        = IFM_ETHER | IFM_FDX | IFM_10_T,
648                 [EFX_LINK_100HDX]       = IFM_ETHER | IFM_HDX | IFM_100_TX,
649                 [EFX_LINK_100FDX]       = IFM_ETHER | IFM_FDX | IFM_100_TX,
650                 [EFX_LINK_1000HDX]      = IFM_ETHER | IFM_HDX | IFM_1000_T,
651                 [EFX_LINK_1000FDX]      = IFM_ETHER | IFM_FDX | IFM_1000_T,
652                 [EFX_LINK_10000FDX]     = IFM_ETHER | IFM_FDX | IFM_10G_T,
653         },
654 };
655
656 static void
657 sfxge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
658 {
659         struct sfxge_softc *sc;
660         efx_phy_media_type_t medium_type;
661         efx_link_mode_t mode;
662
663         sc = ifp->if_softc;
664         SFXGE_ADAPTER_LOCK(sc);
665
666         ifmr->ifm_status = IFM_AVALID;
667         ifmr->ifm_active = IFM_ETHER;
668
669         if (SFXGE_RUNNING(sc) && SFXGE_LINK_UP(sc)) {
670                 ifmr->ifm_status |= IFM_ACTIVE;
671
672                 efx_phy_media_type_get(sc->enp, &medium_type);
673                 mode = sc->port.link_mode;
674                 ifmr->ifm_active |= sfxge_link_mode[medium_type][mode];
675                 ifmr->ifm_active |= sfxge_port_link_fc_ifm(sc);
676         }
677
678         SFXGE_ADAPTER_UNLOCK(sc);
679 }
680
681 static int
682 sfxge_media_change(struct ifnet *ifp)
683 {
684         struct sfxge_softc *sc;
685         struct ifmedia_entry *ifm;
686         int rc;
687
688         sc = ifp->if_softc;
689         ifm = sc->media.ifm_cur;
690
691         SFXGE_ADAPTER_LOCK(sc);
692
693         if (!SFXGE_RUNNING(sc)) {
694                 rc = 0;
695                 goto out;
696         }
697
698         rc = efx_mac_fcntl_set(sc->enp, sfxge_port_wanted_fc(sc), B_TRUE);
699         if (rc != 0)
700                 goto out;
701
702         rc = efx_phy_adv_cap_set(sc->enp, ifm->ifm_data);
703 out:
704         SFXGE_ADAPTER_UNLOCK(sc);
705
706         return (rc);
707 }
708
709 int sfxge_port_ifmedia_init(struct sfxge_softc *sc)
710 {
711         efx_phy_media_type_t medium_type;
712         uint32_t cap_mask, mode_cap_mask;
713         efx_link_mode_t mode;
714         int mode_ifm, best_mode_ifm = 0;
715         int rc;
716
717         /* We need port state to initialise the ifmedia list. */
718         if ((rc = efx_nic_init(sc->enp)) != 0)
719                 goto out;
720         if ((rc = efx_port_init(sc->enp)) != 0)
721                 goto out2;
722
723         /*
724          * Register ifconfig callbacks for querying and setting the
725          * link mode and link status.
726          */
727         ifmedia_init(&sc->media, IFM_IMASK, sfxge_media_change,
728             sfxge_media_status);
729
730         /*
731          * Map firmware medium type and capabilities to ifmedia types.
732          * ifmedia does not distinguish between forcing the link mode
733          * and disabling auto-negotiation.  1000BASE-T and 10GBASE-T
734          * require AN even if only one link mode is enabled, and for
735          * 100BASE-TX it is useful even if the link mode is forced.
736          * Therefore we never disable auto-negotiation.
737          *
738          * Also enable and advertise flow control by default.
739          */
740
741         efx_phy_media_type_get(sc->enp, &medium_type);
742         efx_phy_adv_cap_get(sc->enp, EFX_PHY_CAP_PERM, &cap_mask);
743
744         EFX_STATIC_ASSERT(EFX_LINK_10HDX == EFX_PHY_CAP_10HDX + 1);
745         EFX_STATIC_ASSERT(EFX_LINK_10FDX == EFX_PHY_CAP_10FDX + 1);
746         EFX_STATIC_ASSERT(EFX_LINK_100HDX == EFX_PHY_CAP_100HDX + 1);
747         EFX_STATIC_ASSERT(EFX_LINK_100FDX == EFX_PHY_CAP_100FDX + 1);
748         EFX_STATIC_ASSERT(EFX_LINK_1000HDX == EFX_PHY_CAP_1000HDX + 1);
749         EFX_STATIC_ASSERT(EFX_LINK_1000FDX == EFX_PHY_CAP_1000FDX + 1);
750         EFX_STATIC_ASSERT(EFX_LINK_10000FDX == EFX_PHY_CAP_10000FDX + 1);
751
752         for (mode = EFX_LINK_10HDX; mode <= EFX_LINK_10000FDX; mode++) {
753                 mode_cap_mask = 1 << (mode - 1);
754                 mode_ifm = sfxge_link_mode[medium_type][mode];
755
756                 if ((cap_mask & mode_cap_mask) && mode_ifm) {
757                         mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_AN);
758
759 #ifdef SFXGE_HAVE_PAUSE_MEDIAOPTS
760                         /* No flow-control */
761                         ifmedia_add(&sc->media, mode_ifm, mode_cap_mask, NULL);
762
763                         /* Respond-only.  If using AN, we implicitly
764                          * offer symmetric as well, but that doesn't
765                          * mean we *have* to generate pause frames.
766                          */
767                         mode_cap_mask |= cap_mask & ((1 << EFX_PHY_CAP_PAUSE) |
768                                                      (1 << EFX_PHY_CAP_ASYM));
769                         mode_ifm |= IFM_ETH_RXPAUSE;
770                         ifmedia_add(&sc->media, mode_ifm, mode_cap_mask, NULL);
771
772                         /* Symmetric */
773                         mode_cap_mask &= ~(1 << EFX_PHY_CAP_ASYM);
774                         mode_ifm |= IFM_ETH_TXPAUSE;
775 #else /* !SFXGE_HAVE_PAUSE_MEDIAOPTS */
776                         mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_PAUSE);
777 #endif
778                         ifmedia_add(&sc->media, mode_ifm, mode_cap_mask, NULL);
779
780                         /* Link modes are numbered in order of speed,
781                          * so assume the last one available is the best.
782                          */
783                         best_mode_ifm = mode_ifm;
784                 }
785         }
786
787         if (cap_mask & (1 << EFX_PHY_CAP_AN)) {
788                 /* Add autoselect mode. */
789                 mode_ifm = IFM_ETHER | IFM_AUTO;
790                 ifmedia_add(&sc->media, mode_ifm,
791                             cap_mask & ~(1 << EFX_PHY_CAP_ASYM), NULL);
792                 best_mode_ifm = mode_ifm;
793         }
794
795         if (best_mode_ifm != 0)
796                 ifmedia_set(&sc->media, best_mode_ifm);
797
798         /* Now discard port state until interface is started. */
799         efx_port_fini(sc->enp);
800 out2:
801         efx_nic_fini(sc->enp);
802 out:
803         return (rc);
804 }