if_txp.c revision 147256
1137029Sphk/*	$OpenBSD: if_txp.c,v 1.48 2001/06/27 06:34:50 kjc Exp $	*/
2137029Sphk
331936Sdyson/*-
4251897Sscottl * Copyright (c) 2001
51549Srgrimes *	Jason L. Wright <jason@thought.net>, Theo de Raadt, and
61541Srgrimes *	Aaron Campbell <aaron@monkey.org>.  All rights reserved.
7251897Sscottl *
8251897Sscottl * Redistribution and use in source and binary forms, with or without
9251897Sscottl * modification, are permitted provided that the following conditions
101541Srgrimes * are met:
111541Srgrimes * 1. Redistributions of source code must retain the above copyright
121541Srgrimes *    notice, this list of conditions and the following disclaimer.
131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
14137029Sphk *    notice, this list of conditions and the following disclaimer in the
15137029Sphk *    documentation and/or other materials provided with the distribution.
16137029Sphk * 3. All advertising materials mentioning features or use of this software
17137029Sphk *    must display the following acknowledgement:
18137029Sphk *	This product includes software developed by Jason L. Wright,
19137029Sphk *	Theo de Raadt and Aaron Campbell.
20137029Sphk * 4. Neither the name of the author nor the names of any co-contributors
21137029Sphk *    may be used to endorse or promote products derived from this software
22137029Sphk *    without specific prior written permission.
23137029Sphk *
24137029Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
25137029Sphk * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26137029Sphk * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27137029Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
28137029Sphk * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29137029Sphk * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
301541Srgrimes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
311541Srgrimes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
325455Sdg * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
335455Sdg * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
345455Sdg * THE POSSIBILITY OF SUCH DAMAGE.
355455Sdg */
365455Sdg
375455Sdg#include <sys/cdefs.h>
385455Sdg__FBSDID("$FreeBSD: head/sys/dev/txp/if_txp.c 147256 2005-06-10 16:49:24Z brooks $");
395455Sdg
405455Sdg/*
4142014Sdillon * Driver for 3c990 (Typhoon) Ethernet ASIC
4242014Sdillon */
435455Sdg
445455Sdg#include <sys/cdefs.h>
45116182Sobrien__FBSDID("$FreeBSD: head/sys/dev/txp/if_txp.c 147256 2005-06-10 16:49:24Z brooks $");
46116182Sobrien
47116182Sobrien#include <sys/param.h>
481541Srgrimes#include <sys/systm.h>
491541Srgrimes#include <sys/sockio.h>
5060041Sphk#include <sys/mbuf.h>
51121188Sphk#include <sys/malloc.h>
5255539Sluoqi#include <sys/kernel.h>
53103330Sphk#include <sys/module.h>
5455539Sluoqi#include <sys/socket.h>
55192908Szml
56170475Smarcel#include <net/if.h>
5755539Sluoqi#include <net/if_arp.h>
5855539Sluoqi#include <net/ethernet.h>
5955539Sluoqi#include <net/if_dl.h>
6067365Sjhb#include <net/if_types.h>
611549Srgrimes#include <net/if_vlan_var.h>
6255539Sluoqi
6355539Sluoqi#include <netinet/in.h>
6455539Sluoqi#include <netinet/in_systm.h>
6512623Sphk#include <netinet/in_var.h>
6655539Sluoqi#include <netinet/ip.h>
671549Srgrimes#include <netinet/if_ether.h>
68137029Sphk#include <machine/in_cksum.h>
695455Sdg
7012662Sdg#include <net/if_media.h>
717090Sbde
725455Sdg#include <net/bpf.h>
735455Sdg
745455Sdg#include <vm/vm.h>              /* for vtophys */
7512662Sdg#include <vm/pmap.h>            /* for vtophys */
7620054Sdyson#include <machine/clock.h>	/* for DELAY */
77189627Sjhb#include <machine/bus.h>
78112694Stegge#include <machine/resource.h>
79112694Stegge#include <sys/bus.h>
801541Srgrimes#include <sys/rman.h>
81151897Srwatson
8230309Sphk#include <dev/mii/mii.h>
8334266Sjulian#include <dev/mii/miivar.h>
8434266Sjulian#include <dev/pci/pcireg.h>
8575580Sphk#include <dev/pci/pcivar.h>
86136927Sphk
87136927Sphk#define TXP_USEIOSPACE
88136927Sphk#define __STRICT_ALIGNMENT
89140056Sphk
90166193Skib#include <dev/txp/if_txpreg.h>
9175580Sphk#include <dev/txp/3c990img.h>
9275580Sphk
9391690Seivind#ifndef lint
9491690Seivindstatic const char rcsid[] =
9591690Seivind  "$FreeBSD: head/sys/dev/txp/if_txp.c 147256 2005-06-10 16:49:24Z brooks $";
9691690Seivind#endif
975455Sdg
98251897Sscottl/*
991549Srgrimes * Various supported device vendors/types and their names.
100122031Smckusick */
101122031Smckusickstatic struct txp_type txp_devs[] = {
102137188Sphk	{ TXP_VENDORID_3COM, TXP_DEVICEID_3CR990_TX_95,
103209902Salc	    "3Com 3cR990-TX-95 Etherlink with 3XP Processor" },
104135276Sphk	{ TXP_VENDORID_3COM, TXP_DEVICEID_3CR990_TX_97,
10512819Sphk	    "3Com 3cR990-TX-97 Etherlink with 3XP Processor" },
106192034Salc	{ TXP_VENDORID_3COM, TXP_DEVICEID_3CR990B_TXM,
107192034Salc	    "3Com 3cR990B-TXM Etherlink with 3XP Processor" },
108174140Salc	{ TXP_VENDORID_3COM, TXP_DEVICEID_3CR990_SRV_95,
109208920Skib	    "3Com 3cR990-SRV-95 Etherlink Server with 3XP Processor" },
110208920Skib	{ TXP_VENDORID_3COM, TXP_DEVICEID_3CR990_SRV_97,
111163750Salc	    "3Com 3cR990-SRV-97 Etherlink Server with 3XP Processor" },
11213490Sdyson	{ TXP_VENDORID_3COM, TXP_DEVICEID_3CR990B_SRV,
113110581Sjeff	    "3Com 3cR990B-SRV Etherlink Server with 3XP Processor" },
114110581Sjeff	{ 0, 0, NULL }
115189878Skib};
116189878Skib
11792723Salfredstatic int txp_probe	(device_t);
118141637Sphkstatic int txp_attach	(device_t);
119189627Sjhbstatic int txp_detach	(device_t);
120189627Sjhbstatic void txp_intr	(void *);
121189627Sjhbstatic void txp_tick	(void *);
122189627Sjhbstatic int txp_shutdown	(device_t);
1231541Srgrimesstatic int txp_ioctl	(struct ifnet *, u_long, caddr_t);
12491690Seivindstatic void txp_start	(struct ifnet *);
12591690Seivindstatic void txp_stop	(struct txp_softc *);
12691690Seivindstatic void txp_init	(void *);
127189595Sjhbstatic void txp_watchdog	(struct ifnet *);
128189595Sjhb
12991690Seivindstatic void txp_release_resources(struct txp_softc *);
130189595Sjhbstatic int txp_chip_init(struct txp_softc *);
131189627Sjhbstatic int txp_reset_adapter(struct txp_softc *);
132189627Sjhbstatic int txp_download_fw(struct txp_softc *);
133189627Sjhbstatic int txp_download_fw_wait(struct txp_softc *);
134190331Sjhbstatic int txp_download_fw_section (struct txp_softc *,
135189627Sjhb    struct txp_fw_section_header *, int);
136189595Sjhbstatic int txp_alloc_rings(struct txp_softc *);
137190331Sjhbstatic int txp_rxring_fill(struct txp_softc *);
138189627Sjhbstatic void txp_rxring_empty(struct txp_softc *);
139251897Sscottlstatic void txp_set_filter(struct txp_softc *);
140251897Sscottl
141251897Sscottlstatic int txp_cmd_desc_numfree(struct txp_softc *);
142251897Sscottlstatic int txp_command (struct txp_softc *, u_int16_t, u_int16_t, u_int32_t,
143189595Sjhb    u_int32_t, u_int16_t *, u_int32_t *, u_int32_t *, int);
144189595Sjhbstatic int txp_command2 (struct txp_softc *, u_int16_t, u_int16_t,
14591690Seivind    u_int32_t, u_int32_t, struct txp_ext_desc *, u_int8_t,
146189595Sjhb    struct txp_rsp_desc **, int);
147189595Sjhbstatic int txp_response (struct txp_softc *, u_int32_t, u_int16_t, u_int16_t,
14891690Seivind    struct txp_rsp_desc **);
149189595Sjhbstatic void txp_rsp_fixup (struct txp_softc *, struct txp_rsp_desc *,
150189595Sjhb    struct txp_rsp_desc *);
15191690Seivindstatic void txp_capabilities(struct txp_softc *);
152189595Sjhb
153189595Sjhbstatic void txp_ifmedia_sts(struct ifnet *, struct ifmediareq *);
15491690Seivindstatic int txp_ifmedia_upd(struct ifnet *);
155189595Sjhb#ifdef TXP_DEBUG
156189595Sjhbstatic void txp_show_descriptor(void *);
15791690Seivind#endif
15891690Seivindstatic void txp_tx_reclaim(struct txp_softc *, struct txp_tx_ring *);
15991690Seivindstatic void txp_rxbuf_reclaim(struct txp_softc *);
16091690Seivindstatic void txp_rx_reclaim(struct txp_softc *, struct txp_rx_ring *);
16191690Seivind
16291690Seivind#ifdef TXP_USEIOSPACE
16391690Seivind#define TXP_RES			SYS_RES_IOPORT
16491690Seivind#define TXP_RID			TXP_PCI_LOIO
16591690Seivind#else
16691690Seivind#define TXP_RES			SYS_RES_MEMORY
167189595Sjhb#define TXP_RID			TXP_PCI_LOMEM
168189595Sjhb#endif
16991690Seivind
170189595Sjhbstatic device_method_t txp_methods[] = {
171189595Sjhb        /* Device interface */
17291690Seivind	DEVMETHOD(device_probe,		txp_probe),
173166193Skib	DEVMETHOD(device_attach,	txp_attach),
174111466Smckusick	DEVMETHOD(device_detach,	txp_detach),
175111466Smckusick	DEVMETHOD(device_shutdown,	txp_shutdown),
176166193Skib	{ 0, 0 }
177166193Skib};
178166193Skib
179166193Skibstatic driver_t txp_driver = {
180111466Smckusick	"txp",
181111466Smckusick	txp_methods,
182111511Smckusick	sizeof(struct txp_softc)
183111511Smckusick};
184111511Smckusick
18591690Seivindstatic devclass_t txp_devclass;
18691690Seivind
18791690SeivindDRIVER_MODULE(txp, pci, txp_driver, txp_devclass, 0, 0);
18891690SeivindMODULE_DEPEND(txp, pci, 1, 1, 1);
18991690SeivindMODULE_DEPEND(txp, ether, 1, 1, 1);
19091690Seivind
19191690Seivindstatic int
19291690Seivindtxp_probe(dev)
19391690Seivind	device_t dev;
194166193Skib{
195111466Smckusick	struct txp_type *t;
196111466Smckusick
19791690Seivind	t = txp_devs;
19891690Seivind
19991690Seivind	while(t->txp_name != NULL) {
20091690Seivind		if ((pci_get_vendor(dev) == t->txp_vid) &&
20191690Seivind		    (pci_get_device(dev) == t->txp_did)) {
20291690Seivind			device_set_desc(dev, t->txp_name);
20391690Seivind			return(BUS_PROBE_DEFAULT);
20491690Seivind		}
20591690Seivind		t++;
20691690Seivind	}
20791690Seivind
20891690Seivind	return(ENXIO);
20991690Seivind}
21091690Seivind
21191690Seivindstatic int
212251897Sscottltxp_attach(dev)
213251897Sscottl	device_t dev;
214251897Sscottl{
215251897Sscottl	struct txp_softc *sc;
216189878Skib	struct ifnet *ifp;
217189878Skib	u_int16_t p1;
218189878Skib	u_int32_t p2;
219191135Skib	int unit, error = 0, rid;
220191135Skib	u_char eaddr[6];
221191135Skib
222248665Smckusick	sc = device_get_softc(dev);
223248665Smckusick	unit = device_get_unit(dev);
224248665Smckusick	sc->sc_dev = dev;
225251897Sscottl	sc->sc_cold = 1;
226251897Sscottl
227251897Sscottl	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
22891690Seivind	    MTX_DEF | MTX_RECURSE);
22991690Seivind	/*
23091690Seivind	 * Map control/status registers.
23191690Seivind	 */
23291690Seivind	pci_enable_busmaster(dev);
23391690Seivind
23448544Smckusick	rid = TXP_RID;
23548544Smckusick	sc->sc_res = bus_alloc_resource_any(dev, TXP_RES, &rid,
2361541Srgrimes	    RF_ACTIVE);
237207141Sjeff
238207141Sjeff	if (sc->sc_res == NULL) {
239207141Sjeff		device_printf(dev, "couldn't map ports/memory\n");
240207141Sjeff		error = ENXIO;
241207141Sjeff		goto fail;
242207141Sjeff	}
243207141Sjeff
244207141Sjeff	sc->sc_bt = rman_get_bustag(sc->sc_res);
245110581Sjeff	sc->sc_bh = rman_get_bushandle(sc->sc_res);
246110581Sjeff
247110581Sjeff	/* Allocate interrupt */
248110581Sjeff	rid = 0;
249110581Sjeff	sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
2505455Sdg	    RF_SHAREABLE | RF_ACTIVE);
2516619Sdg
2526619Sdg	if (sc->sc_irq == NULL) {
2536619Sdg		device_printf(dev, "couldn't map interrupt\n");
2546619Sdg		txp_release_resources(sc);
2555455Sdg		error = ENXIO;
2565455Sdg		goto fail;
25791690Seivind	}
25891690Seivind
25991690Seivind	error = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_NET,
26091690Seivind	    txp_intr, sc, &sc->sc_intrhand);
26191690Seivind
26291690Seivind	if (error) {
26391690Seivind		txp_release_resources(sc);
26491690Seivind		device_printf(dev, "couldn't set up irq\n");
265110581Sjeff		goto fail;
266110581Sjeff	}
267110581Sjeff
268110581Sjeff	if (txp_chip_init(sc)) {
269110581Sjeff		txp_release_resources(sc);
270110581Sjeff		/* XXX: set error to ??? */
27191690Seivind		goto fail;
27291690Seivind	}
27391690Seivind
27491690Seivind	sc->sc_fwbuf = contigmalloc(32768, M_DEVBUF,
27591690Seivind	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
27691690Seivind	error = txp_download_fw(sc);
27791690Seivind	contigfree(sc->sc_fwbuf, 32768, M_DEVBUF);
27844679Sjulian	sc->sc_fwbuf = NULL;
2795839Sdg
280110581Sjeff	if (error) {
281110581Sjeff		txp_release_resources(sc);
282110581Sjeff		goto fail;
283110581Sjeff	}
284110581Sjeff
28591690Seivind	sc->sc_ldata = contigmalloc(sizeof(struct txp_ldata), M_DEVBUF,
28691700Seivind	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
28791700Seivind	bzero(sc->sc_ldata, sizeof(struct txp_ldata));
288157319Sjeff
28991700Seivind	if (txp_alloc_rings(sc)) {
29091700Seivind		txp_release_resources(sc);
291119521Sjeff		/* XXX: set error to ??? */
292119521Sjeff		goto fail;
293157319Sjeff	}
294157319Sjeff
295157319Sjeff	if (txp_command(sc, TXP_CMD_MAX_PKT_SIZE_WRITE, TXP_MAX_PKTLEN, 0, 0,
296189878Skib	    NULL, NULL, NULL, 1)) {
29791700Seivind		txp_release_resources(sc);
29891690Seivind		/* XXX: set error to ??? */
29991700Seivind		goto fail;
300251897Sscottl	}
301251897Sscottl
302251897Sscottl	if (txp_command(sc, TXP_CMD_STATION_ADDRESS_READ, 0, 0, 0,
303110581Sjeff	    &p1, &p2, NULL, 1)) {
304110581Sjeff		txp_release_resources(sc);
305110581Sjeff		/* XXX: set error to ??? */
306110581Sjeff		goto fail;
30791690Seivind	}
30891690Seivind
30991690Seivind	txp_set_filter(sc);
31091690Seivind
31191700Seivind	eaddr[0] = ((u_int8_t *)&p1)[1];
3129759Sbde	eaddr[1] = ((u_int8_t *)&p1)[0];
31344679Sjulian	eaddr[2] = ((u_int8_t *)&p2)[3];
31448677Smckusick	eaddr[3] = ((u_int8_t *)&p2)[2];
31544679Sjulian	eaddr[4] = ((u_int8_t *)&p2)[1];
31644679Sjulian	eaddr[5] = ((u_int8_t *)&p2)[0];
31726664Sdyson
318189627Sjhb	sc->sc_cold = 0;
319189627Sjhb
320189627Sjhb	ifmedia_init(&sc->sc_ifmedia, 0, txp_ifmedia_upd, txp_ifmedia_sts);
321189627Sjhb	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
322189627Sjhb	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
323189627Sjhb	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
324189627Sjhb	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
325189627Sjhb	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL);
326192543Sjhb	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
327189627Sjhb	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
328189627Sjhb
329189648Sjhb	sc->sc_xcvr = TXP_XCVR_AUTO;
330189648Sjhb	txp_command(sc, TXP_CMD_XCVR_SELECT, TXP_XCVR_AUTO, 0, 0,
331189648Sjhb	    NULL, NULL, NULL, 0);
332189648Sjhb	ifmedia_set(&sc->sc_ifmedia, IFM_ETHER|IFM_AUTO);
333189627Sjhb
334189627Sjhb	ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
335189627Sjhb	if (ifp == NULL) {
336189627Sjhb		txp_release_resources(sc);
337112694Stegge		device_printf(dev, "couldn't set up irq\n");
338112694Stegge		error = ENOSPC;
339112694Stegge		goto fail;
3406620Sdg	}
34148677Smckusick	ifp->if_softc = sc;
34248677Smckusick	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
34348677Smckusick	ifp->if_mtu = ETHERMTU;
34448677Smckusick	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST |
34548677Smckusick	    IFF_NEEDSGIANT;
34648677Smckusick	ifp->if_ioctl = txp_ioctl;
34748677Smckusick	ifp->if_start = txp_start;
34870374Sdillon	ifp->if_watchdog = txp_watchdog;
34948677Smckusick	ifp->if_init = txp_init;
350135276Sphk	ifp->if_baudrate = 100000000;
35170374Sdillon	ifp->if_snd.ifq_maxlen = TX_ENTRIES;
352110581Sjeff	ifp->if_hwassist = 0;
35348677Smckusick	txp_capabilities(sc);
35448677Smckusick
35548677Smckusick	/*
35648677Smckusick	 * Attach us everywhere
357110581Sjeff	 */
35848677Smckusick	ether_ifattach(ifp, eaddr);
35948677Smckusick	callout_handle_init(&sc->sc_tick);
36048677Smckusick	return(0);
36148677Smckusick
36244679Sjulianfail:
36344679Sjulian	txp_release_resources(sc);
36458706Sdillon	mtx_destroy(&sc->sc_mtx);
36558706Sdillon	return(error);
36658706Sdillon}
36758706Sdillon
36844679Sjulianstatic int
36944679Sjuliantxp_detach(dev)
37044679Sjulian	device_t dev;
37144679Sjulian{
37244679Sjulian	struct txp_softc *sc;
373135276Sphk	struct ifnet *ifp;
37444679Sjulian	int i;
37544679Sjulian
37644679Sjulian	sc = device_get_softc(dev);
37744679Sjulian	ifp = sc->sc_ifp;
37844679Sjulian
379110581Sjeff	txp_stop(sc);
38044679Sjulian	txp_shutdown(dev);
38144679Sjulian
38244679Sjulian	ifmedia_removeall(&sc->sc_ifmedia);
38344679Sjulian	ether_ifdetach(ifp);
384110581Sjeff
38544679Sjulian	for (i = 0; i < RXBUF_ENTRIES; i++)
38644679Sjulian		free(sc->sc_rxbufs[i].rb_sd, M_DEVBUF);
38744679Sjulian
38870374Sdillon	txp_release_resources(sc);
38970374Sdillon
39070374Sdillon	mtx_destroy(&sc->sc_mtx);
391150741Struckman	return(0);
39270374Sdillon}
39370374Sdillon
394135276Sphkstatic void
39570374Sdillontxp_release_resources(sc)
396189595Sjhb	struct txp_softc *sc;
39770374Sdillon{
398110581Sjeff	device_t dev;
39970374Sdillon
40070374Sdillon	dev = sc->sc_dev;
40170374Sdillon
40270374Sdillon	if (sc->sc_ifp)
403110581Sjeff		if_free(sc->sc_ifp);
40470374Sdillon
40570374Sdillon	if (sc->sc_intrhand != NULL)
40670374Sdillon		bus_teardown_intr(dev, sc->sc_irq, sc->sc_intrhand);
40770374Sdillon
40844679Sjulian	if (sc->sc_irq != NULL)
40944679Sjulian		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq);
41044679Sjulian
41144679Sjulian	if (sc->sc_res != NULL)
41244679Sjulian		bus_release_resource(dev, TXP_RES, TXP_RID, sc->sc_res);
41344679Sjulian
41444679Sjulian	if (sc->sc_ldata != NULL)
41544679Sjulian		contigfree(sc->sc_ldata, sizeof(struct txp_ldata), M_DEVBUF);
41644679Sjulian
417209053Smdf	return;
41844679Sjulian}
419209053Smdf
420135276Sphkstatic int
421209053Smdftxp_chip_init(sc)
422209053Smdf	struct txp_softc *sc;
423211213Skib{
424211213Skib	/* disable interrupts */
425209053Smdf	WRITE_REG(sc, TXP_IER, 0);
426209053Smdf	WRITE_REG(sc, TXP_IMR,
427209053Smdf	    TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
428209053Smdf	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
429110581Sjeff	    TXP_INT_LATCH);
43044679Sjulian
43144679Sjulian	/* ack all interrupts */
43244679Sjulian	WRITE_REG(sc, TXP_ISR, TXP_INT_RESERVED | TXP_INT_LATCH |
43344679Sjulian	    TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 |
43444679Sjulian	    TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
43544679Sjulian	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
436110581Sjeff	    TXP_INT_A2H_3 | TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0);
43744679Sjulian
43844679Sjulian	if (txp_reset_adapter(sc))
43944679Sjulian		return (-1);
44070374Sdillon
44170374Sdillon	/* disable interrupts */
44270374Sdillon	WRITE_REG(sc, TXP_IER, 0);
44370374Sdillon	WRITE_REG(sc, TXP_IMR,
44470374Sdillon	    TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
44570374Sdillon	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
44670374Sdillon	    TXP_INT_LATCH);
44770374Sdillon
44870374Sdillon	/* ack all interrupts */
44970374Sdillon	WRITE_REG(sc, TXP_ISR, TXP_INT_RESERVED | TXP_INT_LATCH |
45070374Sdillon	    TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 |
45170374Sdillon	    TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
45270374Sdillon	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
45370374Sdillon	    TXP_INT_A2H_3 | TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0);
454150760Struckman
45570374Sdillon	return (0);
45670374Sdillon}
457135276Sphk
458110581Sjeffstatic int
45970374Sdillontxp_reset_adapter(sc)
46070374Sdillon	struct txp_softc *sc;
461110581Sjeff{
46270374Sdillon	u_int32_t r;
463110581Sjeff	int i;
46470374Sdillon
46570374Sdillon	r = 0;
46670374Sdillon	WRITE_REG(sc, TXP_SRR, TXP_SRR_ALL);
46770374Sdillon	DELAY(1000);
46846349Salc	WRITE_REG(sc, TXP_SRR, 0);
46946349Salc
47046349Salc	/* Should wait max 6 seconds */
47146349Salc	for (i = 0; i < 6000; i++) {
47246349Salc		r = READ_REG(sc, TXP_A2H_0);
47346349Salc		if (r == STAT_WAITING_FOR_HOST_REQUEST)
474131575Sstefanf			break;
47546349Salc		DELAY(1000);
47646349Salc	}
47746349Salc
47846349Salc	if (r != STAT_WAITING_FOR_HOST_REQUEST) {
47946349Salc		device_printf(sc->sc_dev, "reset hung\n");
480135276Sphk		return (-1);
481120762Salc	}
48246349Salc
48346349Salc	return (0);
48446349Salc}
48546349Salc
48646349Salcstatic int
48746349Salctxp_download_fw(sc)
48846349Salc	struct txp_softc *sc;
489167877Skris{
490131575Sstefanf	struct txp_fw_file_header *fileheader;
49148544Smckusick	struct txp_fw_section_header *secthead;
49248544Smckusick	int sect;
49348544Smckusick	u_int32_t r, i, ier, imr;
494135276Sphk
495110581Sjeff	r = 0;
49670374Sdillon	ier = READ_REG(sc, TXP_IER);
49748544Smckusick	WRITE_REG(sc, TXP_IER, ier | TXP_INT_A2H_0);
49848544Smckusick
49948544Smckusick	imr = READ_REG(sc, TXP_IMR);
500110581Sjeff	WRITE_REG(sc, TXP_IMR, imr | TXP_INT_A2H_0);
50148544Smckusick
50246349Salc	for (i = 0; i < 10000; i++) {
50354911Sdillon		r = READ_REG(sc, TXP_A2H_0);
50454911Sdillon		if (r == STAT_WAITING_FOR_HOST_REQUEST)
50554911Sdillon			break;
50648544Smckusick		DELAY(50);
50754911Sdillon	}
50854911Sdillon	if (r != STAT_WAITING_FOR_HOST_REQUEST) {
50954911Sdillon		device_printf(sc->sc_dev, "not waiting for host request\n");
510207141Sjeff		return (-1);
511135276Sphk	}
512207141Sjeff
513207141Sjeff	/* Ack the status */
514207141Sjeff	WRITE_REG(sc, TXP_ISR, TXP_INT_A2H_0);
515207141Sjeff
516207141Sjeff	fileheader = (struct txp_fw_file_header *)tc990image;
517207141Sjeff	if (bcmp("TYPHOON", fileheader->magicid, sizeof(fileheader->magicid))) {
518207141Sjeff		device_printf(sc->sc_dev, "fw invalid magic\n");
519207141Sjeff		return (-1);
520207141Sjeff	}
52154911Sdillon
52254911Sdillon	/* Tell boot firmware to get ready for image */
523251897Sscottl	WRITE_REG(sc, TXP_H2A_1, fileheader->addr);
524251897Sscottl	WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_RUNTIME_IMAGE);
525251897Sscottl
526251897Sscottl	if (txp_download_fw_wait(sc)) {
527251897Sscottl		device_printf(sc->sc_dev, "fw wait failed, initial\n");
528251897Sscottl		return (-1);
52946349Salc	}
53082127Sdillon
53182127Sdillon	secthead = (struct txp_fw_section_header *)(((u_int8_t *)tc990image) +
53282127Sdillon	    sizeof(struct txp_fw_file_header));
53382127Sdillon
5341541Srgrimes	for (sect = 0; sect < fileheader->nsections; sect++) {
53548710Speter		if (txp_download_fw_section(sc, secthead, sect))
536102600Speter			return (-1);
53748677Smckusick		secthead = (struct txp_fw_section_header *)
538189595Sjhb		    (((u_int8_t *)secthead) + secthead->nbytes +
539251897Sscottl		    sizeof(*secthead));
540135276Sphk	}
54182127Sdillon
54287535Sdillon	WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_DOWNLOAD_COMPLETE);
54387535Sdillon
54487535Sdillon	for (i = 0; i < 10000; i++) {
54587535Sdillon		r = READ_REG(sc, TXP_A2H_0);
54687535Sdillon		if (r == STAT_WAITING_FOR_BOOT)
54787535Sdillon			break;
54882127Sdillon		DELAY(50);
54982127Sdillon	}
55082127Sdillon	if (r != STAT_WAITING_FOR_BOOT) {
551172329Sru		device_printf(sc->sc_dev, "not waiting for boot\n");
55282127Sdillon		return (-1);
55382127Sdillon	}
55482127Sdillon
55582127Sdillon	WRITE_REG(sc, TXP_IER, ier);
55682127Sdillon	WRITE_REG(sc, TXP_IMR, imr);
55782127Sdillon
55887535Sdillon	return (0);
55982127Sdillon}
56082127Sdillon
56187535Sdillonstatic int
56287535Sdillontxp_download_fw_wait(sc)
56387535Sdillon	struct txp_softc *sc;
56487535Sdillon{
565253259Skib	u_int32_t i, r;
566253259Skib
56782127Sdillon	r = 0;
56882127Sdillon	for (i = 0; i < 10000; i++) {
56982127Sdillon		r = READ_REG(sc, TXP_ISR);
570189595Sjhb		if (r & TXP_INT_A2H_0)
571189595Sjhb			break;
572189595Sjhb		DELAY(50);
573170475Smarcel	}
574189595Sjhb
575189595Sjhb	if (!(r & TXP_INT_A2H_0)) {
576189595Sjhb		device_printf(sc->sc_dev, "fw wait failed comm0\n");
577189595Sjhb		return (-1);
578189595Sjhb	}
579189595Sjhb
580189595Sjhb	WRITE_REG(sc, TXP_ISR, TXP_INT_A2H_0);
58182127Sdillon
58282127Sdillon	r = READ_REG(sc, TXP_A2H_0);
58382127Sdillon	if (r != STAT_WAITING_FOR_SEGMENT) {
584251897Sscottl		device_printf(sc->sc_dev, "fw not waiting for segment\n");
585251897Sscottl		return (-1);
586251897Sscottl	}
587251897Sscottl	return (0);
588251897Sscottl}
589251897Sscottl
590251897Sscottlstatic int
591251897Sscottltxp_download_fw_section(sc, sect, sectnum)
592251897Sscottl	struct txp_softc *sc;
593251897Sscottl	struct txp_fw_section_header *sect;
594251897Sscottl	int sectnum;
595251897Sscottl{
596251897Sscottl	vm_offset_t dma;
597251897Sscottl	int rseg, err = 0;
598251897Sscottl	struct mbuf m;
599251897Sscottl	u_int16_t csum;
600251897Sscottl
601251897Sscottl	/* Skip zero length sections */
602251897Sscottl	if (sect->nbytes == 0)
603251897Sscottl		return (0);
604251897Sscottl
605251897Sscottl	/* Make sure we aren't past the end of the image */
606251897Sscottl	rseg = ((u_int8_t *)sect) - ((u_int8_t *)tc990image);
607251897Sscottl	if (rseg >= sizeof(tc990image)) {
608251897Sscottl		device_printf(sc->sc_dev, "fw invalid section address, "
609251897Sscottl		    "section %d\n", sectnum);
610251897Sscottl		return (-1);
611251897Sscottl	}
612251897Sscottl
613251897Sscottl	/* Make sure this section doesn't go past the end */
614251897Sscottl	rseg += sect->nbytes;
615251897Sscottl	if (rseg >= sizeof(tc990image)) {
616251897Sscottl		device_printf(sc->sc_dev, "fw truncated section %d\n",
617251897Sscottl		    sectnum);
618251897Sscottl		return (-1);
619251897Sscottl	}
620251897Sscottl
621251897Sscottl	bcopy(((u_int8_t *)sect) + sizeof(*sect), sc->sc_fwbuf, sect->nbytes);
622251897Sscottl	dma = vtophys(sc->sc_fwbuf);
623251897Sscottl
624251897Sscottl	/*
625251897Sscottl	 * dummy up mbuf and verify section checksum
626251897Sscottl	 */
627251897Sscottl	m.m_type = MT_DATA;
628251897Sscottl	m.m_next = m.m_nextpkt = NULL;
629251897Sscottl	m.m_len = sect->nbytes;
630251897Sscottl	m.m_data = sc->sc_fwbuf;
63182127Sdillon	m.m_flags = 0;
63282127Sdillon	csum = in_cksum(&m, sect->nbytes);
63382127Sdillon	if (csum != sect->cksum) {
63482127Sdillon		device_printf(sc->sc_dev, "fw section %d, bad "
635112694Stegge		    "cksum (expected 0x%x got 0x%x)\n",
636112694Stegge		    sectnum, sect->cksum, csum);
637112694Stegge		err = -1;
638112694Stegge		goto bail;
639112694Stegge	}
640112694Stegge
641112694Stegge	WRITE_REG(sc, TXP_H2A_1, sect->nbytes);
64282127Sdillon	WRITE_REG(sc, TXP_H2A_2, sect->cksum);
64382127Sdillon	WRITE_REG(sc, TXP_H2A_3, sect->addr);
64482127Sdillon	WRITE_REG(sc, TXP_H2A_4, 0);
64582127Sdillon	WRITE_REG(sc, TXP_H2A_5, dma & 0xffffffff);
64682127Sdillon	WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_SEGMENT_AVAILABLE);
64782127Sdillon
64882127Sdillon	if (txp_download_fw_wait(sc)) {
64982127Sdillon		device_printf(sc->sc_dev, "fw wait failed, "
65082127Sdillon		    "section %d\n", sectnum);
65182127Sdillon		err = -1;
65248677Smckusick	}
65348677Smckusick
65491690Seivindbail:
6553098Sphk	return (err);
65648677Smckusick}
6571541Srgrimes
6581549Srgrimesstatic void
6591549Srgrimestxp_intr(vsc)
6601541Srgrimes	void *vsc;
661110581Sjeff{
662110581Sjeff	struct txp_softc *sc = vsc;
663110581Sjeff	struct txp_hostvar *hv = sc->sc_hostvar;
664110581Sjeff	u_int32_t isr;
6651549Srgrimes
6661549Srgrimes	/* mask all interrupts */
6675455Sdg	WRITE_REG(sc, TXP_IMR, TXP_INT_RESERVED | TXP_INT_SELF |
6681549Srgrimes	    TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 |
6691549Srgrimes	    TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0 |
6701549Srgrimes	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
6715455Sdg	    TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |  TXP_INT_LATCH);
6721541Srgrimes
6731549Srgrimes	isr = READ_REG(sc, TXP_ISR);
6741549Srgrimes	while (isr) {
6751541Srgrimes		WRITE_REG(sc, TXP_ISR, isr);
6761541Srgrimes
6771564Sdg		if ((*sc->sc_rxhir.r_roff) != (*sc->sc_rxhir.r_woff))
678209053Smdf			txp_rx_reclaim(sc, &sc->sc_rxhir);
67940790Speter		if ((*sc->sc_rxlor.r_roff) != (*sc->sc_rxlor.r_woff))
68034266Sjulian			txp_rx_reclaim(sc, &sc->sc_rxlor);
68148225Smckusick
6821564Sdg		if (hv->hv_rx_buf_write_idx == hv->hv_rx_buf_read_idx)
683251897Sscottl			txp_rxbuf_reclaim(sc);
684251897Sscottl
685251897Sscottl		if (sc->sc_txhir.r_cnt && (sc->sc_txhir.r_cons !=
6861541Srgrimes		    TXP_OFFSET2IDX(*(sc->sc_txhir.r_off))))
68744679Sjulian			txp_tx_reclaim(sc, &sc->sc_txhir);
68844679Sjulian
68958706Sdillon		if (sc->sc_txlor.r_cnt && (sc->sc_txlor.r_cons !=
69058706Sdillon		    TXP_OFFSET2IDX(*(sc->sc_txlor.r_off))))
69158706Sdillon			txp_tx_reclaim(sc, &sc->sc_txlor);
69258706Sdillon
69358706Sdillon		isr = READ_REG(sc, TXP_ISR);
69458706Sdillon	}
69558706Sdillon
69658706Sdillon	/* unmask all interrupts */
69758706Sdillon	WRITE_REG(sc, TXP_IMR, TXP_INT_A2H_3);
69858706Sdillon
69944679Sjulian	txp_start(sc->sc_ifp);
700189595Sjhb
701189595Sjhb	return;
70258706Sdillon}
70358706Sdillon
704210410Sivorasstatic void
705214342Sivorastxp_rx_reclaim(sc, r)
706211123Sivoras	struct txp_softc *sc;
707211123Sivoras	struct txp_rx_ring *r;
708211129Sivoras{
709214342Sivoras	struct ifnet *ifp = sc->sc_ifp;
710211123Sivoras	struct txp_rx_desc *rxd;
711210410Sivoras	struct mbuf *m;
712210295Sivoras	struct txp_swdesc *sd = NULL;
713210295Sivoras	u_int32_t roff, woff;
714214342Sivoras
71570374Sdillon	roff = *r->r_roff;
71614319Sdyson	woff = *r->r_woff;
71714319Sdyson	rxd = r->r_desc + (roff / sizeof(struct txp_rx_desc));
71814319Sdyson
71914319Sdyson	while (roff != woff) {
72014319Sdyson
72114319Sdyson		if (rxd->rx_flags & RX_FLAGS_ERROR) {
72214319Sdyson			device_printf(sc->sc_dev, "error 0x%x\n",
72344679Sjulian			    rxd->rx_stat);
7245455Sdg			ifp->if_ierrors++;
72526664Sdyson			goto next;
72644679Sjulian		}
72744679Sjulian
72826664Sdyson		/* retrieve stashed pointer */
72948677Smckusick		sd = rxd->rx_sd;
730111466Smckusick
73126664Sdyson		m = sd->sd_mbuf;
73252452Sdillon		sd->sd_mbuf = NULL;
73352452Sdillon
73452452Sdillon		m->m_pkthdr.len = m->m_len = rxd->rx_len;
73552452Sdillon
736222220Sru#ifdef __STRICT_ALIGNMENT
73752452Sdillon		{
738189595Sjhb			/*
73952452Sdillon			 * XXX Nice chip, except it won't accept "off by 2"
74052452Sdillon			 * buffers, so we're force to copy.  Supposedly
74170374Sdillon			 * this will be fixed in a newer firmware rev
74244679Sjulian			 * and this will be temporary.
74344679Sjulian			 */
74444679Sjulian			struct mbuf *mnew;
74558706Sdillon
74658706Sdillon			MGETHDR(mnew, M_DONTWAIT, MT_DATA);
74744679Sjulian			if (mnew == NULL) {
74826664Sdyson				m_freem(m);
74926664Sdyson				goto next;
75026664Sdyson			}
75144679Sjulian			if (m->m_len > (MHLEN - 2)) {
752118337Salc				MCLGET(mnew, M_DONTWAIT);
753108715Salc				if (!(mnew->m_flags & M_EXT)) {
754251897Sscottl					m_freem(mnew);
7551541Srgrimes					m_freem(m);
7561541Srgrimes					goto next;
757251897Sscottl				}
758251897Sscottl			}
759251897Sscottl			mnew->m_pkthdr.rcvif = ifp;
760251897Sscottl			m_adj(mnew, 2);
761251897Sscottl			mnew->m_pkthdr.len = mnew->m_len = m->m_len;
762251897Sscottl			m_copydata(m, 0, m->m_pkthdr.len, mtod(mnew, caddr_t));
763251897Sscottl			m_freem(m);
764251897Sscottl			m = mnew;
765251897Sscottl		}
766251897Sscottl#endif
767251897Sscottl
768251897Sscottl		if (rxd->rx_stat & RX_STAT_IPCKSUMBAD)
769251897Sscottl			m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
770251897Sscottl		else if (rxd->rx_stat & RX_STAT_IPCKSUMGOOD)
771251897Sscottl		 	m->m_pkthdr.csum_flags |=
772251897Sscottl			    CSUM_IP_CHECKED|CSUM_IP_VALID;
773251897Sscottl
774251897Sscottl		if ((rxd->rx_stat & RX_STAT_TCPCKSUMGOOD) ||
775251897Sscottl		    (rxd->rx_stat & RX_STAT_UDPCKSUMGOOD)) {
776251897Sscottl			m->m_pkthdr.csum_flags |=
777251897Sscottl			    CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
778251897Sscottl			m->m_pkthdr.csum_data = 0xffff;
779251897Sscottl		}
780251897Sscottl
781251897Sscottl		if (rxd->rx_stat & RX_STAT_VLAN) {
782251897Sscottl			VLAN_INPUT_TAG(ifp,
783251897Sscottl				m, htons(rxd->rx_vlan >> 16), goto next);
784251897Sscottl		}
785251897Sscottl
786251897Sscottl		(*ifp->if_input)(ifp, m);
787251897Sscottl
788251897Sscottlnext:
789251897Sscottl
790251897Sscottl		roff += sizeof(struct txp_rx_desc);
791251897Sscottl		if (roff == (RX_ENTRIES * sizeof(struct txp_rx_desc))) {
792251897Sscottl			roff = 0;
793251897Sscottl			rxd = r->r_desc;
794251897Sscottl		} else
795251897Sscottl			rxd++;
796251897Sscottl		woff = *r->r_woff;
797251897Sscottl	}
798251897Sscottl
799251897Sscottl	*r->r_roff = woff;
800251897Sscottl
801251897Sscottl	return;
802251897Sscottl}
803251897Sscottl
804251897Sscottlstatic void
8051549Srgrimestxp_rxbuf_reclaim(sc)
80658706Sdillon	struct txp_softc *sc;
80758706Sdillon{
80858706Sdillon	struct ifnet *ifp = sc->sc_ifp;
80920054Sdyson	struct txp_hostvar *hv = sc->sc_hostvar;
81020054Sdyson	struct txp_rxbuf_desc *rbd;
811135276Sphk	struct txp_swdesc *sd;
81220054Sdyson	u_int32_t i;
813135276Sphk
814251897Sscottl	if (!(ifp->if_flags & IFF_RUNNING))
815251897Sscottl		return;
816251897Sscottl
817251897Sscottl	i = sc->sc_rxbufprod;
818251897Sscottl	rbd = sc->sc_rxbufs + i;
819251897Sscottl
820251897Sscottl	while (1) {
821251897Sscottl		sd = rbd->rb_sd;
822251897Sscottl		if (sd->sd_mbuf != NULL)
823251897Sscottl			break;
824251897Sscottl
825251897Sscottl		MGETHDR(sd->sd_mbuf, M_DONTWAIT, MT_DATA);
826251897Sscottl		if (sd->sd_mbuf == NULL)
827251897Sscottl			goto err_sd;
828251897Sscottl
829251897Sscottl		MCLGET(sd->sd_mbuf, M_DONTWAIT);
830251897Sscottl		if ((sd->sd_mbuf->m_flags & M_EXT) == 0)
83144679Sjulian			goto err_mbuf;
832251897Sscottl		sd->sd_mbuf->m_pkthdr.rcvif = ifp;
833251897Sscottl		sd->sd_mbuf->m_pkthdr.len = sd->sd_mbuf->m_len = MCLBYTES;
83420054Sdyson
83520054Sdyson		rbd->rb_paddrlo = vtophys(mtod(sd->sd_mbuf, vm_offset_t))
83620054Sdyson		    & 0xffffffff;
83744679Sjulian		rbd->rb_paddrhi = 0;
83844679Sjulian
839137846Sjeff		hv->hv_rx_buf_write_idx = TXP_IDX2OFFSET(i);
840137846Sjeff
8411549Srgrimes		if (++i == RXBUF_ENTRIES) {
8421549Srgrimes			i = 0;
843135276Sphk			rbd = sc->sc_rxbufs;
8441541Srgrimes		} else
845209053Smdf			rbd++;
846135276Sphk	}
847140721Sjeff
848147325Sjeff	sc->sc_rxbufprod = i;
849147325Sjeff
850147325Sjeff	return;
851140721Sjeff
852176249Sattilioerr_mbuf:
853137846Sjeff	m_freem(sd->sd_mbuf);
854137846Sjefferr_sd:
855137846Sjeff	free(sd, M_DEVBUF);
856209053Smdf}
857209053Smdf
858209053Smdf/*
859211213Skib * Reclaim mbufs and entries from a transmit ring.
860211213Skib */
861209053Smdfstatic void
862209053Smdftxp_tx_reclaim(sc, r)
863209053Smdf	struct txp_softc *sc;
864209053Smdf	struct txp_tx_ring *r;
865137846Sjeff{
866137846Sjeff	struct ifnet *ifp = sc->sc_ifp;
867137846Sjeff	u_int32_t idx = TXP_OFFSET2IDX(*(r->r_off));
868137846Sjeff	u_int32_t cons = r->r_cons, cnt = r->r_cnt;
869137846Sjeff	struct txp_tx_desc *txd = r->r_desc + cons;
870137846Sjeff	struct txp_swdesc *sd = sc->sc_txd + cons;
871137846Sjeff	struct mbuf *m;
872137846Sjeff
873137846Sjeff	while (cons != idx) {
874137846Sjeff		if (cnt == 0)
875137846Sjeff			break;
876110987Sjeff
877110987Sjeff		if ((txd->tx_flags & TX_FLAGS_TYPE_M) ==
878110987Sjeff		    TX_FLAGS_TYPE_DATA) {
879110987Sjeff			m = sd->sd_mbuf;
880110987Sjeff			if (m != NULL) {
881137846Sjeff				m_freem(m);
882137846Sjeff				txd->tx_addrlo = 0;
883137846Sjeff				txd->tx_addrhi = 0;
884137846Sjeff				ifp->if_opackets++;
885137846Sjeff			}
886137846Sjeff		}
887141637Sphk		ifp->if_flags &= ~IFF_OACTIVE;
888135276Sphk
889110987Sjeff		if (++cons == TX_ENTRIES) {
890209053Smdf			txd = r->r_desc;
891209053Smdf			cons = 0;
892140721Sjeff			sd = sc->sc_txd;
893140721Sjeff		} else {
894140721Sjeff			txd++;
895140721Sjeff			sd++;
896176249Sattilio		}
897137846Sjeff
89879224Sdillon		cnt--;
899140721Sjeff	}
900251897Sscottl
901251897Sscottl	r->r_cons = cons;
902251897Sscottl	r->r_cnt = cnt;
903251897Sscottl	if (cnt == 0)
904251897Sscottl		ifp->if_timer = 0;
905140721Sjeff}
90644679Sjulian
907137846Sjeffstatic int
908137846Sjefftxp_shutdown(dev)
909137846Sjeff	device_t dev;
910137846Sjeff{
911137846Sjeff	struct txp_softc *sc;
912137846Sjeff
913137846Sjeff	sc = device_get_softc(dev);
914137846Sjeff
91544679Sjulian	/* mask all interrupts */
916137846Sjeff	WRITE_REG(sc, TXP_IMR,
917137846Sjeff	    TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
91844679Sjulian	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
919209053Smdf	    TXP_INT_LATCH);
920209053Smdf
921209053Smdf	txp_command(sc, TXP_CMD_TX_DISABLE, 0, 0, 0, NULL, NULL, NULL, 0);
922211213Skib	txp_command(sc, TXP_CMD_RX_DISABLE, 0, 0, 0, NULL, NULL, NULL, 0);
923211213Skib	txp_command(sc, TXP_CMD_HALT, 0, 0, 0, NULL, NULL, NULL, 0);
924209053Smdf
925209053Smdf	return(0);
926209053Smdf}
927209053Smdf
9281549Srgrimesstatic int
9291541Srgrimestxp_alloc_rings(sc)
9301549Srgrimes	struct txp_softc *sc;
931233630Smckusick{
9321549Srgrimes	struct txp_boot_record *boot;
9331549Srgrimes	struct txp_ldata *ld;
9345455Sdg	u_int32_t r;
935135276Sphk	int i;
9361549Srgrimes
9371549Srgrimes	r = 0;
938233630Smckusick	ld = sc->sc_ldata;
9391541Srgrimes	boot = &ld->txp_boot;
9401541Srgrimes
9411549Srgrimes	/* boot record */
942153192Srodrigc	sc->sc_boot = boot;
943153192Srodrigc
944153192Srodrigc	/* host variables */
945153192Srodrigc	bzero(&ld->txp_hostvar, sizeof(struct txp_hostvar));
946153192Srodrigc	boot->br_hostvar_lo = vtophys(&ld->txp_hostvar);
947153192Srodrigc	boot->br_hostvar_hi = 0;
948153192Srodrigc	sc->sc_hostvar = (struct txp_hostvar *)&ld->txp_hostvar;
949153192Srodrigc
950153192Srodrigc	/* hi priority tx ring */
951153192Srodrigc	boot->br_txhipri_lo = vtophys(&ld->txp_txhiring);;
952153192Srodrigc	boot->br_txhipri_hi = 0;
953153192Srodrigc	boot->br_txhipri_siz = TX_ENTRIES * sizeof(struct txp_tx_desc);
954153192Srodrigc	sc->sc_txhir.r_reg = TXP_H2A_1;
955153192Srodrigc	sc->sc_txhir.r_desc = (struct txp_tx_desc *)&ld->txp_txhiring;
956153192Srodrigc	sc->sc_txhir.r_cons = sc->sc_txhir.r_prod = sc->sc_txhir.r_cnt = 0;
957153192Srodrigc	sc->sc_txhir.r_off = &sc->sc_hostvar->hv_tx_hi_desc_read_idx;
958153192Srodrigc
959167327Sjulian	/* lo priority tx ring */
960170174Sjeff	boot->br_txlopri_lo = vtophys(&ld->txp_txloring);
961153192Srodrigc	boot->br_txlopri_hi = 0;
962153192Srodrigc	boot->br_txlopri_siz = TX_ENTRIES * sizeof(struct txp_tx_desc);
963153192Srodrigc	sc->sc_txlor.r_reg = TXP_H2A_3;
964153192Srodrigc	sc->sc_txlor.r_desc = (struct txp_tx_desc *)&ld->txp_txloring;
965153192Srodrigc	sc->sc_txlor.r_cons = sc->sc_txlor.r_prod = sc->sc_txlor.r_cnt = 0;
966153192Srodrigc	sc->sc_txlor.r_off = &sc->sc_hostvar->hv_tx_lo_desc_read_idx;
967153192Srodrigc
968153192Srodrigc	/* high priority rx ring */
969153192Srodrigc	boot->br_rxhipri_lo = vtophys(&ld->txp_rxhiring);
970153192Srodrigc	boot->br_rxhipri_hi = 0;
971153192Srodrigc	boot->br_rxhipri_siz = RX_ENTRIES * sizeof(struct txp_rx_desc);
972153192Srodrigc	sc->sc_rxhir.r_desc = (struct txp_rx_desc *)&ld->txp_rxhiring;
973153192Srodrigc	sc->sc_rxhir.r_roff = &sc->sc_hostvar->hv_rx_hi_read_idx;
974153192Srodrigc	sc->sc_rxhir.r_woff = &sc->sc_hostvar->hv_rx_hi_write_idx;
975153192Srodrigc
976153192Srodrigc	/* low priority rx ring */
977153192Srodrigc	boot->br_rxlopri_lo = vtophys(&ld->txp_rxloring);
978251145Sscottl	boot->br_rxlopri_hi = 0;
979251145Sscottl	boot->br_rxlopri_siz = RX_ENTRIES * sizeof(struct txp_rx_desc);
980251145Sscottl	sc->sc_rxlor.r_desc = (struct txp_rx_desc *)&ld->txp_rxloring;
981251145Sscottl	sc->sc_rxlor.r_roff = &sc->sc_hostvar->hv_rx_lo_read_idx;
982251145Sscottl	sc->sc_rxlor.r_woff = &sc->sc_hostvar->hv_rx_lo_write_idx;
983251145Sscottl
984251145Sscottl	/* command ring */
985251145Sscottl	bzero(&ld->txp_cmdring, sizeof(struct txp_cmd_desc) * CMD_ENTRIES);
986251145Sscottl	boot->br_cmd_lo = vtophys(&ld->txp_cmdring);
987251145Sscottl	boot->br_cmd_hi = 0;
988251145Sscottl	boot->br_cmd_siz = CMD_ENTRIES * sizeof(struct txp_cmd_desc);
989251145Sscottl	sc->sc_cmdring.base = (struct txp_cmd_desc *)&ld->txp_cmdring;
9901549Srgrimes	sc->sc_cmdring.size = CMD_ENTRIES * sizeof(struct txp_cmd_desc);
991153192Srodrigc	sc->sc_cmdring.lastwrite = 0;
9921549Srgrimes
9931549Srgrimes	/* response ring */
9945455Sdg	bzero(&ld->txp_rspring, sizeof(struct txp_rsp_desc) * RSP_ENTRIES);
9955455Sdg	boot->br_resp_lo = vtophys(&ld->txp_rspring);
996135276Sphk	boot->br_resp_hi = 0;
9971541Srgrimes	boot->br_resp_siz = CMD_ENTRIES * sizeof(struct txp_rsp_desc);
998233630Smckusick	sc->sc_rspring.base = (struct txp_rsp_desc *)&ld->txp_rspring;
999233630Smckusick	sc->sc_rspring.size = RSP_ENTRIES * sizeof(struct txp_rsp_desc);
1000233630Smckusick	sc->sc_rspring.lastwrite = 0;
1001233630Smckusick
1002233630Smckusick	/* receive buffer ring */
1003233630Smckusick	boot->br_rxbuf_lo = vtophys(&ld->txp_rxbufs);
1004233630Smckusick	boot->br_rxbuf_hi = 0;
1005233630Smckusick	boot->br_rxbuf_siz = RXBUF_ENTRIES * sizeof(struct txp_rxbuf_desc);
1006233630Smckusick	sc->sc_rxbufs = (struct txp_rxbuf_desc *)&ld->txp_rxbufs;
1007233630Smckusick
1008233630Smckusick	for (i = 0; i < RXBUF_ENTRIES; i++) {
1009233630Smckusick		struct txp_swdesc *sd;
1010233630Smckusick		if (sc->sc_rxbufs[i].rb_sd != NULL)
1011233630Smckusick			continue;
1012250947Sscottl		sc->sc_rxbufs[i].rb_sd = malloc(sizeof(struct txp_swdesc),
1013250947Sscottl		    M_DEVBUF, M_NOWAIT);
1014233630Smckusick		if (sc->sc_rxbufs[i].rb_sd == NULL)
1015153192Srodrigc			return(ENOBUFS);
10161549Srgrimes		sd = sc->sc_rxbufs[i].rb_sd;
10171541Srgrimes		sd->sd_mbuf = NULL;
1018140721Sjeff	}
1019233630Smckusick	sc->sc_rxbufprod = 0;
1020233630Smckusick
1021233630Smckusick	/* zero dma */
1022233630Smckusick	bzero(&ld->txp_zero, sizeof(u_int32_t));
1023233630Smckusick	boot->br_zero_lo = vtophys(&ld->txp_zero);
1024233630Smckusick	boot->br_zero_hi = 0;
10251549Srgrimes
10261549Srgrimes	/* See if it's waiting for boot, and try to boot it */
10271549Srgrimes	for (i = 0; i < 10000; i++) {
1028167327Sjulian		r = READ_REG(sc, TXP_A2H_0);
1029170174Sjeff		if (r == STAT_WAITING_FOR_BOOT)
103058345Sphk			break;
103158934Sphk		DELAY(50);
103258934Sphk	}
103384827Sjhb
103484827Sjhb	if (r != STAT_WAITING_FOR_BOOT) {
10355455Sdg		device_printf(sc->sc_dev, "not waiting for boot\n");
1036121224Sphk		return(ENXIO);
1037136927Sphk	}
10381549Srgrimes
10391549Srgrimes	WRITE_REG(sc, TXP_H2A_2, 0);
104044679Sjulian	WRITE_REG(sc, TXP_H2A_1, vtophys(sc->sc_boot));
1041153192Srodrigc	WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_REGISTER_BOOT_RECORD);
10421549Srgrimes
10435455Sdg	/* See if it booted */
104459762Sphk	for (i = 0; i < 10000; i++) {
10451549Srgrimes		r = READ_REG(sc, TXP_A2H_0);
10461549Srgrimes		if (r == STAT_RUNNING)
10471541Srgrimes			break;
10481541Srgrimes		DELAY(50);
10491549Srgrimes	}
10501549Srgrimes	if (r != STAT_RUNNING) {
105146349Salc		device_printf(sc->sc_dev, "fw not running\n");
105246349Salc		return(ENXIO);
105346349Salc	}
105446349Salc
105546349Salc	/* Clear TX and CMD ring write registers */
105646349Salc	WRITE_REG(sc, TXP_H2A_1, TXP_BOOTCMD_NULL);
105746349Salc	WRITE_REG(sc, TXP_H2A_2, TXP_BOOTCMD_NULL);
105846349Salc	WRITE_REG(sc, TXP_H2A_3, TXP_BOOTCMD_NULL);
10591549Srgrimes	WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_NULL);
10601549Srgrimes
1061136927Sphk	return (0);
10621541Srgrimes}
1063145704Sjeff
1064165375Skibstatic int
1065165375Skibtxp_ioctl(ifp, command, data)
10661541Srgrimes	struct ifnet *ifp;
1067140721Sjeff	u_long command;
10685455Sdg	caddr_t data;
10691549Srgrimes{
10701549Srgrimes	struct txp_softc *sc = ifp->if_softc;
10715455Sdg	struct ifreq *ifr = (struct ifreq *)data;
107234694Sdyson	int s, error = 0;
1073248665Smckusick
1074248665Smckusick	s = splnet();
1075248665Smckusick
107634694Sdyson	switch(command) {
107734694Sdyson	case SIOCSIFFLAGS:
1078176249Sattilio		if (ifp->if_flags & IFF_UP) {
1079153192Srodrigc			txp_init(sc);
1080153192Srodrigc		} else {
1081153192Srodrigc			if (ifp->if_flags & IFF_RUNNING)
1082153192Srodrigc				txp_stop(sc);
1083141539Sphk		}
1084141539Sphk		break;
1085141539Sphk	case SIOCADDMULTI:
1086165375Skib	case SIOCDELMULTI:
1087165375Skib		/*
1088165375Skib		 * Multicast list has changed; set the hardware
1089165375Skib		 * filter accordingly.
1090165375Skib		 */
1091165375Skib		txp_set_filter(sc);
1092249054Skib		error = 0;
1093249054Skib		break;
1094249054Skib	case SIOCGIFMEDIA:
1095249054Skib	case SIOCSIFMEDIA:
1096249054Skib		error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, command);
1097249054Skib		break;
1098249054Skib	default:
109944679Sjulian		error = ether_ioctl(ifp, command, data);
11001549Srgrimes		break;
110158934Sphk	}
110258934Sphk
1103135280Sphk	(void)splx(s);
110458345Sphk
11051549Srgrimes	return(error);
11065455Sdg}
110773211Sdillon
110873211Sdillonstatic int
110973211Sdillontxp_rxring_fill(sc)
111073211Sdillon	struct txp_softc *sc;
111173211Sdillon{
1112189595Sjhb	int i;
111373211Sdillon	struct ifnet *ifp;
1114167327Sjulian	struct txp_swdesc *sd;
1115170174Sjeff
111648333Speter	ifp = sc->sc_ifp;
111748333Speter
1118121224Sphk	for (i = 0; i < RXBUF_ENTRIES; i++) {
1119136927Sphk		sd = sc->sc_rxbufs[i].rb_sd;
11201549Srgrimes		MGETHDR(sd->sd_mbuf, M_DONTWAIT, MT_DATA);
112118271Sdyson		if (sd->sd_mbuf == NULL)
112259762Sphk			return(ENOBUFS);
11231549Srgrimes
11241549Srgrimes		MCLGET(sd->sd_mbuf, M_DONTWAIT);
1125115456Sphk		if ((sd->sd_mbuf->m_flags & M_EXT) == 0) {
112670374Sdillon			m_freem(sd->sd_mbuf);
112770374Sdillon			return(ENOBUFS);
1128115456Sphk		}
112986089Sdillon		sd->sd_mbuf->m_pkthdr.len = sd->sd_mbuf->m_len = MCLBYTES;
1130122031Smckusick		sd->sd_mbuf->m_pkthdr.rcvif = ifp;
1131122031Smckusick
1132122031Smckusick		sc->sc_rxbufs[i].rb_paddrlo =
113370374Sdillon		    vtophys(mtod(sd->sd_mbuf, vm_offset_t));
1134165375Skib		sc->sc_rxbufs[i].rb_paddrhi = 0;
1135122031Smckusick	}
11365455Sdg
113744679Sjulian	sc->sc_hostvar->hv_rx_buf_write_idx = (RXBUF_ENTRIES - 1) *
11385455Sdg	    sizeof(struct txp_rxbuf_desc);
11391541Srgrimes
11401541Srgrimes	return(0);
1141166193Skib}
1142166193Skib
1143166193Skibstatic void
1144166193Skibtxp_rxring_empty(sc)
1145166193Skib	struct txp_softc *sc;
1146166193Skib{
1147166193Skib	int i;
1148166193Skib	struct txp_swdesc *sd;
1149166193Skib
1150166193Skib	if (sc->sc_rxbufs == NULL)
1151166193Skib		return;
1152166193Skib
1153166193Skib	for (i = 0; i < RXBUF_ENTRIES; i++) {
1154166193Skib		if (&sc->sc_rxbufs[i] == NULL)
1155166193Skib			continue;
1156166193Skib		sd = sc->sc_rxbufs[i].rb_sd;
1157166193Skib		if (sd == NULL)
1158166193Skib			continue;
1159166193Skib		if (sd->sd_mbuf != NULL) {
1160166193Skib			m_freem(sd->sd_mbuf);
1161166193Skib			sd->sd_mbuf = NULL;
1162166193Skib		}
1163166193Skib	}
1164166193Skib
1165166193Skib	return;
1166166193Skib}
1167166193Skib
1168166193Skibstatic void
1169166193Skibtxp_init(xsc)
1170166193Skib	void *xsc;
1171166193Skib{
1172166193Skib	struct txp_softc *sc;
1173166193Skib	struct ifnet *ifp;
1174166193Skib	u_int16_t p1;
1175166193Skib	u_int32_t p2;
1176166193Skib	int s;
1177166193Skib
1178166193Skib	sc = xsc;
1179166193Skib	ifp = sc->sc_ifp;
1180166193Skib
1181166193Skib	if (ifp->if_flags & IFF_RUNNING)
11821549Srgrimes		return;
118346349Salc
118446349Salc	txp_stop(sc);
118546349Salc
118646349Salc	s = splnet();
118746349Salc
118846349Salc	txp_command(sc, TXP_CMD_MAX_PKT_SIZE_WRITE, TXP_MAX_PKTLEN, 0, 0,
118946349Salc	    NULL, NULL, NULL, 1);
11901549Srgrimes
11911549Srgrimes	/* Set station address. */
1192135276Sphk	((u_int8_t *)&p1)[1] = IFP2ENADDR(sc->sc_ifp)[0];
11931541Srgrimes	((u_int8_t *)&p1)[0] = IFP2ENADDR(sc->sc_ifp)[1];
1194111466Smckusick	((u_int8_t *)&p2)[3] = IFP2ENADDR(sc->sc_ifp)[2];
1195111466Smckusick	((u_int8_t *)&p2)[2] = IFP2ENADDR(sc->sc_ifp)[3];
1196136767Sphk	((u_int8_t *)&p2)[1] = IFP2ENADDR(sc->sc_ifp)[4];
1197111466Smckusick	((u_int8_t *)&p2)[0] = IFP2ENADDR(sc->sc_ifp)[5];
1198140721Sjeff	txp_command(sc, TXP_CMD_STATION_ADDRESS_WRITE, p1, p2, 0,
1199136767Sphk	    NULL, NULL, NULL, 1);
1200248665Smckusick
1201248665Smckusick	txp_set_filter(sc);
1202176249Sattilio
120326664Sdyson	txp_rxring_fill(sc);
12045455Sdg
12051549Srgrimes	txp_command(sc, TXP_CMD_TX_ENABLE, 0, 0, 0, NULL, NULL, NULL, 1);
12061549Srgrimes	txp_command(sc, TXP_CMD_RX_ENABLE, 0, 0, 0, NULL, NULL, NULL, 1);
12071549Srgrimes
12088692Sdg	WRITE_REG(sc, TXP_IER, TXP_INT_RESERVED | TXP_INT_SELF |
12098692Sdg	    TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 |
1210111466Smckusick	    TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0 |
1211111466Smckusick	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
1212111466Smckusick	    TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |  TXP_INT_LATCH);
1213111511Smckusick	WRITE_REG(sc, TXP_IMR, TXP_INT_A2H_3);
1214111511Smckusick
1215111466Smckusick	ifp->if_flags |= IFF_RUNNING;
1216111466Smckusick	ifp->if_flags &= ~IFF_OACTIVE;
1217136767Sphk	ifp->if_timer = 0;
1218169006Skib
1219169006Skib	sc->sc_tick = timeout(txp_tick, sc, hz);
1220166193Skib
1221169006Skib	splx(s);
1222169006Skib}
1223140721Sjeff
1224111466Smckusickstatic void
1225111466Smckusicktxp_tick(vsc)
1226111466Smckusick	void *vsc;
122746349Salc{
122846349Salc	struct txp_softc *sc = vsc;
122946349Salc	struct ifnet *ifp = sc->sc_ifp;
123046349Salc	struct txp_rsp_desc *rsp = NULL;
123146349Salc	struct txp_ext_desc *ext;
123246349Salc	int s;
12338692Sdg
12348692Sdg	s = splnet();
12358692Sdg	txp_rxbuf_reclaim(sc);
12368692Sdg
12378692Sdg	if (txp_command2(sc, TXP_CMD_READ_STATISTICS, 0, 0, 0, NULL, 0,
12388692Sdg	    &rsp, 1))
12398692Sdg		goto out;
12408692Sdg	if (rsp->rsp_numdesc != 6)
1241111466Smckusick		goto out;
1242111466Smckusick	if (txp_command(sc, TXP_CMD_CLEAR_STATISTICS, 0, 0, 0,
12436864Sdg	    NULL, NULL, NULL, 1))
12448692Sdg		goto out;
12458692Sdg	ext = (struct txp_ext_desc *)(rsp + 1);
1246208920Skib
1247208920Skib	ifp->if_ierrors += ext[3].ext_2 + ext[3].ext_3 + ext[3].ext_4 +
1248208920Skib	    ext[4].ext_1 + ext[4].ext_4;
1249208920Skib	ifp->if_oerrors += ext[0].ext_1 + ext[1].ext_1 + ext[1].ext_4 +
1250208920Skib	    ext[2].ext_1;
1251208920Skib	ifp->if_collisions += ext[0].ext_2 + ext[0].ext_3 + ext[1].ext_2 +
1252208920Skib	    ext[1].ext_3;
1253208920Skib	ifp->if_opackets += rsp->rsp_par2;
1254208920Skib	ifp->if_ipackets += ext[2].ext_3;
12558692Sdg
1256208920Skibout:
125713490Sdyson	if (rsp != NULL)
125826664Sdyson		free(rsp, M_DEVBUF);
125934266Sjulian
126070374Sdillon	splx(s);
126170374Sdillon	sc->sc_tick = timeout(txp_tick, sc, hz);
126270374Sdillon
126348544Smckusick	return;
126470374Sdillon}
126548544Smckusick
126648544Smckusickstatic void
126748677Smckusicktxp_start(ifp)
126848677Smckusick	struct ifnet *ifp;
126948677Smckusick{
12701541Srgrimes	struct txp_softc *sc = ifp->if_softc;
12711541Srgrimes	struct txp_tx_ring *r = &sc->sc_txhir;
12721549Srgrimes	struct txp_tx_desc *txd;
127344679Sjulian	struct txp_frag_desc *fxd;
127444679Sjulian	struct mbuf *m, *m0;
127558345Sphk	struct txp_swdesc *sd;
127644679Sjulian	u_int32_t firstprod, firstcnt, prod, cnt;
127744679Sjulian	struct m_tag *mtag;
127844679Sjulian
127946349Salc	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
128044679Sjulian		return;
128146349Salc
128246349Salc	prod = r->r_prod;
128346349Salc	cnt = r->r_cnt;
128446349Salc
128544679Sjulian	while (1) {
128644679Sjulian		IF_DEQUEUE(&ifp->if_snd, m);
128744679Sjulian		if (m == NULL)
128844679Sjulian			break;
128934266Sjulian
129034266Sjulian		firstprod = prod;
1291135276Sphk		firstcnt = cnt;
129234266Sjulian
1293135276Sphk		sd = sc->sc_txd + prod;
1294140721Sjeff		sd->sd_mbuf = m;
1295140721Sjeff
1296136767Sphk		if ((TX_ENTRIES - cnt) < 4)
1297137846Sjeff			goto oactive;
129891690Seivind
1299176249Sattilio		txd = r->r_desc + prod;
130058345Sphk
130158345Sphk		txd->tx_flags = TX_FLAGS_TYPE_DATA;
130244679Sjulian		txd->tx_numdesc = 0;
130334266Sjulian		txd->tx_addrlo = 0;
1304140721Sjeff		txd->tx_addrhi = 0;
1305132640Sphk		txd->tx_totlen = 0;
1306110581Sjeff		txd->tx_pflags = 0;
130770374Sdillon
130834266Sjulian		if (++prod == TX_ENTRIES)
130934266Sjulian			prod = 0;
131034266Sjulian
131134266Sjulian		if (++cnt >= (TX_ENTRIES - 4))
131244679Sjulian			goto oactive;
131344679Sjulian
131444679Sjulian		mtag = VLAN_OUTPUT_TAG(ifp, m);
131544679Sjulian		if (mtag != NULL) {
131644679Sjulian			txd->tx_pflags = TX_PFLAGS_VLAN |
131744679Sjulian			    (htons(VLAN_TAG_VALUE(mtag)) << TX_PFLAGS_VLANTAG_S);
131844679Sjulian		}
131944679Sjulian
13201549Srgrimes		if (m->m_pkthdr.csum_flags & CSUM_IP)
132144679Sjulian			txd->tx_pflags |= TX_PFLAGS_IPCKSUM;
13221549Srgrimes
1323135276Sphk#if 0
132444679Sjulian		if (m->m_pkthdr.csum_flags & CSUM_TCP)
1325135276Sphk			txd->tx_pflags |= TX_PFLAGS_TCPCKSUM;
1326140721Sjeff		if (m->m_pkthdr.csum_flags & CSUM_UDP)
1327136767Sphk			txd->tx_pflags |= TX_PFLAGS_UDPCKSUM;
1328137846Sjeff#endif
132991690Seivind
1330176249Sattilio		fxd = (struct txp_frag_desc *)(r->r_desc + prod);
133144679Sjulian		for (m0 = m; m0 != NULL; m0 = m0->m_next) {
133244679Sjulian			if (m0->m_len == 0)
133344679Sjulian				continue;
1334132640Sphk			if (++cnt >= (TX_ENTRIES - 4))
1335110581Sjeff				goto oactive;
133670374Sdillon
133744679Sjulian			txd->tx_numdesc++;
133855697Smckusick
133955697Smckusick			fxd->frag_flags = FRAG_FLAGS_TYPE_FRAG;
134055697Smckusick			fxd->frag_rsvd1 = 0;
134155697Smckusick			fxd->frag_len = m0->m_len;
134244679Sjulian			fxd->frag_addrlo = vtophys(mtod(m0, vm_offset_t));
134344679Sjulian			fxd->frag_addrhi = 0;
134444679Sjulian			fxd->frag_rsvd2 = 0;
134544679Sjulian
134644679Sjulian			if (++prod == TX_ENTRIES) {
134744679Sjulian				fxd = (struct txp_frag_desc *)r->r_desc;
134844679Sjulian				prod = 0;
134946349Salc			} else
135046349Salc				fxd++;
135146349Salc
135244679Sjulian		}
135344679Sjulian
1354135276Sphk		ifp->if_timer = 5;
13551541Srgrimes
1356135276Sphk		BPF_MTAP(ifp, m);
13576620Sdg		WRITE_REG(sc, r->r_reg, TXP_IDX2OFFSET(prod));
1358126853Sphk	}
13591541Srgrimes
13601541Srgrimes	r->r_prod = prod;
13611549Srgrimes	r->r_cnt = cnt;
1362248665Smckusick	return;
1363248665Smckusick
1364248665Smckusickoactive:
1365248665Smckusick	ifp->if_flags |= IFF_OACTIVE;
1366248665Smckusick	r->r_prod = firstprod;
1367248665Smckusick	r->r_cnt = firstcnt;
1368248665Smckusick	IF_PREPEND(&ifp->if_snd, m);
1369248665Smckusick	return;
1370248665Smckusick}
1371248665Smckusick
1372248665Smckusick/*
1373248665Smckusick * Handle simple commands sent to the typhoon
1374248665Smckusick */
1375248665Smckusickstatic int
1376248665Smckusicktxp_command(sc, id, in1, in2, in3, out1, out2, out3, wait)
1377248665Smckusick	struct txp_softc *sc;
1378248665Smckusick	u_int16_t id, in1, *out1;
1379248665Smckusick	u_int32_t in2, in3, *out2, *out3;
1380248665Smckusick	int wait;
1381248665Smckusick{
1382248665Smckusick	struct txp_rsp_desc *rsp = NULL;
1383248665Smckusick
1384248665Smckusick	if (txp_command2(sc, id, in1, in2, in3, NULL, 0, &rsp, wait))
1385248665Smckusick		return (-1);
1386248665Smckusick
1387248665Smckusick	if (!wait)
1388248665Smckusick		return (0);
1389248665Smckusick
1390248665Smckusick	if (out1 != NULL)
1391248665Smckusick		*out1 = rsp->rsp_par1;
1392248665Smckusick	if (out2 != NULL)
1393248665Smckusick		*out2 = rsp->rsp_par2;
1394248665Smckusick	if (out3 != NULL)
1395248665Smckusick		*out3 = rsp->rsp_par3;
139648677Smckusick	free(rsp, M_DEVBUF);
139748677Smckusick	return (0);
139848677Smckusick}
139948677Smckusick
140048677Smckusickstatic int
140148677Smckusicktxp_command2(sc, id, in1, in2, in3, in_extp, in_extn, rspp, wait)
140248677Smckusick	struct txp_softc *sc;
140348677Smckusick	u_int16_t id, in1;
140448677Smckusick	u_int32_t in2, in3;
140548677Smckusick	struct txp_ext_desc *in_extp;
140648677Smckusick	u_int8_t in_extn;
140748677Smckusick	struct txp_rsp_desc **rspp;
1408135276Sphk	int wait;
140970374Sdillon{
1410110581Sjeff	struct txp_hostvar *hv = sc->sc_hostvar;
141170374Sdillon	struct txp_cmd_desc *cmd;
141270374Sdillon	struct txp_ext_desc *ext;
141348677Smckusick	u_int32_t idx, i;
1414110581Sjeff	u_int16_t seq;
1415110581Sjeff
141648677Smckusick	if (txp_cmd_desc_numfree(sc) < (in_extn + 1)) {
1417110657Sjeff		device_printf(sc->sc_dev, "no free cmd descriptors\n");
141848677Smckusick		return (-1);
141948677Smckusick	}
142048677Smckusick
142148677Smckusick	idx = sc->sc_cmdring.lastwrite;
142268885Sdillon	cmd = (struct txp_cmd_desc *)(((u_int8_t *)sc->sc_cmdring.base) + idx);
142368885Sdillon	bzero(cmd, sizeof(*cmd));
142468885Sdillon
142568885Sdillon	cmd->cmd_numdesc = in_extn;
142668885Sdillon	cmd->cmd_seq = seq = sc->sc_seq++;
1427135276Sphk	cmd->cmd_id = id;
142868885Sdillon	cmd->cmd_par1 = in1;
142968885Sdillon	cmd->cmd_par2 = in2;
143068885Sdillon	cmd->cmd_par3 = in3;
1431192908Szml	cmd->cmd_flags = CMD_FLAGS_TYPE_CMD |
1432192908Szml	    (wait ? CMD_FLAGS_RESP : 0) | CMD_FLAGS_VALID;
1433192908Szml
1434192908Szml	idx += sizeof(struct txp_cmd_desc);
1435192908Szml	if (idx == sc->sc_cmdring.size)
1436192908Szml		idx = 0;
1437192908Szml
1438192908Szml	for (i = 0; i < in_extn; i++) {
1439192908Szml		ext = (struct txp_ext_desc *)(((u_int8_t *)sc->sc_cmdring.base) + idx);
144068885Sdillon		bcopy(in_extp, ext, sizeof(struct txp_ext_desc));
144144679Sjulian		in_extp++;
144244679Sjulian		idx += sizeof(struct txp_cmd_desc);
144344679Sjulian		if (idx == sc->sc_cmdring.size)
144444679Sjulian			idx = 0;
144544679Sjulian	}
14461549Srgrimes
14471549Srgrimes	sc->sc_cmdring.lastwrite = idx;
1448135276Sphk
14491541Srgrimes	WRITE_REG(sc, TXP_H2A_2, sc->sc_cmdring.lastwrite);
1450140721Sjeff
1451140721Sjeff	if (!wait)
145291690Seivind		return (0);
145391690Seivind
145444679Sjulian	for (i = 0; i < 10000; i++) {
1455248234Skib		idx = hv->hv_resp_read_idx;
1456248234Skib		if (idx != hv->hv_resp_write_idx) {
1457248234Skib			*rspp = NULL;
1458248234Skib			if (txp_response(sc, idx, id, seq, rspp))
1459248234Skib				return (-1);
1460248234Skib			if (*rspp != NULL)
1461248234Skib				break;
1462248234Skib		}
1463248234Skib		DELAY(50);
1464153192Srodrigc	}
1465153192Srodrigc	if (i == 1000 || (*rspp) == NULL) {
1466153192Srodrigc		device_printf(sc->sc_dev, "0x%x command failed\n", id);
1467153192Srodrigc		return (-1);
1468153192Srodrigc	}
1469174992Simp
1470174992Simp	return (0);
147146349Salc}
147258934Sphk
1473174992Simpstatic int
1474193201Salctxp_response(sc, ridx, id, seq, rspp)
1475174992Simp	struct txp_softc *sc;
147646349Salc	u_int32_t ridx;
147758934Sphk	u_int16_t id;
147843043Sdg	u_int16_t seq;
147958934Sphk	struct txp_rsp_desc **rspp;
1480135135Sphk{
148146349Salc	struct txp_hostvar *hv = sc->sc_hostvar;
148246349Salc	struct txp_rsp_desc *rsp;
148346349Salc
148446349Salc	while (ridx != hv->hv_resp_write_idx) {
14851549Srgrimes		rsp = (struct txp_rsp_desc *)(((u_int8_t *)sc->sc_rspring.base) + ridx);
1486166889Sdelphij
148761724Sphk		if (id == rsp->rsp_id && rsp->rsp_seq == seq) {
148848677Smckusick			*rspp = (struct txp_rsp_desc *)malloc(
1489110581Sjeff			    sizeof(struct txp_rsp_desc) * (rsp->rsp_numdesc + 1),
149070374Sdillon			    M_DEVBUF, M_NOWAIT);
149148677Smckusick			if ((*rspp) == NULL)
149258345Sphk				return (-1);
149334206Sdyson			txp_rsp_fixup(sc, rsp, *rspp);
149413490Sdyson			return (0);
149513490Sdyson		}
149634206Sdyson
1497177687Sattilio		if (rsp->rsp_flags & RSP_FLAGS_ERROR) {
149813490Sdyson			device_printf(sc->sc_dev, "response error!\n");
14991549Srgrimes			txp_rsp_fixup(sc, rsp, NULL);
15008876Srgrimes			ridx = hv->hv_resp_read_idx;
15016619Sdg			continue;
150239658Sdillon		}
150339658Sdillon
150439658Sdillon		switch (rsp->rsp_id) {
150539658Sdillon		case TXP_CMD_CYCLE_STATISTICS:
150639658Sdillon		case TXP_CMD_MEDIA_STATUS_READ:
150739658Sdillon			break;
150839658Sdillon		case TXP_CMD_HELLO_RESPONSE:
150968885Sdillon			device_printf(sc->sc_dev, "hello\n");
151068885Sdillon			break;
151168885Sdillon		default:
151239658Sdillon			device_printf(sc->sc_dev, "unknown id(0x%x)\n",
151339658Sdillon			    rsp->rsp_id);
151439658Sdillon		}
1515192908Szml
1516119521Sjeff		txp_rsp_fixup(sc, rsp, NULL);
1517177475Skib		ridx = hv->hv_resp_read_idx;
1518177475Skib		hv->hv_resp_read_idx = ridx;
1519177475Skib	}
1520177475Skib
1521119521Sjeff	return (0);
1522119597Sjeff}
1523119597Sjeff
1524119597Sjeffstatic void
1525119599Sjefftxp_rsp_fixup(sc, rsp, dst)
1526119599Sjeff	struct txp_softc *sc;
1527119521Sjeff	struct txp_rsp_desc *rsp, *dst;
152839658Sdillon{
152939658Sdillon	struct txp_rsp_desc *src = rsp;
15306619Sdg	struct txp_hostvar *hv = sc->sc_hostvar;
153146349Salc	u_int32_t i, ridx;
153246349Salc
153346349Salc	ridx = hv->hv_resp_read_idx;
153425930Sdfr
153558934Sphk	for (i = 0; i < rsp->rsp_numdesc + 1; i++) {
153658934Sphk		if (dst != NULL)
153746349Salc			bcopy(src, dst++, sizeof(struct txp_rsp_desc));
153842014Sdillon		ridx += sizeof(struct txp_rsp_desc);
153946349Salc		if (ridx == sc->sc_rspring.size) {
154046349Salc			src = sc->sc_rspring.base;
154155697Smckusick			ridx = 0;
154255697Smckusick		} else
154355697Smckusick			src++;
154455697Smckusick		sc->sc_rspring.lastwrite = hv->hv_resp_read_idx = ridx;
15456619Sdg	}
154625930Sdfr
1547103314Snjl	hv->hv_resp_read_idx = ridx;
1548103314Snjl}
154955756Sphk
155068885Sdillonstatic int
155126409Sdfrtxp_cmd_desc_numfree(sc)
155234206Sdyson	struct txp_softc *sc;
155334206Sdyson{
155434206Sdyson	struct txp_hostvar *hv = sc->sc_hostvar;
155534206Sdyson	struct txp_boot_record *br = sc->sc_boot;
155634206Sdyson	u_int32_t widx, ridx, nfree;
15575455Sdg
15581549Srgrimes	widx = sc->sc_cmdring.lastwrite;
1559137193Sphk	ridx = hv->hv_cmd_read_idx;
156026664Sdyson
156142014Sdillon	if (widx == ridx) {
156242014Sdillon		/* Ring is completely free */
156385274Sdillon		nfree = br->br_cmd_siz - sizeof(struct txp_cmd_desc);
156485274Sdillon	} else {
156585274Sdillon		if (widx > ridx)
156642014Sdillon			nfree = br->br_cmd_siz -
156742014Sdillon			    (widx - ridx + sizeof(struct txp_cmd_desc));
156842014Sdillon		else
156942014Sdillon			nfree = ridx - widx - sizeof(struct txp_cmd_desc);
157042014Sdillon	}
157142014Sdillon
157242014Sdillon	return (nfree / sizeof(struct txp_cmd_desc));
157334206Sdyson}
157434611Sdyson
1575122455Salcstatic void
157634206Sdysontxp_stop(sc)
157768885Sdillon	struct txp_softc *sc;
157868885Sdillon{
157934206Sdyson	struct ifnet *ifp;
158068885Sdillon
158168885Sdillon	ifp = sc->sc_ifp;
158268885Sdillon
158368885Sdillon	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
158468885Sdillon
158534206Sdyson	untimeout(txp_tick, sc, sc->sc_tick);
158634611Sdyson
158768885Sdillon	txp_command(sc, TXP_CMD_TX_DISABLE, 0, 0, 0, NULL, NULL, NULL, 1);
158834206Sdyson	txp_command(sc, TXP_CMD_RX_DISABLE, 0, 0, 0, NULL, NULL, NULL, 1);
158934206Sdyson
159068885Sdillon	txp_rxring_empty(sc);
159168885Sdillon
159268885Sdillon	return;
159368885Sdillon}
159468885Sdillon
159534206Sdysonstatic void
159634206Sdysontxp_watchdog(ifp)
159768885Sdillon	struct ifnet *ifp;
15988692Sdg{
15995455Sdg	return;
160034206Sdyson}
1601251897Sscottl
1602251897Sscottlstatic int
1603135276Sphktxp_ifmedia_upd(ifp)
1604137193Sphk	struct ifnet *ifp;
1605137193Sphk{
160634206Sdyson	struct txp_softc *sc = ifp->if_softc;
160768885Sdillon	struct ifmedia *ifm = &sc->sc_ifmedia;
16085455Sdg	u_int16_t new_xcvr;
1609135276Sphk
1610195773Skib	if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
1611195773Skib		return (EINVAL);
161234611Sdyson
161334611Sdyson	if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_T) {
161434611Sdyson		if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
161542453Seivind			new_xcvr = TXP_XCVR_10_FDX;
161642408Seivind		else
1617254086Skib			new_xcvr = TXP_XCVR_10_HDX;
1618254086Skib	} else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_TX) {
161968885Sdillon		if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX)
162068885Sdillon			new_xcvr = TXP_XCVR_100_FDX;
162134206Sdyson		else
162242007Sluoqi			new_xcvr = TXP_XCVR_100_HDX;
162368885Sdillon	} else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) {
16245455Sdg		new_xcvr = TXP_XCVR_AUTO;
1625122455Salc	} else
162613490Sdyson		return (EINVAL);
162713490Sdyson
162834206Sdyson	/* nothing to do */
162932755Sdyson	if (sc->sc_xcvr == new_xcvr)
163034206Sdyson		return (0);
163176827Salfred
163232755Sdyson	txp_command(sc, TXP_CMD_XCVR_SELECT, new_xcvr, 0, 0,
163376827Salfred	    NULL, NULL, NULL, 0);
163434206Sdyson	sc->sc_xcvr = new_xcvr;
1635155229Stegge
1636155229Stegge	return (0);
1637155229Stegge}
1638155229Stegge
1639177687Sattiliostatic void
16405455Sdgtxp_ifmedia_sts(ifp, ifmr)
164132755Sdyson	struct ifnet *ifp;
164244679Sjulian	struct ifmediareq *ifmr;
1643110581Sjeff{
1644137846Sjeff	struct txp_softc *sc = ifp->if_softc;
1645211213Skib	struct ifmedia *ifm = &sc->sc_ifmedia;
1646211213Skib	u_int16_t bmsr, bmcr, anlpar;
1647211213Skib
1648211213Skib	ifmr->ifm_status = IFM_AVALID;
1649211213Skib	ifmr->ifm_active = IFM_ETHER;
1650211213Skib
1651137846Sjeff	if (txp_command(sc, TXP_CMD_PHY_MGMT_READ, 0, MII_BMSR, 0,
1652211213Skib	    &bmsr, NULL, NULL, 1))
1653211213Skib		goto bail;
1654211213Skib	if (txp_command(sc, TXP_CMD_PHY_MGMT_READ, 0, MII_BMSR, 0,
1655137846Sjeff	    &bmsr, NULL, NULL, 1))
1656137846Sjeff		goto bail;
16571549Srgrimes
1658189933Sattilio	if (txp_command(sc, TXP_CMD_PHY_MGMT_READ, 0, MII_BMCR, 0,
1659189933Sattilio	    &bmcr, NULL, NULL, 1))
1660189933Sattilio		goto bail;
1661189933Sattilio
1662189933Sattilio	if (txp_command(sc, TXP_CMD_PHY_MGMT_READ, 0, MII_ANLPAR, 0,
1663189933Sattilio	    &anlpar, NULL, NULL, 1))
1664189933Sattilio		goto bail;
1665189933Sattilio
1666189933Sattilio	if (bmsr & BMSR_LINK)
1667189933Sattilio		ifmr->ifm_status |= IFM_ACTIVE;
1668189933Sattilio
1669189933Sattilio	if (bmcr & BMCR_ISO) {
1670189933Sattilio		ifmr->ifm_active |= IFM_NONE;
1671189933Sattilio		ifmr->ifm_status = 0;
1672189933Sattilio		return;
16731887Sdg	}
16745455Sdg
1675100344Smckusick	if (bmcr & BMCR_LOOP)
1676119521Sjeff		ifmr->ifm_active |= IFM_LOOP;
167755697Smckusick
167852452Sdillon	if (bmcr & BMCR_AUTOEN) {
167948544Smckusick		if ((bmsr & BMSR_ACOMP) == 0) {
168052452Sdillon			ifmr->ifm_active |= IFM_NONE;
168148544Smckusick			return;
168252452Sdillon		}
168348544Smckusick
168426664Sdyson		if (anlpar & ANLPAR_T4)
168591690Seivind			ifmr->ifm_active |= IFM_100_T4;
168691690Seivind		else if (anlpar & ANLPAR_TX_FD)
1687100344Smckusick			ifmr->ifm_active |= IFM_100_TX|IFM_FDX;
1688119521Sjeff		else if (anlpar & ANLPAR_TX)
168955697Smckusick			ifmr->ifm_active |= IFM_100_TX;
169048544Smckusick		else if (anlpar & ANLPAR_10_FD)
169148544Smckusick			ifmr->ifm_active |= IFM_10_T|IFM_FDX;
169248544Smckusick		else if (anlpar & ANLPAR_10)
16931549Srgrimes			ifmr->ifm_active |= IFM_10_T;
1694157469Sjeff		else
1695157469Sjeff			ifmr->ifm_active |= IFM_NONE;
1696157319Sjeff	} else
1697181868Skib		ifmr->ifm_active = ifm->ifm_cur->ifm_media;
169875629Sphk	return;
169975629Sphk
170075629Sphkbail:
1701251897Sscottl	ifmr->ifm_active |= IFM_NONE;
1702251897Sscottl	ifmr->ifm_status &= ~IFM_AVALID;
1703251897Sscottl}
1704251897Sscottl
1705251897Sscottl#ifdef TXP_DEBUG
1706251897Sscottlstatic void
1707251897Sscottltxp_show_descriptor(d)
170826664Sdyson	void *d;
1709251897Sscottl{
1710251897Sscottl	struct txp_cmd_desc *cmd = d;
1711251897Sscottl	struct txp_rsp_desc *rsp = d;
1712110581Sjeff	struct txp_tx_desc *txd = d;
171326664Sdyson	struct txp_frag_desc *frgd = d;
171444679Sjulian
171544679Sjulian	switch (cmd->cmd_flags & CMD_FLAGS_TYPE_M) {
171644679Sjulian	case CMD_FLAGS_TYPE_CMD:
171744679Sjulian		/* command descriptor */
171844679Sjulian		printf("[cmd flags 0x%x num %d id %d seq %d par1 0x%x par2 0x%x par3 0x%x]\n",
171944679Sjulian		    cmd->cmd_flags, cmd->cmd_numdesc, cmd->cmd_id, cmd->cmd_seq,
172044679Sjulian		    cmd->cmd_par1, cmd->cmd_par2, cmd->cmd_par3);
1721211213Skib		break;
1722211213Skib	case CMD_FLAGS_TYPE_RESP:
1723211213Skib		/* response descriptor */
1724211213Skib		printf("[rsp flags 0x%x num %d id %d seq %d par1 0x%x par2 0x%x par3 0x%x]\n",
1725211213Skib		    rsp->rsp_flags, rsp->rsp_numdesc, rsp->rsp_id, rsp->rsp_seq,
1726211213Skib		    rsp->rsp_par1, rsp->rsp_par2, rsp->rsp_par3);
1727209053Smdf		break;
1728211213Skib	case CMD_FLAGS_TYPE_DATA:
1729211213Skib		/* data header (assuming tx for now) */
1730211213Skib		printf("[data flags 0x%x num %d totlen %d addr 0x%x/0x%x pflags 0x%x]",
173144679Sjulian		    txd->tx_flags, txd->tx_numdesc, txd->tx_totlen,
173244679Sjulian		    txd->tx_addrlo, txd->tx_addrhi, txd->tx_pflags);
173371983Sdillon		break;
173444679Sjulian	case CMD_FLAGS_TYPE_FRAG:
173558706Sdillon		/* fragment descriptor */
173644679Sjulian		printf("[frag flags 0x%x rsvd1 0x%x len %d addr 0x%x/0x%x rsvd2 0x%x]",
173744679Sjulian		    frgd->frag_flags, frgd->frag_rsvd1, frgd->frag_len,
1738115456Sphk		    frgd->frag_addrlo, frgd->frag_addrhi, frgd->frag_rsvd2);
173962976Smckusick		break;
174062976Smckusick	default:
1741110581Sjeff		printf("[unknown(%x) flags 0x%x num %d id %d seq %d par1 0x%x par2 0x%x par3 0x%x]\n",
1742110581Sjeff		    cmd->cmd_flags & CMD_FLAGS_TYPE_M,
17431541Srgrimes		    cmd->cmd_flags, cmd->cmd_numdesc, cmd->cmd_id, cmd->cmd_seq,
17441541Srgrimes		    cmd->cmd_par1, cmd->cmd_par2, cmd->cmd_par3);
17455455Sdg		break;
174644679Sjulian	}
174768885Sdillon}
174846349Salc#endif
174946349Salc
175046349Salcstatic void
175146349Salctxp_set_filter(sc)
175246349Salc	struct txp_softc *sc;
175377115Sdillon{
175477115Sdillon	struct ifnet *ifp = sc->sc_ifp;
175513490Sdyson	u_int32_t crc, carry, hashbit, hash[2];
175613490Sdyson	u_int16_t filter;
1757135276Sphk	u_int8_t octet;
175813490Sdyson	int i, j, mcnt = 0;
1759211213Skib	struct ifmultiaddr *ifma;
1760211213Skib	char *enm;
1761140721Sjeff
1762135276Sphk	if (ifp->if_flags & IFF_PROMISC) {
1763135276Sphk		filter = TXP_RXFILT_PROMISC;
176413490Sdyson		goto setit;
1765175486Sattilio	}
176648225Smckusick
176748225Smckusick	filter = TXP_RXFILT_DIRECT;
176848225Smckusick
176948225Smckusick	if (ifp->if_flags & IFF_BROADCAST)
1770153192Srodrigc		filter |= TXP_RXFILT_BROADCAST;
1771211213Skib
1772153192Srodrigc	if (ifp->if_flags & IFF_ALLMULTI)
1773153192Srodrigc		filter |= TXP_RXFILT_ALLMULTI;
1774153192Srodrigc	else {
1775211213Skib		hash[0] = hash[1] = 0;
1776211213Skib
1777153192Srodrigc		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
1778211213Skib			if (ifma->ifma_addr->sa_family != AF_LINK)
1779211213Skib				continue;
1780153192Srodrigc
1781153192Srodrigc			enm = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
1782153192Srodrigc			mcnt++;
1783153192Srodrigc			crc = 0xffffffff;
1784153192Srodrigc
1785153192Srodrigc			for (i = 0; i < ETHER_ADDR_LEN; i++) {
1786153192Srodrigc				octet = enm[i];
1787110581Sjeff				for (j = 0; j < 8; j++) {
1788137846Sjeff					carry = ((crc & 0x80000000) ? 1 : 0) ^
1789211213Skib					    (octet & 1);
1790211213Skib					crc <<= 1;
1791211213Skib					octet >>= 1;
1792137846Sjeff					if (carry)
1793211213Skib						crc = (crc ^ TXP_POLYNOMIAL) |
1794211213Skib						    carry;
1795211213Skib				}
1796137846Sjeff			}
1797137846Sjeff			hashbit = (u_int16_t)(crc & (64 - 1));
1798119521Sjeff			hash[hashbit / 32] |= (1 << hashbit % 32);
1799119521Sjeff		}
1800157319Sjeff
1801157319Sjeff		if (mcnt > 0) {
1802157319Sjeff			filter |= TXP_RXFILT_HASHMULTI;
1803157319Sjeff			txp_command(sc, TXP_CMD_MCAST_HASH_MASK_WRITE,
1804157319Sjeff			    2, hash[0], hash[1], NULL, NULL, NULL, 0);
1805251897Sscottl		}
1806251897Sscottl	}
1807251897Sscottl
1808119521Sjeffsetit:
180968885Sdillon
1810177475Skib	txp_command(sc, TXP_CMD_RX_FILTER_WRITE, filter, 0, 0,
1811177475Skib	    NULL, NULL, NULL, 1);
1812177475Skib
1813177475Skib	return;
1814177475Skib}
181568885Sdillon
1816192908Szmlstatic void
1817119521Sjefftxp_capabilities(sc)
1818119521Sjeff	struct txp_softc *sc;
1819119521Sjeff{
1820251897Sscottl	struct ifnet *ifp = sc->sc_ifp;
1821251897Sscottl	struct txp_rsp_desc *rsp = NULL;
1822251897Sscottl	struct txp_ext_desc *ext;
1823119521Sjeff
1824119521Sjeff	if (txp_command2(sc, TXP_CMD_OFFLOAD_READ, 0, 0, 0, NULL, 0, &rsp, 1))
1825119521Sjeff		goto out;
1826119521Sjeff
1827119521Sjeff	if (rsp->rsp_numdesc != 1)
1828119521Sjeff		goto out;
1829119521Sjeff	ext = (struct txp_ext_desc *)(rsp + 1);
1830119521Sjeff
1831119521Sjeff	sc->sc_tx_capability = ext->ext_1 & OFFLOAD_MASK;
1832119521Sjeff	sc->sc_rx_capability = ext->ext_2 & OFFLOAD_MASK;
183313490Sdyson	ifp->if_capabilities = 0;
1834110581Sjeff
183513490Sdyson	if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_VLAN) {
1836211213Skib		sc->sc_tx_capability |= OFFLOAD_VLAN;
1837211213Skib		sc->sc_rx_capability |= OFFLOAD_VLAN;
1838211213Skib		ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
1839209053Smdf	}
1840211213Skib
1841211213Skib#if 0
1842211213Skib	/* not ready yet */
184326664Sdyson	if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_IPSEC) {
184444679Sjulian		sc->sc_tx_capability |= OFFLOAD_IPSEC;
184571983Sdillon		sc->sc_rx_capability |= OFFLOAD_IPSEC;
184644679Sjulian		ifp->if_capabilities |= IFCAP_IPSEC;
184748677Smckusick	}
184844679Sjulian#endif
184944679Sjulian
185058934Sphk	if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_IPCKSUM) {
185162976Smckusick		sc->sc_tx_capability |= OFFLOAD_IPCKSUM;
185262976Smckusick		sc->sc_rx_capability |= OFFLOAD_IPCKSUM;
1853110581Sjeff		ifp->if_capabilities |= IFCAP_HWCSUM;
1854110581Sjeff		ifp->if_hwassist |= CSUM_IP;
185513490Sdyson	}
185613490Sdyson
185791690Seivind	if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_TCPCKSUM) {
185813490Sdyson#if 0
1859135276Sphk		sc->sc_tx_capability |= OFFLOAD_TCPCKSUM;
186013490Sdyson#endif
186177085Sjhb		sc->sc_rx_capability |= OFFLOAD_TCPCKSUM;
186218401Sdyson		ifp->if_capabilities |= IFCAP_HWCSUM;
186313490Sdyson	}
1864251897Sscottl
1865251897Sscottl	if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_UDPCKSUM) {
1866251897Sscottl#if 0
1867251897Sscottl		sc->sc_tx_capability |= OFFLOAD_UDPCKSUM;
1868251897Sscottl#endif
1869137010Sphk		sc->sc_rx_capability |= OFFLOAD_UDPCKSUM;
187013490Sdyson		ifp->if_capabilities |= IFCAP_HWCSUM;
187113490Sdyson	}
187213490Sdyson	ifp->if_capenable = ifp->if_capabilities;
187318975Sdyson
187440764Sdg	if (txp_command(sc, TXP_CMD_OFFLOAD_WRITE, 0,
187540764Sdg	    sc->sc_tx_capability, sc->sc_rx_capability, NULL, NULL, NULL, 1))
187640764Sdg		goto out;
1877207534Salc
187840764Sdgout:
187940764Sdg	if (rsp != NULL)
188018975Sdyson		free(rsp, M_DEVBUF);
188118975Sdyson
188218975Sdyson	return;
188318975Sdyson}
1884207534Salc