sfxge_port.c revision 279351
135124Sjb/*-
235124Sjb * Copyright (c) 2010-2011 Solarflare Communications, Inc.
335124Sjb * All rights reserved.
435124Sjb *
535124Sjb * This software was developed in part by Philip Paeps under contract for
635124Sjb * Solarflare Communications, Inc.
735124Sjb *
835124Sjb * Redistribution and use in source and binary forms, with or without
935124Sjb * modification, are permitted provided that the following conditions
1035124Sjb * are met:
1135124Sjb * 1. Redistributions of source code must retain the above copyright
1235124Sjb *    notice, this list of conditions and the following disclaimer.
1335124Sjb * 2. Redistributions in binary form must reproduce the above copyright
1435124Sjb *    notice, this list of conditions and the following disclaimer in the
1535124Sjb *    documentation and/or other materials provided with the distribution.
1635124Sjb *
1735124Sjb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1835124Sjb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1935124Sjb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2035124Sjb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2135124Sjb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2235124Sjb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2335124Sjb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2435124Sjb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2535124Sjb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2635124Sjb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2735124Sjb * SUCH DAMAGE.
2835124Sjb */
2935124Sjb
3035124Sjb#include <sys/cdefs.h>
3135124Sjb__FBSDID("$FreeBSD: head/sys/dev/sfxge/sfxge_port.c 279351 2015-02-27 07:39:09Z arybchik $");
3250476Speter
3335124Sjb#include <sys/types.h>
3435124Sjb#include <sys/limits.h>
3535124Sjb#include <net/ethernet.h>
3635124Sjb#include <net/if_dl.h>
3735124Sjb
3835124Sjb#include "common/efx.h"
3935124Sjb
4035124Sjb#include "sfxge.h"
4135124Sjb
4235124Sjbstatic int
4335124Sjbsfxge_mac_stat_update(struct sfxge_softc *sc)
4435124Sjb{
4535124Sjb	struct sfxge_port *port = &sc->port;
4635124Sjb	efsys_mem_t *esmp = &(port->mac_stats.dma_buf);
4735124Sjb	clock_t now;
4835124Sjb	unsigned int count;
4935124Sjb	int rc;
5035124Sjb
5135124Sjb	SFXGE_PORT_LOCK_ASSERT_OWNED(port);
5235124Sjb
5335124Sjb	if (__predict_false(port->init_state != SFXGE_PORT_STARTED)) {
5435124Sjb		rc = 0;
5535124Sjb		goto out;
5671579Sdeischen	}
5735124Sjb
5835124Sjb	now = ticks;
5935124Sjb	if (now - port->mac_stats.update_time < hz) {
6035124Sjb		rc = 0;
6135124Sjb		goto out;
6235124Sjb	}
6335124Sjb
6471579Sdeischen	port->mac_stats.update_time = now;
6535124Sjb
6693399Smarkm	/* If we're unlucky enough to read statistics wduring the DMA, wait
67106866Sdeischen	 * up to 10ms for it to finish (typically takes <500us) */
68106866Sdeischen	for (count = 0; count < 100; ++count) {
69106866Sdeischen		EFSYS_PROBE1(wait, unsigned int, count);
70106866Sdeischen
71106866Sdeischen		/* Synchronize the DMA memory for reading */
72106866Sdeischen		bus_dmamap_sync(esmp->esm_tag, esmp->esm_map,
73156319Sdeischen		    BUS_DMASYNC_POSTREAD);
74156319Sdeischen
75156319Sdeischen		/* Try to update the cached counters */
76156319Sdeischen		if ((rc = efx_mac_stats_update(sc->enp, esmp,
77156319Sdeischen		    port->mac_stats.decode_buf, NULL)) != EAGAIN)
78156319Sdeischen			goto out;
79156319Sdeischen
80156319Sdeischen		DELAY(100);
81156319Sdeischen	}
82156319Sdeischen
83156319Sdeischen	rc = ETIMEDOUT;
84156319Sdeischenout:
85156319Sdeischen	return (rc);
86156319Sdeischen}
87156319Sdeischen
88156319Sdeischenuint64_t
89156319Sdeischensfxge_get_counter(struct ifnet *ifp, ift_counter c)
90156319Sdeischen{
91156319Sdeischen	struct sfxge_softc *sc = ifp->if_softc;
92156319Sdeischen	uint64_t *mac_stats;
93156319Sdeischen	uint64_t val;
94156319Sdeischen
95106866Sdeischen	SFXGE_PORT_LOCK(&sc->port);
96106866Sdeischen
97106866Sdeischen	/* Ignore error and use old values */
98106866Sdeischen	(void)sfxge_mac_stat_update(sc);
99156319Sdeischen
100106866Sdeischen	mac_stats = (uint64_t *)sc->port.mac_stats.decode_buf;
101156319Sdeischen
102156319Sdeischen	switch (c) {
103156319Sdeischen	case IFCOUNTER_IPACKETS:
104106866Sdeischen		val = mac_stats[EFX_MAC_RX_PKTS];
105156319Sdeischen		break;
106106866Sdeischen	case IFCOUNTER_IERRORS:
107106866Sdeischen		val = mac_stats[EFX_MAC_RX_ERRORS];
108156319Sdeischen		break;
109106866Sdeischen	case IFCOUNTER_OPACKETS:
110156319Sdeischen		val = mac_stats[EFX_MAC_TX_PKTS];
111156319Sdeischen		break;
112156319Sdeischen	case IFCOUNTER_OERRORS:
113106866Sdeischen		val = mac_stats[EFX_MAC_TX_ERRORS];
114106866Sdeischen		break;
115106866Sdeischen	case IFCOUNTER_COLLISIONS:
116106866Sdeischen		val = mac_stats[EFX_MAC_TX_SGL_COL_PKTS] +
117106866Sdeischen		      mac_stats[EFX_MAC_TX_MULT_COL_PKTS] +
118106866Sdeischen		      mac_stats[EFX_MAC_TX_EX_COL_PKTS] +
119106866Sdeischen		      mac_stats[EFX_MAC_TX_LATE_COL_PKTS];
120106866Sdeischen		break;
121106866Sdeischen	case IFCOUNTER_IBYTES:
122106866Sdeischen		val = mac_stats[EFX_MAC_RX_OCTETS];
123106866Sdeischen		break;
124106866Sdeischen	case IFCOUNTER_OBYTES:
125106866Sdeischen		val = mac_stats[EFX_MAC_TX_OCTETS];
126106866Sdeischen		break;
127156319Sdeischen	case IFCOUNTER_OMCASTS:
128156319Sdeischen		val = mac_stats[EFX_MAC_TX_MULTICST_PKTS] +
129106866Sdeischen		      mac_stats[EFX_MAC_TX_BRDCST_PKTS];
130106866Sdeischen		break;
131156319Sdeischen	case IFCOUNTER_OQDROPS:
132106866Sdeischen		SFXGE_PORT_UNLOCK(&sc->port);
133106866Sdeischen		return (sfxge_tx_get_drops(sc));
134106866Sdeischen	case IFCOUNTER_IMCASTS:
135106870Sdeischen		/* if_imcasts is maintained in net/if_ethersubr.c */
136106880Sdeischen	case IFCOUNTER_IQDROPS:
137106866Sdeischen		/* if_iqdrops is maintained in net/if_ethersubr.c */
138106880Sdeischen	case IFCOUNTER_NOPROTO:
139106866Sdeischen		/* if_noproto is maintained in net/if_ethersubr.c */
140106866Sdeischen	default:
141111618Snectar		SFXGE_PORT_UNLOCK(&sc->port);
142111618Snectar		return (if_get_counter_default(ifp, c));
143111618Snectar	}
144111618Snectar
145111618Snectar	SFXGE_PORT_UNLOCK(&sc->port);
146111618Snectar
147133754Sdfr	return (val);
148133754Sdfr}
149133754Sdfr
150133754Sdfrstatic int
151111618Snectarsfxge_mac_stat_handler(SYSCTL_HANDLER_ARGS)
152111618Snectar{
153133754Sdfr	struct sfxge_softc *sc = arg1;
154133754Sdfr	unsigned int id = arg2;
155133754Sdfr	int rc;
156133754Sdfr	uint64_t val;
157133754Sdfr
15893399Smarkm	SFXGE_PORT_LOCK(&sc->port);
15993399Smarkm	if ((rc = sfxge_mac_stat_update(sc)) == 0)
16093399Smarkm		val = ((uint64_t *)sc->port.mac_stats.decode_buf)[id];
16193399Smarkm	SFXGE_PORT_UNLOCK(&sc->port);
16293399Smarkm
163122069Sdeischen	if (rc == 0)
164154248Sjasone		rc = SYSCTL_OUT(req, &val, sizeof(val));
165154248Sjasone	return (rc);
166122069Sdeischen}
167154248Sjasone
168154248Sjasonestatic void
169122069Sdeischensfxge_mac_stat_init(struct sfxge_softc *sc)
170150040Sstefanf{
171150040Sstefanf	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev);
172150040Sstefanf	struct sysctl_oid_list *stat_list;
173150040Sstefanf	unsigned int id;
174150040Sstefanf	const char *name;
17535124Sjb
176	stat_list = SYSCTL_CHILDREN(sc->stats_node);
177
178	/* Initialise the named stats */
179	for (id = 0; id < EFX_MAC_NSTATS; id++) {
180		name = efx_mac_stat_name(sc->enp, id);
181		SYSCTL_ADD_PROC(
182			ctx, stat_list,
183			OID_AUTO, name, CTLTYPE_U64|CTLFLAG_RD,
184			sc, id, sfxge_mac_stat_handler, "Q",
185			"");
186	}
187}
188
189#ifdef SFXGE_HAVE_PAUSE_MEDIAOPTS
190
191static unsigned int
192sfxge_port_wanted_fc(struct sfxge_softc *sc)
193{
194	struct ifmedia_entry *ifm = sc->media.ifm_cur;
195
196	if (ifm->ifm_media == (IFM_ETHER | IFM_AUTO))
197		return (EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE);
198	return (((ifm->ifm_media & IFM_ETH_RXPAUSE) ? EFX_FCNTL_RESPOND : 0) |
199		((ifm->ifm_media & IFM_ETH_TXPAUSE) ? EFX_FCNTL_GENERATE : 0));
200}
201
202static unsigned int
203sfxge_port_link_fc_ifm(struct sfxge_softc *sc)
204{
205	unsigned int wanted_fc, link_fc;
206
207	efx_mac_fcntl_get(sc->enp, &wanted_fc, &link_fc);
208	return ((link_fc & EFX_FCNTL_RESPOND) ? IFM_ETH_RXPAUSE : 0) |
209		((link_fc & EFX_FCNTL_GENERATE) ? IFM_ETH_TXPAUSE : 0);
210}
211
212#else /* !SFXGE_HAVE_PAUSE_MEDIAOPTS */
213
214static unsigned int
215sfxge_port_wanted_fc(struct sfxge_softc *sc)
216{
217	return (sc->port.wanted_fc);
218}
219
220static unsigned int
221sfxge_port_link_fc_ifm(struct sfxge_softc *sc)
222{
223	return (0);
224}
225
226static int
227sfxge_port_wanted_fc_handler(SYSCTL_HANDLER_ARGS)
228{
229	struct sfxge_softc *sc;
230	struct sfxge_port *port;
231	unsigned int fcntl;
232	int error;
233
234	sc = arg1;
235	port = &sc->port;
236
237	if (req->newptr != NULL) {
238		if ((error = SYSCTL_IN(req, &fcntl, sizeof(fcntl))) != 0)
239			return (error);
240
241		SFXGE_PORT_LOCK(port);
242
243		if (port->wanted_fc != fcntl) {
244		    if (__predict_false(port->init_state == SFXGE_PORT_STARTED))
245				error = efx_mac_fcntl_set(sc->enp,
246							  port->wanted_fc,
247							  B_TRUE);
248			if (error == 0)
249				port->wanted_fc = fcntl;
250		}
251
252		SFXGE_PORT_UNLOCK(port);
253	} else {
254		SFXGE_PORT_LOCK(port);
255		fcntl = port->wanted_fc;
256		SFXGE_PORT_UNLOCK(port);
257
258		error = SYSCTL_OUT(req, &fcntl, sizeof(fcntl));
259	}
260
261	return (error);
262}
263
264static int
265sfxge_port_link_fc_handler(SYSCTL_HANDLER_ARGS)
266{
267	struct sfxge_softc *sc;
268	struct sfxge_port *port;
269	unsigned int wanted_fc, link_fc;
270
271	sc = arg1;
272	port = &sc->port;
273
274	SFXGE_PORT_LOCK(port);
275	if (__predict_true(port->init_state == SFXGE_PORT_STARTED) &&
276	    SFXGE_LINK_UP(sc))
277		efx_mac_fcntl_get(sc->enp, &wanted_fc, &link_fc);
278	else
279		link_fc = 0;
280	SFXGE_PORT_UNLOCK(port);
281
282	return (SYSCTL_OUT(req, &link_fc, sizeof(link_fc)));
283}
284
285#endif /* SFXGE_HAVE_PAUSE_MEDIAOPTS */
286
287static const uint64_t sfxge_link_baudrate[EFX_LINK_NMODES] = {
288	[EFX_LINK_10HDX]	= IF_Mbps(10),
289	[EFX_LINK_10FDX]	= IF_Mbps(10),
290	[EFX_LINK_100HDX]	= IF_Mbps(100),
291	[EFX_LINK_100FDX]	= IF_Mbps(100),
292	[EFX_LINK_1000HDX]	= IF_Gbps(1),
293	[EFX_LINK_1000FDX]	= IF_Gbps(1),
294	[EFX_LINK_10000FDX]	= IF_Gbps(10),
295};
296
297void
298sfxge_mac_link_update(struct sfxge_softc *sc, efx_link_mode_t mode)
299{
300	struct sfxge_port *port;
301	int link_state;
302
303	port = &sc->port;
304
305	if (port->link_mode == mode)
306		return;
307
308	port->link_mode = mode;
309
310	/* Push link state update to the OS */
311	link_state = (port->link_mode != EFX_LINK_DOWN ?
312		      LINK_STATE_UP : LINK_STATE_DOWN);
313	sc->ifnet->if_baudrate = sfxge_link_baudrate[port->link_mode];
314	if_link_state_change(sc->ifnet, link_state);
315}
316
317static void
318sfxge_mac_poll_work(void *arg, int npending)
319{
320	struct sfxge_softc *sc;
321	efx_nic_t *enp;
322	struct sfxge_port *port;
323	efx_link_mode_t mode;
324
325	sc = (struct sfxge_softc *)arg;
326	enp = sc->enp;
327	port = &sc->port;
328
329	SFXGE_PORT_LOCK(port);
330
331	if (__predict_false(port->init_state != SFXGE_PORT_STARTED))
332		goto done;
333
334	/* This may sleep waiting for MCDI completion */
335	(void)efx_port_poll(enp, &mode);
336	sfxge_mac_link_update(sc, mode);
337
338done:
339	SFXGE_PORT_UNLOCK(port);
340}
341
342static int
343sfxge_mac_filter_set_locked(struct sfxge_softc *sc)
344{
345	unsigned int bucket[EFX_MAC_HASH_BITS];
346	struct ifnet *ifp = sc->ifnet;
347	struct ifmultiaddr *ifma;
348	struct sockaddr_dl *sa;
349	efx_nic_t *enp = sc->enp;
350	unsigned int index;
351	int rc;
352
353	/* Set promisc-unicast and broadcast filter bits */
354	if ((rc = efx_mac_filter_set(enp, !!(ifp->if_flags & IFF_PROMISC),
355				     B_TRUE)) != 0)
356		return (rc);
357
358	/* Set multicast hash filter */
359	if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) {
360		for (index = 0; index < EFX_MAC_HASH_BITS; index++)
361			bucket[index] = 1;
362	} else {
363		/* Broadcast frames also go through the multicast
364		 * filter, and the broadcast address hashes to
365		 * 0xff. */
366		bucket[0xff] = 1;
367
368		if_maddr_rlock(ifp);
369		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
370			if (ifma->ifma_addr->sa_family == AF_LINK) {
371				sa = (struct sockaddr_dl *)ifma->ifma_addr;
372				index = ether_crc32_le(LLADDR(sa), 6) & 0xff;
373				bucket[index] = 1;
374			}
375		}
376		if_maddr_runlock(ifp);
377	}
378	return (efx_mac_hash_set(enp, bucket));
379}
380
381int
382sfxge_mac_filter_set(struct sfxge_softc *sc)
383{
384	struct sfxge_port *port = &sc->port;
385	int rc;
386
387	SFXGE_PORT_LOCK(port);
388	/*
389	 * The function may be called without softc_lock held in the
390	 * case of SIOCADDMULTI and SIOCDELMULTI ioctls. ioctl handler
391	 * checks IFF_DRV_RUNNING flag which implies port started, but
392	 * it is not guaranteed to remain. softc_lock shared lock can't
393	 * be held in the case of these ioctls processing, since it
394	 * results in failure where kernel complains that non-sleepable
395	 * lock is held in sleeping thread. Both problems are repeatable
396	 * on LAG with LACP proto bring up.
397	 */
398	if (__predict_true(port->init_state == SFXGE_PORT_STARTED))
399		rc = sfxge_mac_filter_set_locked(sc);
400	else
401		rc = 0;
402	SFXGE_PORT_UNLOCK(port);
403	return (rc);
404}
405
406void
407sfxge_port_stop(struct sfxge_softc *sc)
408{
409	struct sfxge_port *port;
410	efx_nic_t *enp;
411
412	port = &sc->port;
413	enp = sc->enp;
414
415	SFXGE_PORT_LOCK(port);
416
417	KASSERT(port->init_state == SFXGE_PORT_STARTED,
418	    ("port not started"));
419
420	port->init_state = SFXGE_PORT_INITIALIZED;
421
422	port->mac_stats.update_time = 0;
423
424	/* This may call MCDI */
425	(void)efx_mac_drain(enp, B_TRUE);
426
427	(void)efx_mac_stats_periodic(enp, &port->mac_stats.dma_buf, 0, B_FALSE);
428
429	port->link_mode = EFX_LINK_UNKNOWN;
430
431	/* Destroy the common code port object. */
432	efx_port_fini(sc->enp);
433
434	SFXGE_PORT_UNLOCK(port);
435}
436
437int
438sfxge_port_start(struct sfxge_softc *sc)
439{
440	uint8_t mac_addr[ETHER_ADDR_LEN];
441	struct ifnet *ifp = sc->ifnet;
442	struct sfxge_port *port;
443	efx_nic_t *enp;
444	size_t pdu;
445	int rc;
446
447	port = &sc->port;
448	enp = sc->enp;
449
450	SFXGE_PORT_LOCK(port);
451
452	KASSERT(port->init_state == SFXGE_PORT_INITIALIZED,
453	    ("port not initialized"));
454
455	/* Initialize the port object in the common code. */
456	if ((rc = efx_port_init(sc->enp)) != 0)
457		goto fail;
458
459	/* Set the SDU */
460	pdu = EFX_MAC_PDU(ifp->if_mtu);
461	if ((rc = efx_mac_pdu_set(enp, pdu)) != 0)
462		goto fail2;
463
464	if ((rc = efx_mac_fcntl_set(enp, sfxge_port_wanted_fc(sc), B_TRUE))
465	    != 0)
466		goto fail2;
467
468	/* Set the unicast address */
469	if_addr_rlock(ifp);
470	bcopy(LLADDR((struct sockaddr_dl *)ifp->if_addr->ifa_addr),
471	      mac_addr, sizeof(mac_addr));
472	if_addr_runlock(ifp);
473	if ((rc = efx_mac_addr_set(enp, mac_addr)) != 0)
474		goto fail;
475
476	sfxge_mac_filter_set_locked(sc);
477
478	/* Update MAC stats by DMA every second */
479	if ((rc = efx_mac_stats_periodic(enp, &port->mac_stats.dma_buf,
480	    1000, B_FALSE)) != 0)
481		goto fail2;
482
483	if ((rc = efx_mac_drain(enp, B_FALSE)) != 0)
484		goto fail3;
485
486	if ((rc = efx_phy_adv_cap_set(sc->enp, sc->media.ifm_cur->ifm_data))
487	    != 0)
488		goto fail4;
489
490	port->init_state = SFXGE_PORT_STARTED;
491
492	/* Single poll in case there were missing initial events */
493	SFXGE_PORT_UNLOCK(port);
494	sfxge_mac_poll_work(sc, 0);
495
496	return (0);
497
498fail4:
499	(void)efx_mac_drain(enp, B_TRUE);
500fail3:
501	(void)efx_mac_stats_periodic(enp, &port->mac_stats.dma_buf,
502	    0, B_FALSE);
503fail2:
504	efx_port_fini(sc->enp);
505fail:
506	SFXGE_PORT_UNLOCK(port);
507
508	return (rc);
509}
510
511static int
512sfxge_phy_stat_update(struct sfxge_softc *sc)
513{
514	struct sfxge_port *port = &sc->port;
515	efsys_mem_t *esmp = &port->phy_stats.dma_buf;
516	clock_t now;
517	unsigned int count;
518	int rc;
519
520	SFXGE_PORT_LOCK_ASSERT_OWNED(port);
521
522	if (__predict_false(port->init_state != SFXGE_PORT_STARTED)) {
523		rc = 0;
524		goto out;
525	}
526
527	now = ticks;
528	if (now - port->phy_stats.update_time < hz) {
529		rc = 0;
530		goto out;
531	}
532
533	port->phy_stats.update_time = now;
534
535	/* If we're unlucky enough to read statistics wduring the DMA, wait
536	 * up to 10ms for it to finish (typically takes <500us) */
537	for (count = 0; count < 100; ++count) {
538		EFSYS_PROBE1(wait, unsigned int, count);
539
540		/* Synchronize the DMA memory for reading */
541		bus_dmamap_sync(esmp->esm_tag, esmp->esm_map,
542		    BUS_DMASYNC_POSTREAD);
543
544		/* Try to update the cached counters */
545		if ((rc = efx_phy_stats_update(sc->enp, esmp,
546		    port->phy_stats.decode_buf)) != EAGAIN)
547			goto out;
548
549		DELAY(100);
550	}
551
552	rc = ETIMEDOUT;
553out:
554	return (rc);
555}
556
557static int
558sfxge_phy_stat_handler(SYSCTL_HANDLER_ARGS)
559{
560	struct sfxge_softc *sc = arg1;
561	unsigned int id = arg2;
562	int rc;
563	uint32_t val;
564
565	SFXGE_PORT_LOCK(&sc->port);
566	if ((rc = sfxge_phy_stat_update(sc)) == 0)
567		val = ((uint32_t *)sc->port.phy_stats.decode_buf)[id];
568	SFXGE_PORT_UNLOCK(&sc->port);
569
570	if (rc == 0)
571		rc = SYSCTL_OUT(req, &val, sizeof(val));
572	return (rc);
573}
574
575static void
576sfxge_phy_stat_init(struct sfxge_softc *sc)
577{
578	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev);
579	struct sysctl_oid_list *stat_list;
580	unsigned int id;
581	const char *name;
582	uint64_t stat_mask = efx_nic_cfg_get(sc->enp)->enc_phy_stat_mask;
583
584	stat_list = SYSCTL_CHILDREN(sc->stats_node);
585
586	/* Initialise the named stats */
587	for (id = 0; id < EFX_PHY_NSTATS; id++) {
588		if (!(stat_mask & ((uint64_t)1 << id)))
589			continue;
590		name = efx_phy_stat_name(sc->enp, id);
591		SYSCTL_ADD_PROC(
592			ctx, stat_list,
593			OID_AUTO, name, CTLTYPE_UINT|CTLFLAG_RD,
594			sc, id, sfxge_phy_stat_handler,
595			id == EFX_PHY_STAT_OUI ? "IX" : "IU",
596			"");
597	}
598}
599
600void
601sfxge_port_fini(struct sfxge_softc *sc)
602{
603	struct sfxge_port *port;
604	efsys_mem_t *esmp;
605
606	port = &sc->port;
607	esmp = &port->mac_stats.dma_buf;
608
609	KASSERT(port->init_state == SFXGE_PORT_INITIALIZED,
610	    ("Port not initialized"));
611
612	port->init_state = SFXGE_PORT_UNINITIALIZED;
613
614	port->link_mode = EFX_LINK_UNKNOWN;
615
616	/* Finish with PHY DMA memory */
617	sfxge_dma_free(&port->phy_stats.dma_buf);
618	free(port->phy_stats.decode_buf, M_SFXGE);
619
620	sfxge_dma_free(esmp);
621	free(port->mac_stats.decode_buf, M_SFXGE);
622
623	SFXGE_PORT_LOCK_DESTROY(port);
624
625	port->sc = NULL;
626}
627
628int
629sfxge_port_init(struct sfxge_softc *sc)
630{
631	struct sfxge_port *port;
632	struct sysctl_ctx_list *sysctl_ctx;
633	struct sysctl_oid *sysctl_tree;
634	efsys_mem_t *mac_stats_buf, *phy_stats_buf;
635	int rc;
636
637	port = &sc->port;
638	mac_stats_buf = &port->mac_stats.dma_buf;
639	phy_stats_buf = &port->phy_stats.dma_buf;
640
641	KASSERT(port->init_state == SFXGE_PORT_UNINITIALIZED,
642	    ("Port already initialized"));
643
644	port->sc = sc;
645
646	SFXGE_PORT_LOCK_INIT(port, device_get_nameunit(sc->dev));
647
648	port->phy_stats.decode_buf = malloc(EFX_PHY_NSTATS * sizeof(uint32_t),
649					    M_SFXGE, M_WAITOK | M_ZERO);
650	if ((rc = sfxge_dma_alloc(sc, EFX_PHY_STATS_SIZE, phy_stats_buf)) != 0)
651		goto fail;
652	sfxge_phy_stat_init(sc);
653
654	sysctl_ctx = device_get_sysctl_ctx(sc->dev);
655	sysctl_tree = device_get_sysctl_tree(sc->dev);
656
657#ifndef SFXGE_HAVE_PAUSE_MEDIAOPTS
658	/* If flow control cannot be configured or reported through
659	 * ifmedia, provide sysctls for it. */
660	port->wanted_fc = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
661	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
662	    "wanted_fc", CTLTYPE_UINT|CTLFLAG_RW, sc, 0,
663	    sfxge_port_wanted_fc_handler, "IU", "wanted flow control mode");
664	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
665	    "link_fc", CTLTYPE_UINT|CTLFLAG_RD, sc, 0,
666	    sfxge_port_link_fc_handler, "IU", "link flow control mode");
667#endif
668
669	port->mac_stats.decode_buf = malloc(EFX_MAC_NSTATS * sizeof(uint64_t),
670					    M_SFXGE, M_WAITOK | M_ZERO);
671	if ((rc = sfxge_dma_alloc(sc, EFX_MAC_STATS_SIZE, mac_stats_buf)) != 0)
672		goto fail2;
673	sfxge_mac_stat_init(sc);
674
675	port->init_state = SFXGE_PORT_INITIALIZED;
676
677	return (0);
678
679fail2:
680	free(port->mac_stats.decode_buf, M_SFXGE);
681	sfxge_dma_free(phy_stats_buf);
682fail:
683	free(port->phy_stats.decode_buf, M_SFXGE);
684	SFXGE_PORT_LOCK_DESTROY(port);
685	port->sc = NULL;
686	return (rc);
687}
688
689static int sfxge_link_mode[EFX_PHY_MEDIA_NTYPES][EFX_LINK_NMODES] = {
690	[EFX_PHY_MEDIA_CX4] = {
691		[EFX_LINK_10000FDX]	= IFM_ETHER | IFM_FDX | IFM_10G_CX4,
692	},
693	[EFX_PHY_MEDIA_KX4] = {
694		[EFX_LINK_10000FDX]	= IFM_ETHER | IFM_FDX | IFM_10G_KX4,
695	},
696	[EFX_PHY_MEDIA_XFP] = {
697		/* Don't know the module type, but assume SR for now. */
698		[EFX_LINK_10000FDX]	= IFM_ETHER | IFM_FDX | IFM_10G_SR,
699	},
700	[EFX_PHY_MEDIA_SFP_PLUS] = {
701		/* Don't know the module type, but assume SX/SR for now. */
702		[EFX_LINK_1000FDX]	= IFM_ETHER | IFM_FDX | IFM_1000_SX,
703		[EFX_LINK_10000FDX]	= IFM_ETHER | IFM_FDX | IFM_10G_SR,
704	},
705	[EFX_PHY_MEDIA_BASE_T] = {
706		[EFX_LINK_10HDX]	= IFM_ETHER | IFM_HDX | IFM_10_T,
707		[EFX_LINK_10FDX]	= IFM_ETHER | IFM_FDX | IFM_10_T,
708		[EFX_LINK_100HDX]	= IFM_ETHER | IFM_HDX | IFM_100_TX,
709		[EFX_LINK_100FDX]	= IFM_ETHER | IFM_FDX | IFM_100_TX,
710		[EFX_LINK_1000HDX]	= IFM_ETHER | IFM_HDX | IFM_1000_T,
711		[EFX_LINK_1000FDX]	= IFM_ETHER | IFM_FDX | IFM_1000_T,
712		[EFX_LINK_10000FDX]	= IFM_ETHER | IFM_FDX | IFM_10G_T,
713	},
714};
715
716static void
717sfxge_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
718{
719	struct sfxge_softc *sc;
720	efx_phy_media_type_t medium_type;
721	efx_link_mode_t mode;
722
723	sc = ifp->if_softc;
724	SFXGE_ADAPTER_LOCK(sc);
725
726	ifmr->ifm_status = IFM_AVALID;
727	ifmr->ifm_active = IFM_ETHER;
728
729	if (SFXGE_RUNNING(sc) && SFXGE_LINK_UP(sc)) {
730		ifmr->ifm_status |= IFM_ACTIVE;
731
732		efx_phy_media_type_get(sc->enp, &medium_type);
733		mode = sc->port.link_mode;
734		ifmr->ifm_active |= sfxge_link_mode[medium_type][mode];
735		ifmr->ifm_active |= sfxge_port_link_fc_ifm(sc);
736	}
737
738	SFXGE_ADAPTER_UNLOCK(sc);
739}
740
741static int
742sfxge_media_change(struct ifnet *ifp)
743{
744	struct sfxge_softc *sc;
745	struct ifmedia_entry *ifm;
746	int rc;
747
748	sc = ifp->if_softc;
749	ifm = sc->media.ifm_cur;
750
751	SFXGE_ADAPTER_LOCK(sc);
752
753	if (!SFXGE_RUNNING(sc)) {
754		rc = 0;
755		goto out;
756	}
757
758	rc = efx_mac_fcntl_set(sc->enp, sfxge_port_wanted_fc(sc), B_TRUE);
759	if (rc != 0)
760		goto out;
761
762	rc = efx_phy_adv_cap_set(sc->enp, ifm->ifm_data);
763out:
764	SFXGE_ADAPTER_UNLOCK(sc);
765
766	return (rc);
767}
768
769int sfxge_port_ifmedia_init(struct sfxge_softc *sc)
770{
771	efx_phy_media_type_t medium_type;
772	uint32_t cap_mask, mode_cap_mask;
773	efx_link_mode_t mode;
774	int mode_ifm, best_mode_ifm = 0;
775	int rc;
776
777	/* We need port state to initialise the ifmedia list. */
778	if ((rc = efx_nic_init(sc->enp)) != 0)
779		goto out;
780	if ((rc = efx_port_init(sc->enp)) != 0)
781		goto out2;
782
783	/*
784	 * Register ifconfig callbacks for querying and setting the
785	 * link mode and link status.
786	 */
787	ifmedia_init(&sc->media, IFM_IMASK, sfxge_media_change,
788	    sfxge_media_status);
789
790	/*
791	 * Map firmware medium type and capabilities to ifmedia types.
792	 * ifmedia does not distinguish between forcing the link mode
793	 * and disabling auto-negotiation.  1000BASE-T and 10GBASE-T
794	 * require AN even if only one link mode is enabled, and for
795	 * 100BASE-TX it is useful even if the link mode is forced.
796	 * Therefore we never disable auto-negotiation.
797	 *
798	 * Also enable and advertise flow control by default.
799	 */
800
801	efx_phy_media_type_get(sc->enp, &medium_type);
802	efx_phy_adv_cap_get(sc->enp, EFX_PHY_CAP_PERM, &cap_mask);
803
804	EFX_STATIC_ASSERT(EFX_LINK_10HDX == EFX_PHY_CAP_10HDX + 1);
805	EFX_STATIC_ASSERT(EFX_LINK_10FDX == EFX_PHY_CAP_10FDX + 1);
806	EFX_STATIC_ASSERT(EFX_LINK_100HDX == EFX_PHY_CAP_100HDX + 1);
807	EFX_STATIC_ASSERT(EFX_LINK_100FDX == EFX_PHY_CAP_100FDX + 1);
808	EFX_STATIC_ASSERT(EFX_LINK_1000HDX == EFX_PHY_CAP_1000HDX + 1);
809	EFX_STATIC_ASSERT(EFX_LINK_1000FDX == EFX_PHY_CAP_1000FDX + 1);
810	EFX_STATIC_ASSERT(EFX_LINK_10000FDX == EFX_PHY_CAP_10000FDX + 1);
811
812	for (mode = EFX_LINK_10HDX; mode <= EFX_LINK_10000FDX; mode++) {
813		mode_cap_mask = 1 << (mode - 1);
814		mode_ifm = sfxge_link_mode[medium_type][mode];
815
816		if ((cap_mask & mode_cap_mask) && mode_ifm) {
817			mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_AN);
818
819#ifdef SFXGE_HAVE_PAUSE_MEDIAOPTS
820			/* No flow-control */
821			ifmedia_add(&sc->media, mode_ifm, mode_cap_mask, NULL);
822
823			/* Respond-only.  If using AN, we implicitly
824			 * offer symmetric as well, but that doesn't
825			 * mean we *have* to generate pause frames.
826			 */
827			mode_cap_mask |= cap_mask & ((1 << EFX_PHY_CAP_PAUSE) |
828						     (1 << EFX_PHY_CAP_ASYM));
829			mode_ifm |= IFM_ETH_RXPAUSE;
830			ifmedia_add(&sc->media, mode_ifm, mode_cap_mask, NULL);
831
832			/* Symmetric */
833			mode_cap_mask &= ~(1 << EFX_PHY_CAP_ASYM);
834			mode_ifm |= IFM_ETH_TXPAUSE;
835#else /* !SFXGE_HAVE_PAUSE_MEDIAOPTS */
836			mode_cap_mask |= cap_mask & (1 << EFX_PHY_CAP_PAUSE);
837#endif
838			ifmedia_add(&sc->media, mode_ifm, mode_cap_mask, NULL);
839
840			/* Link modes are numbered in order of speed,
841			 * so assume the last one available is the best.
842			 */
843			best_mode_ifm = mode_ifm;
844		}
845	}
846
847	if (cap_mask & (1 << EFX_PHY_CAP_AN)) {
848		/* Add autoselect mode. */
849		mode_ifm = IFM_ETHER | IFM_AUTO;
850		ifmedia_add(&sc->media, mode_ifm,
851			    cap_mask & ~(1 << EFX_PHY_CAP_ASYM), NULL);
852		best_mode_ifm = mode_ifm;
853	}
854
855	if (best_mode_ifm != 0)
856		ifmedia_set(&sc->media, best_mode_ifm);
857
858	/* Now discard port state until interface is started. */
859	efx_port_fini(sc->enp);
860out2:
861	efx_nic_fini(sc->enp);
862out:
863	return (rc);
864}
865