if_txp.c revision 113038
1227569Sphilip/*	$OpenBSD: if_txp.c,v 1.48 2001/06/27 06:34:50 kjc Exp $	*/
2227569Sphilip
3227569Sphilip/*
4227569Sphilip * Copyright (c) 2001
5227569Sphilip *	Jason L. Wright <jason@thought.net>, Theo de Raadt, and
6227569Sphilip *	Aaron Campbell <aaron@monkey.org>.  All rights reserved.
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 * 3. All advertising materials mentioning features or use of this software
17227569Sphilip *    must display the following acknowledgement:
18227569Sphilip *	This product includes software developed by Jason L. Wright,
19227569Sphilip *	Theo de Raadt and Aaron Campbell.
20227569Sphilip * 4. Neither the name of the author nor the names of any co-contributors
21227569Sphilip *    may be used to endorse or promote products derived from this software
22227569Sphilip *    without specific prior written permission.
23227569Sphilip *
24227569Sphilip * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
25227569Sphilip * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26227569Sphilip * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27227569Sphilip * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
28227569Sphilip * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29227569Sphilip * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30227569Sphilip * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31227569Sphilip * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32227569Sphilip * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33227569Sphilip * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34227569Sphilip * THE POSSIBILITY OF SUCH DAMAGE.
35227569Sphilip */
36227569Sphilip
37227569Sphilip/*
38227569Sphilip * Driver for 3c990 (Typhoon) Ethernet ASIC
39227569Sphilip */
40227569Sphilip
41227569Sphilip#include <sys/cdefs.h>
42227569Sphilip__FBSDID("$FreeBSD: head/sys/dev/txp/if_txp.c 113038 2003-04-03 21:36:33Z obrien $");
43227569Sphilip
44227569Sphilip#include <sys/param.h>
45227569Sphilip#include <sys/systm.h>
46227569Sphilip#include <sys/sockio.h>
47227569Sphilip#include <sys/mbuf.h>
48227569Sphilip#include <sys/malloc.h>
49227569Sphilip#include <sys/kernel.h>
50227569Sphilip#include <sys/socket.h>
51227569Sphilip
52227569Sphilip#include <net/if.h>
53227569Sphilip#include <net/if_arp.h>
54227569Sphilip#include <net/ethernet.h>
55227569Sphilip#include <net/if_dl.h>
56227569Sphilip#include <net/if_types.h>
57227569Sphilip#include <net/if_vlan_var.h>
58227569Sphilip
59227569Sphilip#include <netinet/in.h>
60227569Sphilip#include <netinet/in_systm.h>
61227569Sphilip#include <netinet/in_var.h>
62227569Sphilip#include <netinet/ip.h>
63227569Sphilip#include <netinet/if_ether.h>
64227569Sphilip#include <machine/in_cksum.h>
65227569Sphilip
66227569Sphilip#include <net/if_media.h>
67227569Sphilip
68227700Sphilip#include <net/bpf.h>
69227569Sphilip
70227569Sphilip#include <vm/vm.h>              /* for vtophys */
71227569Sphilip#include <vm/pmap.h>            /* for vtophys */
72227569Sphilip#include <machine/clock.h>	/* for DELAY */
73227569Sphilip#include <machine/bus_pio.h>
74227569Sphilip#include <machine/bus_memio.h>
75227569Sphilip#include <machine/bus.h>
76227569Sphilip#include <machine/resource.h>
77227569Sphilip#include <sys/bus.h>
78227569Sphilip#include <sys/rman.h>
79227569Sphilip
80227569Sphilip#include <dev/mii/mii.h>
81227569Sphilip#include <dev/mii/miivar.h>
82227569Sphilip#include <dev/pci/pcireg.h>
83227569Sphilip#include <dev/pci/pcivar.h>
84227569Sphilip
85227569Sphilip#define TXP_USEIOSPACE
86227569Sphilip#define __STRICT_ALIGNMENT
87227569Sphilip
88227569Sphilip#include <dev/txp/if_txpreg.h>
89227569Sphilip#include <dev/txp/3c990img.h>
90227569Sphilip
91227569Sphilip#ifndef lint
92227569Sphilipstatic const char rcsid[] =
93227569Sphilip  "$FreeBSD: head/sys/dev/txp/if_txp.c 113038 2003-04-03 21:36:33Z obrien $";
94227569Sphilip#endif
95227569Sphilip
96227569Sphilip/*
97227569Sphilip * Various supported device vendors/types and their names.
98227569Sphilip */
99227569Sphilipstatic struct txp_type txp_devs[] = {
100227569Sphilip	{ TXP_VENDORID_3COM, TXP_DEVICEID_3CR990_TX_95,
101227569Sphilip	    "3Com 3cR990-TX-95 Etherlink with 3XP Processor" },
102227569Sphilip	{ TXP_VENDORID_3COM, TXP_DEVICEID_3CR990_TX_97,
103227569Sphilip	    "3Com 3cR990-TX-97 Etherlink with 3XP Processor" },
104227569Sphilip	{ TXP_VENDORID_3COM, TXP_DEVICEID_3CR990B_TXM,
105227569Sphilip	    "3Com 3cR990B-TXM Etherlink with 3XP Processor" },
106227569Sphilip	{ TXP_VENDORID_3COM, TXP_DEVICEID_3CR990_SRV_95,
107227569Sphilip	    "3Com 3cR990-SRV-95 Etherlink Server with 3XP Processor" },
108227569Sphilip	{ TXP_VENDORID_3COM, TXP_DEVICEID_3CR990_SRV_97,
109227569Sphilip	    "3Com 3cR990-SRV-97 Etherlink Server with 3XP Processor" },
110227569Sphilip	{ TXP_VENDORID_3COM, TXP_DEVICEID_3CR990B_SRV,
111227569Sphilip	    "3Com 3cR990B-SRV Etherlink Server with 3XP Processor" },
112227569Sphilip	{ 0, 0, NULL }
113227569Sphilip};
114227569Sphilip
115227569Sphilipstatic int txp_probe	(device_t);
116227569Sphilipstatic int txp_attach	(device_t);
117227569Sphilipstatic int txp_detach	(device_t);
118227569Sphilipstatic void txp_intr	(void *);
119227569Sphilipstatic void txp_tick	(void *);
120227569Sphilipstatic int txp_shutdown	(device_t);
121227569Sphilipstatic int txp_ioctl	(struct ifnet *, u_long, caddr_t);
122227569Sphilipstatic void txp_start	(struct ifnet *);
123227569Sphilipstatic void txp_stop	(struct txp_softc *);
124227569Sphilipstatic void txp_init	(void *);
125227569Sphilipstatic void txp_watchdog	(struct ifnet *);
126227569Sphilip
127227569Sphilipstatic void txp_release_resources(struct txp_softc *);
128227569Sphilipstatic int txp_chip_init(struct txp_softc *);
129227569Sphilipstatic int txp_reset_adapter(struct txp_softc *);
130227569Sphilipstatic int txp_download_fw(struct txp_softc *);
131227569Sphilipstatic int txp_download_fw_wait(struct txp_softc *);
132227569Sphilipstatic int txp_download_fw_section (struct txp_softc *,
133227569Sphilip    struct txp_fw_section_header *, int);
134227700Sphilipstatic int txp_alloc_rings(struct txp_softc *);
135227569Sphilipstatic int txp_rxring_fill(struct txp_softc *);
136227569Sphilipstatic void txp_rxring_empty(struct txp_softc *);
137227569Sphilipstatic void txp_set_filter(struct txp_softc *);
138227569Sphilip
139227569Sphilipstatic int txp_cmd_desc_numfree(struct txp_softc *);
140227569Sphilipstatic int txp_command (struct txp_softc *, u_int16_t, u_int16_t, u_int32_t,
141227569Sphilip    u_int32_t, u_int16_t *, u_int32_t *, u_int32_t *, int);
142227569Sphilipstatic int txp_command2 (struct txp_softc *, u_int16_t, u_int16_t,
143227569Sphilip    u_int32_t, u_int32_t, struct txp_ext_desc *, u_int8_t,
144227569Sphilip    struct txp_rsp_desc **, int);
145227569Sphilipstatic int txp_response (struct txp_softc *, u_int32_t, u_int16_t, u_int16_t,
146227569Sphilip    struct txp_rsp_desc **);
147227569Sphilipstatic void txp_rsp_fixup (struct txp_softc *, struct txp_rsp_desc *,
148227569Sphilip    struct txp_rsp_desc *);
149227569Sphilipstatic void txp_capabilities(struct txp_softc *);
150227569Sphilip
151227569Sphilipstatic void txp_ifmedia_sts(struct ifnet *, struct ifmediareq *);
152227569Sphilipstatic int txp_ifmedia_upd(struct ifnet *);
153227569Sphilip#ifdef TXP_DEBUG
154227569Sphilipstatic void txp_show_descriptor(void *);
155227569Sphilip#endif
156227569Sphilipstatic void txp_tx_reclaim(struct txp_softc *, struct txp_tx_ring *);
157227569Sphilipstatic void txp_rxbuf_reclaim(struct txp_softc *);
158227569Sphilipstatic void txp_rx_reclaim(struct txp_softc *, struct txp_rx_ring *);
159227569Sphilip
160227569Sphilip#ifdef TXP_USEIOSPACE
161227569Sphilip#define TXP_RES			SYS_RES_IOPORT
162227569Sphilip#define TXP_RID			TXP_PCI_LOIO
163227569Sphilip#else
164227569Sphilip#define TXP_RES			SYS_RES_MEMORY
165227569Sphilip#define TXP_RID			TXP_PCI_LOMEM
166227569Sphilip#endif
167227569Sphilip
168227569Sphilipstatic device_method_t txp_methods[] = {
169227569Sphilip        /* Device interface */
170227569Sphilip	DEVMETHOD(device_probe,		txp_probe),
171227569Sphilip	DEVMETHOD(device_attach,	txp_attach),
172227569Sphilip	DEVMETHOD(device_detach,	txp_detach),
173227569Sphilip	DEVMETHOD(device_shutdown,	txp_shutdown),
174227569Sphilip	{ 0, 0 }
175227569Sphilip};
176227569Sphilip
177227569Sphilipstatic driver_t txp_driver = {
178227569Sphilip	"txp",
179227569Sphilip	txp_methods,
180227569Sphilip	sizeof(struct txp_softc)
181227569Sphilip};
182227569Sphilip
183227569Sphilipstatic devclass_t txp_devclass;
184227569Sphilip
185227569SphilipDRIVER_MODULE(if_txp, pci, txp_driver, txp_devclass, 0, 0);
186227569Sphilip
187227569Sphilipstatic int
188227569Sphiliptxp_probe(dev)
189227569Sphilip	device_t dev;
190227569Sphilip{
191227569Sphilip	struct txp_type *t;
192227569Sphilip
193227569Sphilip	t = txp_devs;
194227569Sphilip
195227569Sphilip	while(t->txp_name != NULL) {
196227569Sphilip		if ((pci_get_vendor(dev) == t->txp_vid) &&
197227569Sphilip		    (pci_get_device(dev) == t->txp_did)) {
198227569Sphilip			device_set_desc(dev, t->txp_name);
199227569Sphilip			return(0);
200227569Sphilip		}
201227569Sphilip		t++;
202227569Sphilip	}
203227569Sphilip
204227569Sphilip	return(ENXIO);
205227569Sphilip}
206227569Sphilip
207227569Sphilipstatic int
208227569Sphiliptxp_attach(dev)
209227569Sphilip	device_t dev;
210227569Sphilip{
211227569Sphilip	struct txp_softc *sc;
212227569Sphilip	struct ifnet *ifp;
213227569Sphilip	u_int32_t command;
214227569Sphilip	u_int16_t p1;
215227569Sphilip	u_int32_t p2;
216227569Sphilip	int unit, error = 0, rid;
217227569Sphilip
218227569Sphilip	sc = device_get_softc(dev);
219227569Sphilip	unit = device_get_unit(dev);
220227569Sphilip	sc->sc_dev = dev;
221227569Sphilip	sc->sc_cold = 1;
222227569Sphilip
223227569Sphilip	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
224227569Sphilip	    MTX_DEF | MTX_RECURSE);
225227569Sphilip
226227569Sphilip	/*
227227569Sphilip	 * Handle power management nonsense.
228227569Sphilip	 */
229227569Sphilip	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
230227569Sphilip		u_int32_t		iobase, membase, irq;
231227569Sphilip
232227569Sphilip		/* Save important PCI config data. */
233227569Sphilip		iobase = pci_read_config(dev, TXP_PCI_LOIO, 4);
234227569Sphilip		membase = pci_read_config(dev, TXP_PCI_LOMEM, 4);
235227569Sphilip		irq = pci_read_config(dev, TXP_PCI_INTLINE, 4);
236227569Sphilip
237227569Sphilip		/* Reset the power state. */
238227569Sphilip		device_printf(dev, "chip is in D%d power mode "
239227569Sphilip		    "-- setting to D0\n", pci_get_powerstate(dev));
240227569Sphilip		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
241227569Sphilip
242227569Sphilip		/* Restore PCI config data. */
243227569Sphilip		pci_write_config(dev, TXP_PCI_LOIO, iobase, 4);
244227569Sphilip		pci_write_config(dev, TXP_PCI_LOMEM, membase, 4);
245227569Sphilip		pci_write_config(dev, TXP_PCI_INTLINE, irq, 4);
246227569Sphilip	}
247227569Sphilip
248227569Sphilip	/*
249227569Sphilip	 * Map control/status registers.
250227569Sphilip	 */
251227569Sphilip	pci_enable_busmaster(dev);
252227569Sphilip	pci_enable_io(dev, SYS_RES_IOPORT);
253227569Sphilip	pci_enable_io(dev, SYS_RES_MEMORY);
254227569Sphilip	command = pci_read_config(dev, PCIR_COMMAND, 4);
255227569Sphilip
256227569Sphilip#ifdef TXP_USEIOSPACE
257227569Sphilip	if (!(command & PCIM_CMD_PORTEN)) {
258227569Sphilip		device_printf(dev, "failed to enable I/O ports!\n");
259227569Sphilip		error = ENXIO;
260227569Sphilip		goto fail;
261227569Sphilip	}
262227569Sphilip#else
263227569Sphilip	if (!(command & PCIM_CMD_MEMEN)) {
264227569Sphilip		device_printf(dev, "failed to enable memory mapping!\n");
265227569Sphilip		error = ENXIO;
266227569Sphilip		goto fail;
267227569Sphilip	}
268227569Sphilip#endif
269227569Sphilip
270227569Sphilip	rid = TXP_RID;
271227569Sphilip	sc->sc_res = bus_alloc_resource(dev, TXP_RES, &rid,
272227569Sphilip	    0, ~0, 1, RF_ACTIVE);
273227569Sphilip
274227569Sphilip	if (sc->sc_res == NULL) {
275227569Sphilip		device_printf(dev, "couldn't map ports/memory\n");
276227569Sphilip		error = ENXIO;
277227569Sphilip		goto fail;
278227569Sphilip	}
279227569Sphilip
280227569Sphilip	sc->sc_bt = rman_get_bustag(sc->sc_res);
281227569Sphilip	sc->sc_bh = rman_get_bushandle(sc->sc_res);
282227569Sphilip
283227569Sphilip	/* Allocate interrupt */
284227569Sphilip	rid = 0;
285227569Sphilip	sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
286227569Sphilip	    RF_SHAREABLE | RF_ACTIVE);
287227569Sphilip
288227569Sphilip	if (sc->sc_irq == NULL) {
289227569Sphilip		device_printf(dev, "couldn't map interrupt\n");
290227569Sphilip		txp_release_resources(sc);
291227569Sphilip		error = ENXIO;
292227569Sphilip		goto fail;
293227569Sphilip	}
294227569Sphilip
295227569Sphilip	error = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_NET,
296227569Sphilip	    txp_intr, sc, &sc->sc_intrhand);
297227569Sphilip
298227569Sphilip	if (error) {
299227569Sphilip		txp_release_resources(sc);
300227569Sphilip		device_printf(dev, "couldn't set up irq\n");
301227569Sphilip		goto fail;
302227569Sphilip	}
303227569Sphilip
304227569Sphilip	if (txp_chip_init(sc)) {
305227569Sphilip		txp_release_resources(sc);
306227569Sphilip		goto fail;
307227569Sphilip	}
308227569Sphilip
309227569Sphilip	sc->sc_fwbuf = contigmalloc(32768, M_DEVBUF,
310227569Sphilip	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
311227569Sphilip	error = txp_download_fw(sc);
312227569Sphilip	contigfree(sc->sc_fwbuf, 32768, M_DEVBUF);
313227569Sphilip	sc->sc_fwbuf = NULL;
314227569Sphilip
315227569Sphilip	if (error) {
316227569Sphilip		txp_release_resources(sc);
317227569Sphilip		goto fail;
318227569Sphilip	}
319227569Sphilip
320227569Sphilip	sc->sc_ldata = contigmalloc(sizeof(struct txp_ldata), M_DEVBUF,
321227569Sphilip	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
322227569Sphilip	bzero(sc->sc_ldata, sizeof(struct txp_ldata));
323227569Sphilip
324227569Sphilip	if (txp_alloc_rings(sc)) {
325227569Sphilip		txp_release_resources(sc);
326227569Sphilip		goto fail;
327227569Sphilip	}
328227569Sphilip
329227569Sphilip	if (txp_command(sc, TXP_CMD_MAX_PKT_SIZE_WRITE, TXP_MAX_PKTLEN, 0, 0,
330227569Sphilip	    NULL, NULL, NULL, 1)) {
331227569Sphilip		txp_release_resources(sc);
332227569Sphilip		goto fail;
333227569Sphilip	}
334227569Sphilip
335227569Sphilip	if (txp_command(sc, TXP_CMD_STATION_ADDRESS_READ, 0, 0, 0,
336227569Sphilip	    &p1, &p2, NULL, 1)) {
337227569Sphilip		txp_release_resources(sc);
338227569Sphilip		goto fail;
339227569Sphilip	}
340227569Sphilip
341227569Sphilip	txp_set_filter(sc);
342227569Sphilip
343227569Sphilip	sc->sc_arpcom.ac_enaddr[0] = ((u_int8_t *)&p1)[1];
344227569Sphilip	sc->sc_arpcom.ac_enaddr[1] = ((u_int8_t *)&p1)[0];
345227569Sphilip	sc->sc_arpcom.ac_enaddr[2] = ((u_int8_t *)&p2)[3];
346227569Sphilip	sc->sc_arpcom.ac_enaddr[3] = ((u_int8_t *)&p2)[2];
347227569Sphilip	sc->sc_arpcom.ac_enaddr[4] = ((u_int8_t *)&p2)[1];
348227569Sphilip	sc->sc_arpcom.ac_enaddr[5] = ((u_int8_t *)&p2)[0];
349227569Sphilip
350227569Sphilip	printf("txp%d: Ethernet address %6D\n", unit,
351227569Sphilip	    sc->sc_arpcom.ac_enaddr, ":");
352227569Sphilip
353227569Sphilip	sc->sc_cold = 0;
354227569Sphilip
355227569Sphilip	ifmedia_init(&sc->sc_ifmedia, 0, txp_ifmedia_upd, txp_ifmedia_sts);
356227569Sphilip	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
357227569Sphilip	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
358227569Sphilip	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
359227569Sphilip	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
360227569Sphilip	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL);
361227569Sphilip	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
362227569Sphilip	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
363227569Sphilip
364227569Sphilip	sc->sc_xcvr = TXP_XCVR_AUTO;
365227569Sphilip	txp_command(sc, TXP_CMD_XCVR_SELECT, TXP_XCVR_AUTO, 0, 0,
366227569Sphilip	    NULL, NULL, NULL, 0);
367227569Sphilip	ifmedia_set(&sc->sc_ifmedia, IFM_ETHER|IFM_AUTO);
368227569Sphilip
369227569Sphilip	ifp = &sc->sc_arpcom.ac_if;
370227569Sphilip	ifp->if_softc = sc;
371227569Sphilip	ifp->if_unit = unit;
372227569Sphilip	ifp->if_name = "txp";
373227569Sphilip	ifp->if_mtu = ETHERMTU;
374227569Sphilip	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
375227569Sphilip	ifp->if_ioctl = txp_ioctl;
376227569Sphilip	ifp->if_output = ether_output;
377227569Sphilip	ifp->if_start = txp_start;
378227569Sphilip	ifp->if_watchdog = txp_watchdog;
379227569Sphilip	ifp->if_init = txp_init;
380227569Sphilip	ifp->if_baudrate = 100000000;
381227569Sphilip	ifp->if_snd.ifq_maxlen = TX_ENTRIES;
382227569Sphilip	ifp->if_hwassist = 0;
383227569Sphilip	txp_capabilities(sc);
384227569Sphilip
385227569Sphilip	/*
386227569Sphilip	 * Attach us everywhere
387227569Sphilip	 */
388227569Sphilip	ether_ifattach(ifp, sc->sc_arpcom.ac_enaddr);
389227569Sphilip	callout_handle_init(&sc->sc_tick);
390227569Sphilip	return(0);
391227569Sphilip
392227569Sphilipfail:
393227569Sphilip	txp_release_resources(sc);
394227569Sphilip	mtx_destroy(&sc->sc_mtx);
395227569Sphilip	return(error);
396227569Sphilip}
397227569Sphilip
398227569Sphilipstatic int
399227569Sphiliptxp_detach(dev)
400227569Sphilip	device_t dev;
401227569Sphilip{
402227569Sphilip	struct txp_softc *sc;
403227569Sphilip	struct ifnet *ifp;
404227569Sphilip	int i;
405227569Sphilip
406227569Sphilip	sc = device_get_softc(dev);
407227569Sphilip	ifp = &sc->sc_arpcom.ac_if;
408227569Sphilip
409227569Sphilip	txp_stop(sc);
410227569Sphilip	txp_shutdown(dev);
411227569Sphilip
412227569Sphilip	ifmedia_removeall(&sc->sc_ifmedia);
413227569Sphilip	ether_ifdetach(ifp);
414227569Sphilip
415227569Sphilip	for (i = 0; i < RXBUF_ENTRIES; i++)
416227569Sphilip		free(sc->sc_rxbufs[i].rb_sd, M_DEVBUF);
417227569Sphilip
418227569Sphilip	txp_release_resources(sc);
419227569Sphilip
420227569Sphilip	mtx_destroy(&sc->sc_mtx);
421227569Sphilip	return(0);
422227569Sphilip}
423227569Sphilip
424227569Sphilipstatic void
425227569Sphiliptxp_release_resources(sc)
426227569Sphilip	struct txp_softc *sc;
427227569Sphilip{
428227569Sphilip	device_t dev;
429227569Sphilip
430227569Sphilip	dev = sc->sc_dev;
431227569Sphilip
432227569Sphilip	if (sc->sc_intrhand != NULL)
433227569Sphilip		bus_teardown_intr(dev, sc->sc_irq, sc->sc_intrhand);
434227569Sphilip
435227569Sphilip	if (sc->sc_irq != NULL)
436227569Sphilip		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq);
437227569Sphilip
438227569Sphilip	if (sc->sc_res != NULL)
439227569Sphilip		bus_release_resource(dev, TXP_RES, TXP_RID, sc->sc_res);
440227569Sphilip
441227569Sphilip	if (sc->sc_ldata != NULL)
442227569Sphilip		contigfree(sc->sc_ldata, sizeof(struct txp_ldata), M_DEVBUF);
443227569Sphilip
444227569Sphilip	return;
445227569Sphilip}
446227569Sphilip
447227569Sphilipstatic int
448227569Sphiliptxp_chip_init(sc)
449227569Sphilip	struct txp_softc *sc;
450227569Sphilip{
451227569Sphilip	/* disable interrupts */
452227569Sphilip	WRITE_REG(sc, TXP_IER, 0);
453227569Sphilip	WRITE_REG(sc, TXP_IMR,
454227569Sphilip	    TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
455227569Sphilip	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
456227569Sphilip	    TXP_INT_LATCH);
457227569Sphilip
458227569Sphilip	/* ack all interrupts */
459227569Sphilip	WRITE_REG(sc, TXP_ISR, TXP_INT_RESERVED | TXP_INT_LATCH |
460227569Sphilip	    TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 |
461227569Sphilip	    TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
462227569Sphilip	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
463227569Sphilip	    TXP_INT_A2H_3 | TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0);
464227700Sphilip
465227569Sphilip	if (txp_reset_adapter(sc))
466227569Sphilip		return (-1);
467227569Sphilip
468227569Sphilip	/* disable interrupts */
469227569Sphilip	WRITE_REG(sc, TXP_IER, 0);
470227569Sphilip	WRITE_REG(sc, TXP_IMR,
471227569Sphilip	    TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
472227569Sphilip	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
473227569Sphilip	    TXP_INT_LATCH);
474227569Sphilip
475227569Sphilip	/* ack all interrupts */
476227569Sphilip	WRITE_REG(sc, TXP_ISR, TXP_INT_RESERVED | TXP_INT_LATCH |
477227569Sphilip	    TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 |
478227569Sphilip	    TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
479227569Sphilip	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
480227569Sphilip	    TXP_INT_A2H_3 | TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0);
481227569Sphilip
482227569Sphilip	return (0);
483227569Sphilip}
484227569Sphilip
485227569Sphilipstatic int
486227569Sphiliptxp_reset_adapter(sc)
487227569Sphilip	struct txp_softc *sc;
488227569Sphilip{
489227569Sphilip	u_int32_t r;
490227569Sphilip	int i;
491227569Sphilip
492227569Sphilip	r = 0;
493227569Sphilip	WRITE_REG(sc, TXP_SRR, TXP_SRR_ALL);
494227569Sphilip	DELAY(1000);
495227569Sphilip	WRITE_REG(sc, TXP_SRR, 0);
496227569Sphilip
497227569Sphilip	/* Should wait max 6 seconds */
498227569Sphilip	for (i = 0; i < 6000; i++) {
499227569Sphilip		r = READ_REG(sc, TXP_A2H_0);
500227569Sphilip		if (r == STAT_WAITING_FOR_HOST_REQUEST)
501227569Sphilip			break;
502227569Sphilip		DELAY(1000);
503227569Sphilip	}
504227569Sphilip
505227569Sphilip	if (r != STAT_WAITING_FOR_HOST_REQUEST) {
506227569Sphilip		device_printf(sc->sc_dev, "reset hung\n");
507227569Sphilip		return (-1);
508227569Sphilip	}
509227569Sphilip
510227569Sphilip	return (0);
511227569Sphilip}
512227569Sphilip
513227569Sphilipstatic int
514227569Sphiliptxp_download_fw(sc)
515227569Sphilip	struct txp_softc *sc;
516227569Sphilip{
517227569Sphilip	struct txp_fw_file_header *fileheader;
518227569Sphilip	struct txp_fw_section_header *secthead;
519227569Sphilip	int sect;
520227569Sphilip	u_int32_t r, i, ier, imr;
521227569Sphilip
522227569Sphilip	r = 0;
523227569Sphilip	ier = READ_REG(sc, TXP_IER);
524227569Sphilip	WRITE_REG(sc, TXP_IER, ier | TXP_INT_A2H_0);
525227569Sphilip
526227569Sphilip	imr = READ_REG(sc, TXP_IMR);
527227569Sphilip	WRITE_REG(sc, TXP_IMR, imr | TXP_INT_A2H_0);
528227569Sphilip
529227569Sphilip	for (i = 0; i < 10000; i++) {
530227569Sphilip		r = READ_REG(sc, TXP_A2H_0);
531227569Sphilip		if (r == STAT_WAITING_FOR_HOST_REQUEST)
532227569Sphilip			break;
533227569Sphilip		DELAY(50);
534227569Sphilip	}
535227569Sphilip	if (r != STAT_WAITING_FOR_HOST_REQUEST) {
536227569Sphilip		device_printf(sc->sc_dev, "not waiting for host request\n");
537227569Sphilip		return (-1);
538227569Sphilip	}
539227569Sphilip
540227569Sphilip	/* Ack the status */
541227569Sphilip	WRITE_REG(sc, TXP_ISR, TXP_INT_A2H_0);
542227569Sphilip
543227569Sphilip	fileheader = (struct txp_fw_file_header *)tc990image;
544227569Sphilip	if (bcmp("TYPHOON", fileheader->magicid, sizeof(fileheader->magicid))) {
545227569Sphilip		device_printf(sc->sc_dev, "fw invalid magic\n");
546227569Sphilip		return (-1);
547227569Sphilip	}
548227569Sphilip
549227569Sphilip	/* Tell boot firmware to get ready for image */
550227569Sphilip	WRITE_REG(sc, TXP_H2A_1, fileheader->addr);
551227569Sphilip	WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_RUNTIME_IMAGE);
552227569Sphilip
553227569Sphilip	if (txp_download_fw_wait(sc)) {
554227569Sphilip		device_printf(sc->sc_dev, "fw wait failed, initial\n");
555227569Sphilip		return (-1);
556227569Sphilip	}
557
558	secthead = (struct txp_fw_section_header *)(((u_int8_t *)tc990image) +
559	    sizeof(struct txp_fw_file_header));
560
561	for (sect = 0; sect < fileheader->nsections; sect++) {
562		if (txp_download_fw_section(sc, secthead, sect))
563			return (-1);
564		secthead = (struct txp_fw_section_header *)
565		    (((u_int8_t *)secthead) + secthead->nbytes +
566		    sizeof(*secthead));
567	}
568
569	WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_DOWNLOAD_COMPLETE);
570
571	for (i = 0; i < 10000; i++) {
572		r = READ_REG(sc, TXP_A2H_0);
573		if (r == STAT_WAITING_FOR_BOOT)
574			break;
575		DELAY(50);
576	}
577	if (r != STAT_WAITING_FOR_BOOT) {
578		device_printf(sc->sc_dev, "not waiting for boot\n");
579		return (-1);
580	}
581
582	WRITE_REG(sc, TXP_IER, ier);
583	WRITE_REG(sc, TXP_IMR, imr);
584
585	return (0);
586}
587
588static int
589txp_download_fw_wait(sc)
590	struct txp_softc *sc;
591{
592	u_int32_t i, r;
593
594	r = 0;
595	for (i = 0; i < 10000; i++) {
596		r = READ_REG(sc, TXP_ISR);
597		if (r & TXP_INT_A2H_0)
598			break;
599		DELAY(50);
600	}
601
602	if (!(r & TXP_INT_A2H_0)) {
603		device_printf(sc->sc_dev, "fw wait failed comm0\n");
604		return (-1);
605	}
606
607	WRITE_REG(sc, TXP_ISR, TXP_INT_A2H_0);
608
609	r = READ_REG(sc, TXP_A2H_0);
610	if (r != STAT_WAITING_FOR_SEGMENT) {
611		device_printf(sc->sc_dev, "fw not waiting for segment\n");
612		return (-1);
613	}
614	return (0);
615}
616
617static int
618txp_download_fw_section(sc, sect, sectnum)
619	struct txp_softc *sc;
620	struct txp_fw_section_header *sect;
621	int sectnum;
622{
623	vm_offset_t dma;
624	int rseg, err = 0;
625	struct mbuf m;
626	u_int16_t csum;
627
628	/* Skip zero length sections */
629	if (sect->nbytes == 0)
630		return (0);
631
632	/* Make sure we aren't past the end of the image */
633	rseg = ((u_int8_t *)sect) - ((u_int8_t *)tc990image);
634	if (rseg >= sizeof(tc990image)) {
635		device_printf(sc->sc_dev, "fw invalid section address, "
636		    "section %d\n", sectnum);
637		return (-1);
638	}
639
640	/* Make sure this section doesn't go past the end */
641	rseg += sect->nbytes;
642	if (rseg >= sizeof(tc990image)) {
643		device_printf(sc->sc_dev, "fw truncated section %d\n",
644		    sectnum);
645		return (-1);
646	}
647
648	bcopy(((u_int8_t *)sect) + sizeof(*sect), sc->sc_fwbuf, sect->nbytes);
649	dma = vtophys(sc->sc_fwbuf);
650
651	/*
652	 * dummy up mbuf and verify section checksum
653	 */
654	m.m_type = MT_DATA;
655	m.m_next = m.m_nextpkt = NULL;
656	m.m_len = sect->nbytes;
657	m.m_data = sc->sc_fwbuf;
658	m.m_flags = 0;
659	csum = in_cksum(&m, sect->nbytes);
660	if (csum != sect->cksum) {
661		device_printf(sc->sc_dev, "fw section %d, bad "
662		    "cksum (expected 0x%x got 0x%x)\n",
663		    sectnum, sect->cksum, csum);
664		err = -1;
665		goto bail;
666	}
667
668	WRITE_REG(sc, TXP_H2A_1, sect->nbytes);
669	WRITE_REG(sc, TXP_H2A_2, sect->cksum);
670	WRITE_REG(sc, TXP_H2A_3, sect->addr);
671	WRITE_REG(sc, TXP_H2A_4, 0);
672	WRITE_REG(sc, TXP_H2A_5, dma & 0xffffffff);
673	WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_SEGMENT_AVAILABLE);
674
675	if (txp_download_fw_wait(sc)) {
676		device_printf(sc->sc_dev, "fw wait failed, "
677		    "section %d\n", sectnum);
678		err = -1;
679	}
680
681bail:
682	return (err);
683}
684
685static void
686txp_intr(vsc)
687	void *vsc;
688{
689	struct txp_softc *sc = vsc;
690	struct txp_hostvar *hv = sc->sc_hostvar;
691	u_int32_t isr;
692
693	/* mask all interrupts */
694	WRITE_REG(sc, TXP_IMR, TXP_INT_RESERVED | TXP_INT_SELF |
695	    TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 |
696	    TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0 |
697	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
698	    TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |  TXP_INT_LATCH);
699
700	isr = READ_REG(sc, TXP_ISR);
701	while (isr) {
702		WRITE_REG(sc, TXP_ISR, isr);
703
704		if ((*sc->sc_rxhir.r_roff) != (*sc->sc_rxhir.r_woff))
705			txp_rx_reclaim(sc, &sc->sc_rxhir);
706		if ((*sc->sc_rxlor.r_roff) != (*sc->sc_rxlor.r_woff))
707			txp_rx_reclaim(sc, &sc->sc_rxlor);
708
709		if (hv->hv_rx_buf_write_idx == hv->hv_rx_buf_read_idx)
710			txp_rxbuf_reclaim(sc);
711
712		if (sc->sc_txhir.r_cnt && (sc->sc_txhir.r_cons !=
713		    TXP_OFFSET2IDX(*(sc->sc_txhir.r_off))))
714			txp_tx_reclaim(sc, &sc->sc_txhir);
715
716		if (sc->sc_txlor.r_cnt && (sc->sc_txlor.r_cons !=
717		    TXP_OFFSET2IDX(*(sc->sc_txlor.r_off))))
718			txp_tx_reclaim(sc, &sc->sc_txlor);
719
720		isr = READ_REG(sc, TXP_ISR);
721	}
722
723	/* unmask all interrupts */
724	WRITE_REG(sc, TXP_IMR, TXP_INT_A2H_3);
725
726	txp_start(&sc->sc_arpcom.ac_if);
727
728	return;
729}
730
731static void
732txp_rx_reclaim(sc, r)
733	struct txp_softc *sc;
734	struct txp_rx_ring *r;
735{
736	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
737	struct txp_rx_desc *rxd;
738	struct mbuf *m;
739	struct txp_swdesc *sd = NULL;
740	u_int32_t roff, woff;
741
742	roff = *r->r_roff;
743	woff = *r->r_woff;
744	rxd = r->r_desc + (roff / sizeof(struct txp_rx_desc));
745
746	while (roff != woff) {
747
748		if (rxd->rx_flags & RX_FLAGS_ERROR) {
749			device_printf(sc->sc_dev, "error 0x%x\n",
750			    rxd->rx_stat);
751			ifp->if_ierrors++;
752			goto next;
753		}
754
755		/* retrieve stashed pointer */
756		sd = rxd->rx_sd;
757
758		m = sd->sd_mbuf;
759		sd->sd_mbuf = NULL;
760
761		m->m_pkthdr.len = m->m_len = rxd->rx_len;
762
763#ifdef __STRICT_ALIGNMENT
764		{
765			/*
766			 * XXX Nice chip, except it won't accept "off by 2"
767			 * buffers, so we're force to copy.  Supposedly
768			 * this will be fixed in a newer firmware rev
769			 * and this will be temporary.
770			 */
771			struct mbuf *mnew;
772
773			MGETHDR(mnew, M_DONTWAIT, MT_DATA);
774			if (mnew == NULL) {
775				m_freem(m);
776				goto next;
777			}
778			if (m->m_len > (MHLEN - 2)) {
779				MCLGET(mnew, M_DONTWAIT);
780				if (!(mnew->m_flags & M_EXT)) {
781					m_freem(mnew);
782					m_freem(m);
783					goto next;
784				}
785			}
786			mnew->m_pkthdr.rcvif = ifp;
787			m_adj(mnew, 2);
788			mnew->m_pkthdr.len = mnew->m_len = m->m_len;
789			m_copydata(m, 0, m->m_pkthdr.len, mtod(mnew, caddr_t));
790			m_freem(m);
791			m = mnew;
792		}
793#endif
794
795		if (rxd->rx_stat & RX_STAT_IPCKSUMBAD)
796			m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
797		else if (rxd->rx_stat & RX_STAT_IPCKSUMGOOD)
798		 	m->m_pkthdr.csum_flags |=
799			    CSUM_IP_CHECKED|CSUM_IP_VALID;
800
801		if ((rxd->rx_stat & RX_STAT_TCPCKSUMGOOD) ||
802		    (rxd->rx_stat & RX_STAT_UDPCKSUMGOOD)) {
803			m->m_pkthdr.csum_flags |=
804			    CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
805			m->m_pkthdr.csum_data = 0xffff;
806		}
807
808		if (rxd->rx_stat & RX_STAT_VLAN) {
809			VLAN_INPUT_TAG(ifp,
810				m, htons(rxd->rx_vlan >> 16), goto next);
811		}
812
813		(*ifp->if_input)(ifp, m);
814
815next:
816
817		roff += sizeof(struct txp_rx_desc);
818		if (roff == (RX_ENTRIES * sizeof(struct txp_rx_desc))) {
819			roff = 0;
820			rxd = r->r_desc;
821		} else
822			rxd++;
823		woff = *r->r_woff;
824	}
825
826	*r->r_roff = woff;
827
828	return;
829}
830
831static void
832txp_rxbuf_reclaim(sc)
833	struct txp_softc *sc;
834{
835	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
836	struct txp_hostvar *hv = sc->sc_hostvar;
837	struct txp_rxbuf_desc *rbd;
838	struct txp_swdesc *sd;
839	u_int32_t i;
840
841	if (!(ifp->if_flags & IFF_RUNNING))
842		return;
843
844	i = sc->sc_rxbufprod;
845	rbd = sc->sc_rxbufs + i;
846
847	while (1) {
848		sd = rbd->rb_sd;
849		if (sd->sd_mbuf != NULL)
850			break;
851
852		MGETHDR(sd->sd_mbuf, M_DONTWAIT, MT_DATA);
853		if (sd->sd_mbuf == NULL)
854			goto err_sd;
855
856		MCLGET(sd->sd_mbuf, M_DONTWAIT);
857		if ((sd->sd_mbuf->m_flags & M_EXT) == 0)
858			goto err_mbuf;
859		sd->sd_mbuf->m_pkthdr.rcvif = ifp;
860		sd->sd_mbuf->m_pkthdr.len = sd->sd_mbuf->m_len = MCLBYTES;
861
862		rbd->rb_paddrlo = vtophys(mtod(sd->sd_mbuf, vm_offset_t))
863		    & 0xffffffff;
864		rbd->rb_paddrhi = 0;
865
866		hv->hv_rx_buf_write_idx = TXP_IDX2OFFSET(i);
867
868		if (++i == RXBUF_ENTRIES) {
869			i = 0;
870			rbd = sc->sc_rxbufs;
871		} else
872			rbd++;
873	}
874
875	sc->sc_rxbufprod = i;
876
877	return;
878
879err_mbuf:
880	m_freem(sd->sd_mbuf);
881err_sd:
882	free(sd, M_DEVBUF);
883}
884
885/*
886 * Reclaim mbufs and entries from a transmit ring.
887 */
888static void
889txp_tx_reclaim(sc, r)
890	struct txp_softc *sc;
891	struct txp_tx_ring *r;
892{
893	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
894	u_int32_t idx = TXP_OFFSET2IDX(*(r->r_off));
895	u_int32_t cons = r->r_cons, cnt = r->r_cnt;
896	struct txp_tx_desc *txd = r->r_desc + cons;
897	struct txp_swdesc *sd = sc->sc_txd + cons;
898	struct mbuf *m;
899
900	while (cons != idx) {
901		if (cnt == 0)
902			break;
903
904		if ((txd->tx_flags & TX_FLAGS_TYPE_M) ==
905		    TX_FLAGS_TYPE_DATA) {
906			m = sd->sd_mbuf;
907			if (m != NULL) {
908				m_freem(m);
909				txd->tx_addrlo = 0;
910				txd->tx_addrhi = 0;
911				ifp->if_opackets++;
912			}
913		}
914		ifp->if_flags &= ~IFF_OACTIVE;
915
916		if (++cons == TX_ENTRIES) {
917			txd = r->r_desc;
918			cons = 0;
919			sd = sc->sc_txd;
920		} else {
921			txd++;
922			sd++;
923		}
924
925		cnt--;
926	}
927
928	r->r_cons = cons;
929	r->r_cnt = cnt;
930	if (cnt == 0)
931		ifp->if_timer = 0;
932}
933
934static int
935txp_shutdown(dev)
936	device_t dev;
937{
938	struct txp_softc *sc;
939
940	sc = device_get_softc(dev);
941
942	/* mask all interrupts */
943	WRITE_REG(sc, TXP_IMR,
944	    TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
945	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
946	    TXP_INT_LATCH);
947
948	txp_command(sc, TXP_CMD_TX_DISABLE, 0, 0, 0, NULL, NULL, NULL, 0);
949	txp_command(sc, TXP_CMD_RX_DISABLE, 0, 0, 0, NULL, NULL, NULL, 0);
950	txp_command(sc, TXP_CMD_HALT, 0, 0, 0, NULL, NULL, NULL, 0);
951
952	return(0);
953}
954
955static int
956txp_alloc_rings(sc)
957	struct txp_softc *sc;
958{
959	struct txp_boot_record *boot;
960	struct txp_ldata *ld;
961	u_int32_t r;
962	int i;
963
964	r = 0;
965	ld = sc->sc_ldata;
966	boot = &ld->txp_boot;
967
968	/* boot record */
969	sc->sc_boot = boot;
970
971	/* host variables */
972	bzero(&ld->txp_hostvar, sizeof(struct txp_hostvar));
973	boot->br_hostvar_lo = vtophys(&ld->txp_hostvar);
974	boot->br_hostvar_hi = 0;
975	sc->sc_hostvar = (struct txp_hostvar *)&ld->txp_hostvar;
976
977	/* hi priority tx ring */
978	boot->br_txhipri_lo = vtophys(&ld->txp_txhiring);;
979	boot->br_txhipri_hi = 0;
980	boot->br_txhipri_siz = TX_ENTRIES * sizeof(struct txp_tx_desc);
981	sc->sc_txhir.r_reg = TXP_H2A_1;
982	sc->sc_txhir.r_desc = (struct txp_tx_desc *)&ld->txp_txhiring;
983	sc->sc_txhir.r_cons = sc->sc_txhir.r_prod = sc->sc_txhir.r_cnt = 0;
984	sc->sc_txhir.r_off = &sc->sc_hostvar->hv_tx_hi_desc_read_idx;
985
986	/* lo priority tx ring */
987	boot->br_txlopri_lo = vtophys(&ld->txp_txloring);
988	boot->br_txlopri_hi = 0;
989	boot->br_txlopri_siz = TX_ENTRIES * sizeof(struct txp_tx_desc);
990	sc->sc_txlor.r_reg = TXP_H2A_3;
991	sc->sc_txlor.r_desc = (struct txp_tx_desc *)&ld->txp_txloring;
992	sc->sc_txlor.r_cons = sc->sc_txlor.r_prod = sc->sc_txlor.r_cnt = 0;
993	sc->sc_txlor.r_off = &sc->sc_hostvar->hv_tx_lo_desc_read_idx;
994
995	/* high priority rx ring */
996	boot->br_rxhipri_lo = vtophys(&ld->txp_rxhiring);
997	boot->br_rxhipri_hi = 0;
998	boot->br_rxhipri_siz = RX_ENTRIES * sizeof(struct txp_rx_desc);
999	sc->sc_rxhir.r_desc = (struct txp_rx_desc *)&ld->txp_rxhiring;
1000	sc->sc_rxhir.r_roff = &sc->sc_hostvar->hv_rx_hi_read_idx;
1001	sc->sc_rxhir.r_woff = &sc->sc_hostvar->hv_rx_hi_write_idx;
1002
1003	/* low priority rx ring */
1004	boot->br_rxlopri_lo = vtophys(&ld->txp_rxloring);
1005	boot->br_rxlopri_hi = 0;
1006	boot->br_rxlopri_siz = RX_ENTRIES * sizeof(struct txp_rx_desc);
1007	sc->sc_rxlor.r_desc = (struct txp_rx_desc *)&ld->txp_rxloring;
1008	sc->sc_rxlor.r_roff = &sc->sc_hostvar->hv_rx_lo_read_idx;
1009	sc->sc_rxlor.r_woff = &sc->sc_hostvar->hv_rx_lo_write_idx;
1010
1011	/* command ring */
1012	bzero(&ld->txp_cmdring, sizeof(struct txp_cmd_desc) * CMD_ENTRIES);
1013	boot->br_cmd_lo = vtophys(&ld->txp_cmdring);
1014	boot->br_cmd_hi = 0;
1015	boot->br_cmd_siz = CMD_ENTRIES * sizeof(struct txp_cmd_desc);
1016	sc->sc_cmdring.base = (struct txp_cmd_desc *)&ld->txp_cmdring;
1017	sc->sc_cmdring.size = CMD_ENTRIES * sizeof(struct txp_cmd_desc);
1018	sc->sc_cmdring.lastwrite = 0;
1019
1020	/* response ring */
1021	bzero(&ld->txp_rspring, sizeof(struct txp_rsp_desc) * RSP_ENTRIES);
1022	boot->br_resp_lo = vtophys(&ld->txp_rspring);
1023	boot->br_resp_hi = 0;
1024	boot->br_resp_siz = CMD_ENTRIES * sizeof(struct txp_rsp_desc);
1025	sc->sc_rspring.base = (struct txp_rsp_desc *)&ld->txp_rspring;
1026	sc->sc_rspring.size = RSP_ENTRIES * sizeof(struct txp_rsp_desc);
1027	sc->sc_rspring.lastwrite = 0;
1028
1029	/* receive buffer ring */
1030	boot->br_rxbuf_lo = vtophys(&ld->txp_rxbufs);
1031	boot->br_rxbuf_hi = 0;
1032	boot->br_rxbuf_siz = RXBUF_ENTRIES * sizeof(struct txp_rxbuf_desc);
1033	sc->sc_rxbufs = (struct txp_rxbuf_desc *)&ld->txp_rxbufs;
1034
1035	for (i = 0; i < RXBUF_ENTRIES; i++) {
1036		struct txp_swdesc *sd;
1037		if (sc->sc_rxbufs[i].rb_sd != NULL)
1038			continue;
1039		sc->sc_rxbufs[i].rb_sd = malloc(sizeof(struct txp_swdesc),
1040		    M_DEVBUF, M_NOWAIT);
1041		if (sc->sc_rxbufs[i].rb_sd == NULL)
1042			return(ENOBUFS);
1043		sd = sc->sc_rxbufs[i].rb_sd;
1044		sd->sd_mbuf = NULL;
1045	}
1046	sc->sc_rxbufprod = 0;
1047
1048	/* zero dma */
1049	bzero(&ld->txp_zero, sizeof(u_int32_t));
1050	boot->br_zero_lo = vtophys(&ld->txp_zero);
1051	boot->br_zero_hi = 0;
1052
1053	/* See if it's waiting for boot, and try to boot it */
1054	for (i = 0; i < 10000; i++) {
1055		r = READ_REG(sc, TXP_A2H_0);
1056		if (r == STAT_WAITING_FOR_BOOT)
1057			break;
1058		DELAY(50);
1059	}
1060
1061	if (r != STAT_WAITING_FOR_BOOT) {
1062		device_printf(sc->sc_dev, "not waiting for boot\n");
1063		return(ENXIO);
1064	}
1065
1066	WRITE_REG(sc, TXP_H2A_2, 0);
1067	WRITE_REG(sc, TXP_H2A_1, vtophys(sc->sc_boot));
1068	WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_REGISTER_BOOT_RECORD);
1069
1070	/* See if it booted */
1071	for (i = 0; i < 10000; i++) {
1072		r = READ_REG(sc, TXP_A2H_0);
1073		if (r == STAT_RUNNING)
1074			break;
1075		DELAY(50);
1076	}
1077	if (r != STAT_RUNNING) {
1078		device_printf(sc->sc_dev, "fw not running\n");
1079		return(ENXIO);
1080	}
1081
1082	/* Clear TX and CMD ring write registers */
1083	WRITE_REG(sc, TXP_H2A_1, TXP_BOOTCMD_NULL);
1084	WRITE_REG(sc, TXP_H2A_2, TXP_BOOTCMD_NULL);
1085	WRITE_REG(sc, TXP_H2A_3, TXP_BOOTCMD_NULL);
1086	WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_NULL);
1087
1088	return (0);
1089}
1090
1091static int
1092txp_ioctl(ifp, command, data)
1093	struct ifnet *ifp;
1094	u_long command;
1095	caddr_t data;
1096{
1097	struct txp_softc *sc = ifp->if_softc;
1098	struct ifreq *ifr = (struct ifreq *)data;
1099	int s, error = 0;
1100
1101	s = splnet();
1102
1103	switch(command) {
1104	case SIOCSIFFLAGS:
1105		if (ifp->if_flags & IFF_UP) {
1106			txp_init(sc);
1107		} else {
1108			if (ifp->if_flags & IFF_RUNNING)
1109				txp_stop(sc);
1110		}
1111		break;
1112	case SIOCADDMULTI:
1113	case SIOCDELMULTI:
1114		/*
1115		 * Multicast list has changed; set the hardware
1116		 * filter accordingly.
1117		 */
1118		txp_set_filter(sc);
1119		error = 0;
1120		break;
1121	case SIOCGIFMEDIA:
1122	case SIOCSIFMEDIA:
1123		error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, command);
1124		break;
1125	default:
1126		error = ether_ioctl(ifp, command, data);
1127		break;
1128	}
1129
1130	(void)splx(s);
1131
1132	return(error);
1133}
1134
1135static int
1136txp_rxring_fill(sc)
1137	struct txp_softc *sc;
1138{
1139	int i;
1140	struct ifnet *ifp;
1141	struct txp_swdesc *sd;
1142
1143	ifp = &sc->sc_arpcom.ac_if;
1144
1145	for (i = 0; i < RXBUF_ENTRIES; i++) {
1146		sd = sc->sc_rxbufs[i].rb_sd;
1147		MGETHDR(sd->sd_mbuf, M_DONTWAIT, MT_DATA);
1148		if (sd->sd_mbuf == NULL)
1149			return(ENOBUFS);
1150
1151		MCLGET(sd->sd_mbuf, M_DONTWAIT);
1152		if ((sd->sd_mbuf->m_flags & M_EXT) == 0) {
1153			m_freem(sd->sd_mbuf);
1154			return(ENOBUFS);
1155		}
1156		sd->sd_mbuf->m_pkthdr.len = sd->sd_mbuf->m_len = MCLBYTES;
1157		sd->sd_mbuf->m_pkthdr.rcvif = ifp;
1158
1159		sc->sc_rxbufs[i].rb_paddrlo =
1160		    vtophys(mtod(sd->sd_mbuf, vm_offset_t));
1161		sc->sc_rxbufs[i].rb_paddrhi = 0;
1162	}
1163
1164	sc->sc_hostvar->hv_rx_buf_write_idx = (RXBUF_ENTRIES - 1) *
1165	    sizeof(struct txp_rxbuf_desc);
1166
1167	return(0);
1168}
1169
1170static void
1171txp_rxring_empty(sc)
1172	struct txp_softc *sc;
1173{
1174	int i;
1175	struct txp_swdesc *sd;
1176
1177	if (sc->sc_rxbufs == NULL)
1178		return;
1179
1180	for (i = 0; i < RXBUF_ENTRIES; i++) {
1181		if (&sc->sc_rxbufs[i] == NULL)
1182			continue;
1183		sd = sc->sc_rxbufs[i].rb_sd;
1184		if (sd == NULL)
1185			continue;
1186		if (sd->sd_mbuf != NULL) {
1187			m_freem(sd->sd_mbuf);
1188			sd->sd_mbuf = NULL;
1189		}
1190	}
1191
1192	return;
1193}
1194
1195static void
1196txp_init(xsc)
1197	void *xsc;
1198{
1199	struct txp_softc *sc;
1200	struct ifnet *ifp;
1201	u_int16_t p1;
1202	u_int32_t p2;
1203	int s;
1204
1205	sc = xsc;
1206	ifp = &sc->sc_arpcom.ac_if;
1207
1208	if (ifp->if_flags & IFF_RUNNING)
1209		return;
1210
1211	txp_stop(sc);
1212
1213	s = splnet();
1214
1215	txp_command(sc, TXP_CMD_MAX_PKT_SIZE_WRITE, TXP_MAX_PKTLEN, 0, 0,
1216	    NULL, NULL, NULL, 1);
1217
1218	/* Set station address. */
1219	((u_int8_t *)&p1)[1] = sc->sc_arpcom.ac_enaddr[0];
1220	((u_int8_t *)&p1)[0] = sc->sc_arpcom.ac_enaddr[1];
1221	((u_int8_t *)&p2)[3] = sc->sc_arpcom.ac_enaddr[2];
1222	((u_int8_t *)&p2)[2] = sc->sc_arpcom.ac_enaddr[3];
1223	((u_int8_t *)&p2)[1] = sc->sc_arpcom.ac_enaddr[4];
1224	((u_int8_t *)&p2)[0] = sc->sc_arpcom.ac_enaddr[5];
1225	txp_command(sc, TXP_CMD_STATION_ADDRESS_WRITE, p1, p2, 0,
1226	    NULL, NULL, NULL, 1);
1227
1228	txp_set_filter(sc);
1229
1230	txp_rxring_fill(sc);
1231
1232	txp_command(sc, TXP_CMD_TX_ENABLE, 0, 0, 0, NULL, NULL, NULL, 1);
1233	txp_command(sc, TXP_CMD_RX_ENABLE, 0, 0, 0, NULL, NULL, NULL, 1);
1234
1235	WRITE_REG(sc, TXP_IER, TXP_INT_RESERVED | TXP_INT_SELF |
1236	    TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 |
1237	    TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0 |
1238	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
1239	    TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |  TXP_INT_LATCH);
1240	WRITE_REG(sc, TXP_IMR, TXP_INT_A2H_3);
1241
1242	ifp->if_flags |= IFF_RUNNING;
1243	ifp->if_flags &= ~IFF_OACTIVE;
1244	ifp->if_timer = 0;
1245
1246	sc->sc_tick = timeout(txp_tick, sc, hz);
1247
1248	splx(s);
1249}
1250
1251static void
1252txp_tick(vsc)
1253	void *vsc;
1254{
1255	struct txp_softc *sc = vsc;
1256	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
1257	struct txp_rsp_desc *rsp = NULL;
1258	struct txp_ext_desc *ext;
1259	int s;
1260
1261	s = splnet();
1262	txp_rxbuf_reclaim(sc);
1263
1264	if (txp_command2(sc, TXP_CMD_READ_STATISTICS, 0, 0, 0, NULL, 0,
1265	    &rsp, 1))
1266		goto out;
1267	if (rsp->rsp_numdesc != 6)
1268		goto out;
1269	if (txp_command(sc, TXP_CMD_CLEAR_STATISTICS, 0, 0, 0,
1270	    NULL, NULL, NULL, 1))
1271		goto out;
1272	ext = (struct txp_ext_desc *)(rsp + 1);
1273
1274	ifp->if_ierrors += ext[3].ext_2 + ext[3].ext_3 + ext[3].ext_4 +
1275	    ext[4].ext_1 + ext[4].ext_4;
1276	ifp->if_oerrors += ext[0].ext_1 + ext[1].ext_1 + ext[1].ext_4 +
1277	    ext[2].ext_1;
1278	ifp->if_collisions += ext[0].ext_2 + ext[0].ext_3 + ext[1].ext_2 +
1279	    ext[1].ext_3;
1280	ifp->if_opackets += rsp->rsp_par2;
1281	ifp->if_ipackets += ext[2].ext_3;
1282
1283out:
1284	if (rsp != NULL)
1285		free(rsp, M_DEVBUF);
1286
1287	splx(s);
1288	sc->sc_tick = timeout(txp_tick, sc, hz);
1289
1290	return;
1291}
1292
1293static void
1294txp_start(ifp)
1295	struct ifnet *ifp;
1296{
1297	struct txp_softc *sc = ifp->if_softc;
1298	struct txp_tx_ring *r = &sc->sc_txhir;
1299	struct txp_tx_desc *txd;
1300	struct txp_frag_desc *fxd;
1301	struct mbuf *m, *m0;
1302	struct txp_swdesc *sd;
1303	u_int32_t firstprod, firstcnt, prod, cnt;
1304	struct m_tag *mtag;
1305
1306	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
1307		return;
1308
1309	prod = r->r_prod;
1310	cnt = r->r_cnt;
1311
1312	while (1) {
1313		IF_DEQUEUE(&ifp->if_snd, m);
1314		if (m == NULL)
1315			break;
1316
1317		firstprod = prod;
1318		firstcnt = cnt;
1319
1320		sd = sc->sc_txd + prod;
1321		sd->sd_mbuf = m;
1322
1323		if ((TX_ENTRIES - cnt) < 4)
1324			goto oactive;
1325
1326		txd = r->r_desc + prod;
1327
1328		txd->tx_flags = TX_FLAGS_TYPE_DATA;
1329		txd->tx_numdesc = 0;
1330		txd->tx_addrlo = 0;
1331		txd->tx_addrhi = 0;
1332		txd->tx_totlen = 0;
1333		txd->tx_pflags = 0;
1334
1335		if (++prod == TX_ENTRIES)
1336			prod = 0;
1337
1338		if (++cnt >= (TX_ENTRIES - 4))
1339			goto oactive;
1340
1341		mtag = VLAN_OUTPUT_TAG(ifp, m);
1342		if (mtag != NULL) {
1343			txd->tx_pflags = TX_PFLAGS_VLAN |
1344			    (htons(VLAN_TAG_VALUE(mtag)) << TX_PFLAGS_VLANTAG_S);
1345		}
1346
1347		if (m->m_pkthdr.csum_flags & CSUM_IP)
1348			txd->tx_pflags |= TX_PFLAGS_IPCKSUM;
1349
1350#if 0
1351		if (m->m_pkthdr.csum_flags & CSUM_TCP)
1352			txd->tx_pflags |= TX_PFLAGS_TCPCKSUM;
1353		if (m->m_pkthdr.csum_flags & CSUM_UDP)
1354			txd->tx_pflags |= TX_PFLAGS_UDPCKSUM;
1355#endif
1356
1357		fxd = (struct txp_frag_desc *)(r->r_desc + prod);
1358		for (m0 = m; m0 != NULL; m0 = m0->m_next) {
1359			if (m0->m_len == 0)
1360				continue;
1361			if (++cnt >= (TX_ENTRIES - 4))
1362				goto oactive;
1363
1364			txd->tx_numdesc++;
1365
1366			fxd->frag_flags = FRAG_FLAGS_TYPE_FRAG;
1367			fxd->frag_rsvd1 = 0;
1368			fxd->frag_len = m0->m_len;
1369			fxd->frag_addrlo = vtophys(mtod(m0, vm_offset_t));
1370			fxd->frag_addrhi = 0;
1371			fxd->frag_rsvd2 = 0;
1372
1373			if (++prod == TX_ENTRIES) {
1374				fxd = (struct txp_frag_desc *)r->r_desc;
1375				prod = 0;
1376			} else
1377				fxd++;
1378
1379		}
1380
1381		ifp->if_timer = 5;
1382
1383		BPF_MTAP(ifp, m);
1384		WRITE_REG(sc, r->r_reg, TXP_IDX2OFFSET(prod));
1385	}
1386
1387	r->r_prod = prod;
1388	r->r_cnt = cnt;
1389	return;
1390
1391oactive:
1392	ifp->if_flags |= IFF_OACTIVE;
1393	r->r_prod = firstprod;
1394	r->r_cnt = firstcnt;
1395	IF_PREPEND(&ifp->if_snd, m);
1396	return;
1397}
1398
1399/*
1400 * Handle simple commands sent to the typhoon
1401 */
1402static int
1403txp_command(sc, id, in1, in2, in3, out1, out2, out3, wait)
1404	struct txp_softc *sc;
1405	u_int16_t id, in1, *out1;
1406	u_int32_t in2, in3, *out2, *out3;
1407	int wait;
1408{
1409	struct txp_rsp_desc *rsp = NULL;
1410
1411	if (txp_command2(sc, id, in1, in2, in3, NULL, 0, &rsp, wait))
1412		return (-1);
1413
1414	if (!wait)
1415		return (0);
1416
1417	if (out1 != NULL)
1418		*out1 = rsp->rsp_par1;
1419	if (out2 != NULL)
1420		*out2 = rsp->rsp_par2;
1421	if (out3 != NULL)
1422		*out3 = rsp->rsp_par3;
1423	free(rsp, M_DEVBUF);
1424	return (0);
1425}
1426
1427static int
1428txp_command2(sc, id, in1, in2, in3, in_extp, in_extn, rspp, wait)
1429	struct txp_softc *sc;
1430	u_int16_t id, in1;
1431	u_int32_t in2, in3;
1432	struct txp_ext_desc *in_extp;
1433	u_int8_t in_extn;
1434	struct txp_rsp_desc **rspp;
1435	int wait;
1436{
1437	struct txp_hostvar *hv = sc->sc_hostvar;
1438	struct txp_cmd_desc *cmd;
1439	struct txp_ext_desc *ext;
1440	u_int32_t idx, i;
1441	u_int16_t seq;
1442
1443	if (txp_cmd_desc_numfree(sc) < (in_extn + 1)) {
1444		device_printf(sc->sc_dev, "no free cmd descriptors\n");
1445		return (-1);
1446	}
1447
1448	idx = sc->sc_cmdring.lastwrite;
1449	cmd = (struct txp_cmd_desc *)(((u_int8_t *)sc->sc_cmdring.base) + idx);
1450	bzero(cmd, sizeof(*cmd));
1451
1452	cmd->cmd_numdesc = in_extn;
1453	cmd->cmd_seq = seq = sc->sc_seq++;
1454	cmd->cmd_id = id;
1455	cmd->cmd_par1 = in1;
1456	cmd->cmd_par2 = in2;
1457	cmd->cmd_par3 = in3;
1458	cmd->cmd_flags = CMD_FLAGS_TYPE_CMD |
1459	    (wait ? CMD_FLAGS_RESP : 0) | CMD_FLAGS_VALID;
1460
1461	idx += sizeof(struct txp_cmd_desc);
1462	if (idx == sc->sc_cmdring.size)
1463		idx = 0;
1464
1465	for (i = 0; i < in_extn; i++) {
1466		ext = (struct txp_ext_desc *)(((u_int8_t *)sc->sc_cmdring.base) + idx);
1467		bcopy(in_extp, ext, sizeof(struct txp_ext_desc));
1468		in_extp++;
1469		idx += sizeof(struct txp_cmd_desc);
1470		if (idx == sc->sc_cmdring.size)
1471			idx = 0;
1472	}
1473
1474	sc->sc_cmdring.lastwrite = idx;
1475
1476	WRITE_REG(sc, TXP_H2A_2, sc->sc_cmdring.lastwrite);
1477
1478	if (!wait)
1479		return (0);
1480
1481	for (i = 0; i < 10000; i++) {
1482		idx = hv->hv_resp_read_idx;
1483		if (idx != hv->hv_resp_write_idx) {
1484			*rspp = NULL;
1485			if (txp_response(sc, idx, id, seq, rspp))
1486				return (-1);
1487			if (*rspp != NULL)
1488				break;
1489		}
1490		DELAY(50);
1491	}
1492	if (i == 1000 || (*rspp) == NULL) {
1493		device_printf(sc->sc_dev, "0x%x command failed\n", id);
1494		return (-1);
1495	}
1496
1497	return (0);
1498}
1499
1500static int
1501txp_response(sc, ridx, id, seq, rspp)
1502	struct txp_softc *sc;
1503	u_int32_t ridx;
1504	u_int16_t id;
1505	u_int16_t seq;
1506	struct txp_rsp_desc **rspp;
1507{
1508	struct txp_hostvar *hv = sc->sc_hostvar;
1509	struct txp_rsp_desc *rsp;
1510
1511	while (ridx != hv->hv_resp_write_idx) {
1512		rsp = (struct txp_rsp_desc *)(((u_int8_t *)sc->sc_rspring.base) + ridx);
1513
1514		if (id == rsp->rsp_id && rsp->rsp_seq == seq) {
1515			*rspp = (struct txp_rsp_desc *)malloc(
1516			    sizeof(struct txp_rsp_desc) * (rsp->rsp_numdesc + 1),
1517			    M_DEVBUF, M_NOWAIT);
1518			if ((*rspp) == NULL)
1519				return (-1);
1520			txp_rsp_fixup(sc, rsp, *rspp);
1521			return (0);
1522		}
1523
1524		if (rsp->rsp_flags & RSP_FLAGS_ERROR) {
1525			device_printf(sc->sc_dev, "response error!\n");
1526			txp_rsp_fixup(sc, rsp, NULL);
1527			ridx = hv->hv_resp_read_idx;
1528			continue;
1529		}
1530
1531		switch (rsp->rsp_id) {
1532		case TXP_CMD_CYCLE_STATISTICS:
1533		case TXP_CMD_MEDIA_STATUS_READ:
1534			break;
1535		case TXP_CMD_HELLO_RESPONSE:
1536			device_printf(sc->sc_dev, "hello\n");
1537			break;
1538		default:
1539			device_printf(sc->sc_dev, "unknown id(0x%x)\n",
1540			    rsp->rsp_id);
1541		}
1542
1543		txp_rsp_fixup(sc, rsp, NULL);
1544		ridx = hv->hv_resp_read_idx;
1545		hv->hv_resp_read_idx = ridx;
1546	}
1547
1548	return (0);
1549}
1550
1551static void
1552txp_rsp_fixup(sc, rsp, dst)
1553	struct txp_softc *sc;
1554	struct txp_rsp_desc *rsp, *dst;
1555{
1556	struct txp_rsp_desc *src = rsp;
1557	struct txp_hostvar *hv = sc->sc_hostvar;
1558	u_int32_t i, ridx;
1559
1560	ridx = hv->hv_resp_read_idx;
1561
1562	for (i = 0; i < rsp->rsp_numdesc + 1; i++) {
1563		if (dst != NULL)
1564			bcopy(src, dst++, sizeof(struct txp_rsp_desc));
1565		ridx += sizeof(struct txp_rsp_desc);
1566		if (ridx == sc->sc_rspring.size) {
1567			src = sc->sc_rspring.base;
1568			ridx = 0;
1569		} else
1570			src++;
1571		sc->sc_rspring.lastwrite = hv->hv_resp_read_idx = ridx;
1572	}
1573
1574	hv->hv_resp_read_idx = ridx;
1575}
1576
1577static int
1578txp_cmd_desc_numfree(sc)
1579	struct txp_softc *sc;
1580{
1581	struct txp_hostvar *hv = sc->sc_hostvar;
1582	struct txp_boot_record *br = sc->sc_boot;
1583	u_int32_t widx, ridx, nfree;
1584
1585	widx = sc->sc_cmdring.lastwrite;
1586	ridx = hv->hv_cmd_read_idx;
1587
1588	if (widx == ridx) {
1589		/* Ring is completely free */
1590		nfree = br->br_cmd_siz - sizeof(struct txp_cmd_desc);
1591	} else {
1592		if (widx > ridx)
1593			nfree = br->br_cmd_siz -
1594			    (widx - ridx + sizeof(struct txp_cmd_desc));
1595		else
1596			nfree = ridx - widx - sizeof(struct txp_cmd_desc);
1597	}
1598
1599	return (nfree / sizeof(struct txp_cmd_desc));
1600}
1601
1602static void
1603txp_stop(sc)
1604	struct txp_softc *sc;
1605{
1606	struct ifnet *ifp;
1607
1608	ifp = &sc->sc_arpcom.ac_if;
1609
1610	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
1611
1612	untimeout(txp_tick, sc, sc->sc_tick);
1613
1614	txp_command(sc, TXP_CMD_TX_DISABLE, 0, 0, 0, NULL, NULL, NULL, 1);
1615	txp_command(sc, TXP_CMD_RX_DISABLE, 0, 0, 0, NULL, NULL, NULL, 1);
1616
1617	txp_rxring_empty(sc);
1618
1619	return;
1620}
1621
1622static void
1623txp_watchdog(ifp)
1624	struct ifnet *ifp;
1625{
1626	return;
1627}
1628
1629static int
1630txp_ifmedia_upd(ifp)
1631	struct ifnet *ifp;
1632{
1633	struct txp_softc *sc = ifp->if_softc;
1634	struct ifmedia *ifm = &sc->sc_ifmedia;
1635	u_int16_t new_xcvr;
1636
1637	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
1638		return (EINVAL);
1639
1640	if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_T) {
1641		if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
1642			new_xcvr = TXP_XCVR_10_FDX;
1643		else
1644			new_xcvr = TXP_XCVR_10_HDX;
1645	} else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_TX) {
1646		if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
1647			new_xcvr = TXP_XCVR_100_FDX;
1648		else
1649			new_xcvr = TXP_XCVR_100_HDX;
1650	} else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) {
1651		new_xcvr = TXP_XCVR_AUTO;
1652	} else
1653		return (EINVAL);
1654
1655	/* nothing to do */
1656	if (sc->sc_xcvr == new_xcvr)
1657		return (0);
1658
1659	txp_command(sc, TXP_CMD_XCVR_SELECT, new_xcvr, 0, 0,
1660	    NULL, NULL, NULL, 0);
1661	sc->sc_xcvr = new_xcvr;
1662
1663	return (0);
1664}
1665
1666static void
1667txp_ifmedia_sts(ifp, ifmr)
1668	struct ifnet *ifp;
1669	struct ifmediareq *ifmr;
1670{
1671	struct txp_softc *sc = ifp->if_softc;
1672	struct ifmedia *ifm = &sc->sc_ifmedia;
1673	u_int16_t bmsr, bmcr, anlpar;
1674
1675	ifmr->ifm_status = IFM_AVALID;
1676	ifmr->ifm_active = IFM_ETHER;
1677
1678	if (txp_command(sc, TXP_CMD_PHY_MGMT_READ, 0, MII_BMSR, 0,
1679	    &bmsr, NULL, NULL, 1))
1680		goto bail;
1681	if (txp_command(sc, TXP_CMD_PHY_MGMT_READ, 0, MII_BMSR, 0,
1682	    &bmsr, NULL, NULL, 1))
1683		goto bail;
1684
1685	if (txp_command(sc, TXP_CMD_PHY_MGMT_READ, 0, MII_BMCR, 0,
1686	    &bmcr, NULL, NULL, 1))
1687		goto bail;
1688
1689	if (txp_command(sc, TXP_CMD_PHY_MGMT_READ, 0, MII_ANLPAR, 0,
1690	    &anlpar, NULL, NULL, 1))
1691		goto bail;
1692
1693	if (bmsr & BMSR_LINK)
1694		ifmr->ifm_status |= IFM_ACTIVE;
1695
1696	if (bmcr & BMCR_ISO) {
1697		ifmr->ifm_active |= IFM_NONE;
1698		ifmr->ifm_status = 0;
1699		return;
1700	}
1701
1702	if (bmcr & BMCR_LOOP)
1703		ifmr->ifm_active |= IFM_LOOP;
1704
1705	if (bmcr & BMCR_AUTOEN) {
1706		if ((bmsr & BMSR_ACOMP) == 0) {
1707			ifmr->ifm_active |= IFM_NONE;
1708			return;
1709		}
1710
1711		if (anlpar & ANLPAR_T4)
1712			ifmr->ifm_active |= IFM_100_T4;
1713		else if (anlpar & ANLPAR_TX_FD)
1714			ifmr->ifm_active |= IFM_100_TX|IFM_FDX;
1715		else if (anlpar & ANLPAR_TX)
1716			ifmr->ifm_active |= IFM_100_TX;
1717		else if (anlpar & ANLPAR_10_FD)
1718			ifmr->ifm_active |= IFM_10_T|IFM_FDX;
1719		else if (anlpar & ANLPAR_10)
1720			ifmr->ifm_active |= IFM_10_T;
1721		else
1722			ifmr->ifm_active |= IFM_NONE;
1723	} else
1724		ifmr->ifm_active = ifm->ifm_cur->ifm_media;
1725	return;
1726
1727bail:
1728	ifmr->ifm_active |= IFM_NONE;
1729	ifmr->ifm_status &= ~IFM_AVALID;
1730}
1731
1732#ifdef TXP_DEBUG
1733static void
1734txp_show_descriptor(d)
1735	void *d;
1736{
1737	struct txp_cmd_desc *cmd = d;
1738	struct txp_rsp_desc *rsp = d;
1739	struct txp_tx_desc *txd = d;
1740	struct txp_frag_desc *frgd = d;
1741
1742	switch (cmd->cmd_flags & CMD_FLAGS_TYPE_M) {
1743	case CMD_FLAGS_TYPE_CMD:
1744		/* command descriptor */
1745		printf("[cmd flags 0x%x num %d id %d seq %d par1 0x%x par2 0x%x par3 0x%x]\n",
1746		    cmd->cmd_flags, cmd->cmd_numdesc, cmd->cmd_id, cmd->cmd_seq,
1747		    cmd->cmd_par1, cmd->cmd_par2, cmd->cmd_par3);
1748		break;
1749	case CMD_FLAGS_TYPE_RESP:
1750		/* response descriptor */
1751		printf("[rsp flags 0x%x num %d id %d seq %d par1 0x%x par2 0x%x par3 0x%x]\n",
1752		    rsp->rsp_flags, rsp->rsp_numdesc, rsp->rsp_id, rsp->rsp_seq,
1753		    rsp->rsp_par1, rsp->rsp_par2, rsp->rsp_par3);
1754		break;
1755	case CMD_FLAGS_TYPE_DATA:
1756		/* data header (assuming tx for now) */
1757		printf("[data flags 0x%x num %d totlen %d addr 0x%x/0x%x pflags 0x%x]",
1758		    txd->tx_flags, txd->tx_numdesc, txd->tx_totlen,
1759		    txd->tx_addrlo, txd->tx_addrhi, txd->tx_pflags);
1760		break;
1761	case CMD_FLAGS_TYPE_FRAG:
1762		/* fragment descriptor */
1763		printf("[frag flags 0x%x rsvd1 0x%x len %d addr 0x%x/0x%x rsvd2 0x%x]",
1764		    frgd->frag_flags, frgd->frag_rsvd1, frgd->frag_len,
1765		    frgd->frag_addrlo, frgd->frag_addrhi, frgd->frag_rsvd2);
1766		break;
1767	default:
1768		printf("[unknown(%x) flags 0x%x num %d id %d seq %d par1 0x%x par2 0x%x par3 0x%x]\n",
1769		    cmd->cmd_flags & CMD_FLAGS_TYPE_M,
1770		    cmd->cmd_flags, cmd->cmd_numdesc, cmd->cmd_id, cmd->cmd_seq,
1771		    cmd->cmd_par1, cmd->cmd_par2, cmd->cmd_par3);
1772		break;
1773	}
1774}
1775#endif
1776
1777static void
1778txp_set_filter(sc)
1779	struct txp_softc *sc;
1780{
1781	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
1782	u_int32_t crc, carry, hashbit, hash[2];
1783	u_int16_t filter;
1784	u_int8_t octet;
1785	int i, j, mcnt = 0;
1786	struct ifmultiaddr *ifma;
1787	char *enm;
1788
1789	if (ifp->if_flags & IFF_PROMISC) {
1790		filter = TXP_RXFILT_PROMISC;
1791		goto setit;
1792	}
1793
1794	filter = TXP_RXFILT_DIRECT;
1795
1796	if (ifp->if_flags & IFF_BROADCAST)
1797		filter |= TXP_RXFILT_BROADCAST;
1798
1799	if (ifp->if_flags & IFF_ALLMULTI)
1800		filter |= TXP_RXFILT_ALLMULTI;
1801	else {
1802		hash[0] = hash[1] = 0;
1803
1804		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1805			if (ifma->ifma_addr->sa_family != AF_LINK)
1806				continue;
1807
1808			enm = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
1809			mcnt++;
1810			crc = 0xffffffff;
1811
1812			for (i = 0; i < ETHER_ADDR_LEN; i++) {
1813				octet = enm[i];
1814				for (j = 0; j < 8; j++) {
1815					carry = ((crc & 0x80000000) ? 1 : 0) ^
1816					    (octet & 1);
1817					crc <<= 1;
1818					octet >>= 1;
1819					if (carry)
1820						crc = (crc ^ TXP_POLYNOMIAL) |
1821						    carry;
1822				}
1823			}
1824			hashbit = (u_int16_t)(crc & (64 - 1));
1825			hash[hashbit / 32] |= (1 << hashbit % 32);
1826		}
1827
1828		if (mcnt > 0) {
1829			filter |= TXP_RXFILT_HASHMULTI;
1830			txp_command(sc, TXP_CMD_MCAST_HASH_MASK_WRITE,
1831			    2, hash[0], hash[1], NULL, NULL, NULL, 0);
1832		}
1833	}
1834
1835setit:
1836
1837	txp_command(sc, TXP_CMD_RX_FILTER_WRITE, filter, 0, 0,
1838	    NULL, NULL, NULL, 1);
1839
1840	return;
1841}
1842
1843static void
1844txp_capabilities(sc)
1845	struct txp_softc *sc;
1846{
1847	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
1848	struct txp_rsp_desc *rsp = NULL;
1849	struct txp_ext_desc *ext;
1850
1851	if (txp_command2(sc, TXP_CMD_OFFLOAD_READ, 0, 0, 0, NULL, 0, &rsp, 1))
1852		goto out;
1853
1854	if (rsp->rsp_numdesc != 1)
1855		goto out;
1856	ext = (struct txp_ext_desc *)(rsp + 1);
1857
1858	sc->sc_tx_capability = ext->ext_1 & OFFLOAD_MASK;
1859	sc->sc_rx_capability = ext->ext_2 & OFFLOAD_MASK;
1860	ifp->if_capabilities = 0;
1861
1862	if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_VLAN) {
1863		sc->sc_tx_capability |= OFFLOAD_VLAN;
1864		sc->sc_rx_capability |= OFFLOAD_VLAN;
1865		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
1866	}
1867
1868#if 0
1869	/* not ready yet */
1870	if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_IPSEC) {
1871		sc->sc_tx_capability |= OFFLOAD_IPSEC;
1872		sc->sc_rx_capability |= OFFLOAD_IPSEC;
1873		ifp->if_capabilities |= IFCAP_IPSEC;
1874	}
1875#endif
1876
1877	if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_IPCKSUM) {
1878		sc->sc_tx_capability |= OFFLOAD_IPCKSUM;
1879		sc->sc_rx_capability |= OFFLOAD_IPCKSUM;
1880		ifp->if_capabilities |= IFCAP_HWCSUM;
1881		ifp->if_hwassist |= CSUM_IP;
1882	}
1883
1884	if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_TCPCKSUM) {
1885#if 0
1886		sc->sc_tx_capability |= OFFLOAD_TCPCKSUM;
1887#endif
1888		sc->sc_rx_capability |= OFFLOAD_TCPCKSUM;
1889		ifp->if_capabilities |= IFCAP_HWCSUM;
1890	}
1891
1892	if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_UDPCKSUM) {
1893#if 0
1894		sc->sc_tx_capability |= OFFLOAD_UDPCKSUM;
1895#endif
1896		sc->sc_rx_capability |= OFFLOAD_UDPCKSUM;
1897		ifp->if_capabilities |= IFCAP_HWCSUM;
1898	}
1899	ifp->if_capenable = ifp->if_capabilities;
1900
1901	if (txp_command(sc, TXP_CMD_OFFLOAD_WRITE, 0,
1902	    sc->sc_tx_capability, sc->sc_rx_capability, NULL, NULL, NULL, 1))
1903		goto out;
1904
1905out:
1906	if (rsp != NULL)
1907		free(rsp, M_DEVBUF);
1908
1909	return;
1910}
1911