sfxge.c revision 283212
1227569Sphilip/*-
2227569Sphilip * Copyright (c) 2010-2011 Solarflare Communications, Inc.
3227569Sphilip * All rights reserved.
4227569Sphilip *
5227569Sphilip * This software was developed in part by Philip Paeps under contract for
6227569Sphilip * Solarflare Communications, Inc.
7227569Sphilip *
8227569Sphilip * Redistribution and use in source and binary forms, with or without
9227569Sphilip * modification, are permitted provided that the following conditions
10227569Sphilip * are met:
11227569Sphilip * 1. Redistributions of source code must retain the above copyright
12227569Sphilip *    notice, this list of conditions and the following disclaimer.
13227569Sphilip * 2. Redistributions in binary form must reproduce the above copyright
14227569Sphilip *    notice, this list of conditions and the following disclaimer in the
15227569Sphilip *    documentation and/or other materials provided with the distribution.
16227569Sphilip *
17227569Sphilip * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18227569Sphilip * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19227569Sphilip * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20227569Sphilip * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21227569Sphilip * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22227569Sphilip * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23227569Sphilip * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24227569Sphilip * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25227569Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26227569Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27227569Sphilip * SUCH DAMAGE.
28227569Sphilip */
29227569Sphilip
30227569Sphilip#include <sys/cdefs.h>
31227569Sphilip__FBSDID("$FreeBSD: stable/10/sys/dev/sfxge/sfxge.c 283212 2015-05-21 09:13:47Z arybchik $");
32227569Sphilip
33227569Sphilip#include <sys/param.h>
34227569Sphilip#include <sys/kernel.h>
35227569Sphilip#include <sys/bus.h>
36227569Sphilip#include <sys/rman.h>
37227569Sphilip#include <sys/lock.h>
38227569Sphilip#include <sys/module.h>
39227569Sphilip#include <sys/mutex.h>
40227569Sphilip#include <sys/smp.h>
41227569Sphilip#include <sys/socket.h>
42227569Sphilip#include <sys/taskqueue.h>
43227569Sphilip#include <sys/sockio.h>
44227569Sphilip#include <sys/sysctl.h>
45280502Sarybchik#include <sys/syslog.h>
46227569Sphilip
47227569Sphilip#include <dev/pci/pcireg.h>
48227569Sphilip#include <dev/pci/pcivar.h>
49227569Sphilip
50227569Sphilip#include <net/ethernet.h>
51227569Sphilip#include <net/if.h>
52227569Sphilip#include <net/if_media.h>
53227569Sphilip#include <net/if_types.h>
54227569Sphilip
55227569Sphilip#include "common/efx.h"
56227569Sphilip
57227569Sphilip#include "sfxge.h"
58227569Sphilip#include "sfxge_rx.h"
59280601Sarybchik#include "sfxge_version.h"
60227569Sphilip
61283204Sarybchik#define	SFXGE_CAP (IFCAP_VLAN_MTU | IFCAP_VLAN_HWCSUM |			\
62283204Sarybchik		   IFCAP_RXCSUM | IFCAP_TXCSUM | IFCAP_TSO |		\
63283205Sarybchik		   IFCAP_RXCSUM_IPV6 | IFCAP_TXCSUM_IPV6 |		\
64227569Sphilip		   IFCAP_JUMBO_MTU | IFCAP_LRO |			\
65227569Sphilip		   IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE)
66280501Sarybchik#define	SFXGE_CAP_ENABLE SFXGE_CAP
67283209Sarybchik#define	SFXGE_CAP_FIXED (IFCAP_VLAN_MTU | IFCAP_VLAN_HWCSUM |		\
68227569Sphilip			 IFCAP_JUMBO_MTU | IFCAP_LINKSTATE)
69227569Sphilip
70227569SphilipMALLOC_DEFINE(M_SFXGE, "sfxge", "Solarflare 10GigE driver");
71227569Sphilip
72280502Sarybchik
73280502SarybchikSYSCTL_NODE(_hw, OID_AUTO, sfxge, CTLFLAG_RD, 0,
74280502Sarybchik	    "SFXGE driver parameters");
75280502Sarybchik
76280502Sarybchik#define	SFXGE_PARAM_RX_RING	SFXGE_PARAM(rx_ring)
77280502Sarybchikstatic int sfxge_rx_ring_entries = SFXGE_NDESCS;
78280502SarybchikTUNABLE_INT(SFXGE_PARAM_RX_RING, &sfxge_rx_ring_entries);
79280502SarybchikSYSCTL_INT(_hw_sfxge, OID_AUTO, rx_ring, CTLFLAG_RDTUN,
80280502Sarybchik	   &sfxge_rx_ring_entries, 0,
81280502Sarybchik	   "Maximum number of descriptors in a receive ring");
82280502Sarybchik
83280502Sarybchik#define	SFXGE_PARAM_TX_RING	SFXGE_PARAM(tx_ring)
84280502Sarybchikstatic int sfxge_tx_ring_entries = SFXGE_NDESCS;
85280502SarybchikTUNABLE_INT(SFXGE_PARAM_TX_RING, &sfxge_tx_ring_entries);
86280502SarybchikSYSCTL_INT(_hw_sfxge, OID_AUTO, tx_ring, CTLFLAG_RDTUN,
87280502Sarybchik	   &sfxge_tx_ring_entries, 0,
88280502Sarybchik	   "Maximum number of descriptors in a transmit ring");
89280502Sarybchik
90280502Sarybchik
91227569Sphilipstatic void
92227569Sphilipsfxge_reset(void *arg, int npending);
93227569Sphilip
94227569Sphilipstatic int
95227569Sphilipsfxge_start(struct sfxge_softc *sc)
96227569Sphilip{
97227569Sphilip	int rc;
98227569Sphilip
99280522Sarybchik	SFXGE_ADAPTER_LOCK_ASSERT_OWNED(sc);
100227569Sphilip
101227569Sphilip	if (sc->init_state == SFXGE_STARTED)
102280501Sarybchik		return (0);
103227569Sphilip
104227569Sphilip	if (sc->init_state != SFXGE_REGISTERED) {
105227569Sphilip		rc = EINVAL;
106227569Sphilip		goto fail;
107227569Sphilip	}
108227569Sphilip
109227569Sphilip	if ((rc = efx_nic_init(sc->enp)) != 0)
110227569Sphilip		goto fail;
111227569Sphilip
112227569Sphilip	/* Start processing interrupts. */
113227569Sphilip	if ((rc = sfxge_intr_start(sc)) != 0)
114227569Sphilip		goto fail2;
115227569Sphilip
116227569Sphilip	/* Start processing events. */
117227569Sphilip	if ((rc = sfxge_ev_start(sc)) != 0)
118227569Sphilip		goto fail3;
119227569Sphilip
120227569Sphilip	/* Start the receiver side. */
121227569Sphilip	if ((rc = sfxge_rx_start(sc)) != 0)
122227569Sphilip		goto fail4;
123227569Sphilip
124227569Sphilip	/* Start the transmitter side. */
125227569Sphilip	if ((rc = sfxge_tx_start(sc)) != 0)
126227569Sphilip		goto fail5;
127227569Sphilip
128227569Sphilip	/* Fire up the port. */
129227569Sphilip	if ((rc = sfxge_port_start(sc)) != 0)
130227569Sphilip		goto fail6;
131227569Sphilip
132227569Sphilip	sc->init_state = SFXGE_STARTED;
133227569Sphilip
134227569Sphilip	/* Tell the stack we're running. */
135227569Sphilip	sc->ifnet->if_drv_flags |= IFF_DRV_RUNNING;
136227569Sphilip	sc->ifnet->if_drv_flags &= ~IFF_DRV_OACTIVE;
137227569Sphilip
138227569Sphilip	return (0);
139227569Sphilip
140227569Sphilipfail6:
141227569Sphilip	sfxge_tx_stop(sc);
142227569Sphilip
143227569Sphilipfail5:
144227569Sphilip	sfxge_rx_stop(sc);
145227569Sphilip
146227569Sphilipfail4:
147227569Sphilip	sfxge_ev_stop(sc);
148227569Sphilip
149227569Sphilipfail3:
150227569Sphilip	sfxge_intr_stop(sc);
151227569Sphilip
152227569Sphilipfail2:
153227569Sphilip	efx_nic_fini(sc->enp);
154227569Sphilip
155227569Sphilipfail:
156227569Sphilip	device_printf(sc->dev, "sfxge_start: %d\n", rc);
157227569Sphilip
158227569Sphilip	return (rc);
159227569Sphilip}
160227569Sphilip
161227569Sphilipstatic void
162227569Sphilipsfxge_if_init(void *arg)
163227569Sphilip{
164227569Sphilip	struct sfxge_softc *sc;
165227569Sphilip
166227569Sphilip	sc = (struct sfxge_softc *)arg;
167227569Sphilip
168280522Sarybchik	SFXGE_ADAPTER_LOCK(sc);
169227569Sphilip	(void)sfxge_start(sc);
170280522Sarybchik	SFXGE_ADAPTER_UNLOCK(sc);
171227569Sphilip}
172227569Sphilip
173227569Sphilipstatic void
174227569Sphilipsfxge_stop(struct sfxge_softc *sc)
175227569Sphilip{
176280522Sarybchik	SFXGE_ADAPTER_LOCK_ASSERT_OWNED(sc);
177227569Sphilip
178227569Sphilip	if (sc->init_state != SFXGE_STARTED)
179227569Sphilip		return;
180227569Sphilip
181227569Sphilip	sc->init_state = SFXGE_REGISTERED;
182227569Sphilip
183227569Sphilip	/* Stop the port. */
184227569Sphilip	sfxge_port_stop(sc);
185227569Sphilip
186227569Sphilip	/* Stop the transmitter. */
187227569Sphilip	sfxge_tx_stop(sc);
188227569Sphilip
189227569Sphilip	/* Stop the receiver. */
190227569Sphilip	sfxge_rx_stop(sc);
191227569Sphilip
192227569Sphilip	/* Stop processing events. */
193227569Sphilip	sfxge_ev_stop(sc);
194227569Sphilip
195227569Sphilip	/* Stop processing interrupts. */
196227569Sphilip	sfxge_intr_stop(sc);
197227569Sphilip
198227569Sphilip	efx_nic_fini(sc->enp);
199227569Sphilip
200227569Sphilip	sc->ifnet->if_drv_flags &= ~IFF_DRV_RUNNING;
201227569Sphilip}
202227569Sphilip
203227569Sphilipstatic int
204227569Sphilipsfxge_if_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data)
205227569Sphilip{
206227569Sphilip	struct sfxge_softc *sc;
207227569Sphilip	struct ifreq *ifr;
208227569Sphilip	int error;
209227569Sphilip
210227569Sphilip	ifr = (struct ifreq *)data;
211227569Sphilip	sc = ifp->if_softc;
212227569Sphilip	error = 0;
213227569Sphilip
214227569Sphilip	switch (command) {
215227569Sphilip	case SIOCSIFFLAGS:
216280522Sarybchik		SFXGE_ADAPTER_LOCK(sc);
217227569Sphilip		if (ifp->if_flags & IFF_UP) {
218227569Sphilip			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
219227569Sphilip				if ((ifp->if_flags ^ sc->if_flags) &
220227569Sphilip				    (IFF_PROMISC | IFF_ALLMULTI)) {
221227569Sphilip					sfxge_mac_filter_set(sc);
222227569Sphilip				}
223227569Sphilip			} else
224227569Sphilip				sfxge_start(sc);
225227569Sphilip		} else
226227569Sphilip			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
227227569Sphilip				sfxge_stop(sc);
228227569Sphilip		sc->if_flags = ifp->if_flags;
229280522Sarybchik		SFXGE_ADAPTER_UNLOCK(sc);
230227569Sphilip		break;
231227569Sphilip	case SIOCSIFMTU:
232227569Sphilip		if (ifr->ifr_mtu == ifp->if_mtu) {
233227569Sphilip			/* Nothing to do */
234227569Sphilip			error = 0;
235227569Sphilip		} else if (ifr->ifr_mtu > SFXGE_MAX_MTU) {
236227569Sphilip			error = EINVAL;
237227569Sphilip		} else if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
238227569Sphilip			ifp->if_mtu = ifr->ifr_mtu;
239227569Sphilip			error = 0;
240227569Sphilip		} else {
241227569Sphilip			/* Restart required */
242280522Sarybchik			SFXGE_ADAPTER_LOCK(sc);
243227569Sphilip			sfxge_stop(sc);
244227569Sphilip			ifp->if_mtu = ifr->ifr_mtu;
245227569Sphilip			error = sfxge_start(sc);
246280522Sarybchik			SFXGE_ADAPTER_UNLOCK(sc);
247280501Sarybchik			if (error != 0) {
248227569Sphilip				ifp->if_flags &= ~IFF_UP;
249227569Sphilip				ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
250227569Sphilip				if_down(ifp);
251227569Sphilip			}
252227569Sphilip		}
253227569Sphilip		break;
254227569Sphilip	case SIOCADDMULTI:
255227569Sphilip	case SIOCDELMULTI:
256227569Sphilip		if (ifp->if_drv_flags & IFF_DRV_RUNNING)
257227569Sphilip			sfxge_mac_filter_set(sc);
258227569Sphilip		break;
259227569Sphilip	case SIOCSIFCAP:
260283212Sarybchik	{
261283212Sarybchik		int reqcap = ifr->ifr_reqcap;
262283212Sarybchik		int capchg_mask;
263283212Sarybchik
264280522Sarybchik		SFXGE_ADAPTER_LOCK(sc);
265227569Sphilip
266283212Sarybchik		/* Capabilities to be changed in accordance with request */
267283212Sarybchik		capchg_mask = ifp->if_capenable ^ reqcap;
268283212Sarybchik
269227569Sphilip		/*
270227569Sphilip		 * The networking core already rejects attempts to
271227569Sphilip		 * enable capabilities we don't have.  We still have
272227569Sphilip		 * to reject attempts to disable capabilities that we
273227569Sphilip		 * can't (yet) disable.
274227569Sphilip		 */
275283212Sarybchik		KASSERT((reqcap & ~ifp->if_capabilities) == 0,
276283212Sarybchik		    ("Unsupported capabilities %x requested %x vs %x",
277283212Sarybchik		     reqcap & ~ifp->if_capabilities,
278283212Sarybchik		     reqcap , ifp->if_capabilities));
279283212Sarybchik		if (capchg_mask & SFXGE_CAP_FIXED) {
280227569Sphilip			error = EINVAL;
281280522Sarybchik			SFXGE_ADAPTER_UNLOCK(sc);
282227569Sphilip			break;
283227569Sphilip		}
284227569Sphilip
285283212Sarybchik		if (reqcap & IFCAP_TXCSUM)
286227569Sphilip			ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP);
287227569Sphilip		else
288227569Sphilip			ifp->if_hwassist &= ~(CSUM_IP | CSUM_TCP | CSUM_UDP);
289283212Sarybchik		if (reqcap & IFCAP_TXCSUM_IPV6)
290283205Sarybchik			ifp->if_hwassist |= (CSUM_TCP_IPV6 | CSUM_UDP_IPV6);
291283205Sarybchik		else
292283205Sarybchik			ifp->if_hwassist &= ~(CSUM_TCP_IPV6 | CSUM_UDP_IPV6);
293227569Sphilip
294283207Sarybchik		/*
295283207Sarybchik		 * The kernel takes both IFCAP_TSOx and CSUM_TSO into
296283207Sarybchik		 * account before using TSO. So, we do not touch
297283207Sarybchik		 * checksum flags when IFCAP_TSOx is modified.
298283207Sarybchik		 * Note that CSUM_TSO is (CSUM_IP_TSO|CSUM_IP6_TSO),
299283207Sarybchik		 * but both bits are set in IPv4 and IPv6 mbufs.
300283207Sarybchik		 */
301283207Sarybchik
302283212Sarybchik		ifp->if_capenable = reqcap;
303283212Sarybchik
304280522Sarybchik		SFXGE_ADAPTER_UNLOCK(sc);
305227569Sphilip		break;
306283212Sarybchik	}
307227569Sphilip	case SIOCSIFMEDIA:
308227569Sphilip	case SIOCGIFMEDIA:
309227569Sphilip		error = ifmedia_ioctl(ifp, ifr, &sc->media, command);
310227569Sphilip		break;
311227569Sphilip	default:
312227569Sphilip		error = ether_ioctl(ifp, command, data);
313227569Sphilip	}
314227569Sphilip
315227569Sphilip	return (error);
316227569Sphilip}
317227569Sphilip
318227569Sphilipstatic void
319227569Sphilipsfxge_ifnet_fini(struct ifnet *ifp)
320227569Sphilip{
321227569Sphilip	struct sfxge_softc *sc = ifp->if_softc;
322227569Sphilip
323280522Sarybchik	SFXGE_ADAPTER_LOCK(sc);
324227569Sphilip	sfxge_stop(sc);
325280522Sarybchik	SFXGE_ADAPTER_UNLOCK(sc);
326227569Sphilip
327227569Sphilip	ifmedia_removeall(&sc->media);
328227569Sphilip	ether_ifdetach(ifp);
329227569Sphilip	if_free(ifp);
330227569Sphilip}
331227569Sphilip
332280501Sarybchikstatic int
333227569Sphilipsfxge_ifnet_init(struct ifnet *ifp, struct sfxge_softc *sc)
334227569Sphilip{
335227569Sphilip	const efx_nic_cfg_t *encp = efx_nic_cfg_get(sc->enp);
336227569Sphilip	device_t dev;
337227569Sphilip	int rc;
338227569Sphilip
339227569Sphilip	dev = sc->dev;
340227569Sphilip	sc->ifnet = ifp;
341227569Sphilip
342227569Sphilip	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
343227569Sphilip	ifp->if_init = sfxge_if_init;
344227569Sphilip	ifp->if_softc = sc;
345227569Sphilip	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
346227569Sphilip	ifp->if_ioctl = sfxge_if_ioctl;
347227569Sphilip
348227569Sphilip	ifp->if_capabilities = SFXGE_CAP;
349227569Sphilip	ifp->if_capenable = SFXGE_CAP_ENABLE;
350283205Sarybchik	ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO |
351283205Sarybchik			   CSUM_TCP_IPV6 | CSUM_UDP_IPV6;
352227569Sphilip
353227569Sphilip	ether_ifattach(ifp, encp->enc_mac_addr);
354227569Sphilip
355227569Sphilip	ifp->if_transmit = sfxge_if_transmit;
356227569Sphilip	ifp->if_qflush = sfxge_if_qflush;
357227569Sphilip
358227569Sphilip	if ((rc = sfxge_port_ifmedia_init(sc)) != 0)
359227569Sphilip		goto fail;
360227569Sphilip
361280501Sarybchik	return (0);
362227569Sphilip
363227569Sphilipfail:
364227569Sphilip	ether_ifdetach(sc->ifnet);
365280501Sarybchik	return (rc);
366227569Sphilip}
367227569Sphilip
368227569Sphilipvoid
369227569Sphilipsfxge_sram_buf_tbl_alloc(struct sfxge_softc *sc, size_t n, uint32_t *idp)
370227569Sphilip{
371227569Sphilip	KASSERT(sc->buffer_table_next + n <=
372227569Sphilip		efx_nic_cfg_get(sc->enp)->enc_buftbl_limit,
373227569Sphilip		("buffer table full"));
374227569Sphilip
375227569Sphilip	*idp = sc->buffer_table_next;
376227569Sphilip	sc->buffer_table_next += n;
377227569Sphilip}
378227569Sphilip
379227569Sphilipstatic int
380227569Sphilipsfxge_bar_init(struct sfxge_softc *sc)
381227569Sphilip{
382227569Sphilip	efsys_bar_t *esbp = &sc->bar;
383227569Sphilip
384280501Sarybchik	esbp->esb_rid = PCIR_BAR(EFX_MEM_BAR);
385227569Sphilip	if ((esbp->esb_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
386227569Sphilip	    &esbp->esb_rid, RF_ACTIVE)) == NULL) {
387227569Sphilip		device_printf(sc->dev, "Cannot allocate BAR region %d\n",
388227569Sphilip		    EFX_MEM_BAR);
389227569Sphilip		return (ENXIO);
390227569Sphilip	}
391227569Sphilip	esbp->esb_tag = rman_get_bustag(esbp->esb_res);
392227569Sphilip	esbp->esb_handle = rman_get_bushandle(esbp->esb_res);
393227569Sphilip
394280524Sarybchik	SFXGE_BAR_LOCK_INIT(esbp, device_get_nameunit(sc->dev));
395280524Sarybchik
396227569Sphilip	return (0);
397227569Sphilip}
398227569Sphilip
399227569Sphilipstatic void
400227569Sphilipsfxge_bar_fini(struct sfxge_softc *sc)
401227569Sphilip{
402227569Sphilip	efsys_bar_t *esbp = &sc->bar;
403227569Sphilip
404227569Sphilip	bus_release_resource(sc->dev, SYS_RES_MEMORY, esbp->esb_rid,
405227569Sphilip	    esbp->esb_res);
406280522Sarybchik	SFXGE_BAR_LOCK_DESTROY(esbp);
407227569Sphilip}
408227569Sphilip
409227569Sphilipstatic int
410227569Sphilipsfxge_create(struct sfxge_softc *sc)
411227569Sphilip{
412227569Sphilip	device_t dev;
413227569Sphilip	efx_nic_t *enp;
414227569Sphilip	int error;
415280518Sarybchik	char rss_param_name[sizeof(SFXGE_PARAM(%d.max_rss_channels))];
416227569Sphilip
417227569Sphilip	dev = sc->dev;
418227569Sphilip
419280524Sarybchik	SFXGE_ADAPTER_LOCK_INIT(sc, device_get_nameunit(sc->dev));
420227569Sphilip
421280518Sarybchik	sc->max_rss_channels = 0;
422280518Sarybchik	snprintf(rss_param_name, sizeof(rss_param_name),
423280518Sarybchik		 SFXGE_PARAM(%d.max_rss_channels),
424280518Sarybchik		 (int)device_get_unit(dev));
425280518Sarybchik	TUNABLE_INT_FETCH(rss_param_name, &sc->max_rss_channels);
426280518Sarybchik
427227569Sphilip	sc->stats_node = SYSCTL_ADD_NODE(
428227569Sphilip		device_get_sysctl_ctx(dev),
429227569Sphilip		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
430227569Sphilip		OID_AUTO, "stats", CTLFLAG_RD, NULL, "Statistics");
431280501Sarybchik	if (sc->stats_node == NULL) {
432227569Sphilip		error = ENOMEM;
433227569Sphilip		goto fail;
434227569Sphilip	}
435227569Sphilip
436227569Sphilip	TASK_INIT(&sc->task_reset, 0, sfxge_reset, sc);
437227569Sphilip
438227569Sphilip	(void) pci_enable_busmaster(dev);
439227569Sphilip
440227569Sphilip	/* Initialize DMA mappings. */
441227569Sphilip	if ((error = sfxge_dma_init(sc)) != 0)
442227569Sphilip		goto fail;
443227569Sphilip
444227569Sphilip	/* Map the device registers. */
445227569Sphilip	if ((error = sfxge_bar_init(sc)) != 0)
446227569Sphilip		goto fail;
447227569Sphilip
448227569Sphilip	error = efx_family(pci_get_vendor(dev), pci_get_device(dev),
449227569Sphilip	    &sc->family);
450227569Sphilip	KASSERT(error == 0, ("Family should be filtered by sfxge_probe()"));
451227569Sphilip
452227569Sphilip	/* Create the common code nic object. */
453280524Sarybchik	SFXGE_EFSYS_LOCK_INIT(&sc->enp_lock,
454280524Sarybchik			      device_get_nameunit(sc->dev), "nic");
455227569Sphilip	if ((error = efx_nic_create(sc->family, (efsys_identifier_t *)sc,
456227569Sphilip	    &sc->bar, &sc->enp_lock, &enp)) != 0)
457227569Sphilip		goto fail3;
458227569Sphilip	sc->enp = enp;
459227569Sphilip
460280502Sarybchik	if (!ISP2(sfxge_rx_ring_entries) ||
461280502Sarybchik	    !(sfxge_rx_ring_entries & EFX_RXQ_NDESCS_MASK)) {
462280502Sarybchik		log(LOG_ERR, "%s=%d must be power of 2 from %u to %u",
463280502Sarybchik		    SFXGE_PARAM_RX_RING, sfxge_rx_ring_entries,
464280502Sarybchik		    EFX_RXQ_MINNDESCS, EFX_RXQ_MAXNDESCS);
465280502Sarybchik		error = EINVAL;
466280502Sarybchik		goto fail_rx_ring_entries;
467280502Sarybchik	}
468280502Sarybchik	sc->rxq_entries = sfxge_rx_ring_entries;
469280502Sarybchik
470280502Sarybchik	if (!ISP2(sfxge_tx_ring_entries) ||
471280502Sarybchik	    !(sfxge_tx_ring_entries & EFX_TXQ_NDESCS_MASK)) {
472280502Sarybchik		log(LOG_ERR, "%s=%d must be power of 2 from %u to %u",
473280502Sarybchik		    SFXGE_PARAM_TX_RING, sfxge_tx_ring_entries,
474280502Sarybchik		    EFX_TXQ_MINNDESCS, EFX_TXQ_MAXNDESCS);
475280502Sarybchik		error = EINVAL;
476280502Sarybchik		goto fail_tx_ring_entries;
477280502Sarybchik	}
478280502Sarybchik	sc->txq_entries = sfxge_tx_ring_entries;
479280502Sarybchik
480227569Sphilip	/* Initialize MCDI to talk to the microcontroller. */
481227569Sphilip	if ((error = sfxge_mcdi_init(sc)) != 0)
482227569Sphilip		goto fail4;
483227569Sphilip
484227569Sphilip	/* Probe the NIC and build the configuration data area. */
485227569Sphilip	if ((error = efx_nic_probe(enp)) != 0)
486227569Sphilip		goto fail5;
487227569Sphilip
488280601Sarybchik	SYSCTL_ADD_STRING(device_get_sysctl_ctx(dev),
489280601Sarybchik			  SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
490280601Sarybchik			  OID_AUTO, "version", CTLFLAG_RD,
491280601Sarybchik			  SFXGE_VERSION_STRING, 0,
492280601Sarybchik			  "Driver version");
493280601Sarybchik
494227569Sphilip	/* Initialize the NVRAM. */
495227569Sphilip	if ((error = efx_nvram_init(enp)) != 0)
496227569Sphilip		goto fail6;
497227569Sphilip
498227569Sphilip	/* Initialize the VPD. */
499227569Sphilip	if ((error = efx_vpd_init(enp)) != 0)
500227569Sphilip		goto fail7;
501227569Sphilip
502227569Sphilip	/* Reset the NIC. */
503227569Sphilip	if ((error = efx_nic_reset(enp)) != 0)
504227569Sphilip		goto fail8;
505227569Sphilip
506227569Sphilip	/* Initialize buffer table allocation. */
507227569Sphilip	sc->buffer_table_next = 0;
508227569Sphilip
509227569Sphilip	/* Set up interrupts. */
510227569Sphilip	if ((error = sfxge_intr_init(sc)) != 0)
511227569Sphilip		goto fail8;
512227569Sphilip
513227569Sphilip	/* Initialize event processing state. */
514227569Sphilip	if ((error = sfxge_ev_init(sc)) != 0)
515227569Sphilip		goto fail11;
516227569Sphilip
517227569Sphilip	/* Initialize receive state. */
518227569Sphilip	if ((error = sfxge_rx_init(sc)) != 0)
519227569Sphilip		goto fail12;
520227569Sphilip
521227569Sphilip	/* Initialize transmit state. */
522227569Sphilip	if ((error = sfxge_tx_init(sc)) != 0)
523227569Sphilip		goto fail13;
524227569Sphilip
525227569Sphilip	/* Initialize port state. */
526227569Sphilip	if ((error = sfxge_port_init(sc)) != 0)
527227569Sphilip		goto fail14;
528227569Sphilip
529227569Sphilip	sc->init_state = SFXGE_INITIALIZED;
530227569Sphilip
531227569Sphilip	return (0);
532227569Sphilip
533227569Sphilipfail14:
534227569Sphilip	sfxge_tx_fini(sc);
535227569Sphilip
536227569Sphilipfail13:
537227569Sphilip	sfxge_rx_fini(sc);
538227569Sphilip
539227569Sphilipfail12:
540227569Sphilip	sfxge_ev_fini(sc);
541227569Sphilip
542227569Sphilipfail11:
543227569Sphilip	sfxge_intr_fini(sc);
544227569Sphilip
545227569Sphilipfail8:
546227569Sphilip	efx_vpd_fini(enp);
547227569Sphilip
548227569Sphilipfail7:
549227569Sphilip	efx_nvram_fini(enp);
550227569Sphilip
551227569Sphilipfail6:
552227569Sphilip	efx_nic_unprobe(enp);
553227569Sphilip
554227569Sphilipfail5:
555227569Sphilip	sfxge_mcdi_fini(sc);
556227569Sphilip
557227569Sphilipfail4:
558280502Sarybchikfail_tx_ring_entries:
559280502Sarybchikfail_rx_ring_entries:
560227569Sphilip	sc->enp = NULL;
561227569Sphilip	efx_nic_destroy(enp);
562280524Sarybchik	SFXGE_EFSYS_LOCK_DESTROY(&sc->enp_lock);
563227569Sphilip
564227569Sphilipfail3:
565227569Sphilip	sfxge_bar_fini(sc);
566227569Sphilip	(void) pci_disable_busmaster(sc->dev);
567227569Sphilip
568227569Sphilipfail:
569227569Sphilip	sc->dev = NULL;
570280522Sarybchik	SFXGE_ADAPTER_LOCK_DESTROY(sc);
571227569Sphilip	return (error);
572227569Sphilip}
573227569Sphilip
574227569Sphilipstatic void
575227569Sphilipsfxge_destroy(struct sfxge_softc *sc)
576227569Sphilip{
577227569Sphilip	efx_nic_t *enp;
578227569Sphilip
579227569Sphilip	/* Clean up port state. */
580227569Sphilip	sfxge_port_fini(sc);
581227569Sphilip
582227569Sphilip	/* Clean up transmit state. */
583227569Sphilip	sfxge_tx_fini(sc);
584227569Sphilip
585227569Sphilip	/* Clean up receive state. */
586227569Sphilip	sfxge_rx_fini(sc);
587227569Sphilip
588227569Sphilip	/* Clean up event processing state. */
589227569Sphilip	sfxge_ev_fini(sc);
590227569Sphilip
591227569Sphilip	/* Clean up interrupts. */
592227569Sphilip	sfxge_intr_fini(sc);
593227569Sphilip
594227569Sphilip	/* Tear down common code subsystems. */
595227569Sphilip	efx_nic_reset(sc->enp);
596227569Sphilip	efx_vpd_fini(sc->enp);
597227569Sphilip	efx_nvram_fini(sc->enp);
598227569Sphilip	efx_nic_unprobe(sc->enp);
599227569Sphilip
600227569Sphilip	/* Tear down MCDI. */
601227569Sphilip	sfxge_mcdi_fini(sc);
602227569Sphilip
603227569Sphilip	/* Destroy common code context. */
604227569Sphilip	enp = sc->enp;
605227569Sphilip	sc->enp = NULL;
606227569Sphilip	efx_nic_destroy(enp);
607227569Sphilip
608227569Sphilip	/* Free DMA memory. */
609227569Sphilip	sfxge_dma_fini(sc);
610227569Sphilip
611227569Sphilip	/* Free mapped BARs. */
612227569Sphilip	sfxge_bar_fini(sc);
613227569Sphilip
614227569Sphilip	(void) pci_disable_busmaster(sc->dev);
615227569Sphilip
616227569Sphilip	taskqueue_drain(taskqueue_thread, &sc->task_reset);
617227569Sphilip
618227569Sphilip	/* Destroy the softc lock. */
619280522Sarybchik	SFXGE_ADAPTER_LOCK_DESTROY(sc);
620227569Sphilip}
621227569Sphilip
622227569Sphilipstatic int
623227569Sphilipsfxge_vpd_handler(SYSCTL_HANDLER_ARGS)
624227569Sphilip{
625227569Sphilip	struct sfxge_softc *sc = arg1;
626227569Sphilip	efx_vpd_value_t value;
627227569Sphilip	int rc;
628280501Sarybchik
629227569Sphilip	value.evv_tag = arg2 >> 16;
630227569Sphilip	value.evv_keyword = arg2 & 0xffff;
631227569Sphilip	if ((rc = efx_vpd_get(sc->enp, sc->vpd_data, sc->vpd_size, &value))
632227569Sphilip	    != 0)
633280501Sarybchik		return (rc);
634227569Sphilip
635280501Sarybchik	return (SYSCTL_OUT(req, value.evv_value, value.evv_length));
636227569Sphilip}
637227569Sphilip
638227569Sphilipstatic void
639227569Sphilipsfxge_vpd_try_add(struct sfxge_softc *sc, struct sysctl_oid_list *list,
640227569Sphilip		  efx_vpd_tag_t tag, const char *keyword)
641227569Sphilip{
642227569Sphilip	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev);
643227569Sphilip	efx_vpd_value_t value;
644227569Sphilip
645227569Sphilip	/* Check whether VPD tag/keyword is present */
646227569Sphilip	value.evv_tag = tag;
647227569Sphilip	value.evv_keyword = EFX_VPD_KEYWORD(keyword[0], keyword[1]);
648227569Sphilip	if (efx_vpd_get(sc->enp, sc->vpd_data, sc->vpd_size, &value) != 0)
649227569Sphilip		return;
650227569Sphilip
651227569Sphilip	SYSCTL_ADD_PROC(
652227569Sphilip		ctx, list, OID_AUTO, keyword, CTLTYPE_STRING|CTLFLAG_RD,
653227569Sphilip		sc, tag << 16 | EFX_VPD_KEYWORD(keyword[0], keyword[1]),
654227569Sphilip		sfxge_vpd_handler, "A", "");
655227569Sphilip}
656227569Sphilip
657227569Sphilipstatic int
658227569Sphilipsfxge_vpd_init(struct sfxge_softc *sc)
659227569Sphilip{
660227569Sphilip	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev);
661227569Sphilip	struct sysctl_oid *vpd_node;
662227569Sphilip	struct sysctl_oid_list *vpd_list;
663227569Sphilip	char keyword[3];
664227569Sphilip	efx_vpd_value_t value;
665227569Sphilip	int rc;
666227569Sphilip
667227569Sphilip	if ((rc = efx_vpd_size(sc->enp, &sc->vpd_size)) != 0)
668227569Sphilip		goto fail;
669227569Sphilip	sc->vpd_data = malloc(sc->vpd_size, M_SFXGE, M_WAITOK);
670227569Sphilip	if ((rc = efx_vpd_read(sc->enp, sc->vpd_data, sc->vpd_size)) != 0)
671227569Sphilip		goto fail2;
672227569Sphilip
673227569Sphilip	/* Copy ID (product name) into device description, and log it. */
674227569Sphilip	value.evv_tag = EFX_VPD_ID;
675227569Sphilip	if (efx_vpd_get(sc->enp, sc->vpd_data, sc->vpd_size, &value) == 0) {
676227569Sphilip		value.evv_value[value.evv_length] = 0;
677227569Sphilip		device_set_desc_copy(sc->dev, value.evv_value);
678227569Sphilip		device_printf(sc->dev, "%s\n", value.evv_value);
679227569Sphilip	}
680227569Sphilip
681227569Sphilip	vpd_node = SYSCTL_ADD_NODE(
682227569Sphilip		ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)),
683227569Sphilip		OID_AUTO, "vpd", CTLFLAG_RD, NULL, "Vital Product Data");
684227569Sphilip	vpd_list = SYSCTL_CHILDREN(vpd_node);
685227569Sphilip
686227569Sphilip	/* Add sysctls for all expected and any vendor-defined keywords. */
687227569Sphilip	sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, "PN");
688227569Sphilip	sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, "EC");
689227569Sphilip	sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, "SN");
690227569Sphilip	keyword[0] = 'V';
691227569Sphilip	keyword[2] = 0;
692227569Sphilip	for (keyword[1] = '0'; keyword[1] <= '9'; keyword[1]++)
693227569Sphilip		sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, keyword);
694227569Sphilip	for (keyword[1] = 'A'; keyword[1] <= 'Z'; keyword[1]++)
695227569Sphilip		sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, keyword);
696227569Sphilip
697280501Sarybchik	return (0);
698280501Sarybchik
699227569Sphilipfail2:
700227569Sphilip	free(sc->vpd_data, M_SFXGE);
701227569Sphilipfail:
702280501Sarybchik	return (rc);
703227569Sphilip}
704227569Sphilip
705227569Sphilipstatic void
706227569Sphilipsfxge_vpd_fini(struct sfxge_softc *sc)
707227569Sphilip{
708227569Sphilip	free(sc->vpd_data, M_SFXGE);
709227569Sphilip}
710227569Sphilip
711227569Sphilipstatic void
712227569Sphilipsfxge_reset(void *arg, int npending)
713227569Sphilip{
714227569Sphilip	struct sfxge_softc *sc;
715227569Sphilip	int rc;
716227569Sphilip
717227569Sphilip	(void)npending;
718227569Sphilip
719227569Sphilip	sc = (struct sfxge_softc *)arg;
720227569Sphilip
721280522Sarybchik	SFXGE_ADAPTER_LOCK(sc);
722227569Sphilip
723227569Sphilip	if (sc->init_state != SFXGE_STARTED)
724227569Sphilip		goto done;
725227569Sphilip
726227569Sphilip	sfxge_stop(sc);
727227569Sphilip	efx_nic_reset(sc->enp);
728227569Sphilip	if ((rc = sfxge_start(sc)) != 0)
729227569Sphilip		device_printf(sc->dev,
730227569Sphilip			      "reset failed (%d); interface is now stopped\n",
731227569Sphilip			      rc);
732227569Sphilip
733227569Sphilipdone:
734280522Sarybchik	SFXGE_ADAPTER_UNLOCK(sc);
735227569Sphilip}
736227569Sphilip
737227569Sphilipvoid
738227569Sphilipsfxge_schedule_reset(struct sfxge_softc *sc)
739227569Sphilip{
740227569Sphilip	taskqueue_enqueue(taskqueue_thread, &sc->task_reset);
741227569Sphilip}
742227569Sphilip
743227569Sphilipstatic int
744227569Sphilipsfxge_attach(device_t dev)
745227569Sphilip{
746227569Sphilip	struct sfxge_softc *sc;
747227569Sphilip	struct ifnet *ifp;
748227569Sphilip	int error;
749227569Sphilip
750227569Sphilip	sc = device_get_softc(dev);
751227569Sphilip	sc->dev = dev;
752227569Sphilip
753227569Sphilip	/* Allocate ifnet. */
754227569Sphilip	ifp = if_alloc(IFT_ETHER);
755227569Sphilip	if (ifp == NULL) {
756227569Sphilip		device_printf(dev, "Couldn't allocate ifnet\n");
757227569Sphilip		error = ENOMEM;
758227569Sphilip		goto fail;
759227569Sphilip	}
760227569Sphilip	sc->ifnet = ifp;
761227569Sphilip
762227569Sphilip	/* Initialize hardware. */
763227569Sphilip	if ((error = sfxge_create(sc)) != 0)
764227569Sphilip		goto fail2;
765227569Sphilip
766227569Sphilip	/* Create the ifnet for the port. */
767227569Sphilip	if ((error = sfxge_ifnet_init(ifp, sc)) != 0)
768227569Sphilip		goto fail3;
769227569Sphilip
770227569Sphilip	if ((error = sfxge_vpd_init(sc)) != 0)
771227569Sphilip		goto fail4;
772227569Sphilip
773227569Sphilip	sc->init_state = SFXGE_REGISTERED;
774227569Sphilip
775227569Sphilip	return (0);
776227569Sphilip
777227569Sphilipfail4:
778227569Sphilip	sfxge_ifnet_fini(ifp);
779227569Sphilipfail3:
780227569Sphilip	sfxge_destroy(sc);
781227569Sphilip
782227569Sphilipfail2:
783227569Sphilip	if_free(sc->ifnet);
784227569Sphilip
785227569Sphilipfail:
786227569Sphilip	return (error);
787227569Sphilip}
788227569Sphilip
789227569Sphilipstatic int
790227569Sphilipsfxge_detach(device_t dev)
791227569Sphilip{
792227569Sphilip	struct sfxge_softc *sc;
793227569Sphilip
794227569Sphilip	sc = device_get_softc(dev);
795227569Sphilip
796227569Sphilip	sfxge_vpd_fini(sc);
797227569Sphilip
798227569Sphilip	/* Destroy the ifnet. */
799227569Sphilip	sfxge_ifnet_fini(sc->ifnet);
800227569Sphilip
801227569Sphilip	/* Tear down hardware. */
802227569Sphilip	sfxge_destroy(sc);
803227569Sphilip
804227569Sphilip	return (0);
805227569Sphilip}
806227569Sphilip
807227569Sphilipstatic int
808227569Sphilipsfxge_probe(device_t dev)
809227569Sphilip{
810227569Sphilip	uint16_t pci_vendor_id;
811227569Sphilip	uint16_t pci_device_id;
812227569Sphilip	efx_family_t family;
813227569Sphilip	int rc;
814227569Sphilip
815227569Sphilip	pci_vendor_id = pci_get_vendor(dev);
816227569Sphilip	pci_device_id = pci_get_device(dev);
817227569Sphilip
818227569Sphilip	rc = efx_family(pci_vendor_id, pci_device_id, &family);
819280501Sarybchik	if (rc != 0)
820280501Sarybchik		return (ENXIO);
821227569Sphilip
822227569Sphilip	KASSERT(family == EFX_FAMILY_SIENA, ("impossible controller family"));
823227569Sphilip	device_set_desc(dev, "Solarflare SFC9000 family");
824280501Sarybchik	return (0);
825227569Sphilip}
826227569Sphilip
827227569Sphilipstatic device_method_t sfxge_methods[] = {
828227569Sphilip	DEVMETHOD(device_probe,		sfxge_probe),
829227569Sphilip	DEVMETHOD(device_attach,	sfxge_attach),
830227569Sphilip	DEVMETHOD(device_detach,	sfxge_detach),
831227569Sphilip
832227843Smarius	DEVMETHOD_END
833227569Sphilip};
834227569Sphilip
835227569Sphilipstatic devclass_t sfxge_devclass;
836227569Sphilip
837227569Sphilipstatic driver_t sfxge_driver = {
838227569Sphilip	"sfxge",
839227569Sphilip	sfxge_methods,
840227569Sphilip	sizeof(struct sfxge_softc)
841227569Sphilip};
842227569Sphilip
843227569SphilipDRIVER_MODULE(sfxge, pci, sfxge_driver, sfxge_devclass, 0, 0);
844