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$");
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>
45227569Sphilip
46227569Sphilip#include <dev/pci/pcireg.h>
47227569Sphilip#include <dev/pci/pcivar.h>
48227569Sphilip
49227569Sphilip#include <net/ethernet.h>
50227569Sphilip#include <net/if.h>
51227569Sphilip#include <net/if_media.h>
52227569Sphilip#include <net/if_types.h>
53227569Sphilip
54227569Sphilip#include "common/efx.h"
55227569Sphilip
56227569Sphilip#include "sfxge.h"
57227569Sphilip#include "sfxge_rx.h"
58227569Sphilip
59227569Sphilip#define SFXGE_CAP (IFCAP_VLAN_MTU | \
60227569Sphilip		   IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO |	\
61227569Sphilip		   IFCAP_JUMBO_MTU | IFCAP_LRO |			\
62227569Sphilip		   IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE)
63227569Sphilip#define SFXGE_CAP_ENABLE SFXGE_CAP
64227569Sphilip#define SFXGE_CAP_FIXED (IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | \
65227569Sphilip			 IFCAP_JUMBO_MTU | IFCAP_LINKSTATE)
66227569Sphilip
67227569SphilipMALLOC_DEFINE(M_SFXGE, "sfxge", "Solarflare 10GigE driver");
68227569Sphilip
69227569Sphilipstatic void
70227569Sphilipsfxge_reset(void *arg, int npending);
71227569Sphilip
72227569Sphilipstatic int
73227569Sphilipsfxge_start(struct sfxge_softc *sc)
74227569Sphilip{
75227569Sphilip	int rc;
76227569Sphilip
77227569Sphilip	sx_assert(&sc->softc_lock, LA_XLOCKED);
78227569Sphilip
79227569Sphilip	if (sc->init_state == SFXGE_STARTED)
80227569Sphilip		return 0;
81227569Sphilip
82227569Sphilip	if (sc->init_state != SFXGE_REGISTERED) {
83227569Sphilip		rc = EINVAL;
84227569Sphilip		goto fail;
85227569Sphilip	}
86227569Sphilip
87227569Sphilip	if ((rc = efx_nic_init(sc->enp)) != 0)
88227569Sphilip		goto fail;
89227569Sphilip
90227569Sphilip	/* Start processing interrupts. */
91227569Sphilip	if ((rc = sfxge_intr_start(sc)) != 0)
92227569Sphilip		goto fail2;
93227569Sphilip
94227569Sphilip	/* Start processing events. */
95227569Sphilip	if ((rc = sfxge_ev_start(sc)) != 0)
96227569Sphilip		goto fail3;
97227569Sphilip
98227569Sphilip	/* Start the receiver side. */
99227569Sphilip	if ((rc = sfxge_rx_start(sc)) != 0)
100227569Sphilip		goto fail4;
101227569Sphilip
102227569Sphilip	/* Start the transmitter side. */
103227569Sphilip	if ((rc = sfxge_tx_start(sc)) != 0)
104227569Sphilip		goto fail5;
105227569Sphilip
106227569Sphilip	/* Fire up the port. */
107227569Sphilip	if ((rc = sfxge_port_start(sc)) != 0)
108227569Sphilip		goto fail6;
109227569Sphilip
110227569Sphilip	sc->init_state = SFXGE_STARTED;
111227569Sphilip
112227569Sphilip	/* Tell the stack we're running. */
113227569Sphilip	sc->ifnet->if_drv_flags |= IFF_DRV_RUNNING;
114227569Sphilip	sc->ifnet->if_drv_flags &= ~IFF_DRV_OACTIVE;
115227569Sphilip
116227569Sphilip	return (0);
117227569Sphilip
118227569Sphilipfail6:
119227569Sphilip	sfxge_tx_stop(sc);
120227569Sphilip
121227569Sphilipfail5:
122227569Sphilip	sfxge_rx_stop(sc);
123227569Sphilip
124227569Sphilipfail4:
125227569Sphilip	sfxge_ev_stop(sc);
126227569Sphilip
127227569Sphilipfail3:
128227569Sphilip	sfxge_intr_stop(sc);
129227569Sphilip
130227569Sphilipfail2:
131227569Sphilip	efx_nic_fini(sc->enp);
132227569Sphilip
133227569Sphilipfail:
134227569Sphilip	device_printf(sc->dev, "sfxge_start: %d\n", rc);
135227569Sphilip
136227569Sphilip	return (rc);
137227569Sphilip}
138227569Sphilip
139227569Sphilipstatic void
140227569Sphilipsfxge_if_init(void *arg)
141227569Sphilip{
142227569Sphilip	struct sfxge_softc *sc;
143227569Sphilip
144227569Sphilip	sc = (struct sfxge_softc *)arg;
145227569Sphilip
146227569Sphilip	sx_xlock(&sc->softc_lock);
147227569Sphilip	(void)sfxge_start(sc);
148227569Sphilip	sx_xunlock(&sc->softc_lock);
149227569Sphilip}
150227569Sphilip
151227569Sphilipstatic void
152227569Sphilipsfxge_stop(struct sfxge_softc *sc)
153227569Sphilip{
154227569Sphilip	sx_assert(&sc->softc_lock, LA_XLOCKED);
155227569Sphilip
156227569Sphilip	if (sc->init_state != SFXGE_STARTED)
157227569Sphilip		return;
158227569Sphilip
159227569Sphilip	sc->init_state = SFXGE_REGISTERED;
160227569Sphilip
161227569Sphilip	/* Stop the port. */
162227569Sphilip	sfxge_port_stop(sc);
163227569Sphilip
164227569Sphilip	/* Stop the transmitter. */
165227569Sphilip	sfxge_tx_stop(sc);
166227569Sphilip
167227569Sphilip	/* Stop the receiver. */
168227569Sphilip	sfxge_rx_stop(sc);
169227569Sphilip
170227569Sphilip	/* Stop processing events. */
171227569Sphilip	sfxge_ev_stop(sc);
172227569Sphilip
173227569Sphilip	/* Stop processing interrupts. */
174227569Sphilip	sfxge_intr_stop(sc);
175227569Sphilip
176227569Sphilip	efx_nic_fini(sc->enp);
177227569Sphilip
178227569Sphilip	sc->ifnet->if_drv_flags &= ~IFF_DRV_RUNNING;
179227569Sphilip}
180227569Sphilip
181227569Sphilipstatic int
182227569Sphilipsfxge_if_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data)
183227569Sphilip{
184227569Sphilip	struct sfxge_softc *sc;
185227569Sphilip	struct ifreq *ifr;
186227569Sphilip	int error;
187227569Sphilip
188227569Sphilip	ifr = (struct ifreq *)data;
189227569Sphilip	sc = ifp->if_softc;
190227569Sphilip	error = 0;
191227569Sphilip
192227569Sphilip	switch (command) {
193227569Sphilip	case SIOCSIFFLAGS:
194227569Sphilip		sx_xlock(&sc->softc_lock);
195227569Sphilip		if (ifp->if_flags & IFF_UP) {
196227569Sphilip			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
197227569Sphilip				if ((ifp->if_flags ^ sc->if_flags) &
198227569Sphilip				    (IFF_PROMISC | IFF_ALLMULTI)) {
199227569Sphilip					sfxge_mac_filter_set(sc);
200227569Sphilip				}
201227569Sphilip			} else
202227569Sphilip				sfxge_start(sc);
203227569Sphilip		} else
204227569Sphilip			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
205227569Sphilip				sfxge_stop(sc);
206227569Sphilip		sc->if_flags = ifp->if_flags;
207227569Sphilip		sx_xunlock(&sc->softc_lock);
208227569Sphilip		break;
209227569Sphilip	case SIOCSIFMTU:
210227569Sphilip		if (ifr->ifr_mtu == ifp->if_mtu) {
211227569Sphilip			/* Nothing to do */
212227569Sphilip			error = 0;
213227569Sphilip		} else if (ifr->ifr_mtu > SFXGE_MAX_MTU) {
214227569Sphilip			error = EINVAL;
215227569Sphilip		} else if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
216227569Sphilip			ifp->if_mtu = ifr->ifr_mtu;
217227569Sphilip			error = 0;
218227569Sphilip		} else {
219227569Sphilip			/* Restart required */
220227569Sphilip			sx_xlock(&sc->softc_lock);
221227569Sphilip			sfxge_stop(sc);
222227569Sphilip			ifp->if_mtu = ifr->ifr_mtu;
223227569Sphilip			error = sfxge_start(sc);
224227569Sphilip			sx_xunlock(&sc->softc_lock);
225227569Sphilip			if (error) {
226227569Sphilip				ifp->if_flags &= ~IFF_UP;
227227569Sphilip				ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
228227569Sphilip				if_down(ifp);
229227569Sphilip			}
230227569Sphilip		}
231227569Sphilip		break;
232227569Sphilip	case SIOCADDMULTI:
233227569Sphilip	case SIOCDELMULTI:
234227569Sphilip		if (ifp->if_drv_flags & IFF_DRV_RUNNING)
235227569Sphilip			sfxge_mac_filter_set(sc);
236227569Sphilip		break;
237227569Sphilip	case SIOCSIFCAP:
238227569Sphilip		sx_xlock(&sc->softc_lock);
239227569Sphilip
240227569Sphilip		/*
241227569Sphilip		 * The networking core already rejects attempts to
242227569Sphilip		 * enable capabilities we don't have.  We still have
243227569Sphilip		 * to reject attempts to disable capabilities that we
244227569Sphilip		 * can't (yet) disable.
245227569Sphilip		 */
246227569Sphilip		if (~ifr->ifr_reqcap & SFXGE_CAP_FIXED) {
247227569Sphilip			error = EINVAL;
248227569Sphilip			sx_xunlock(&sc->softc_lock);
249227569Sphilip			break;
250227569Sphilip		}
251227569Sphilip
252227569Sphilip		ifp->if_capenable = ifr->ifr_reqcap;
253227569Sphilip		if (ifp->if_capenable & IFCAP_TXCSUM)
254227569Sphilip			ifp->if_hwassist |= (CSUM_IP | CSUM_TCP | CSUM_UDP);
255227569Sphilip		else
256227569Sphilip			ifp->if_hwassist &= ~(CSUM_IP | CSUM_TCP | CSUM_UDP);
257227569Sphilip		if (ifp->if_capenable & IFCAP_TSO)
258227569Sphilip			ifp->if_hwassist |= CSUM_TSO;
259227569Sphilip		else
260227569Sphilip			ifp->if_hwassist &= ~CSUM_TSO;
261227569Sphilip
262227569Sphilip		sx_xunlock(&sc->softc_lock);
263227569Sphilip		break;
264227569Sphilip	case SIOCSIFMEDIA:
265227569Sphilip	case SIOCGIFMEDIA:
266227569Sphilip		error = ifmedia_ioctl(ifp, ifr, &sc->media, command);
267227569Sphilip		break;
268227569Sphilip	default:
269227569Sphilip		error = ether_ioctl(ifp, command, data);
270227569Sphilip	}
271227569Sphilip
272227569Sphilip	return (error);
273227569Sphilip}
274227569Sphilip
275227569Sphilipstatic void
276227569Sphilipsfxge_ifnet_fini(struct ifnet *ifp)
277227569Sphilip{
278227569Sphilip	struct sfxge_softc *sc = ifp->if_softc;
279227569Sphilip
280227569Sphilip	sx_xlock(&sc->softc_lock);
281227569Sphilip	sfxge_stop(sc);
282227569Sphilip	sx_xunlock(&sc->softc_lock);
283227569Sphilip
284227569Sphilip	ifmedia_removeall(&sc->media);
285227569Sphilip	ether_ifdetach(ifp);
286227569Sphilip	if_free(ifp);
287227569Sphilip}
288227569Sphilip
289227569Sphilipstatic int
290227569Sphilipsfxge_ifnet_init(struct ifnet *ifp, struct sfxge_softc *sc)
291227569Sphilip{
292227569Sphilip	const efx_nic_cfg_t *encp = efx_nic_cfg_get(sc->enp);
293227569Sphilip	device_t dev;
294227569Sphilip	int rc;
295227569Sphilip
296227569Sphilip	dev = sc->dev;
297227569Sphilip	sc->ifnet = ifp;
298227569Sphilip
299227569Sphilip	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
300227569Sphilip	ifp->if_init = sfxge_if_init;
301227569Sphilip	ifp->if_softc = sc;
302227569Sphilip	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
303227569Sphilip	ifp->if_ioctl = sfxge_if_ioctl;
304227569Sphilip
305227569Sphilip	ifp->if_capabilities = SFXGE_CAP;
306227569Sphilip	ifp->if_capenable = SFXGE_CAP_ENABLE;
307227569Sphilip	ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO;
308227569Sphilip
309227569Sphilip	ether_ifattach(ifp, encp->enc_mac_addr);
310227569Sphilip
311227569Sphilip#ifdef SFXGE_HAVE_MQ
312227569Sphilip	ifp->if_transmit = sfxge_if_transmit;
313227569Sphilip	ifp->if_qflush = sfxge_if_qflush;
314227569Sphilip#else
315227569Sphilip	ifp->if_start = sfxge_if_start;
316227569Sphilip	IFQ_SET_MAXLEN(&ifp->if_snd, SFXGE_NDESCS - 1);
317227569Sphilip	ifp->if_snd.ifq_drv_maxlen = SFXGE_NDESCS - 1;
318227569Sphilip	IFQ_SET_READY(&ifp->if_snd);
319227569Sphilip
320227569Sphilip	mtx_init(&sc->tx_lock, "txq", NULL, MTX_DEF);
321227569Sphilip#endif
322227569Sphilip
323227569Sphilip	if ((rc = sfxge_port_ifmedia_init(sc)) != 0)
324227569Sphilip		goto fail;
325227569Sphilip
326227569Sphilip	return 0;
327227569Sphilip
328227569Sphilipfail:
329227569Sphilip	ether_ifdetach(sc->ifnet);
330227569Sphilip	return rc;
331227569Sphilip}
332227569Sphilip
333227569Sphilipvoid
334227569Sphilipsfxge_sram_buf_tbl_alloc(struct sfxge_softc *sc, size_t n, uint32_t *idp)
335227569Sphilip{
336227569Sphilip	KASSERT(sc->buffer_table_next + n <=
337227569Sphilip		efx_nic_cfg_get(sc->enp)->enc_buftbl_limit,
338227569Sphilip		("buffer table full"));
339227569Sphilip
340227569Sphilip	*idp = sc->buffer_table_next;
341227569Sphilip	sc->buffer_table_next += n;
342227569Sphilip}
343227569Sphilip
344227569Sphilipstatic int
345227569Sphilipsfxge_bar_init(struct sfxge_softc *sc)
346227569Sphilip{
347227569Sphilip	efsys_bar_t *esbp = &sc->bar;
348227569Sphilip
349227569Sphilip	esbp->esb_rid = PCIR_BAR(EFX_MEM_BAR);
350227569Sphilip	if ((esbp->esb_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
351227569Sphilip	    &esbp->esb_rid, RF_ACTIVE)) == NULL) {
352227569Sphilip		device_printf(sc->dev, "Cannot allocate BAR region %d\n",
353227569Sphilip		    EFX_MEM_BAR);
354227569Sphilip		return (ENXIO);
355227569Sphilip	}
356227569Sphilip	esbp->esb_tag = rman_get_bustag(esbp->esb_res);
357227569Sphilip	esbp->esb_handle = rman_get_bushandle(esbp->esb_res);
358227569Sphilip	mtx_init(&esbp->esb_lock, "sfxge_efsys_bar", NULL, MTX_DEF);
359227569Sphilip
360227569Sphilip	return (0);
361227569Sphilip}
362227569Sphilip
363227569Sphilipstatic void
364227569Sphilipsfxge_bar_fini(struct sfxge_softc *sc)
365227569Sphilip{
366227569Sphilip	efsys_bar_t *esbp = &sc->bar;
367227569Sphilip
368227569Sphilip	bus_release_resource(sc->dev, SYS_RES_MEMORY, esbp->esb_rid,
369227569Sphilip	    esbp->esb_res);
370227569Sphilip	mtx_destroy(&esbp->esb_lock);
371227569Sphilip}
372227569Sphilip
373227569Sphilipstatic int
374227569Sphilipsfxge_create(struct sfxge_softc *sc)
375227569Sphilip{
376227569Sphilip	device_t dev;
377227569Sphilip	efx_nic_t *enp;
378227569Sphilip	int error;
379227569Sphilip
380227569Sphilip	dev = sc->dev;
381227569Sphilip
382227569Sphilip	sx_init(&sc->softc_lock, "sfxge_softc");
383227569Sphilip
384227569Sphilip	sc->stats_node = SYSCTL_ADD_NODE(
385227569Sphilip		device_get_sysctl_ctx(dev),
386227569Sphilip		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
387227569Sphilip		OID_AUTO, "stats", CTLFLAG_RD, NULL, "Statistics");
388227569Sphilip	if (!sc->stats_node) {
389227569Sphilip		error = ENOMEM;
390227569Sphilip		goto fail;
391227569Sphilip	}
392227569Sphilip
393227569Sphilip	TASK_INIT(&sc->task_reset, 0, sfxge_reset, sc);
394227569Sphilip
395227569Sphilip	(void) pci_enable_busmaster(dev);
396227569Sphilip
397227569Sphilip	/* Initialize DMA mappings. */
398227569Sphilip	if ((error = sfxge_dma_init(sc)) != 0)
399227569Sphilip		goto fail;
400227569Sphilip
401227569Sphilip	/* Map the device registers. */
402227569Sphilip	if ((error = sfxge_bar_init(sc)) != 0)
403227569Sphilip		goto fail;
404227569Sphilip
405227569Sphilip	error = efx_family(pci_get_vendor(dev), pci_get_device(dev),
406227569Sphilip	    &sc->family);
407227569Sphilip	KASSERT(error == 0, ("Family should be filtered by sfxge_probe()"));
408227569Sphilip
409227569Sphilip	/* Create the common code nic object. */
410227569Sphilip	mtx_init(&sc->enp_lock, "sfxge_nic", NULL, MTX_DEF);
411227569Sphilip	if ((error = efx_nic_create(sc->family, (efsys_identifier_t *)sc,
412227569Sphilip	    &sc->bar, &sc->enp_lock, &enp)) != 0)
413227569Sphilip		goto fail3;
414227569Sphilip	sc->enp = enp;
415227569Sphilip
416227569Sphilip	/* Initialize MCDI to talk to the microcontroller. */
417227569Sphilip	if ((error = sfxge_mcdi_init(sc)) != 0)
418227569Sphilip		goto fail4;
419227569Sphilip
420227569Sphilip	/* Probe the NIC and build the configuration data area. */
421227569Sphilip	if ((error = efx_nic_probe(enp)) != 0)
422227569Sphilip		goto fail5;
423227569Sphilip
424227569Sphilip	/* Initialize the NVRAM. */
425227569Sphilip	if ((error = efx_nvram_init(enp)) != 0)
426227569Sphilip		goto fail6;
427227569Sphilip
428227569Sphilip	/* Initialize the VPD. */
429227569Sphilip	if ((error = efx_vpd_init(enp)) != 0)
430227569Sphilip		goto fail7;
431227569Sphilip
432227569Sphilip	/* Reset the NIC. */
433227569Sphilip	if ((error = efx_nic_reset(enp)) != 0)
434227569Sphilip		goto fail8;
435227569Sphilip
436227569Sphilip	/* Initialize buffer table allocation. */
437227569Sphilip	sc->buffer_table_next = 0;
438227569Sphilip
439227569Sphilip	/* Set up interrupts. */
440227569Sphilip	if ((error = sfxge_intr_init(sc)) != 0)
441227569Sphilip		goto fail8;
442227569Sphilip
443227569Sphilip	/* Initialize event processing state. */
444227569Sphilip	if ((error = sfxge_ev_init(sc)) != 0)
445227569Sphilip		goto fail11;
446227569Sphilip
447227569Sphilip	/* Initialize receive state. */
448227569Sphilip	if ((error = sfxge_rx_init(sc)) != 0)
449227569Sphilip		goto fail12;
450227569Sphilip
451227569Sphilip	/* Initialize transmit state. */
452227569Sphilip	if ((error = sfxge_tx_init(sc)) != 0)
453227569Sphilip		goto fail13;
454227569Sphilip
455227569Sphilip	/* Initialize port state. */
456227569Sphilip	if ((error = sfxge_port_init(sc)) != 0)
457227569Sphilip		goto fail14;
458227569Sphilip
459227569Sphilip	sc->init_state = SFXGE_INITIALIZED;
460227569Sphilip
461227569Sphilip	return (0);
462227569Sphilip
463227569Sphilipfail14:
464227569Sphilip	sfxge_tx_fini(sc);
465227569Sphilip
466227569Sphilipfail13:
467227569Sphilip	sfxge_rx_fini(sc);
468227569Sphilip
469227569Sphilipfail12:
470227569Sphilip	sfxge_ev_fini(sc);
471227569Sphilip
472227569Sphilipfail11:
473227569Sphilip	sfxge_intr_fini(sc);
474227569Sphilip
475227569Sphilipfail8:
476227569Sphilip	efx_vpd_fini(enp);
477227569Sphilip
478227569Sphilipfail7:
479227569Sphilip	efx_nvram_fini(enp);
480227569Sphilip
481227569Sphilipfail6:
482227569Sphilip	efx_nic_unprobe(enp);
483227569Sphilip
484227569Sphilipfail5:
485227569Sphilip	sfxge_mcdi_fini(sc);
486227569Sphilip
487227569Sphilipfail4:
488227569Sphilip	sc->enp = NULL;
489227569Sphilip	efx_nic_destroy(enp);
490227569Sphilip	mtx_destroy(&sc->enp_lock);
491227569Sphilip
492227569Sphilipfail3:
493227569Sphilip	sfxge_bar_fini(sc);
494227569Sphilip	(void) pci_disable_busmaster(sc->dev);
495227569Sphilip
496227569Sphilipfail:
497227569Sphilip	sc->dev = NULL;
498227569Sphilip	sx_destroy(&sc->softc_lock);
499227569Sphilip	return (error);
500227569Sphilip}
501227569Sphilip
502227569Sphilipstatic void
503227569Sphilipsfxge_destroy(struct sfxge_softc *sc)
504227569Sphilip{
505227569Sphilip	efx_nic_t *enp;
506227569Sphilip
507227569Sphilip	/* Clean up port state. */
508227569Sphilip	sfxge_port_fini(sc);
509227569Sphilip
510227569Sphilip	/* Clean up transmit state. */
511227569Sphilip	sfxge_tx_fini(sc);
512227569Sphilip
513227569Sphilip	/* Clean up receive state. */
514227569Sphilip	sfxge_rx_fini(sc);
515227569Sphilip
516227569Sphilip	/* Clean up event processing state. */
517227569Sphilip	sfxge_ev_fini(sc);
518227569Sphilip
519227569Sphilip	/* Clean up interrupts. */
520227569Sphilip	sfxge_intr_fini(sc);
521227569Sphilip
522227569Sphilip	/* Tear down common code subsystems. */
523227569Sphilip	efx_nic_reset(sc->enp);
524227569Sphilip	efx_vpd_fini(sc->enp);
525227569Sphilip	efx_nvram_fini(sc->enp);
526227569Sphilip	efx_nic_unprobe(sc->enp);
527227569Sphilip
528227569Sphilip	/* Tear down MCDI. */
529227569Sphilip	sfxge_mcdi_fini(sc);
530227569Sphilip
531227569Sphilip	/* Destroy common code context. */
532227569Sphilip	enp = sc->enp;
533227569Sphilip	sc->enp = NULL;
534227569Sphilip	efx_nic_destroy(enp);
535227569Sphilip
536227569Sphilip	/* Free DMA memory. */
537227569Sphilip	sfxge_dma_fini(sc);
538227569Sphilip
539227569Sphilip	/* Free mapped BARs. */
540227569Sphilip	sfxge_bar_fini(sc);
541227569Sphilip
542227569Sphilip	(void) pci_disable_busmaster(sc->dev);
543227569Sphilip
544227569Sphilip	taskqueue_drain(taskqueue_thread, &sc->task_reset);
545227569Sphilip
546227569Sphilip	/* Destroy the softc lock. */
547227569Sphilip	sx_destroy(&sc->softc_lock);
548227569Sphilip}
549227569Sphilip
550227569Sphilipstatic int
551227569Sphilipsfxge_vpd_handler(SYSCTL_HANDLER_ARGS)
552227569Sphilip{
553227569Sphilip	struct sfxge_softc *sc = arg1;
554227569Sphilip	efx_vpd_value_t value;
555227569Sphilip	int rc;
556227569Sphilip
557227569Sphilip	value.evv_tag = arg2 >> 16;
558227569Sphilip	value.evv_keyword = arg2 & 0xffff;
559227569Sphilip	if ((rc = efx_vpd_get(sc->enp, sc->vpd_data, sc->vpd_size, &value))
560227569Sphilip	    != 0)
561227569Sphilip		return rc;
562227569Sphilip
563227569Sphilip	return SYSCTL_OUT(req, value.evv_value, value.evv_length);
564227569Sphilip}
565227569Sphilip
566227569Sphilipstatic void
567227569Sphilipsfxge_vpd_try_add(struct sfxge_softc *sc, struct sysctl_oid_list *list,
568227569Sphilip		  efx_vpd_tag_t tag, const char *keyword)
569227569Sphilip{
570227569Sphilip	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev);
571227569Sphilip	efx_vpd_value_t value;
572227569Sphilip
573227569Sphilip	/* Check whether VPD tag/keyword is present */
574227569Sphilip	value.evv_tag = tag;
575227569Sphilip	value.evv_keyword = EFX_VPD_KEYWORD(keyword[0], keyword[1]);
576227569Sphilip	if (efx_vpd_get(sc->enp, sc->vpd_data, sc->vpd_size, &value) != 0)
577227569Sphilip		return;
578227569Sphilip
579227569Sphilip	SYSCTL_ADD_PROC(
580227569Sphilip		ctx, list, OID_AUTO, keyword, CTLTYPE_STRING|CTLFLAG_RD,
581227569Sphilip		sc, tag << 16 | EFX_VPD_KEYWORD(keyword[0], keyword[1]),
582227569Sphilip		sfxge_vpd_handler, "A", "");
583227569Sphilip}
584227569Sphilip
585227569Sphilipstatic int
586227569Sphilipsfxge_vpd_init(struct sfxge_softc *sc)
587227569Sphilip{
588227569Sphilip	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev);
589227569Sphilip	struct sysctl_oid *vpd_node;
590227569Sphilip	struct sysctl_oid_list *vpd_list;
591227569Sphilip	char keyword[3];
592227569Sphilip	efx_vpd_value_t value;
593227569Sphilip	int rc;
594227569Sphilip
595227569Sphilip	if ((rc = efx_vpd_size(sc->enp, &sc->vpd_size)) != 0)
596227569Sphilip		goto fail;
597227569Sphilip	sc->vpd_data = malloc(sc->vpd_size, M_SFXGE, M_WAITOK);
598227569Sphilip	if ((rc = efx_vpd_read(sc->enp, sc->vpd_data, sc->vpd_size)) != 0)
599227569Sphilip		goto fail2;
600227569Sphilip
601227569Sphilip	/* Copy ID (product name) into device description, and log it. */
602227569Sphilip	value.evv_tag = EFX_VPD_ID;
603227569Sphilip	if (efx_vpd_get(sc->enp, sc->vpd_data, sc->vpd_size, &value) == 0) {
604227569Sphilip		value.evv_value[value.evv_length] = 0;
605227569Sphilip		device_set_desc_copy(sc->dev, value.evv_value);
606227569Sphilip		device_printf(sc->dev, "%s\n", value.evv_value);
607227569Sphilip	}
608227569Sphilip
609227569Sphilip	vpd_node = SYSCTL_ADD_NODE(
610227569Sphilip		ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)),
611227569Sphilip		OID_AUTO, "vpd", CTLFLAG_RD, NULL, "Vital Product Data");
612227569Sphilip	vpd_list = SYSCTL_CHILDREN(vpd_node);
613227569Sphilip
614227569Sphilip	/* Add sysctls for all expected and any vendor-defined keywords. */
615227569Sphilip	sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, "PN");
616227569Sphilip	sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, "EC");
617227569Sphilip	sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, "SN");
618227569Sphilip	keyword[0] = 'V';
619227569Sphilip	keyword[2] = 0;
620227569Sphilip	for (keyword[1] = '0'; keyword[1] <= '9'; keyword[1]++)
621227569Sphilip		sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, keyword);
622227569Sphilip	for (keyword[1] = 'A'; keyword[1] <= 'Z'; keyword[1]++)
623227569Sphilip		sfxge_vpd_try_add(sc, vpd_list, EFX_VPD_RO, keyword);
624227569Sphilip
625227569Sphilip	return 0;
626227569Sphilip
627227569Sphilipfail2:
628227569Sphilip	free(sc->vpd_data, M_SFXGE);
629227569Sphilipfail:
630227569Sphilip	return rc;
631227569Sphilip}
632227569Sphilip
633227569Sphilipstatic void
634227569Sphilipsfxge_vpd_fini(struct sfxge_softc *sc)
635227569Sphilip{
636227569Sphilip	free(sc->vpd_data, M_SFXGE);
637227569Sphilip}
638227569Sphilip
639227569Sphilipstatic void
640227569Sphilipsfxge_reset(void *arg, int npending)
641227569Sphilip{
642227569Sphilip	struct sfxge_softc *sc;
643227569Sphilip	int rc;
644227569Sphilip
645227569Sphilip	(void)npending;
646227569Sphilip
647227569Sphilip	sc = (struct sfxge_softc *)arg;
648227569Sphilip
649227569Sphilip	sx_xlock(&sc->softc_lock);
650227569Sphilip
651227569Sphilip	if (sc->init_state != SFXGE_STARTED)
652227569Sphilip		goto done;
653227569Sphilip
654227569Sphilip	sfxge_stop(sc);
655227569Sphilip	efx_nic_reset(sc->enp);
656227569Sphilip	if ((rc = sfxge_start(sc)) != 0)
657227569Sphilip		device_printf(sc->dev,
658227569Sphilip			      "reset failed (%d); interface is now stopped\n",
659227569Sphilip			      rc);
660227569Sphilip
661227569Sphilipdone:
662227569Sphilip	sx_xunlock(&sc->softc_lock);
663227569Sphilip}
664227569Sphilip
665227569Sphilipvoid
666227569Sphilipsfxge_schedule_reset(struct sfxge_softc *sc)
667227569Sphilip{
668227569Sphilip	taskqueue_enqueue(taskqueue_thread, &sc->task_reset);
669227569Sphilip}
670227569Sphilip
671227569Sphilipstatic int
672227569Sphilipsfxge_attach(device_t dev)
673227569Sphilip{
674227569Sphilip	struct sfxge_softc *sc;
675227569Sphilip	struct ifnet *ifp;
676227569Sphilip	int error;
677227569Sphilip
678227569Sphilip	sc = device_get_softc(dev);
679227569Sphilip	sc->dev = dev;
680227569Sphilip
681227569Sphilip	/* Allocate ifnet. */
682227569Sphilip	ifp = if_alloc(IFT_ETHER);
683227569Sphilip	if (ifp == NULL) {
684227569Sphilip		device_printf(dev, "Couldn't allocate ifnet\n");
685227569Sphilip		error = ENOMEM;
686227569Sphilip		goto fail;
687227569Sphilip	}
688227569Sphilip	sc->ifnet = ifp;
689227569Sphilip
690227569Sphilip	/* Initialize hardware. */
691227569Sphilip	if ((error = sfxge_create(sc)) != 0)
692227569Sphilip		goto fail2;
693227569Sphilip
694227569Sphilip	/* Create the ifnet for the port. */
695227569Sphilip	if ((error = sfxge_ifnet_init(ifp, sc)) != 0)
696227569Sphilip		goto fail3;
697227569Sphilip
698227569Sphilip	if ((error = sfxge_vpd_init(sc)) != 0)
699227569Sphilip		goto fail4;
700227569Sphilip
701227569Sphilip	sc->init_state = SFXGE_REGISTERED;
702227569Sphilip
703227569Sphilip	return (0);
704227569Sphilip
705227569Sphilipfail4:
706227569Sphilip	sfxge_ifnet_fini(ifp);
707227569Sphilipfail3:
708227569Sphilip	sfxge_destroy(sc);
709227569Sphilip
710227569Sphilipfail2:
711227569Sphilip	if_free(sc->ifnet);
712227569Sphilip
713227569Sphilipfail:
714227569Sphilip	return (error);
715227569Sphilip}
716227569Sphilip
717227569Sphilipstatic int
718227569Sphilipsfxge_detach(device_t dev)
719227569Sphilip{
720227569Sphilip	struct sfxge_softc *sc;
721227569Sphilip
722227569Sphilip	sc = device_get_softc(dev);
723227569Sphilip
724227569Sphilip	sfxge_vpd_fini(sc);
725227569Sphilip
726227569Sphilip	/* Destroy the ifnet. */
727227569Sphilip	sfxge_ifnet_fini(sc->ifnet);
728227569Sphilip
729227569Sphilip	/* Tear down hardware. */
730227569Sphilip	sfxge_destroy(sc);
731227569Sphilip
732227569Sphilip	return (0);
733227569Sphilip}
734227569Sphilip
735227569Sphilipstatic int
736227569Sphilipsfxge_probe(device_t dev)
737227569Sphilip{
738227569Sphilip	uint16_t pci_vendor_id;
739227569Sphilip	uint16_t pci_device_id;
740227569Sphilip	efx_family_t family;
741227569Sphilip	int rc;
742227569Sphilip
743227569Sphilip	pci_vendor_id = pci_get_vendor(dev);
744227569Sphilip	pci_device_id = pci_get_device(dev);
745227569Sphilip
746227569Sphilip	rc = efx_family(pci_vendor_id, pci_device_id, &family);
747227569Sphilip	if (rc)
748227569Sphilip		return ENXIO;
749227569Sphilip
750227569Sphilip	KASSERT(family == EFX_FAMILY_SIENA, ("impossible controller family"));
751227569Sphilip	device_set_desc(dev, "Solarflare SFC9000 family");
752227569Sphilip	return 0;
753227569Sphilip}
754227569Sphilip
755227569Sphilipstatic device_method_t sfxge_methods[] = {
756227569Sphilip	DEVMETHOD(device_probe,		sfxge_probe),
757227569Sphilip	DEVMETHOD(device_attach,	sfxge_attach),
758227569Sphilip	DEVMETHOD(device_detach,	sfxge_detach),
759227569Sphilip
760227843Smarius	DEVMETHOD_END
761227569Sphilip};
762227569Sphilip
763227569Sphilipstatic devclass_t sfxge_devclass;
764227569Sphilip
765227569Sphilipstatic driver_t sfxge_driver = {
766227569Sphilip	"sfxge",
767227569Sphilip	sfxge_methods,
768227569Sphilip	sizeof(struct sfxge_softc)
769227569Sphilip};
770227569Sphilip
771227569SphilipDRIVER_MODULE(sfxge, pci, sfxge_driver, sfxge_devclass, 0, 0);
772