if_txp.c revision 113038
150276Speter/*	$OpenBSD: if_txp.c,v 1.48 2001/06/27 06:34:50 kjc Exp $	*/
250276Speter
397049Speter/*
4178866Srafan * Copyright (c) 2001
5178866Srafan *	Jason L. Wright <jason@thought.net>, Theo de Raadt, and
662449Speter *	Aaron Campbell <aaron@monkey.org>.  All rights reserved.
7184989Srafan *
862449Speter * Redistribution and use in source and binary forms, with or without
950276Speter * modification, are permitted provided that the following conditions
1050276Speter * are met:
1150276Speter * 1. Redistributions of source code must retain the above copyright
1250276Speter *    notice, this list of conditions and the following disclaimer.
1350276Speter * 2. Redistributions in binary form must reproduce the above copyright
1450276Speter *    notice, this list of conditions and the following disclaimer in the
1550276Speter *    documentation and/or other materials provided with the distribution.
1650276Speter * 3. All advertising materials mentioning features or use of this software
1750276Speter *    must display the following acknowledgement:
1850276Speter *	This product includes software developed by Jason L. Wright,
1950276Speter *	Theo de Raadt and Aaron Campbell.
2050276Speter * 4. Neither the name of the author nor the names of any co-contributors
21166124Srafan *    may be used to endorse or promote products derived from this software
22166124Srafan *    without specific prior written permission.
2350276Speter *
2450276Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
2550276Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2650276Speter * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2750276Speter * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
2850276Speter * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29166124Srafan * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3097049Speter * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3197049Speter * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3297049Speter * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3350276Speter * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3450276Speter * THE POSSIBILITY OF SUCH DAMAGE.
3550276Speter */
3650276Speter
3750276Speter/*
3850276Speter * Driver for 3c990 (Typhoon) Ethernet ASIC
3976726Speter */
4050276Speter
4162449Speter#include <sys/cdefs.h>
4262449Speter__FBSDID("$FreeBSD: head/sys/dev/txp/if_txp.c 113038 2003-04-03 21:36:33Z obrien $");
4362449Speter
4462449Speter#include <sys/param.h>
4562449Speter#include <sys/systm.h>
4676726Speter#include <sys/sockio.h>
4762449Speter#include <sys/mbuf.h>
4862449Speter#include <sys/malloc.h>
4976726Speter#include <sys/kernel.h>
5076726Speter#include <sys/socket.h>
5176726Speter
5262449Speter#include <net/if.h>
5376726Speter#include <net/if_arp.h>
5476726Speter#include <net/ethernet.h>
5576726Speter#include <net/if_dl.h>
5676726Speter#include <net/if_types.h>
5776726Speter#include <net/if_vlan_var.h>
5876726Speter
59178866Srafan#include <netinet/in.h>
60178866Srafan#include <netinet/in_systm.h>
6176726Speter#include <netinet/in_var.h>
6276726Speter#include <netinet/ip.h>
6376726Speter#include <netinet/if_ether.h>
6476726Speter#include <machine/in_cksum.h>
6562449Speter
6662449Speter#include <net/if_media.h>
6762449Speter
6862449Speter#include <net/bpf.h>
6962449Speter
7076726Speter#include <vm/vm.h>              /* for vtophys */
7176726Speter#include <vm/pmap.h>            /* for vtophys */
72166124Srafan#include <machine/clock.h>	/* for DELAY */
7376726Speter#include <machine/bus_pio.h>
74166124Srafan#include <machine/bus_memio.h>
7562449Speter#include <machine/bus.h>
76166124Srafan#include <machine/resource.h>
7762449Speter#include <sys/bus.h>
7862449Speter#include <sys/rman.h>
7962449Speter
8062449Speter#include <dev/mii/mii.h>
8162449Speter#include <dev/mii/miivar.h>
8276726Speter#include <dev/pci/pcireg.h>
8362449Speter#include <dev/pci/pcivar.h>
8462449Speter
8562449Speter#define TXP_USEIOSPACE
8662449Speter#define __STRICT_ALIGNMENT
8762449Speter
8862449Speter#include <dev/txp/if_txpreg.h>
8962449Speter#include <dev/txp/3c990img.h>
9062449Speter
9162449Speter#ifndef lint
9262449Speterstatic const char rcsid[] =
9362449Speter  "$FreeBSD: head/sys/dev/txp/if_txp.c 113038 2003-04-03 21:36:33Z obrien $";
94166124Srafan#endif
9562449Speter
96166124Srafan/*
97166124Srafan * Various supported device vendors/types and their names.
98166124Srafan */
99166124Srafanstatic struct txp_type txp_devs[] = {
10062449Speter	{ TXP_VENDORID_3COM, TXP_DEVICEID_3CR990_TX_95,
10176726Speter	    "3Com 3cR990-TX-95 Etherlink with 3XP Processor" },
10276726Speter	{ TXP_VENDORID_3COM, TXP_DEVICEID_3CR990_TX_97,
10376726Speter	    "3Com 3cR990-TX-97 Etherlink with 3XP Processor" },
104166124Srafan	{ TXP_VENDORID_3COM, TXP_DEVICEID_3CR990B_TXM,
105166124Srafan	    "3Com 3cR990B-TXM Etherlink with 3XP Processor" },
106166124Srafan	{ TXP_VENDORID_3COM, TXP_DEVICEID_3CR990_SRV_95,
107166124Srafan	    "3Com 3cR990-SRV-95 Etherlink Server with 3XP Processor" },
108166124Srafan	{ TXP_VENDORID_3COM, TXP_DEVICEID_3CR990_SRV_97,
109166124Srafan	    "3Com 3cR990-SRV-97 Etherlink Server with 3XP Processor" },
110166124Srafan	{ TXP_VENDORID_3COM, TXP_DEVICEID_3CR990B_SRV,
111166124Srafan	    "3Com 3cR990B-SRV Etherlink Server with 3XP Processor" },
112166124Srafan	{ 0, 0, NULL }
113166124Srafan};
114166124Srafan
115166124Srafanstatic int txp_probe	(device_t);
116166124Srafanstatic int txp_attach	(device_t);
117166124Srafanstatic int txp_detach	(device_t);
11897049Speterstatic void txp_intr	(void *);
119166124Srafanstatic void txp_tick	(void *);
12097049Speterstatic int txp_shutdown	(device_t);
12197049Speterstatic int txp_ioctl	(struct ifnet *, u_long, caddr_t);
12297049Speterstatic void txp_start	(struct ifnet *);
12376726Speterstatic void txp_stop	(struct txp_softc *);
12497049Speterstatic void txp_init	(void *);
12576726Speterstatic void txp_watchdog	(struct ifnet *);
12676726Speter
12776726Speterstatic void txp_release_resources(struct txp_softc *);
12876726Speterstatic int txp_chip_init(struct txp_softc *);
129166124Srafanstatic int txp_reset_adapter(struct txp_softc *);
13076726Speterstatic int txp_download_fw(struct txp_softc *);
13150276Speterstatic int txp_download_fw_wait(struct txp_softc *);
13297049Speterstatic int txp_download_fw_section (struct txp_softc *,
13350276Speter    struct txp_fw_section_header *, int);
13450276Speterstatic int txp_alloc_rings(struct txp_softc *);
13550276Speterstatic int txp_rxring_fill(struct txp_softc *);
13650276Speterstatic void txp_rxring_empty(struct txp_softc *);
13750276Speterstatic void txp_set_filter(struct txp_softc *);
13850276Speter
13976726Speterstatic int txp_cmd_desc_numfree(struct txp_softc *);
14050276Speterstatic int txp_command (struct txp_softc *, u_int16_t, u_int16_t, u_int32_t,
14150276Speter    u_int32_t, u_int16_t *, u_int32_t *, u_int32_t *, int);
14250276Speterstatic int txp_command2 (struct txp_softc *, u_int16_t, u_int16_t,
14350276Speter    u_int32_t, u_int32_t, struct txp_ext_desc *, u_int8_t,
14450276Speter    struct txp_rsp_desc **, int);
14562449Speterstatic int txp_response (struct txp_softc *, u_int32_t, u_int16_t, u_int16_t,
14697049Speter    struct txp_rsp_desc **);
14762449Speterstatic void txp_rsp_fixup (struct txp_softc *, struct txp_rsp_desc *,
14862449Speter    struct txp_rsp_desc *);
14962449Speterstatic void txp_capabilities(struct txp_softc *);
15062449Speter
15162449Speterstatic void txp_ifmedia_sts(struct ifnet *, struct ifmediareq *);
15262449Speterstatic int txp_ifmedia_upd(struct ifnet *);
15397049Speter#ifdef TXP_DEBUG
15497049Speterstatic void txp_show_descriptor(void *);
15597049Speter#endif
15697049Speterstatic void txp_tx_reclaim(struct txp_softc *, struct txp_tx_ring *);
15797049Speterstatic void txp_rxbuf_reclaim(struct txp_softc *);
15897049Speterstatic void txp_rx_reclaim(struct txp_softc *, struct txp_rx_ring *);
15997049Speter
160166124Srafan#ifdef TXP_USEIOSPACE
16197049Speter#define TXP_RES			SYS_RES_IOPORT
16297049Speter#define TXP_RID			TXP_PCI_LOIO
16397049Speter#else
164174993Srafan#define TXP_RES			SYS_RES_MEMORY
16597049Speter#define TXP_RID			TXP_PCI_LOMEM
16662449Speter#endif
16776726Speter
16876726Speterstatic device_method_t txp_methods[] = {
16997049Speter        /* Device interface */
17097049Speter	DEVMETHOD(device_probe,		txp_probe),
17197049Speter	DEVMETHOD(device_attach,	txp_attach),
17276726Speter	DEVMETHOD(device_detach,	txp_detach),
17376726Speter	DEVMETHOD(device_shutdown,	txp_shutdown),
17476726Speter	{ 0, 0 }
17576726Speter};
17676726Speter
17776726Speterstatic driver_t txp_driver = {
17876726Speter	"txp",
17976726Speter	txp_methods,
18076726Speter	sizeof(struct txp_softc)
18176726Speter};
18276726Speter
183184989Srafanstatic devclass_t txp_devclass;
18476726Speter
18576726SpeterDRIVER_MODULE(if_txp, pci, txp_driver, txp_devclass, 0, 0);
18662449Speter
187166124Srafanstatic int
188166124Srafantxp_probe(dev)
189166124Srafan	device_t dev;
190166124Srafan{
191166124Srafan	struct txp_type *t;
192166124Srafan
193166124Srafan	t = txp_devs;
194166124Srafan
195166124Srafan	while(t->txp_name != NULL) {
196166124Srafan		if ((pci_get_vendor(dev) == t->txp_vid) &&
197166124Srafan		    (pci_get_device(dev) == t->txp_did)) {
198166124Srafan			device_set_desc(dev, t->txp_name);
19962449Speter			return(0);
20062449Speter		}
20162449Speter		t++;
20262449Speter	}
203166124Srafan
20497049Speter	return(ENXIO);
205166124Srafan}
206166124Srafan
207166124Srafanstatic int
208166124Srafantxp_attach(dev)
209166124Srafan	device_t dev;
210166124Srafan{
211166124Srafan	struct txp_softc *sc;
212166124Srafan	struct ifnet *ifp;
213166124Srafan	u_int32_t command;
214166124Srafan	u_int16_t p1;
215166124Srafan	u_int32_t p2;
216166124Srafan	int unit, error = 0, rid;
217166124Srafan
218166124Srafan	sc = device_get_softc(dev);
219166124Srafan	unit = device_get_unit(dev);
22050276Speter	sc->sc_dev = dev;
221166124Srafan	sc->sc_cold = 1;
222184989Srafan
22350276Speter	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
224166124Srafan	    MTX_DEF | MTX_RECURSE);
225184989Srafan
226184989Srafan	/*
227166124Srafan	 * Handle power management nonsense.
228166124Srafan	 */
229166124Srafan	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
230166124Srafan		u_int32_t		iobase, membase, irq;
231166124Srafan
232166124Srafan		/* Save important PCI config data. */
233166124Srafan		iobase = pci_read_config(dev, TXP_PCI_LOIO, 4);
234166124Srafan		membase = pci_read_config(dev, TXP_PCI_LOMEM, 4);
235166124Srafan		irq = pci_read_config(dev, TXP_PCI_INTLINE, 4);
236166124Srafan
237166124Srafan		/* Reset the power state. */
238166124Srafan		device_printf(dev, "chip is in D%d power mode "
239166124Srafan		    "-- setting to D0\n", pci_get_powerstate(dev));
240166124Srafan		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
241166124Srafan
242166124Srafan		/* Restore PCI config data. */
243166124Srafan		pci_write_config(dev, TXP_PCI_LOIO, iobase, 4);
244166124Srafan		pci_write_config(dev, TXP_PCI_LOMEM, membase, 4);
245166124Srafan		pci_write_config(dev, TXP_PCI_INTLINE, irq, 4);
246166124Srafan	}
247166124Srafan
248166124Srafan	/*
249166124Srafan	 * Map control/status registers.
250166124Srafan	 */
251166124Srafan	pci_enable_busmaster(dev);
252166124Srafan	pci_enable_io(dev, SYS_RES_IOPORT);
253166124Srafan	pci_enable_io(dev, SYS_RES_MEMORY);
254166124Srafan	command = pci_read_config(dev, PCIR_COMMAND, 4);
255166124Srafan
256166124Srafan#ifdef TXP_USEIOSPACE
257166124Srafan	if (!(command & PCIM_CMD_PORTEN)) {
258166124Srafan		device_printf(dev, "failed to enable I/O ports!\n");
259166124Srafan		error = ENXIO;
260166124Srafan		goto fail;
261166124Srafan	}
262166124Srafan#else
263166124Srafan	if (!(command & PCIM_CMD_MEMEN)) {
264166124Srafan		device_printf(dev, "failed to enable memory mapping!\n");
265166124Srafan		error = ENXIO;
266166124Srafan		goto fail;
26750276Speter	}
26850276Speter#endif
26950276Speter
27050276Speter	rid = TXP_RID;
271166124Srafan	sc->sc_res = bus_alloc_resource(dev, TXP_RES, &rid,
272166124Srafan	    0, ~0, 1, RF_ACTIVE);
27362449Speter
27462449Speter	if (sc->sc_res == NULL) {
27562449Speter		device_printf(dev, "couldn't map ports/memory\n");
27662449Speter		error = ENXIO;
27762449Speter		goto fail;
278166124Srafan	}
27950276Speter
28050276Speter	sc->sc_bt = rman_get_bustag(sc->sc_res);
281166124Srafan	sc->sc_bh = rman_get_bushandle(sc->sc_res);
28250276Speter
28376726Speter	/* Allocate interrupt */
284166124Srafan	rid = 0;
28550276Speter	sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
28650276Speter	    RF_SHAREABLE | RF_ACTIVE);
287166124Srafan
28897049Speter	if (sc->sc_irq == NULL) {
28997049Speter		device_printf(dev, "couldn't map interrupt\n");
290166124Srafan		txp_release_resources(sc);
29162449Speter		error = ENXIO;
29262449Speter		goto fail;
293166124Srafan	}
294166124Srafan
295166124Srafan	error = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_NET,
296166124Srafan	    txp_intr, sc, &sc->sc_intrhand);
297166124Srafan
298184989Srafan	if (error) {
299166124Srafan		txp_release_resources(sc);
30050276Speter		device_printf(dev, "couldn't set up irq\n");
30150276Speter		goto fail;
302166124Srafan	}
303166124Srafan
304166124Srafan	if (txp_chip_init(sc)) {
305166124Srafan		txp_release_resources(sc);
30676726Speter		goto fail;
30750276Speter	}
308166124Srafan
30962449Speter	sc->sc_fwbuf = contigmalloc(32768, M_DEVBUF,
31050276Speter	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
31150276Speter	error = txp_download_fw(sc);
31250276Speter	contigfree(sc->sc_fwbuf, 32768, M_DEVBUF);
31350276Speter	sc->sc_fwbuf = NULL;
31450276Speter
31550276Speter	if (error) {
316166124Srafan		txp_release_resources(sc);
31762449Speter		goto fail;
31850276Speter	}
319166124Srafan
320166124Srafan	sc->sc_ldata = contigmalloc(sizeof(struct txp_ldata), M_DEVBUF,
321166124Srafan	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
322166124Srafan	bzero(sc->sc_ldata, sizeof(struct txp_ldata));
323166124Srafan
324166124Srafan	if (txp_alloc_rings(sc)) {
325166124Srafan		txp_release_resources(sc);
326166124Srafan		goto fail;
32750276Speter	}
32850276Speter
329166124Srafan	if (txp_command(sc, TXP_CMD_MAX_PKT_SIZE_WRITE, TXP_MAX_PKTLEN, 0, 0,
33050276Speter	    NULL, NULL, NULL, 1)) {
33150276Speter		txp_release_resources(sc);
332166124Srafan		goto fail;
333178866Srafan	}
33450276Speter
335166124Srafan	if (txp_command(sc, TXP_CMD_STATION_ADDRESS_READ, 0, 0, 0,
33650276Speter	    &p1, &p2, NULL, 1)) {
33750276Speter		txp_release_resources(sc);
33850276Speter		goto fail;
33950276Speter	}
34050276Speter
341166124Srafan	txp_set_filter(sc);
34250276Speter
34350276Speter	sc->sc_arpcom.ac_enaddr[0] = ((u_int8_t *)&p1)[1];
34450276Speter	sc->sc_arpcom.ac_enaddr[1] = ((u_int8_t *)&p1)[0];
34550276Speter	sc->sc_arpcom.ac_enaddr[2] = ((u_int8_t *)&p2)[3];
34650276Speter	sc->sc_arpcom.ac_enaddr[3] = ((u_int8_t *)&p2)[2];
34750276Speter	sc->sc_arpcom.ac_enaddr[4] = ((u_int8_t *)&p2)[1];
34850276Speter	sc->sc_arpcom.ac_enaddr[5] = ((u_int8_t *)&p2)[0];
34950276Speter
350166124Srafan	printf("txp%d: Ethernet address %6D\n", unit,
35150276Speter	    sc->sc_arpcom.ac_enaddr, ":");
35250276Speter
353166124Srafan	sc->sc_cold = 0;
35450276Speter
35597049Speter	ifmedia_init(&sc->sc_ifmedia, 0, txp_ifmedia_upd, txp_ifmedia_sts);
35650276Speter	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_10_T, 0, NULL);
35750276Speter	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL);
35850276Speter	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL);
35950276Speter	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL);
36050276Speter	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL);
36150276Speter	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL);
36250276Speter	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
36350276Speter
36450276Speter	sc->sc_xcvr = TXP_XCVR_AUTO;
365166124Srafan	txp_command(sc, TXP_CMD_XCVR_SELECT, TXP_XCVR_AUTO, 0, 0,
36650276Speter	    NULL, NULL, NULL, 0);
36750276Speter	ifmedia_set(&sc->sc_ifmedia, IFM_ETHER|IFM_AUTO);
368166124Srafan
36962449Speter	ifp = &sc->sc_arpcom.ac_if;
37062449Speter	ifp->if_softc = sc;
37162449Speter	ifp->if_unit = unit;
37262449Speter	ifp->if_name = "txp";
37362449Speter	ifp->if_mtu = ETHERMTU;
37462449Speter	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
37562449Speter	ifp->if_ioctl = txp_ioctl;
37662449Speter	ifp->if_output = ether_output;
37762449Speter	ifp->if_start = txp_start;
378184989Srafan	ifp->if_watchdog = txp_watchdog;
379166124Srafan	ifp->if_init = txp_init;
38062449Speter	ifp->if_baudrate = 100000000;
38162449Speter	ifp->if_snd.ifq_maxlen = TX_ENTRIES;
382184989Srafan	ifp->if_hwassist = 0;
38362449Speter	txp_capabilities(sc);
384184989Srafan
385166124Srafan	/*
38662449Speter	 * Attach us everywhere
387184989Srafan	 */
388184989Srafan	ether_ifattach(ifp, sc->sc_arpcom.ac_enaddr);
38962449Speter	callout_handle_init(&sc->sc_tick);
390184989Srafan	return(0);
391184989Srafan
39262449Speterfail:
393184989Srafan	txp_release_resources(sc);
394184989Srafan	mtx_destroy(&sc->sc_mtx);
395166124Srafan	return(error);
396166124Srafan}
397166124Srafan
39850276Speterstatic int
39950276Spetertxp_detach(dev)
400166124Srafan	device_t dev;
40150276Speter{
40250276Speter	struct txp_softc *sc;
403166124Srafan	struct ifnet *ifp;
40450276Speter	int i;
40550276Speter
406166124Srafan	sc = device_get_softc(dev);
40750276Speter	ifp = &sc->sc_arpcom.ac_if;
40850276Speter
409166124Srafan	txp_stop(sc);
41050276Speter	txp_shutdown(dev);
41150276Speter
412166124Srafan	ifmedia_removeall(&sc->sc_ifmedia);
41350276Speter	ether_ifdetach(ifp);
41497049Speter
41562449Speter	for (i = 0; i < RXBUF_ENTRIES; i++)
41662449Speter		free(sc->sc_rxbufs[i].rb_sd, M_DEVBUF);
41762449Speter
41862449Speter	txp_release_resources(sc);
41962449Speter
42062449Speter	mtx_destroy(&sc->sc_mtx);
42162449Speter	return(0);
42250276Speter}
42350276Speter
42450276Speterstatic void
42550276Spetertxp_release_resources(sc)
42650276Speter	struct txp_softc *sc;
42750276Speter{
42850276Speter	device_t dev;
42950276Speter
43050276Speter	dev = sc->sc_dev;
43150276Speter
43250276Speter	if (sc->sc_intrhand != NULL)
43350276Speter		bus_teardown_intr(dev, sc->sc_irq, sc->sc_intrhand);
43450276Speter
43550276Speter	if (sc->sc_irq != NULL)
436166124Srafan		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq);
437166124Srafan
438166124Srafan	if (sc->sc_res != NULL)
439166124Srafan		bus_release_resource(dev, TXP_RES, TXP_RID, sc->sc_res);
44050276Speter
441166124Srafan	if (sc->sc_ldata != NULL)
44297049Speter		contigfree(sc->sc_ldata, sizeof(struct txp_ldata), M_DEVBUF);
44397049Speter
444166124Srafan	return;
445166124Srafan}
446166124Srafan
447166124Srafanstatic int
448166124Srafantxp_chip_init(sc)
449166124Srafan	struct txp_softc *sc;
450166124Srafan{
45150276Speter	/* disable interrupts */
45250276Speter	WRITE_REG(sc, TXP_IER, 0);
453166124Srafan	WRITE_REG(sc, TXP_IMR,
45450276Speter	    TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
45550276Speter	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
456166124Srafan	    TXP_INT_LATCH);
45750276Speter
45850276Speter	/* ack all interrupts */
459166124Srafan	WRITE_REG(sc, TXP_ISR, TXP_INT_RESERVED | TXP_INT_LATCH |
46050276Speter	    TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 |
46150276Speter	    TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
462166124Srafan	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
46350276Speter	    TXP_INT_A2H_3 | TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0);
464184989Srafan
465184989Srafan	if (txp_reset_adapter(sc))
46662449Speter		return (-1);
46762449Speter
46862449Speter	/* disable interrupts */
46962449Speter	WRITE_REG(sc, TXP_IER, 0);
47062449Speter	WRITE_REG(sc, TXP_IMR,
47150276Speter	    TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
47262449Speter	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
47362449Speter	    TXP_INT_LATCH);
47462449Speter
47550276Speter	/* ack all interrupts */
47662449Speter	WRITE_REG(sc, TXP_ISR, TXP_INT_RESERVED | TXP_INT_LATCH |
47750276Speter	    TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 |
478166124Srafan	    TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
47950276Speter	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
48050276Speter	    TXP_INT_A2H_3 | TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0);
481166124Srafan
48250276Speter	return (0);
48350276Speter}
48450276Speter
485166124Srafanstatic int
48650276Spetertxp_reset_adapter(sc)
48750276Speter	struct txp_softc *sc;
488166124Srafan{
48950276Speter	u_int32_t r;
49050276Speter	int i;
491166124Srafan
49250276Speter	r = 0;
49350276Speter	WRITE_REG(sc, TXP_SRR, TXP_SRR_ALL);
494166124Srafan	DELAY(1000);
49576726Speter	WRITE_REG(sc, TXP_SRR, 0);
496166124Srafan
497166124Srafan	/* Should wait max 6 seconds */
49897049Speter	for (i = 0; i < 6000; i++) {
49950276Speter		r = READ_REG(sc, TXP_A2H_0);
500166124Srafan		if (r == STAT_WAITING_FOR_HOST_REQUEST)
50176726Speter			break;
50276726Speter		DELAY(1000);
50376726Speter	}
50476726Speter
50576726Speter	if (r != STAT_WAITING_FOR_HOST_REQUEST) {
50676726Speter		device_printf(sc->sc_dev, "reset hung\n");
50776726Speter		return (-1);
508166124Srafan	}
50950276Speter
51050276Speter	return (0);
51197049Speter}
51262449Speter
51350276Speterstatic int
51450276Spetertxp_download_fw(sc)
51550276Speter	struct txp_softc *sc;
51650276Speter{
51750276Speter	struct txp_fw_file_header *fileheader;
51850276Speter	struct txp_fw_section_header *secthead;
51950276Speter	int sect;
52050276Speter	u_int32_t r, i, ier, imr;
52150276Speter
52250276Speter	r = 0;
523166124Srafan	ier = READ_REG(sc, TXP_IER);
524166124Srafan	WRITE_REG(sc, TXP_IER, ier | TXP_INT_A2H_0);
525166124Srafan
526166124Srafan	imr = READ_REG(sc, TXP_IMR);
527166124Srafan	WRITE_REG(sc, TXP_IMR, imr | TXP_INT_A2H_0);
528166124Srafan
52950276Speter	for (i = 0; i < 10000; i++) {
53050276Speter		r = READ_REG(sc, TXP_A2H_0);
53150276Speter		if (r == STAT_WAITING_FOR_HOST_REQUEST)
53250276Speter			break;
53350276Speter		DELAY(50);
534166124Srafan	}
535178866Srafan	if (r != STAT_WAITING_FOR_HOST_REQUEST) {
53697049Speter		device_printf(sc->sc_dev, "not waiting for host request\n");
53776726Speter		return (-1);
53850276Speter	}
53950276Speter
54050276Speter	/* Ack the status */
54150276Speter	WRITE_REG(sc, TXP_ISR, TXP_INT_A2H_0);
54250276Speter
54350276Speter	fileheader = (struct txp_fw_file_header *)tc990image;
54450276Speter	if (bcmp("TYPHOON", fileheader->magicid, sizeof(fileheader->magicid))) {
54576726Speter		device_printf(sc->sc_dev, "fw invalid magic\n");
54650276Speter		return (-1);
54750276Speter	}
548166124Srafan
54950276Speter	/* Tell boot firmware to get ready for image */
55050276Speter	WRITE_REG(sc, TXP_H2A_1, fileheader->addr);
551166124Srafan	WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_RUNTIME_IMAGE);
55250276Speter
55350276Speter	if (txp_download_fw_wait(sc)) {
554166124Srafan		device_printf(sc->sc_dev, "fw wait failed, initial\n");
55562449Speter		return (-1);
55650276Speter	}
557166124Srafan
55850276Speter	secthead = (struct txp_fw_section_header *)(((u_int8_t *)tc990image) +
55950276Speter	    sizeof(struct txp_fw_file_header));
560166124Srafan
56150276Speter	for (sect = 0; sect < fileheader->nsections; sect++) {
56250276Speter		if (txp_download_fw_section(sc, secthead, sect))
563166124Srafan			return (-1);
56450276Speter		secthead = (struct txp_fw_section_header *)
56550276Speter		    (((u_int8_t *)secthead) + secthead->nbytes +
566166124Srafan		    sizeof(*secthead));
56750276Speter	}
56850276Speter
569166124Srafan	WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_DOWNLOAD_COMPLETE);
57050276Speter
57176726Speter	for (i = 0; i < 10000; i++) {
57250276Speter		r = READ_REG(sc, TXP_A2H_0);
57350276Speter		if (r == STAT_WAITING_FOR_BOOT)
57450276Speter			break;
57562449Speter		DELAY(50);
57697049Speter	}
57797049Speter	if (r != STAT_WAITING_FOR_BOOT) {
578184989Srafan		device_printf(sc->sc_dev, "not waiting for boot\n");
579184989Srafan		return (-1);
58076726Speter	}
58176726Speter
58276726Speter	WRITE_REG(sc, TXP_IER, ier);
58376726Speter	WRITE_REG(sc, TXP_IMR, imr);
58476726Speter
58576726Speter	return (0);
58697049Speter}
58776726Speter
58876726Speterstatic int
58997049Spetertxp_download_fw_wait(sc)
59097049Speter	struct txp_softc *sc;
59197049Speter{
59297049Speter	u_int32_t i, r;
59362449Speter
59462449Speter	r = 0;
59550276Speter	for (i = 0; i < 10000; i++) {
59650276Speter		r = READ_REG(sc, TXP_ISR);
59750276Speter		if (r & TXP_INT_A2H_0)
59850276Speter			break;
59950276Speter		DELAY(50);
60050276Speter	}
60150276Speter
60250276Speter	if (!(r & TXP_INT_A2H_0)) {
60350276Speter		device_printf(sc->sc_dev, "fw wait failed comm0\n");
60450276Speter		return (-1);
60550276Speter	}
60650276Speter
60750276Speter	WRITE_REG(sc, TXP_ISR, TXP_INT_A2H_0);
60850276Speter
60950276Speter	r = READ_REG(sc, TXP_A2H_0);
61050276Speter	if (r != STAT_WAITING_FOR_SEGMENT) {
61150276Speter		device_printf(sc->sc_dev, "fw not waiting for segment\n");
61250276Speter		return (-1);
61350276Speter	}
61450276Speter	return (0);
61550276Speter}
61650276Speter
61750276Speterstatic int
61850276Spetertxp_download_fw_section(sc, sect, sectnum)
61950276Speter	struct txp_softc *sc;
62050276Speter	struct txp_fw_section_header *sect;
62150276Speter	int sectnum;
62250276Speter{
62350276Speter	vm_offset_t dma;
62450276Speter	int rseg, err = 0;
625166124Srafan	struct mbuf m;
626166124Srafan	u_int16_t csum;
62797049Speter
62850276Speter	/* Skip zero length sections */
629166124Srafan	if (sect->nbytes == 0)
630166124Srafan		return (0);
631166124Srafan
632166124Srafan	/* Make sure we aren't past the end of the image */
633166124Srafan	rseg = ((u_int8_t *)sect) - ((u_int8_t *)tc990image);
634166124Srafan	if (rseg >= sizeof(tc990image)) {
635166124Srafan		device_printf(sc->sc_dev, "fw invalid section address, "
636166124Srafan		    "section %d\n", sectnum);
637166124Srafan		return (-1);
638166124Srafan	}
639166124Srafan
640166124Srafan	/* Make sure this section doesn't go past the end */
641166124Srafan	rseg += sect->nbytes;
642166124Srafan	if (rseg >= sizeof(tc990image)) {
643166124Srafan		device_printf(sc->sc_dev, "fw truncated section %d\n",
644166124Srafan		    sectnum);
645166124Srafan		return (-1);
646166124Srafan	}
647166124Srafan
648166124Srafan	bcopy(((u_int8_t *)sect) + sizeof(*sect), sc->sc_fwbuf, sect->nbytes);
649166124Srafan	dma = vtophys(sc->sc_fwbuf);
65050276Speter
651166124Srafan	/*
65276726Speter	 * dummy up mbuf and verify section checksum
65376726Speter	 */
65476726Speter	m.m_type = MT_DATA;
655166124Srafan	m.m_next = m.m_nextpkt = NULL;
65650276Speter	m.m_len = sect->nbytes;
65797049Speter	m.m_data = sc->sc_fwbuf;
65862449Speter	m.m_flags = 0;
65950276Speter	csum = in_cksum(&m, sect->nbytes);
66050276Speter	if (csum != sect->cksum) {
66150276Speter		device_printf(sc->sc_dev, "fw section %d, bad "
66250276Speter		    "cksum (expected 0x%x got 0x%x)\n",
66350276Speter		    sectnum, sect->cksum, csum);
66450276Speter		err = -1;
66550276Speter		goto bail;
66650276Speter	}
66750276Speter
66850276Speter	WRITE_REG(sc, TXP_H2A_1, sect->nbytes);
66950276Speter	WRITE_REG(sc, TXP_H2A_2, sect->cksum);
67050276Speter	WRITE_REG(sc, TXP_H2A_3, sect->addr);
67150276Speter	WRITE_REG(sc, TXP_H2A_4, 0);
67250276Speter	WRITE_REG(sc, TXP_H2A_5, dma & 0xffffffff);
67350276Speter	WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_SEGMENT_AVAILABLE);
67450276Speter
67550276Speter	if (txp_download_fw_wait(sc)) {
67650276Speter		device_printf(sc->sc_dev, "fw wait failed, "
67750276Speter		    "section %d\n", sectnum);
67850276Speter		err = -1;
67950276Speter	}
68050276Speter
68150276Speterbail:
68250276Speter	return (err);
683166124Srafan}
684166124Srafan
68550276Speterstatic void
686166124Srafantxp_intr(vsc)
68750276Speter	void *vsc;
68850276Speter{
689166124Srafan	struct txp_softc *sc = vsc;
69050276Speter	struct txp_hostvar *hv = sc->sc_hostvar;
69150276Speter	u_int32_t isr;
692166124Srafan
69397049Speter	/* mask all interrupts */
69462449Speter	WRITE_REG(sc, TXP_IMR, TXP_INT_RESERVED | TXP_INT_SELF |
695166124Srafan	    TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 |
69650276Speter	    TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0 |
69750276Speter	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
698166124Srafan	    TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |  TXP_INT_LATCH);
69950276Speter
70050276Speter	isr = READ_REG(sc, TXP_ISR);
701166124Srafan	while (isr) {
70297049Speter		WRITE_REG(sc, TXP_ISR, isr);
70350276Speter
70450276Speter		if ((*sc->sc_rxhir.r_roff) != (*sc->sc_rxhir.r_woff))
70550276Speter			txp_rx_reclaim(sc, &sc->sc_rxhir);
70650276Speter		if ((*sc->sc_rxlor.r_roff) != (*sc->sc_rxlor.r_woff))
70750276Speter			txp_rx_reclaim(sc, &sc->sc_rxlor);
708166124Srafan
70950276Speter		if (hv->hv_rx_buf_write_idx == hv->hv_rx_buf_read_idx)
71050276Speter			txp_rxbuf_reclaim(sc);
711166124Srafan
71250276Speter		if (sc->sc_txhir.r_cnt && (sc->sc_txhir.r_cons !=
71350276Speter		    TXP_OFFSET2IDX(*(sc->sc_txhir.r_off))))
714184989Srafan			txp_tx_reclaim(sc, &sc->sc_txhir);
71550276Speter
71650276Speter		if (sc->sc_txlor.r_cnt && (sc->sc_txlor.r_cons !=
71750276Speter		    TXP_OFFSET2IDX(*(sc->sc_txlor.r_off))))
71850276Speter			txp_tx_reclaim(sc, &sc->sc_txlor);
71950276Speter
720184989Srafan		isr = READ_REG(sc, TXP_ISR);
72150276Speter	}
72250276Speter
723184989Srafan	/* unmask all interrupts */
72450276Speter	WRITE_REG(sc, TXP_IMR, TXP_INT_A2H_3);
72550276Speter
726184989Srafan	txp_start(&sc->sc_arpcom.ac_if);
72750276Speter
72850276Speter	return;
729184989Srafan}
73050276Speter
73197049Speterstatic void
732166124Srafantxp_rx_reclaim(sc, r)
73350276Speter	struct txp_softc *sc;
73450276Speter	struct txp_rx_ring *r;
73550276Speter{
73697049Speter	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
73797049Speter	struct txp_rx_desc *rxd;
738166124Srafan	struct mbuf *m;
73950276Speter	struct txp_swdesc *sd = NULL;
74062449Speter	u_int32_t roff, woff;
741166124Srafan
74276726Speter	roff = *r->r_roff;
74376726Speter	woff = *r->r_woff;
744166124Srafan	rxd = r->r_desc + (roff / sizeof(struct txp_rx_desc));
74562449Speter
74662449Speter	while (roff != woff) {
747166124Srafan
748166124Srafan		if (rxd->rx_flags & RX_FLAGS_ERROR) {
749166124Srafan			device_printf(sc->sc_dev, "error 0x%x\n",
750166124Srafan			    rxd->rx_stat);
75176726Speter			ifp->if_ierrors++;
75276726Speter			goto next;
753184989Srafan		}
754184989Srafan
755184989Srafan		/* retrieve stashed pointer */
756184989Srafan		sd = rxd->rx_sd;
757166124Srafan
758184989Srafan		m = sd->sd_mbuf;
759184989Srafan		sd->sd_mbuf = NULL;
760184989Srafan
761166124Srafan		m->m_pkthdr.len = m->m_len = rxd->rx_len;
76297049Speter
76362449Speter#ifdef __STRICT_ALIGNMENT
764166124Srafan		{
76550276Speter			/*
76650276Speter			 * XXX Nice chip, except it won't accept "off by 2"
767166124Srafan			 * buffers, so we're force to copy.  Supposedly
76862449Speter			 * this will be fixed in a newer firmware rev
76962449Speter			 * and this will be temporary.
770166124Srafan			 */
77150276Speter			struct mbuf *mnew;
772166124Srafan
773166124Srafan			MGETHDR(mnew, M_DONTWAIT, MT_DATA);
774166124Srafan			if (mnew == NULL) {
775166124Srafan				m_freem(m);
776166124Srafan				goto next;
777166124Srafan			}
778166124Srafan			if (m->m_len > (MHLEN - 2)) {
779166124Srafan				MCLGET(mnew, M_DONTWAIT);
780166124Srafan				if (!(mnew->m_flags & M_EXT)) {
78150276Speter					m_freem(mnew);
78250276Speter					m_freem(m);
783166124Srafan					goto next;
784174993Srafan				}
78550276Speter			}
786166124Srafan			mnew->m_pkthdr.rcvif = ifp;
787166124Srafan			m_adj(mnew, 2);
788184989Srafan			mnew->m_pkthdr.len = mnew->m_len = m->m_len;
789184989Srafan			m_copydata(m, 0, m->m_pkthdr.len, mtod(mnew, caddr_t));
790166124Srafan			m_freem(m);
79176726Speter			m = mnew;
79276726Speter		}
793166124Srafan#endif
794174993Srafan
795184989Srafan		if (rxd->rx_stat & RX_STAT_IPCKSUMBAD)
796178866Srafan			m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
797174993Srafan		else if (rxd->rx_stat & RX_STAT_IPCKSUMGOOD)
798174993Srafan		 	m->m_pkthdr.csum_flags |=
799174993Srafan			    CSUM_IP_CHECKED|CSUM_IP_VALID;
800174993Srafan
801174993Srafan		if ((rxd->rx_stat & RX_STAT_TCPCKSUMGOOD) ||
802178866Srafan		    (rxd->rx_stat & RX_STAT_UDPCKSUMGOOD)) {
803184989Srafan			m->m_pkthdr.csum_flags |=
804184989Srafan			    CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
805174993Srafan			m->m_pkthdr.csum_data = 0xffff;
806166124Srafan		}
807166124Srafan
808166124Srafan		if (rxd->rx_stat & RX_STAT_VLAN) {
80962449Speter			VLAN_INPUT_TAG(ifp,
81062449Speter				m, htons(rxd->rx_vlan >> 16), goto next);
81162449Speter		}
81262449Speter
813166124Srafan		(*ifp->if_input)(ifp, m);
814166124Srafan
81562449Speternext:
81662449Speter
817166124Srafan		roff += sizeof(struct txp_rx_desc);
818166124Srafan		if (roff == (RX_ENTRIES * sizeof(struct txp_rx_desc))) {
819166124Srafan			roff = 0;
820166124Srafan			rxd = r->r_desc;
82150276Speter		} else
82250276Speter			rxd++;
823166124Srafan		woff = *r->r_woff;
82450276Speter	}
82550276Speter
826166124Srafan	*r->r_roff = woff;
82750276Speter
828166124Srafan	return;
82950276Speter}
830166124Srafan
831166124Srafanstatic void
832166124Srafantxp_rxbuf_reclaim(sc)
833166124Srafan	struct txp_softc *sc;
834166124Srafan{
83562449Speter	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
83662449Speter	struct txp_hostvar *hv = sc->sc_hostvar;
837166124Srafan	struct txp_rxbuf_desc *rbd;
83876726Speter	struct txp_swdesc *sd;
839178866Srafan	u_int32_t i;
840184989Srafan
841184989Srafan	if (!(ifp->if_flags & IFF_RUNNING))
842178866Srafan		return;
843178866Srafan
844178866Srafan	i = sc->sc_rxbufprod;
845178866Srafan	rbd = sc->sc_rxbufs + i;
846178866Srafan
847166124Srafan	while (1) {
848166124Srafan		sd = rbd->rb_sd;
849166124Srafan		if (sd->sd_mbuf != NULL)
850166124Srafan			break;
851166124Srafan
852166124Srafan		MGETHDR(sd->sd_mbuf, M_DONTWAIT, MT_DATA);
853166124Srafan		if (sd->sd_mbuf == NULL)
854166124Srafan			goto err_sd;
855166124Srafan
856166124Srafan		MCLGET(sd->sd_mbuf, M_DONTWAIT);
857166124Srafan		if ((sd->sd_mbuf->m_flags & M_EXT) == 0)
858184989Srafan			goto err_mbuf;
859166124Srafan		sd->sd_mbuf->m_pkthdr.rcvif = ifp;
86076726Speter		sd->sd_mbuf->m_pkthdr.len = sd->sd_mbuf->m_len = MCLBYTES;
86197049Speter
862166124Srafan		rbd->rb_paddrlo = vtophys(mtod(sd->sd_mbuf, vm_offset_t))
863166124Srafan		    & 0xffffffff;
864166124Srafan		rbd->rb_paddrhi = 0;
865166124Srafan
86676726Speter		hv->hv_rx_buf_write_idx = TXP_IDX2OFFSET(i);
86776726Speter
868166124Srafan		if (++i == RXBUF_ENTRIES) {
86976726Speter			i = 0;
87097049Speter			rbd = sc->sc_rxbufs;
87197049Speter		} else
87297049Speter			rbd++;
87397049Speter	}
87497049Speter
87597049Speter	sc->sc_rxbufprod = i;
87697049Speter
87797049Speter	return;
87897049Speter
87997049Spetererr_mbuf:
88097049Speter	m_freem(sd->sd_mbuf);
88197049Spetererr_sd:
88297049Speter	free(sd, M_DEVBUF);
88397049Speter}
88476726Speter
885166124Srafan/*
886184989Srafan * Reclaim mbufs and entries from a transmit ring.
887184989Srafan */
888184989Srafanstatic void
889184989Srafantxp_tx_reclaim(sc, r)
890166124Srafan	struct txp_softc *sc;
89176726Speter	struct txp_tx_ring *r;
892166124Srafan{
893166124Srafan	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
894166124Srafan	u_int32_t idx = TXP_OFFSET2IDX(*(r->r_off));
895166124Srafan	u_int32_t cons = r->r_cons, cnt = r->r_cnt;
896166124Srafan	struct txp_tx_desc *txd = r->r_desc + cons;
897166124Srafan	struct txp_swdesc *sd = sc->sc_txd + cons;
898166124Srafan	struct mbuf *m;
899166124Srafan
900166124Srafan	while (cons != idx) {
901166124Srafan		if (cnt == 0)
902166124Srafan			break;
903166124Srafan
904166124Srafan		if ((txd->tx_flags & TX_FLAGS_TYPE_M) ==
905166124Srafan		    TX_FLAGS_TYPE_DATA) {
906166124Srafan			m = sd->sd_mbuf;
907166124Srafan			if (m != NULL) {
908166124Srafan				m_freem(m);
909184989Srafan				txd->tx_addrlo = 0;
910184989Srafan				txd->tx_addrhi = 0;
911184989Srafan				ifp->if_opackets++;
912184989Srafan			}
913166124Srafan		}
914166124Srafan		ifp->if_flags &= ~IFF_OACTIVE;
915166124Srafan
916184989Srafan		if (++cons == TX_ENTRIES) {
917184989Srafan			txd = r->r_desc;
91876726Speter			cons = 0;
91997049Speter			sd = sc->sc_txd;
920166124Srafan		} else {
92197049Speter			txd++;
92297049Speter			sd++;
923166124Srafan		}
92476726Speter
92597049Speter		cnt--;
92697049Speter	}
92797049Speter
92897049Speter	r->r_cons = cons;
92997049Speter	r->r_cnt = cnt;
93097049Speter	if (cnt == 0)
93197049Speter		ifp->if_timer = 0;
93297049Speter}
933184989Srafan
93497049Speterstatic int
93597049Spetertxp_shutdown(dev)
93676726Speter	device_t dev;
937166124Srafan{
93876726Speter	struct txp_softc *sc;
93976726Speter
94076726Speter	sc = device_get_softc(dev);
94176726Speter
94276726Speter	/* mask all interrupts */
94376726Speter	WRITE_REG(sc, TXP_IMR,
94476726Speter	    TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |
945166124Srafan	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
94676726Speter	    TXP_INT_LATCH);
94776726Speter
948166124Srafan	txp_command(sc, TXP_CMD_TX_DISABLE, 0, 0, 0, NULL, NULL, NULL, 0);
94976726Speter	txp_command(sc, TXP_CMD_RX_DISABLE, 0, 0, 0, NULL, NULL, NULL, 0);
95076726Speter	txp_command(sc, TXP_CMD_HALT, 0, 0, 0, NULL, NULL, NULL, 0);
951166124Srafan
952166124Srafan	return(0);
953184989Srafan}
954166124Srafan
95576726Speterstatic int
95676726Spetertxp_alloc_rings(sc)
957166124Srafan	struct txp_softc *sc;
95876726Speter{
95976726Speter	struct txp_boot_record *boot;
960166124Srafan	struct txp_ldata *ld;
961166124Srafan	u_int32_t r;
962166124Srafan	int i;
963166124Srafan
96476726Speter	r = 0;
96576726Speter	ld = sc->sc_ldata;
966166124Srafan	boot = &ld->txp_boot;
967178866Srafan
968184989Srafan	/* boot record */
969174993Srafan	sc->sc_boot = boot;
97097049Speter
97176726Speter	/* host variables */
97276726Speter	bzero(&ld->txp_hostvar, sizeof(struct txp_hostvar));
97376726Speter	boot->br_hostvar_lo = vtophys(&ld->txp_hostvar);
97497049Speter	boot->br_hostvar_hi = 0;
97597049Speter	sc->sc_hostvar = (struct txp_hostvar *)&ld->txp_hostvar;
97697049Speter
97776726Speter	/* hi priority tx ring */
97897049Speter	boot->br_txhipri_lo = vtophys(&ld->txp_txhiring);;
97976726Speter	boot->br_txhipri_hi = 0;
98076726Speter	boot->br_txhipri_siz = TX_ENTRIES * sizeof(struct txp_tx_desc);
981184989Srafan	sc->sc_txhir.r_reg = TXP_H2A_1;
98297049Speter	sc->sc_txhir.r_desc = (struct txp_tx_desc *)&ld->txp_txhiring;
98376726Speter	sc->sc_txhir.r_cons = sc->sc_txhir.r_prod = sc->sc_txhir.r_cnt = 0;
98476726Speter	sc->sc_txhir.r_off = &sc->sc_hostvar->hv_tx_hi_desc_read_idx;
98597049Speter
98697049Speter	/* lo priority tx ring */
987166124Srafan	boot->br_txlopri_lo = vtophys(&ld->txp_txloring);
98897049Speter	boot->br_txlopri_hi = 0;
98997049Speter	boot->br_txlopri_siz = TX_ENTRIES * sizeof(struct txp_tx_desc);
99097049Speter	sc->sc_txlor.r_reg = TXP_H2A_3;
99197049Speter	sc->sc_txlor.r_desc = (struct txp_tx_desc *)&ld->txp_txloring;
992166124Srafan	sc->sc_txlor.r_cons = sc->sc_txlor.r_prod = sc->sc_txlor.r_cnt = 0;
99350276Speter	sc->sc_txlor.r_off = &sc->sc_hostvar->hv_tx_lo_desc_read_idx;
99476726Speter
99597049Speter	/* high priority rx ring */
99697049Speter	boot->br_rxhipri_lo = vtophys(&ld->txp_rxhiring);
99797049Speter	boot->br_rxhipri_hi = 0;
99897049Speter	boot->br_rxhipri_siz = RX_ENTRIES * sizeof(struct txp_rx_desc);
99997049Speter	sc->sc_rxhir.r_desc = (struct txp_rx_desc *)&ld->txp_rxhiring;
100097049Speter	sc->sc_rxhir.r_roff = &sc->sc_hostvar->hv_rx_hi_read_idx;
100197049Speter	sc->sc_rxhir.r_woff = &sc->sc_hostvar->hv_rx_hi_write_idx;
100297049Speter
100397049Speter	/* low priority rx ring */
100497049Speter	boot->br_rxlopri_lo = vtophys(&ld->txp_rxloring);
100597049Speter	boot->br_rxlopri_hi = 0;
100697049Speter	boot->br_rxlopri_siz = RX_ENTRIES * sizeof(struct txp_rx_desc);
100797049Speter	sc->sc_rxlor.r_desc = (struct txp_rx_desc *)&ld->txp_rxloring;
100897049Speter	sc->sc_rxlor.r_roff = &sc->sc_hostvar->hv_rx_lo_read_idx;
1009166124Srafan	sc->sc_rxlor.r_woff = &sc->sc_hostvar->hv_rx_lo_write_idx;
101097049Speter
101197049Speter	/* command ring */
101297049Speter	bzero(&ld->txp_cmdring, sizeof(struct txp_cmd_desc) * CMD_ENTRIES);
101397049Speter	boot->br_cmd_lo = vtophys(&ld->txp_cmdring);
101497049Speter	boot->br_cmd_hi = 0;
1015166124Srafan	boot->br_cmd_siz = CMD_ENTRIES * sizeof(struct txp_cmd_desc);
1016166124Srafan	sc->sc_cmdring.base = (struct txp_cmd_desc *)&ld->txp_cmdring;
1017166124Srafan	sc->sc_cmdring.size = CMD_ENTRIES * sizeof(struct txp_cmd_desc);
101850276Speter	sc->sc_cmdring.lastwrite = 0;
1019166124Srafan
1020184989Srafan	/* response ring */
1021184989Srafan	bzero(&ld->txp_rspring, sizeof(struct txp_rsp_desc) * RSP_ENTRIES);
1022184989Srafan	boot->br_resp_lo = vtophys(&ld->txp_rspring);
1023184989Srafan	boot->br_resp_hi = 0;
1024166124Srafan	boot->br_resp_siz = CMD_ENTRIES * sizeof(struct txp_rsp_desc);
1025166124Srafan	sc->sc_rspring.base = (struct txp_rsp_desc *)&ld->txp_rspring;
1026166124Srafan	sc->sc_rspring.size = RSP_ENTRIES * sizeof(struct txp_rsp_desc);
1027166124Srafan	sc->sc_rspring.lastwrite = 0;
1028166124Srafan
102976726Speter	/* receive buffer ring */
103097049Speter	boot->br_rxbuf_lo = vtophys(&ld->txp_rxbufs);
103197049Speter	boot->br_rxbuf_hi = 0;
103297049Speter	boot->br_rxbuf_siz = RXBUF_ENTRIES * sizeof(struct txp_rxbuf_desc);
103397049Speter	sc->sc_rxbufs = (struct txp_rxbuf_desc *)&ld->txp_rxbufs;
103450276Speter
1035166124Srafan	for (i = 0; i < RXBUF_ENTRIES; i++) {
103697049Speter		struct txp_swdesc *sd;
1037184989Srafan		if (sc->sc_rxbufs[i].rb_sd != NULL)
1038184989Srafan			continue;
1039184989Srafan		sc->sc_rxbufs[i].rb_sd = malloc(sizeof(struct txp_swdesc),
104050276Speter		    M_DEVBUF, M_NOWAIT);
1041184989Srafan		if (sc->sc_rxbufs[i].rb_sd == NULL)
104250276Speter			return(ENOBUFS);
1043166124Srafan		sd = sc->sc_rxbufs[i].rb_sd;
1044166124Srafan		sd->sd_mbuf = NULL;
1045166124Srafan	}
1046166124Srafan	sc->sc_rxbufprod = 0;
1047166124Srafan
1048166124Srafan	/* zero dma */
1049166124Srafan	bzero(&ld->txp_zero, sizeof(u_int32_t));
1050166124Srafan	boot->br_zero_lo = vtophys(&ld->txp_zero);
1051166124Srafan	boot->br_zero_hi = 0;
1052166124Srafan
1053166124Srafan	/* See if it's waiting for boot, and try to boot it */
1054166124Srafan	for (i = 0; i < 10000; i++) {
1055166124Srafan		r = READ_REG(sc, TXP_A2H_0);
1056166124Srafan		if (r == STAT_WAITING_FOR_BOOT)
1057166124Srafan			break;
1058166124Srafan		DELAY(50);
1059166124Srafan	}
1060166124Srafan
1061166124Srafan	if (r != STAT_WAITING_FOR_BOOT) {
1062166124Srafan		device_printf(sc->sc_dev, "not waiting for boot\n");
1063166124Srafan		return(ENXIO);
106497049Speter	}
106562449Speter
106662449Speter	WRITE_REG(sc, TXP_H2A_2, 0);
106762449Speter	WRITE_REG(sc, TXP_H2A_1, vtophys(sc->sc_boot));
106850276Speter	WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_REGISTER_BOOT_RECORD);
106962449Speter
107050276Speter	/* See if it booted */
1071166124Srafan	for (i = 0; i < 10000; i++) {
1072166124Srafan		r = READ_REG(sc, TXP_A2H_0);
1073184989Srafan		if (r == STAT_RUNNING)
107497049Speter			break;
107597049Speter		DELAY(50);
107697049Speter	}
107797049Speter	if (r != STAT_RUNNING) {
107897049Speter		device_printf(sc->sc_dev, "fw not running\n");
107997049Speter		return(ENXIO);
1080166124Srafan	}
108197049Speter
108250276Speter	/* Clear TX and CMD ring write registers */
108350276Speter	WRITE_REG(sc, TXP_H2A_1, TXP_BOOTCMD_NULL);
108450276Speter	WRITE_REG(sc, TXP_H2A_2, TXP_BOOTCMD_NULL);
108550276Speter	WRITE_REG(sc, TXP_H2A_3, TXP_BOOTCMD_NULL);
1086166124Srafan	WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_NULL);
1087166124Srafan
1088166124Srafan	return (0);
108950276Speter}
1090166124Srafan
109162449Speterstatic int
1092166124Srafantxp_ioctl(ifp, command, data)
109362449Speter	struct ifnet *ifp;
109450276Speter	u_long command;
109550276Speter	caddr_t data;
109650276Speter{
109750276Speter	struct txp_softc *sc = ifp->if_softc;
1098166124Srafan	struct ifreq *ifr = (struct ifreq *)data;
109950276Speter	int s, error = 0;
110062449Speter
1101184989Srafan	s = splnet();
1102184989Srafan
110350276Speter	switch(command) {
1104184989Srafan	case SIOCSIFFLAGS:
110550276Speter		if (ifp->if_flags & IFF_UP) {
110650276Speter			txp_init(sc);
1107166124Srafan		} else {
110850276Speter			if (ifp->if_flags & IFF_RUNNING)
110950276Speter				txp_stop(sc);
1110166124Srafan		}
111150276Speter		break;
111250276Speter	case SIOCADDMULTI:
111350276Speter	case SIOCDELMULTI:
111450276Speter		/*
111550276Speter		 * Multicast list has changed; set the hardware
111650276Speter		 * filter accordingly.
1117166124Srafan		 */
111850276Speter		txp_set_filter(sc);
111950276Speter		error = 0;
112050276Speter		break;
1121166124Srafan	case SIOCGIFMEDIA:
1122166124Srafan	case SIOCSIFMEDIA:
1123166124Srafan		error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, command);
1124166124Srafan		break;
1125166124Srafan	default:
1126166124Srafan		error = ether_ioctl(ifp, command, data);
1127166124Srafan		break;
1128166124Srafan	}
1129166124Srafan
1130166124Srafan	(void)splx(s);
113150276Speter
113250276Speter	return(error);
113350276Speter}
113450276Speter
1135166124Srafanstatic int
113650276Spetertxp_rxring_fill(sc)
1137166124Srafan	struct txp_softc *sc;
113850276Speter{
1139184989Srafan	int i;
1140184989Srafan	struct ifnet *ifp;
114197049Speter	struct txp_swdesc *sd;
114250276Speter
1143166124Srafan	ifp = &sc->sc_arpcom.ac_if;
114450276Speter
114550276Speter	for (i = 0; i < RXBUF_ENTRIES; i++) {
1146166124Srafan		sd = sc->sc_rxbufs[i].rb_sd;
114750276Speter		MGETHDR(sd->sd_mbuf, M_DONTWAIT, MT_DATA);
114850276Speter		if (sd->sd_mbuf == NULL)
1149166124Srafan			return(ENOBUFS);
115076726Speter
115150276Speter		MCLGET(sd->sd_mbuf, M_DONTWAIT);
1152166124Srafan		if ((sd->sd_mbuf->m_flags & M_EXT) == 0) {
115397049Speter			m_freem(sd->sd_mbuf);
115476726Speter			return(ENOBUFS);
1155166124Srafan		}
115650276Speter		sd->sd_mbuf->m_pkthdr.len = sd->sd_mbuf->m_len = MCLBYTES;
115750276Speter		sd->sd_mbuf->m_pkthdr.rcvif = ifp;
1158166124Srafan
115962449Speter		sc->sc_rxbufs[i].rb_paddrlo =
116062449Speter		    vtophys(mtod(sd->sd_mbuf, vm_offset_t));
1161166124Srafan		sc->sc_rxbufs[i].rb_paddrhi = 0;
116250276Speter	}
116350276Speter
1164166124Srafan	sc->sc_hostvar->hv_rx_buf_write_idx = (RXBUF_ENTRIES - 1) *
116550276Speter	    sizeof(struct txp_rxbuf_desc);
116650276Speter
116750276Speter	return(0);
116850276Speter}
116950276Speter
117050276Speterstatic void
117150276Spetertxp_rxring_empty(sc)
1172166124Srafan	struct txp_softc *sc;
117397049Speter{
1174184989Srafan	int i;
1175184989Srafan	struct txp_swdesc *sd;
1176184989Srafan
117750276Speter	if (sc->sc_rxbufs == NULL)
117850276Speter		return;
117950276Speter
118050276Speter	for (i = 0; i < RXBUF_ENTRIES; i++) {
1181166124Srafan		if (&sc->sc_rxbufs[i] == NULL)
118250276Speter			continue;
118350276Speter		sd = sc->sc_rxbufs[i].rb_sd;
118450276Speter		if (sd == NULL)
1185166124Srafan			continue;
1186166124Srafan		if (sd->sd_mbuf != NULL) {
1187166124Srafan			m_freem(sd->sd_mbuf);
1188166124Srafan			sd->sd_mbuf = NULL;
1189166124Srafan		}
119097049Speter	}
119197049Speter
119297049Speter	return;
1193166124Srafan}
119450276Speter
119550276Speterstatic void
1196166124Srafantxp_init(xsc)
119776726Speter	void *xsc;
119850276Speter{
1199166124Srafan	struct txp_softc *sc;
120062449Speter	struct ifnet *ifp;
120150276Speter	u_int16_t p1;
120250276Speter	u_int32_t p2;
120350276Speter	int s;
120450276Speter
120550276Speter	sc = xsc;
1206184989Srafan	ifp = &sc->sc_arpcom.ac_if;
120750276Speter
120850276Speter	if (ifp->if_flags & IFF_RUNNING)
1209166124Srafan		return;
121050276Speter
121150276Speter	txp_stop(sc);
1212166124Srafan
121350276Speter	s = splnet();
121450276Speter
1215166124Srafan	txp_command(sc, TXP_CMD_MAX_PKT_SIZE_WRITE, TXP_MAX_PKTLEN, 0, 0,
1216178866Srafan	    NULL, NULL, NULL, 1);
1217178866Srafan
1218178866Srafan	/* Set station address. */
121962449Speter	((u_int8_t *)&p1)[1] = sc->sc_arpcom.ac_enaddr[0];
122062449Speter	((u_int8_t *)&p1)[0] = sc->sc_arpcom.ac_enaddr[1];
1221166124Srafan	((u_int8_t *)&p2)[3] = sc->sc_arpcom.ac_enaddr[2];
122262449Speter	((u_int8_t *)&p2)[2] = sc->sc_arpcom.ac_enaddr[3];
122362449Speter	((u_int8_t *)&p2)[1] = sc->sc_arpcom.ac_enaddr[4];
1224166124Srafan	((u_int8_t *)&p2)[0] = sc->sc_arpcom.ac_enaddr[5];
1225166124Srafan	txp_command(sc, TXP_CMD_STATION_ADDRESS_WRITE, p1, p2, 0,
1226166124Srafan	    NULL, NULL, NULL, 1);
1227166124Srafan
1228174993Srafan	txp_set_filter(sc);
1229174993Srafan
1230174993Srafan	txp_rxring_fill(sc);
1231174993Srafan
1232174993Srafan	txp_command(sc, TXP_CMD_TX_ENABLE, 0, 0, 0, NULL, NULL, NULL, 1);
1233174993Srafan	txp_command(sc, TXP_CMD_RX_ENABLE, 0, 0, 0, NULL, NULL, NULL, 1);
1234174993Srafan
1235174993Srafan	WRITE_REG(sc, TXP_IER, TXP_INT_RESERVED | TXP_INT_SELF |
1236174993Srafan	    TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 |
123762449Speter	    TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0 |
123862449Speter	    TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 |
1239166124Srafan	    TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT |  TXP_INT_LATCH);
124062449Speter	WRITE_REG(sc, TXP_IMR, TXP_INT_A2H_3);
124162449Speter
1242166124Srafan	ifp->if_flags |= IFF_RUNNING;
124362449Speter	ifp->if_flags &= ~IFF_OACTIVE;
1244166124Srafan	ifp->if_timer = 0;
1245166124Srafan
1246166124Srafan	sc->sc_tick = timeout(txp_tick, sc, hz);
1247166124Srafan
1248166124Srafan	splx(s);
1249166124Srafan}
125062449Speter
125197049Speterstatic void
125297049Spetertxp_tick(vsc)
1253184989Srafan	void *vsc;
1254184989Srafan{
125562449Speter	struct txp_softc *sc = vsc;
125697049Speter	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
1257166124Srafan	struct txp_rsp_desc *rsp = NULL;
125862449Speter	struct txp_ext_desc *ext;
125962449Speter	int s;
1260166124Srafan
1261166124Srafan	s = splnet();
1262166124Srafan	txp_rxbuf_reclaim(sc);
1263166124Srafan
1264166124Srafan	if (txp_command2(sc, TXP_CMD_READ_STATISTICS, 0, 0, 0, NULL, 0,
126562449Speter	    &rsp, 1))
1266166124Srafan		goto out;
126776726Speter	if (rsp->rsp_numdesc != 6)
126876726Speter		goto out;
1269166124Srafan	if (txp_command(sc, TXP_CMD_CLEAR_STATISTICS, 0, 0, 0,
127062449Speter	    NULL, NULL, NULL, 1))
127162449Speter		goto out;
1272166124Srafan	ext = (struct txp_ext_desc *)(rsp + 1);
127362449Speter
127462449Speter	ifp->if_ierrors += ext[3].ext_2 + ext[3].ext_3 + ext[3].ext_4 +
1275166124Srafan	    ext[4].ext_1 + ext[4].ext_4;
127676726Speter	ifp->if_oerrors += ext[0].ext_1 + ext[1].ext_1 + ext[1].ext_4 +
127776726Speter	    ext[2].ext_1;
127876726Speter	ifp->if_collisions += ext[0].ext_2 + ext[0].ext_3 + ext[1].ext_2 +
127976726Speter	    ext[1].ext_3;
128076726Speter	ifp->if_opackets += rsp->rsp_par2;
128176726Speter	ifp->if_ipackets += ext[2].ext_3;
128276726Speter
128376726Speterout:
128476726Speter	if (rsp != NULL)
128576726Speter		free(rsp, M_DEVBUF);
1286166124Srafan
128776726Speter	splx(s);
128876726Speter	sc->sc_tick = timeout(txp_tick, sc, hz);
1289166124Srafan
129076726Speter	return;
129176726Speter}
1292166124Srafan
129376726Speterstatic void
129476726Spetertxp_start(ifp)
1295166124Srafan	struct ifnet *ifp;
129676726Speter{
129776726Speter	struct txp_softc *sc = ifp->if_softc;
1298166124Srafan	struct txp_tx_ring *r = &sc->sc_txhir;
129976726Speter	struct txp_tx_desc *txd;
130076726Speter	struct txp_frag_desc *fxd;
1301166124Srafan	struct mbuf *m, *m0;
130276726Speter	struct txp_swdesc *sd;
130376726Speter	u_int32_t firstprod, firstcnt, prod, cnt;
1304166124Srafan	struct m_tag *mtag;
1305166124Srafan
1306184989Srafan	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
1307166124Srafan		return;
1308166124Srafan
1309166124Srafan	prod = r->r_prod;
1310166124Srafan	cnt = r->r_cnt;
1311166124Srafan
1312184989Srafan	while (1) {
1313166124Srafan		IF_DEQUEUE(&ifp->if_snd, m);
1314166124Srafan		if (m == NULL)
1315166124Srafan			break;
1316166124Srafan
1317166124Srafan		firstprod = prod;
1318166124Srafan		firstcnt = cnt;
1319166124Srafan
1320166124Srafan		sd = sc->sc_txd + prod;
1321166124Srafan		sd->sd_mbuf = m;
1322166124Srafan
1323166124Srafan		if ((TX_ENTRIES - cnt) < 4)
1324166124Srafan			goto oactive;
1325166124Srafan
1326166124Srafan		txd = r->r_desc + prod;
132750276Speter
132850276Speter		txd->tx_flags = TX_FLAGS_TYPE_DATA;
132950276Speter		txd->tx_numdesc = 0;
133050276Speter		txd->tx_addrlo = 0;
133150276Speter		txd->tx_addrhi = 0;
133297049Speter		txd->tx_totlen = 0;
133362449Speter		txd->tx_pflags = 0;
133450276Speter
133550276Speter		if (++prod == TX_ENTRIES)
133650276Speter			prod = 0;
133750276Speter
133850276Speter		if (++cnt >= (TX_ENTRIES - 4))
133950276Speter			goto oactive;
134050276Speter
134150276Speter		mtag = VLAN_OUTPUT_TAG(ifp, m);
134250276Speter		if (mtag != NULL) {
134350276Speter			txd->tx_pflags = TX_PFLAGS_VLAN |
134450276Speter			    (htons(VLAN_TAG_VALUE(mtag)) << TX_PFLAGS_VLANTAG_S);
134550276Speter		}
134650276Speter
134750276Speter		if (m->m_pkthdr.csum_flags & CSUM_IP)
134850276Speter			txd->tx_pflags |= TX_PFLAGS_IPCKSUM;
134950276Speter
135050276Speter#if 0
135150276Speter		if (m->m_pkthdr.csum_flags & CSUM_TCP)
135250276Speter			txd->tx_pflags |= TX_PFLAGS_TCPCKSUM;
135350276Speter		if (m->m_pkthdr.csum_flags & CSUM_UDP)
135450276Speter			txd->tx_pflags |= TX_PFLAGS_UDPCKSUM;
135550276Speter#endif
135650276Speter
135750276Speter		fxd = (struct txp_frag_desc *)(r->r_desc + prod);
1358166124Srafan		for (m0 = m; m0 != NULL; m0 = m0->m_next) {
135950276Speter			if (m0->m_len == 0)
136050276Speter				continue;
136150276Speter			if (++cnt >= (TX_ENTRIES - 4))
136250276Speter				goto oactive;
136350276Speter
136450276Speter			txd->tx_numdesc++;
136550276Speter
136650276Speter			fxd->frag_flags = FRAG_FLAGS_TYPE_FRAG;
136750276Speter			fxd->frag_rsvd1 = 0;
136850276Speter			fxd->frag_len = m0->m_len;
136950276Speter			fxd->frag_addrlo = vtophys(mtod(m0, vm_offset_t));
137050276Speter			fxd->frag_addrhi = 0;
137162449Speter			fxd->frag_rsvd2 = 0;
137262449Speter
137362449Speter			if (++prod == TX_ENTRIES) {
137462449Speter				fxd = (struct txp_frag_desc *)r->r_desc;
137550276Speter				prod = 0;
137650276Speter			} else
137750276Speter				fxd++;
137850276Speter
137950276Speter		}
138050276Speter
138150276Speter		ifp->if_timer = 5;
138250276Speter
138350276Speter		BPF_MTAP(ifp, m);
138450276Speter		WRITE_REG(sc, r->r_reg, TXP_IDX2OFFSET(prod));
138550276Speter	}
138650276Speter
138750276Speter	r->r_prod = prod;
138850276Speter	r->r_cnt = cnt;
138950276Speter	return;
139050276Speter
139150276Speteroactive:
139250276Speter	ifp->if_flags |= IFF_OACTIVE;
139350276Speter	r->r_prod = firstprod;
139450276Speter	r->r_cnt = firstcnt;
139550276Speter	IF_PREPEND(&ifp->if_snd, m);
139650276Speter	return;
139750276Speter}
139850276Speter
139950276Speter/*
140050276Speter * Handle simple commands sent to the typhoon
140150276Speter */
140250276Speterstatic int
140350276Spetertxp_command(sc, id, in1, in2, in3, out1, out2, out3, wait)
140450276Speter	struct txp_softc *sc;
140550276Speter	u_int16_t id, in1, *out1;
140650276Speter	u_int32_t in2, in3, *out2, *out3;
140750276Speter	int wait;
140850276Speter{
140950276Speter	struct txp_rsp_desc *rsp = NULL;
141050276Speter
141150276Speter	if (txp_command2(sc, id, in1, in2, in3, NULL, 0, &rsp, wait))
141250276Speter		return (-1);
141350276Speter
141450276Speter	if (!wait)
141550276Speter		return (0);
141650276Speter
141750276Speter	if (out1 != NULL)
141850276Speter		*out1 = rsp->rsp_par1;
141976726Speter	if (out2 != NULL)
142076726Speter		*out2 = rsp->rsp_par2;
142176726Speter	if (out3 != NULL)
142276726Speter		*out3 = rsp->rsp_par3;
142376726Speter	free(rsp, M_DEVBUF);
142476726Speter	return (0);
142576726Speter}
142676726Speter
142776726Speterstatic int
142876726Spetertxp_command2(sc, id, in1, in2, in3, in_extp, in_extn, rspp, wait)
142976726Speter	struct txp_softc *sc;
143076726Speter	u_int16_t id, in1;
143176726Speter	u_int32_t in2, in3;
143276726Speter	struct txp_ext_desc *in_extp;
143376726Speter	u_int8_t in_extn;
143476726Speter	struct txp_rsp_desc **rspp;
143576726Speter	int wait;
143676726Speter{
143750276Speter	struct txp_hostvar *hv = sc->sc_hostvar;
143850276Speter	struct txp_cmd_desc *cmd;
143950276Speter	struct txp_ext_desc *ext;
144050276Speter	u_int32_t idx, i;
144150276Speter	u_int16_t seq;
144250276Speter
144350276Speter	if (txp_cmd_desc_numfree(sc) < (in_extn + 1)) {
144450276Speter		device_printf(sc->sc_dev, "no free cmd descriptors\n");
144550276Speter		return (-1);
144650276Speter	}
1447166124Srafan
1448166124Srafan	idx = sc->sc_cmdring.lastwrite;
144950276Speter	cmd = (struct txp_cmd_desc *)(((u_int8_t *)sc->sc_cmdring.base) + idx);
145050276Speter	bzero(cmd, sizeof(*cmd));
145150276Speter
1452166124Srafan	cmd->cmd_numdesc = in_extn;
145350276Speter	cmd->cmd_seq = seq = sc->sc_seq++;
145450276Speter	cmd->cmd_id = id;
145550276Speter	cmd->cmd_par1 = in1;
145650276Speter	cmd->cmd_par2 = in2;
145750276Speter	cmd->cmd_par3 = in3;
145850276Speter	cmd->cmd_flags = CMD_FLAGS_TYPE_CMD |
145950276Speter	    (wait ? CMD_FLAGS_RESP : 0) | CMD_FLAGS_VALID;
146050276Speter
1461166124Srafan	idx += sizeof(struct txp_cmd_desc);
146250276Speter	if (idx == sc->sc_cmdring.size)
146350276Speter		idx = 0;
146450276Speter
146550276Speter	for (i = 0; i < in_extn; i++) {
146650276Speter		ext = (struct txp_ext_desc *)(((u_int8_t *)sc->sc_cmdring.base) + idx);
1467166124Srafan		bcopy(in_extp, ext, sizeof(struct txp_ext_desc));
146850276Speter		in_extp++;
146950276Speter		idx += sizeof(struct txp_cmd_desc);
1470166124Srafan		if (idx == sc->sc_cmdring.size)
147150276Speter			idx = 0;
147250276Speter	}
1473166124Srafan
147450276Speter	sc->sc_cmdring.lastwrite = idx;
147550276Speter
1476166124Srafan	WRITE_REG(sc, TXP_H2A_2, sc->sc_cmdring.lastwrite);
147750276Speter
147850276Speter	if (!wait)
147950276Speter		return (0);
148062449Speter
148162449Speter	for (i = 0; i < 10000; i++) {
148250276Speter		idx = hv->hv_resp_read_idx;
148376726Speter		if (idx != hv->hv_resp_write_idx) {
148476726Speter			*rspp = NULL;
148576726Speter			if (txp_response(sc, idx, id, seq, rspp))
148662449Speter				return (-1);
1487184989Srafan			if (*rspp != NULL)
1488166124Srafan				break;
1489184989Srafan		}
149062449Speter		DELAY(50);
149162449Speter	}
149262449Speter	if (i == 1000 || (*rspp) == NULL) {
149362449Speter		device_printf(sc->sc_dev, "0x%x command failed\n", id);
149462449Speter		return (-1);
149562449Speter	}
149676726Speter
149762449Speter	return (0);
149862449Speter}
149962449Speter
150062449Speterstatic int
150162449Spetertxp_response(sc, ridx, id, seq, rspp)
150262449Speter	struct txp_softc *sc;
150362449Speter	u_int32_t ridx;
150462449Speter	u_int16_t id;
150562449Speter	u_int16_t seq;
150662449Speter	struct txp_rsp_desc **rspp;
150762449Speter{
150862449Speter	struct txp_hostvar *hv = sc->sc_hostvar;
150962449Speter	struct txp_rsp_desc *rsp;
151062449Speter
151162449Speter	while (ridx != hv->hv_resp_write_idx) {
151262449Speter		rsp = (struct txp_rsp_desc *)(((u_int8_t *)sc->sc_rspring.base) + ridx);
151362449Speter
151462449Speter		if (id == rsp->rsp_id && rsp->rsp_seq == seq) {
151562449Speter			*rspp = (struct txp_rsp_desc *)malloc(
151662449Speter			    sizeof(struct txp_rsp_desc) * (rsp->rsp_numdesc + 1),
151762449Speter			    M_DEVBUF, M_NOWAIT);
151862449Speter			if ((*rspp) == NULL)
151950276Speter				return (-1);
152062449Speter			txp_rsp_fixup(sc, rsp, *rspp);
152162449Speter			return (0);
152262449Speter		}
152376726Speter
152462449Speter		if (rsp->rsp_flags & RSP_FLAGS_ERROR) {
152562449Speter			device_printf(sc->sc_dev, "response error!\n");
152662449Speter			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