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