if_txp.c revision 189687
180219Swpaul/* $OpenBSD: if_txp.c,v 1.48 2001/06/27 06:34:50 kjc Exp $ */ 280219Swpaul 3139749Simp/*- 480219Swpaul * Copyright (c) 2001 580219Swpaul * Jason L. Wright <jason@thought.net>, Theo de Raadt, and 680219Swpaul * Aaron Campbell <aaron@monkey.org>. All rights reserved. 780219Swpaul * 880219Swpaul * Redistribution and use in source and binary forms, with or without 980219Swpaul * modification, are permitted provided that the following conditions 1080219Swpaul * are met: 1180219Swpaul * 1. Redistributions of source code must retain the above copyright 1280219Swpaul * notice, this list of conditions and the following disclaimer. 1380219Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1480219Swpaul * notice, this list of conditions and the following disclaimer in the 1580219Swpaul * documentation and/or other materials provided with the distribution. 1680219Swpaul * 3. All advertising materials mentioning features or use of this software 1780219Swpaul * must display the following acknowledgement: 1880219Swpaul * This product includes software developed by Jason L. Wright, 1980219Swpaul * Theo de Raadt and Aaron Campbell. 2080219Swpaul * 4. Neither the name of the author nor the names of any co-contributors 2180219Swpaul * may be used to endorse or promote products derived from this software 2280219Swpaul * without specific prior written permission. 2380219Swpaul * 2480219Swpaul * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 2580219Swpaul * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 2680219Swpaul * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2780219Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2880219Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2980219Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3080219Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3180219Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3280219Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3380219Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3480219Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 3580219Swpaul */ 3680219Swpaul 37119418Sobrien#include <sys/cdefs.h> 38119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/txp/if_txp.c 189687 2009-03-11 08:41:57Z yongari $"); 39119418Sobrien 4080219Swpaul/* 4180219Swpaul * Driver for 3c990 (Typhoon) Ethernet ASIC 4280219Swpaul */ 4380219Swpaul#include <sys/param.h> 4480219Swpaul#include <sys/systm.h> 4580219Swpaul#include <sys/sockio.h> 4680219Swpaul#include <sys/mbuf.h> 4780219Swpaul#include <sys/malloc.h> 4880219Swpaul#include <sys/kernel.h> 49129879Sphk#include <sys/module.h> 5080219Swpaul#include <sys/socket.h> 5180219Swpaul 5280219Swpaul#include <net/if.h> 5380219Swpaul#include <net/if_arp.h> 5480219Swpaul#include <net/ethernet.h> 5580219Swpaul#include <net/if_dl.h> 5680219Swpaul#include <net/if_types.h> 5783115Sbrooks#include <net/if_vlan_var.h> 5880219Swpaul 5980219Swpaul#include <netinet/in.h> 6080219Swpaul#include <netinet/in_systm.h> 6180219Swpaul#include <netinet/in_var.h> 6280219Swpaul#include <netinet/ip.h> 6380219Swpaul#include <netinet/if_ether.h> 6480219Swpaul#include <machine/in_cksum.h> 6580219Swpaul 6680219Swpaul#include <net/if_media.h> 6780219Swpaul 6880219Swpaul#include <net/bpf.h> 6980219Swpaul 7080219Swpaul#include <vm/vm.h> /* for vtophys */ 7180219Swpaul#include <vm/pmap.h> /* for vtophys */ 7280219Swpaul#include <machine/bus.h> 7380219Swpaul#include <machine/resource.h> 7480219Swpaul#include <sys/bus.h> 7580219Swpaul#include <sys/rman.h> 7680219Swpaul 7780219Swpaul#include <dev/mii/mii.h> 7880219Swpaul#include <dev/mii/miivar.h> 7980219Swpaul#include <dev/pci/pcireg.h> 8080219Swpaul#include <dev/pci/pcivar.h> 8180219Swpaul 8280219Swpaul#define TXP_USEIOSPACE 8380229Swpaul#define __STRICT_ALIGNMENT 8480219Swpaul 8580219Swpaul#include <dev/txp/if_txpreg.h> 8680219Swpaul#include <dev/txp/3c990img.h> 8780219Swpaul 8880219Swpaul#ifndef lint 8980219Swpaulstatic const char rcsid[] = 9080219Swpaul "$FreeBSD: head/sys/dev/txp/if_txp.c 189687 2009-03-11 08:41:57Z yongari $"; 9180219Swpaul#endif 9280219Swpaul 9380219Swpaul/* 9480219Swpaul * Various supported device vendors/types and their names. 9580219Swpaul */ 9680219Swpaulstatic struct txp_type txp_devs[] = { 9780219Swpaul { TXP_VENDORID_3COM, TXP_DEVICEID_3CR990_TX_95, 9880219Swpaul "3Com 3cR990-TX-95 Etherlink with 3XP Processor" }, 9980219Swpaul { TXP_VENDORID_3COM, TXP_DEVICEID_3CR990_TX_97, 10080219Swpaul "3Com 3cR990-TX-97 Etherlink with 3XP Processor" }, 10180219Swpaul { TXP_VENDORID_3COM, TXP_DEVICEID_3CR990B_TXM, 10280219Swpaul "3Com 3cR990B-TXM Etherlink with 3XP Processor" }, 10380219Swpaul { TXP_VENDORID_3COM, TXP_DEVICEID_3CR990_SRV_95, 10480219Swpaul "3Com 3cR990-SRV-95 Etherlink Server with 3XP Processor" }, 10580219Swpaul { TXP_VENDORID_3COM, TXP_DEVICEID_3CR990_SRV_97, 10680219Swpaul "3Com 3cR990-SRV-97 Etherlink Server with 3XP Processor" }, 10780219Swpaul { TXP_VENDORID_3COM, TXP_DEVICEID_3CR990B_SRV, 10880219Swpaul "3Com 3cR990B-SRV Etherlink Server with 3XP Processor" }, 10980219Swpaul { 0, 0, NULL } 11080219Swpaul}; 11180219Swpaul 112149678Sjhbstatic int txp_probe(device_t); 113149678Sjhbstatic int txp_attach(device_t); 114149678Sjhbstatic int txp_detach(device_t); 115149678Sjhbstatic void txp_intr(void *); 116149678Sjhbstatic void txp_tick(void *); 117149678Sjhbstatic int txp_shutdown(device_t); 118149678Sjhbstatic int txp_ioctl(struct ifnet *, u_long, caddr_t); 119149678Sjhbstatic void txp_start(struct ifnet *); 120151772Sjhbstatic void txp_start_locked(struct ifnet *); 121149678Sjhbstatic void txp_stop(struct txp_softc *); 122149678Sjhbstatic void txp_init(void *); 123151772Sjhbstatic void txp_init_locked(struct txp_softc *); 124149678Sjhbstatic void txp_watchdog(struct ifnet *); 12580219Swpaul 12692739Salfredstatic void txp_release_resources(struct txp_softc *); 12792739Salfredstatic int txp_chip_init(struct txp_softc *); 12892739Salfredstatic int txp_reset_adapter(struct txp_softc *); 12992739Salfredstatic int txp_download_fw(struct txp_softc *); 13092739Salfredstatic int txp_download_fw_wait(struct txp_softc *); 131149678Sjhbstatic int txp_download_fw_section(struct txp_softc *, 13292739Salfred struct txp_fw_section_header *, int); 13392739Salfredstatic int txp_alloc_rings(struct txp_softc *); 13492739Salfredstatic int txp_rxring_fill(struct txp_softc *); 13592739Salfredstatic void txp_rxring_empty(struct txp_softc *); 13692739Salfredstatic void txp_set_filter(struct txp_softc *); 13780219Swpaul 13892739Salfredstatic int txp_cmd_desc_numfree(struct txp_softc *); 139149678Sjhbstatic int txp_command(struct txp_softc *, u_int16_t, u_int16_t, u_int32_t, 14092739Salfred u_int32_t, u_int16_t *, u_int32_t *, u_int32_t *, int); 141149678Sjhbstatic int txp_command2(struct txp_softc *, u_int16_t, u_int16_t, 14280219Swpaul u_int32_t, u_int32_t, struct txp_ext_desc *, u_int8_t, 14392739Salfred struct txp_rsp_desc **, int); 144149678Sjhbstatic int txp_response(struct txp_softc *, u_int32_t, u_int16_t, u_int16_t, 14592739Salfred struct txp_rsp_desc **); 146149678Sjhbstatic void txp_rsp_fixup(struct txp_softc *, struct txp_rsp_desc *, 14792739Salfred struct txp_rsp_desc *); 14892739Salfredstatic void txp_capabilities(struct txp_softc *); 14980219Swpaul 15092739Salfredstatic void txp_ifmedia_sts(struct ifnet *, struct ifmediareq *); 15192739Salfredstatic int txp_ifmedia_upd(struct ifnet *); 15280219Swpaul#ifdef TXP_DEBUG 15392739Salfredstatic void txp_show_descriptor(void *); 15480219Swpaul#endif 15592739Salfredstatic void txp_tx_reclaim(struct txp_softc *, struct txp_tx_ring *); 15692739Salfredstatic void txp_rxbuf_reclaim(struct txp_softc *); 15792739Salfredstatic void txp_rx_reclaim(struct txp_softc *, struct txp_rx_ring *); 15880219Swpaul 15980219Swpaul#ifdef TXP_USEIOSPACE 16080219Swpaul#define TXP_RES SYS_RES_IOPORT 16180219Swpaul#define TXP_RID TXP_PCI_LOIO 16280219Swpaul#else 16380219Swpaul#define TXP_RES SYS_RES_MEMORY 16480219Swpaul#define TXP_RID TXP_PCI_LOMEM 16580219Swpaul#endif 16680219Swpaul 16780219Swpaulstatic device_method_t txp_methods[] = { 16880219Swpaul /* Device interface */ 16980219Swpaul DEVMETHOD(device_probe, txp_probe), 17080219Swpaul DEVMETHOD(device_attach, txp_attach), 17180219Swpaul DEVMETHOD(device_detach, txp_detach), 17280219Swpaul DEVMETHOD(device_shutdown, txp_shutdown), 17380219Swpaul { 0, 0 } 17480219Swpaul}; 17580219Swpaul 17680219Swpaulstatic driver_t txp_driver = { 17780219Swpaul "txp", 17880219Swpaul txp_methods, 17980219Swpaul sizeof(struct txp_softc) 18080219Swpaul}; 18180219Swpaul 18280219Swpaulstatic devclass_t txp_devclass; 18380219Swpaul 184113506SmdoddDRIVER_MODULE(txp, pci, txp_driver, txp_devclass, 0, 0); 185113506SmdoddMODULE_DEPEND(txp, pci, 1, 1, 1); 186113506SmdoddMODULE_DEPEND(txp, ether, 1, 1, 1); 18780219Swpaul 18880219Swpaulstatic int 189189685Syongaritxp_probe(device_t dev) 19080219Swpaul{ 19180219Swpaul struct txp_type *t; 19280219Swpaul 19380219Swpaul t = txp_devs; 19480219Swpaul 19580219Swpaul while(t->txp_name != NULL) { 19680219Swpaul if ((pci_get_vendor(dev) == t->txp_vid) && 19780219Swpaul (pci_get_device(dev) == t->txp_did)) { 19880219Swpaul device_set_desc(dev, t->txp_name); 199142880Simp return(BUS_PROBE_DEFAULT); 20080219Swpaul } 20180219Swpaul t++; 20280219Swpaul } 20380219Swpaul 20480219Swpaul return(ENXIO); 20580219Swpaul} 20680219Swpaul 20780219Swpaulstatic int 208189685Syongaritxp_attach(device_t dev) 20980219Swpaul{ 21080219Swpaul struct txp_softc *sc; 21180219Swpaul struct ifnet *ifp; 21280219Swpaul u_int16_t p1; 21380219Swpaul u_int32_t p2; 214151772Sjhb int error = 0, rid; 215147256Sbrooks u_char eaddr[6]; 21680219Swpaul 21780219Swpaul sc = device_get_softc(dev); 21880219Swpaul sc->sc_dev = dev; 21980219Swpaul sc->sc_cold = 1; 22080219Swpaul 22193818Sjhb mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 222151772Sjhb MTX_DEF); 223151772Sjhb callout_init_mtx(&sc->sc_tick, &sc->sc_mtx, 0); 224151772Sjhb 22580219Swpaul /* 22680219Swpaul * Map control/status registers. 22780219Swpaul */ 22880219Swpaul pci_enable_busmaster(dev); 22980219Swpaul 23080219Swpaul rid = TXP_RID; 231127135Snjl sc->sc_res = bus_alloc_resource_any(dev, TXP_RES, &rid, 232127135Snjl RF_ACTIVE); 23380219Swpaul 23480219Swpaul if (sc->sc_res == NULL) { 23580219Swpaul device_printf(dev, "couldn't map ports/memory\n"); 23680219Swpaul error = ENXIO; 23780219Swpaul goto fail; 23880219Swpaul } 23980219Swpaul 24080219Swpaul sc->sc_bt = rman_get_bustag(sc->sc_res); 24180219Swpaul sc->sc_bh = rman_get_bushandle(sc->sc_res); 24280219Swpaul 24380219Swpaul /* Allocate interrupt */ 24480219Swpaul rid = 0; 245127135Snjl sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 24680219Swpaul RF_SHAREABLE | RF_ACTIVE); 24780219Swpaul 24880219Swpaul if (sc->sc_irq == NULL) { 24980219Swpaul device_printf(dev, "couldn't map interrupt\n"); 25080219Swpaul error = ENXIO; 25180219Swpaul goto fail; 25280219Swpaul } 25380219Swpaul 25480219Swpaul if (txp_chip_init(sc)) { 255149678Sjhb error = ENXIO; 25680219Swpaul goto fail; 25780219Swpaul } 25880219Swpaul 25980219Swpaul sc->sc_fwbuf = contigmalloc(32768, M_DEVBUF, 26080219Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 261170596Syongari if (sc->sc_fwbuf == NULL) { 262170596Syongari device_printf(dev, "no memory for firmware\n"); 263170596Syongari error = ENXIO; 264170596Syongari goto fail; 265170596Syongari } 26680219Swpaul error = txp_download_fw(sc); 26780219Swpaul contigfree(sc->sc_fwbuf, 32768, M_DEVBUF); 26880219Swpaul sc->sc_fwbuf = NULL; 26980219Swpaul 270149678Sjhb if (error) 27180219Swpaul goto fail; 27280219Swpaul 27380219Swpaul sc->sc_ldata = contigmalloc(sizeof(struct txp_ldata), M_DEVBUF, 27480219Swpaul M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0); 275170596Syongari if (sc->sc_ldata == NULL) { 276170596Syongari device_printf(dev, "no memory for descriptor ring\n"); 277170596Syongari error = ENXIO; 278170596Syongari goto fail; 279170596Syongari } 28080457Swpaul bzero(sc->sc_ldata, sizeof(struct txp_ldata)); 28180219Swpaul 28280219Swpaul if (txp_alloc_rings(sc)) { 283149678Sjhb error = ENXIO; 28480219Swpaul goto fail; 28580219Swpaul } 28680219Swpaul 28780219Swpaul if (txp_command(sc, TXP_CMD_MAX_PKT_SIZE_WRITE, TXP_MAX_PKTLEN, 0, 0, 28880219Swpaul NULL, NULL, NULL, 1)) { 289149678Sjhb error = ENXIO; 29080219Swpaul goto fail; 29180219Swpaul } 29280219Swpaul 29380219Swpaul if (txp_command(sc, TXP_CMD_STATION_ADDRESS_READ, 0, 0, 0, 29480219Swpaul &p1, &p2, NULL, 1)) { 295149678Sjhb error = ENXIO; 29680219Swpaul goto fail; 29780219Swpaul } 29880219Swpaul 299147256Sbrooks eaddr[0] = ((u_int8_t *)&p1)[1]; 300147256Sbrooks eaddr[1] = ((u_int8_t *)&p1)[0]; 301147256Sbrooks eaddr[2] = ((u_int8_t *)&p2)[3]; 302147256Sbrooks eaddr[3] = ((u_int8_t *)&p2)[2]; 303147256Sbrooks eaddr[4] = ((u_int8_t *)&p2)[1]; 304147256Sbrooks eaddr[5] = ((u_int8_t *)&p2)[0]; 30580219Swpaul 30680219Swpaul sc->sc_cold = 0; 30780219Swpaul 30880219Swpaul ifmedia_init(&sc->sc_ifmedia, 0, txp_ifmedia_upd, txp_ifmedia_sts); 30980219Swpaul ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_10_T, 0, NULL); 31080219Swpaul ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); 31180219Swpaul ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); 31280219Swpaul ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_100_TX, 0, NULL); 31380219Swpaul ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_100_TX|IFM_HDX, 0, NULL); 31480219Swpaul ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); 31580219Swpaul ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); 31680219Swpaul 31780219Swpaul sc->sc_xcvr = TXP_XCVR_AUTO; 31880219Swpaul txp_command(sc, TXP_CMD_XCVR_SELECT, TXP_XCVR_AUTO, 0, 0, 31980219Swpaul NULL, NULL, NULL, 0); 32080219Swpaul ifmedia_set(&sc->sc_ifmedia, IFM_ETHER|IFM_AUTO); 32180219Swpaul 322147256Sbrooks ifp = sc->sc_ifp = if_alloc(IFT_ETHER); 323147256Sbrooks if (ifp == NULL) { 324150184Sru device_printf(dev, "can not if_alloc()\n"); 325147256Sbrooks error = ENOSPC; 326147256Sbrooks goto fail; 327147256Sbrooks } 32880219Swpaul ifp->if_softc = sc; 329121816Sbrooks if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 33080219Swpaul ifp->if_mtu = ETHERMTU; 331151772Sjhb ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 33280219Swpaul ifp->if_ioctl = txp_ioctl; 33380219Swpaul ifp->if_start = txp_start; 33480219Swpaul ifp->if_watchdog = txp_watchdog; 33580219Swpaul ifp->if_init = txp_init; 33680219Swpaul ifp->if_baudrate = 100000000; 33780219Swpaul ifp->if_snd.ifq_maxlen = TX_ENTRIES; 33880219Swpaul ifp->if_hwassist = 0; 33980219Swpaul txp_capabilities(sc); 34080219Swpaul 34180219Swpaul /* 34280219Swpaul * Attach us everywhere 34380219Swpaul */ 344147256Sbrooks ether_ifattach(ifp, eaddr); 345149678Sjhb 346151772Sjhb error = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_NET | INTR_MPSAFE, 347166901Spiso NULL, txp_intr, sc, &sc->sc_intrhand); 348149678Sjhb 349149678Sjhb if (error) { 350149678Sjhb ether_ifdetach(ifp); 351149678Sjhb device_printf(dev, "couldn't set up irq\n"); 352149678Sjhb goto fail; 353149678Sjhb } 354149678Sjhb 35580219Swpaul return(0); 35680219Swpaul 35780219Swpaulfail: 35880219Swpaul txp_release_resources(sc); 35980219Swpaul mtx_destroy(&sc->sc_mtx); 36080219Swpaul return(error); 36180219Swpaul} 36280219Swpaul 36380219Swpaulstatic int 364189685Syongaritxp_detach(device_t dev) 36580219Swpaul{ 36680219Swpaul struct txp_softc *sc; 36780219Swpaul struct ifnet *ifp; 36880219Swpaul int i; 36980219Swpaul 37080219Swpaul sc = device_get_softc(dev); 371147256Sbrooks ifp = sc->sc_ifp; 37280219Swpaul 373151772Sjhb TXP_LOCK(sc); 37480219Swpaul txp_stop(sc); 375151772Sjhb TXP_UNLOCK(sc); 37680219Swpaul txp_shutdown(dev); 377151772Sjhb callout_drain(&sc->sc_tick); 37880219Swpaul 37980219Swpaul ifmedia_removeall(&sc->sc_ifmedia); 380106937Ssam ether_ifdetach(ifp); 38180219Swpaul 38280219Swpaul for (i = 0; i < RXBUF_ENTRIES; i++) 38380219Swpaul free(sc->sc_rxbufs[i].rb_sd, M_DEVBUF); 38480219Swpaul 38580219Swpaul txp_release_resources(sc); 38680219Swpaul 38780219Swpaul mtx_destroy(&sc->sc_mtx); 38880219Swpaul return(0); 38980219Swpaul} 39080219Swpaul 39180219Swpaulstatic void 392189685Syongaritxp_release_resources(struct txp_softc *sc) 39380219Swpaul{ 39480219Swpaul device_t dev; 39580219Swpaul 39680219Swpaul dev = sc->sc_dev; 39780219Swpaul 39880219Swpaul if (sc->sc_intrhand != NULL) 39980219Swpaul bus_teardown_intr(dev, sc->sc_irq, sc->sc_intrhand); 40080219Swpaul 40180219Swpaul if (sc->sc_irq != NULL) 40280219Swpaul bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq); 40380219Swpaul 40480219Swpaul if (sc->sc_res != NULL) 40580219Swpaul bus_release_resource(dev, TXP_RES, TXP_RID, sc->sc_res); 40680219Swpaul 40780219Swpaul if (sc->sc_ldata != NULL) 40880219Swpaul contigfree(sc->sc_ldata, sizeof(struct txp_ldata), M_DEVBUF); 40980219Swpaul 410150306Simp if (sc->sc_ifp) 411150306Simp if_free(sc->sc_ifp); 41280219Swpaul} 41380219Swpaul 41480219Swpaulstatic int 415189685Syongaritxp_chip_init(struct txp_softc *sc) 41680219Swpaul{ 41780219Swpaul /* disable interrupts */ 41880219Swpaul WRITE_REG(sc, TXP_IER, 0); 41980219Swpaul WRITE_REG(sc, TXP_IMR, 42080219Swpaul TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT | 42180219Swpaul TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 | 42280219Swpaul TXP_INT_LATCH); 42380219Swpaul 42480219Swpaul /* ack all interrupts */ 42580219Swpaul WRITE_REG(sc, TXP_ISR, TXP_INT_RESERVED | TXP_INT_LATCH | 42680219Swpaul TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 | 42780219Swpaul TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT | 42880219Swpaul TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 | 42980219Swpaul TXP_INT_A2H_3 | TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0); 43080219Swpaul 43180219Swpaul if (txp_reset_adapter(sc)) 43280219Swpaul return (-1); 43380219Swpaul 43480219Swpaul /* disable interrupts */ 43580219Swpaul WRITE_REG(sc, TXP_IER, 0); 43680219Swpaul WRITE_REG(sc, TXP_IMR, 43780219Swpaul TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT | 43880219Swpaul TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 | 43980219Swpaul TXP_INT_LATCH); 44080219Swpaul 44180219Swpaul /* ack all interrupts */ 44280219Swpaul WRITE_REG(sc, TXP_ISR, TXP_INT_RESERVED | TXP_INT_LATCH | 44380219Swpaul TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 | 44480219Swpaul TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT | 44580219Swpaul TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 | 44680219Swpaul TXP_INT_A2H_3 | TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0); 44780219Swpaul 44880219Swpaul return (0); 44980219Swpaul} 45080219Swpaul 45180219Swpaulstatic int 452189685Syongaritxp_reset_adapter(struct txp_softc *sc) 45380219Swpaul{ 45480219Swpaul u_int32_t r; 45580219Swpaul int i; 45680219Swpaul 45792643Sjeff r = 0; 45880219Swpaul WRITE_REG(sc, TXP_SRR, TXP_SRR_ALL); 45980219Swpaul DELAY(1000); 46080219Swpaul WRITE_REG(sc, TXP_SRR, 0); 46180219Swpaul 46280219Swpaul /* Should wait max 6 seconds */ 46380219Swpaul for (i = 0; i < 6000; i++) { 46480219Swpaul r = READ_REG(sc, TXP_A2H_0); 46580219Swpaul if (r == STAT_WAITING_FOR_HOST_REQUEST) 46680219Swpaul break; 46780219Swpaul DELAY(1000); 46880219Swpaul } 46980219Swpaul 47080219Swpaul if (r != STAT_WAITING_FOR_HOST_REQUEST) { 47180219Swpaul device_printf(sc->sc_dev, "reset hung\n"); 47280219Swpaul return (-1); 47380219Swpaul } 47480219Swpaul 47580219Swpaul return (0); 47680219Swpaul} 47780219Swpaul 47880219Swpaulstatic int 479189685Syongaritxp_download_fw(struct txp_softc *sc) 48080219Swpaul{ 48180219Swpaul struct txp_fw_file_header *fileheader; 48280219Swpaul struct txp_fw_section_header *secthead; 483189022Syongari int error, sect; 48480219Swpaul u_int32_t r, i, ier, imr; 48580219Swpaul 48692643Sjeff r = 0; 487189022Syongari error = 0; 48880219Swpaul ier = READ_REG(sc, TXP_IER); 48980219Swpaul WRITE_REG(sc, TXP_IER, ier | TXP_INT_A2H_0); 49080219Swpaul 49180219Swpaul imr = READ_REG(sc, TXP_IMR); 49280219Swpaul WRITE_REG(sc, TXP_IMR, imr | TXP_INT_A2H_0); 49380219Swpaul 49480219Swpaul for (i = 0; i < 10000; i++) { 49580219Swpaul r = READ_REG(sc, TXP_A2H_0); 49680219Swpaul if (r == STAT_WAITING_FOR_HOST_REQUEST) 49780219Swpaul break; 49880219Swpaul DELAY(50); 49980219Swpaul } 50080219Swpaul if (r != STAT_WAITING_FOR_HOST_REQUEST) { 50180219Swpaul device_printf(sc->sc_dev, "not waiting for host request\n"); 502189022Syongari error = -1; 503189022Syongari goto fail; 50480219Swpaul } 50580219Swpaul 50680219Swpaul /* Ack the status */ 50780219Swpaul WRITE_REG(sc, TXP_ISR, TXP_INT_A2H_0); 50880219Swpaul 50980219Swpaul fileheader = (struct txp_fw_file_header *)tc990image; 51080219Swpaul if (bcmp("TYPHOON", fileheader->magicid, sizeof(fileheader->magicid))) { 51180219Swpaul device_printf(sc->sc_dev, "fw invalid magic\n"); 512189022Syongari error = -1; 513189022Syongari goto fail; 51480219Swpaul } 51580219Swpaul 51680219Swpaul /* Tell boot firmware to get ready for image */ 51780219Swpaul WRITE_REG(sc, TXP_H2A_1, fileheader->addr); 518189022Syongari WRITE_REG(sc, TXP_H2A_2, fileheader->hmac[0]); 519189022Syongari WRITE_REG(sc, TXP_H2A_3, fileheader->hmac[1]); 520189022Syongari WRITE_REG(sc, TXP_H2A_4, fileheader->hmac[2]); 521189022Syongari WRITE_REG(sc, TXP_H2A_5, fileheader->hmac[3]); 522189022Syongari WRITE_REG(sc, TXP_H2A_6, fileheader->hmac[4]); 52380219Swpaul WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_RUNTIME_IMAGE); 52480219Swpaul 52580219Swpaul if (txp_download_fw_wait(sc)) { 52680219Swpaul device_printf(sc->sc_dev, "fw wait failed, initial\n"); 527189022Syongari error = -1; 528189022Syongari goto fail; 52980219Swpaul } 53080219Swpaul 53180219Swpaul secthead = (struct txp_fw_section_header *)(((u_int8_t *)tc990image) + 53280219Swpaul sizeof(struct txp_fw_file_header)); 53380219Swpaul 53480219Swpaul for (sect = 0; sect < fileheader->nsections; sect++) { 535189686Syongari 536189022Syongari if (txp_download_fw_section(sc, secthead, sect)) { 537189022Syongari error = -1; 538189022Syongari goto fail; 539189022Syongari } 54080219Swpaul secthead = (struct txp_fw_section_header *) 54180219Swpaul (((u_int8_t *)secthead) + secthead->nbytes + 54280219Swpaul sizeof(*secthead)); 54380219Swpaul } 54480219Swpaul 54580219Swpaul WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_DOWNLOAD_COMPLETE); 54680219Swpaul 54780219Swpaul for (i = 0; i < 10000; i++) { 54880219Swpaul r = READ_REG(sc, TXP_A2H_0); 54980219Swpaul if (r == STAT_WAITING_FOR_BOOT) 55080219Swpaul break; 55180219Swpaul DELAY(50); 55280219Swpaul } 55380219Swpaul if (r != STAT_WAITING_FOR_BOOT) { 55480219Swpaul device_printf(sc->sc_dev, "not waiting for boot\n"); 555189022Syongari error = -1; 556189022Syongari goto fail; 55780219Swpaul } 55880219Swpaul 559189022Syongarifail: 56080219Swpaul WRITE_REG(sc, TXP_IER, ier); 56180219Swpaul WRITE_REG(sc, TXP_IMR, imr); 56280219Swpaul 563189022Syongari return (error); 56480219Swpaul} 56580219Swpaul 56680219Swpaulstatic int 567189685Syongaritxp_download_fw_wait(struct txp_softc *sc) 56880219Swpaul{ 56980219Swpaul u_int32_t i, r; 57080219Swpaul 57192643Sjeff r = 0; 57280219Swpaul for (i = 0; i < 10000; i++) { 57380219Swpaul r = READ_REG(sc, TXP_ISR); 57480219Swpaul if (r & TXP_INT_A2H_0) 57580219Swpaul break; 57680219Swpaul DELAY(50); 57780219Swpaul } 57880219Swpaul 57980219Swpaul if (!(r & TXP_INT_A2H_0)) { 58080219Swpaul device_printf(sc->sc_dev, "fw wait failed comm0\n"); 58180219Swpaul return (-1); 58280219Swpaul } 58380219Swpaul 58480219Swpaul WRITE_REG(sc, TXP_ISR, TXP_INT_A2H_0); 58580219Swpaul 58680219Swpaul r = READ_REG(sc, TXP_A2H_0); 58780219Swpaul if (r != STAT_WAITING_FOR_SEGMENT) { 58880219Swpaul device_printf(sc->sc_dev, "fw not waiting for segment\n"); 58980219Swpaul return (-1); 59080219Swpaul } 59180219Swpaul return (0); 59280219Swpaul} 59380219Swpaul 59480219Swpaulstatic int 595189685Syongaritxp_download_fw_section(struct txp_softc *sc, 596189685Syongari struct txp_fw_section_header *sect, int sectnum) 59780219Swpaul{ 59880219Swpaul vm_offset_t dma; 59980219Swpaul int rseg, err = 0; 60080219Swpaul struct mbuf m; 60180219Swpaul u_int16_t csum; 60280219Swpaul 60380219Swpaul /* Skip zero length sections */ 60480219Swpaul if (sect->nbytes == 0) 60580219Swpaul return (0); 60680219Swpaul 60780219Swpaul /* Make sure we aren't past the end of the image */ 60880219Swpaul rseg = ((u_int8_t *)sect) - ((u_int8_t *)tc990image); 60980219Swpaul if (rseg >= sizeof(tc990image)) { 61080219Swpaul device_printf(sc->sc_dev, "fw invalid section address, " 61180219Swpaul "section %d\n", sectnum); 61280219Swpaul return (-1); 61380219Swpaul } 61480219Swpaul 61580219Swpaul /* Make sure this section doesn't go past the end */ 61680219Swpaul rseg += sect->nbytes; 61780219Swpaul if (rseg >= sizeof(tc990image)) { 61880219Swpaul device_printf(sc->sc_dev, "fw truncated section %d\n", 61980219Swpaul sectnum); 62080219Swpaul return (-1); 62180219Swpaul } 62280219Swpaul 62380219Swpaul bcopy(((u_int8_t *)sect) + sizeof(*sect), sc->sc_fwbuf, sect->nbytes); 62480219Swpaul dma = vtophys(sc->sc_fwbuf); 62580219Swpaul 62680219Swpaul /* 62780219Swpaul * dummy up mbuf and verify section checksum 62880219Swpaul */ 62980219Swpaul m.m_type = MT_DATA; 63080219Swpaul m.m_next = m.m_nextpkt = NULL; 63180219Swpaul m.m_len = sect->nbytes; 63280219Swpaul m.m_data = sc->sc_fwbuf; 63380219Swpaul m.m_flags = 0; 63480219Swpaul csum = in_cksum(&m, sect->nbytes); 63580219Swpaul if (csum != sect->cksum) { 63680219Swpaul device_printf(sc->sc_dev, "fw section %d, bad " 63780219Swpaul "cksum (expected 0x%x got 0x%x)\n", 63880219Swpaul sectnum, sect->cksum, csum); 63980219Swpaul err = -1; 64080219Swpaul goto bail; 64180219Swpaul } 64280219Swpaul 64380219Swpaul WRITE_REG(sc, TXP_H2A_1, sect->nbytes); 64480219Swpaul WRITE_REG(sc, TXP_H2A_2, sect->cksum); 64580219Swpaul WRITE_REG(sc, TXP_H2A_3, sect->addr); 64680219Swpaul WRITE_REG(sc, TXP_H2A_4, 0); 64780219Swpaul WRITE_REG(sc, TXP_H2A_5, dma & 0xffffffff); 64880219Swpaul WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_SEGMENT_AVAILABLE); 64980219Swpaul 65080219Swpaul if (txp_download_fw_wait(sc)) { 65180219Swpaul device_printf(sc->sc_dev, "fw wait failed, " 65280219Swpaul "section %d\n", sectnum); 65380219Swpaul err = -1; 65480219Swpaul } 65580219Swpaul 65680219Swpaulbail: 65780219Swpaul return (err); 65880219Swpaul} 65980219Swpaul 660189686Syongaristatic void 661189685Syongaritxp_intr(void *vsc) 66280219Swpaul{ 66380219Swpaul struct txp_softc *sc = vsc; 66480219Swpaul struct txp_hostvar *hv = sc->sc_hostvar; 66580219Swpaul u_int32_t isr; 66680219Swpaul 66780219Swpaul /* mask all interrupts */ 668151772Sjhb TXP_LOCK(sc); 66980219Swpaul WRITE_REG(sc, TXP_IMR, TXP_INT_RESERVED | TXP_INT_SELF | 67080219Swpaul TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 | 67180219Swpaul TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0 | 67280219Swpaul TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 | 67380219Swpaul TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT | TXP_INT_LATCH); 67480219Swpaul 67580219Swpaul isr = READ_REG(sc, TXP_ISR); 67680219Swpaul while (isr) { 67780219Swpaul WRITE_REG(sc, TXP_ISR, isr); 67880219Swpaul 67980219Swpaul if ((*sc->sc_rxhir.r_roff) != (*sc->sc_rxhir.r_woff)) 68080219Swpaul txp_rx_reclaim(sc, &sc->sc_rxhir); 68180219Swpaul if ((*sc->sc_rxlor.r_roff) != (*sc->sc_rxlor.r_woff)) 68280219Swpaul txp_rx_reclaim(sc, &sc->sc_rxlor); 68380219Swpaul 68480219Swpaul if (hv->hv_rx_buf_write_idx == hv->hv_rx_buf_read_idx) 68580219Swpaul txp_rxbuf_reclaim(sc); 68680219Swpaul 68780219Swpaul if (sc->sc_txhir.r_cnt && (sc->sc_txhir.r_cons != 68880219Swpaul TXP_OFFSET2IDX(*(sc->sc_txhir.r_off)))) 68980219Swpaul txp_tx_reclaim(sc, &sc->sc_txhir); 69080219Swpaul 69180219Swpaul if (sc->sc_txlor.r_cnt && (sc->sc_txlor.r_cons != 69280219Swpaul TXP_OFFSET2IDX(*(sc->sc_txlor.r_off)))) 69380219Swpaul txp_tx_reclaim(sc, &sc->sc_txlor); 69480219Swpaul 69580219Swpaul isr = READ_REG(sc, TXP_ISR); 69680219Swpaul } 69780219Swpaul 69880219Swpaul /* unmask all interrupts */ 69980219Swpaul WRITE_REG(sc, TXP_IMR, TXP_INT_A2H_3); 70080219Swpaul 701151772Sjhb txp_start_locked(sc->sc_ifp); 702151772Sjhb TXP_UNLOCK(sc); 70380219Swpaul} 70480219Swpaul 70580219Swpaulstatic void 706189685Syongaritxp_rx_reclaim(struct txp_softc *sc, struct txp_rx_ring *r) 70780219Swpaul{ 708147256Sbrooks struct ifnet *ifp = sc->sc_ifp; 70980219Swpaul struct txp_rx_desc *rxd; 71080219Swpaul struct mbuf *m; 71180219Swpaul struct txp_swdesc *sd = NULL; 71280219Swpaul u_int32_t roff, woff; 71380219Swpaul 714151772Sjhb TXP_LOCK_ASSERT(sc); 71580219Swpaul roff = *r->r_roff; 71680219Swpaul woff = *r->r_woff; 71780219Swpaul rxd = r->r_desc + (roff / sizeof(struct txp_rx_desc)); 71880219Swpaul 71980219Swpaul while (roff != woff) { 72080219Swpaul 72180219Swpaul if (rxd->rx_flags & RX_FLAGS_ERROR) { 72280219Swpaul device_printf(sc->sc_dev, "error 0x%x\n", 72380219Swpaul rxd->rx_stat); 72480219Swpaul ifp->if_ierrors++; 72580219Swpaul goto next; 72680219Swpaul } 72780219Swpaul 72880219Swpaul /* retrieve stashed pointer */ 72980219Swpaul sd = rxd->rx_sd; 73080219Swpaul 73180219Swpaul m = sd->sd_mbuf; 73280219Swpaul sd->sd_mbuf = NULL; 73380219Swpaul 73480219Swpaul m->m_pkthdr.len = m->m_len = rxd->rx_len; 73580219Swpaul 73680219Swpaul#ifdef __STRICT_ALIGNMENT 73780219Swpaul { 73880219Swpaul /* 73980219Swpaul * XXX Nice chip, except it won't accept "off by 2" 74080219Swpaul * buffers, so we're force to copy. Supposedly 74180219Swpaul * this will be fixed in a newer firmware rev 74280219Swpaul * and this will be temporary. 74380219Swpaul */ 74480219Swpaul struct mbuf *mnew; 74580219Swpaul 746151772Sjhb mnew = m_devget(mtod(m, caddr_t), rxd->rx_len, 747151772Sjhb ETHER_ALIGN, ifp, NULL); 748151772Sjhb m_freem(m); 74980219Swpaul if (mnew == NULL) { 750151772Sjhb ifp->if_ierrors++; 75180219Swpaul goto next; 75280219Swpaul } 75380219Swpaul m = mnew; 75480219Swpaul } 75580219Swpaul#endif 75680219Swpaul 75780219Swpaul if (rxd->rx_stat & RX_STAT_IPCKSUMBAD) 75880219Swpaul m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; 75980219Swpaul else if (rxd->rx_stat & RX_STAT_IPCKSUMGOOD) 76080219Swpaul m->m_pkthdr.csum_flags |= 76180219Swpaul CSUM_IP_CHECKED|CSUM_IP_VALID; 76280219Swpaul 76380219Swpaul if ((rxd->rx_stat & RX_STAT_TCPCKSUMGOOD) || 76480219Swpaul (rxd->rx_stat & RX_STAT_UDPCKSUMGOOD)) { 76580219Swpaul m->m_pkthdr.csum_flags |= 76680219Swpaul CSUM_DATA_VALID|CSUM_PSEUDO_HDR; 76780219Swpaul m->m_pkthdr.csum_data = 0xffff; 76880219Swpaul } 76980219Swpaul 77080219Swpaul if (rxd->rx_stat & RX_STAT_VLAN) { 771162375Sandre m->m_pkthdr.ether_vtag = htons(rxd->rx_vlan >> 16); 772162375Sandre m->m_flags |= M_VLANTAG; 77380219Swpaul } 77483115Sbrooks 775151772Sjhb TXP_UNLOCK(sc); 776106937Ssam (*ifp->if_input)(ifp, m); 777151772Sjhb TXP_LOCK(sc); 77880219Swpaul 77980219Swpaulnext: 78080219Swpaul 78180219Swpaul roff += sizeof(struct txp_rx_desc); 78280219Swpaul if (roff == (RX_ENTRIES * sizeof(struct txp_rx_desc))) { 78380219Swpaul roff = 0; 78480219Swpaul rxd = r->r_desc; 78580219Swpaul } else 78680219Swpaul rxd++; 78780219Swpaul woff = *r->r_woff; 78880219Swpaul } 78980219Swpaul 79080219Swpaul *r->r_roff = woff; 79180219Swpaul} 79280219Swpaul 79380219Swpaulstatic void 794189685Syongaritxp_rxbuf_reclaim(struct txp_softc *sc) 79580219Swpaul{ 796147256Sbrooks struct ifnet *ifp = sc->sc_ifp; 79780219Swpaul struct txp_hostvar *hv = sc->sc_hostvar; 79880219Swpaul struct txp_rxbuf_desc *rbd; 79980219Swpaul struct txp_swdesc *sd; 80080219Swpaul u_int32_t i; 80180219Swpaul 802151772Sjhb TXP_LOCK_ASSERT(sc); 803148887Srwatson if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 80480219Swpaul return; 80580219Swpaul 80680219Swpaul i = sc->sc_rxbufprod; 80780219Swpaul rbd = sc->sc_rxbufs + i; 80880219Swpaul 80980219Swpaul while (1) { 81080219Swpaul sd = rbd->rb_sd; 81180219Swpaul if (sd->sd_mbuf != NULL) 81280219Swpaul break; 81380219Swpaul 814151772Sjhb sd->sd_mbuf = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 81580219Swpaul if (sd->sd_mbuf == NULL) 816151772Sjhb return; 81780219Swpaul sd->sd_mbuf->m_pkthdr.rcvif = ifp; 81880219Swpaul sd->sd_mbuf->m_pkthdr.len = sd->sd_mbuf->m_len = MCLBYTES; 81980219Swpaul 82080219Swpaul rbd->rb_paddrlo = vtophys(mtod(sd->sd_mbuf, vm_offset_t)) 82180219Swpaul & 0xffffffff; 82280219Swpaul rbd->rb_paddrhi = 0; 82380219Swpaul 82480219Swpaul hv->hv_rx_buf_write_idx = TXP_IDX2OFFSET(i); 82580219Swpaul 82680219Swpaul if (++i == RXBUF_ENTRIES) { 82780219Swpaul i = 0; 82880219Swpaul rbd = sc->sc_rxbufs; 82980219Swpaul } else 83080219Swpaul rbd++; 83180219Swpaul } 83280219Swpaul 83380219Swpaul sc->sc_rxbufprod = i; 83480219Swpaul} 83580219Swpaul 83680219Swpaul/* 83780219Swpaul * Reclaim mbufs and entries from a transmit ring. 83880219Swpaul */ 83980219Swpaulstatic void 840189685Syongaritxp_tx_reclaim(struct txp_softc *sc, struct txp_tx_ring *r) 84180219Swpaul{ 842147256Sbrooks struct ifnet *ifp = sc->sc_ifp; 84380219Swpaul u_int32_t idx = TXP_OFFSET2IDX(*(r->r_off)); 84480219Swpaul u_int32_t cons = r->r_cons, cnt = r->r_cnt; 84580219Swpaul struct txp_tx_desc *txd = r->r_desc + cons; 84680219Swpaul struct txp_swdesc *sd = sc->sc_txd + cons; 84780219Swpaul struct mbuf *m; 84880219Swpaul 849151772Sjhb TXP_LOCK_ASSERT(sc); 85080219Swpaul while (cons != idx) { 85180219Swpaul if (cnt == 0) 85280219Swpaul break; 85380219Swpaul 85480219Swpaul if ((txd->tx_flags & TX_FLAGS_TYPE_M) == 85580219Swpaul TX_FLAGS_TYPE_DATA) { 85680219Swpaul m = sd->sd_mbuf; 85780219Swpaul if (m != NULL) { 85880219Swpaul m_freem(m); 85980219Swpaul txd->tx_addrlo = 0; 86080219Swpaul txd->tx_addrhi = 0; 86180219Swpaul ifp->if_opackets++; 86280219Swpaul } 86380219Swpaul } 864148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 86580219Swpaul 86680219Swpaul if (++cons == TX_ENTRIES) { 86780219Swpaul txd = r->r_desc; 86880219Swpaul cons = 0; 86980219Swpaul sd = sc->sc_txd; 87080219Swpaul } else { 87180219Swpaul txd++; 87280219Swpaul sd++; 87380219Swpaul } 87480219Swpaul 87580219Swpaul cnt--; 87680219Swpaul } 87780219Swpaul 87880219Swpaul r->r_cons = cons; 87980219Swpaul r->r_cnt = cnt; 88080219Swpaul if (cnt == 0) 88180219Swpaul ifp->if_timer = 0; 88280219Swpaul} 88380219Swpaul 88480219Swpaulstatic int 885189685Syongaritxp_shutdown(device_t dev) 88680219Swpaul{ 88780219Swpaul struct txp_softc *sc; 88880219Swpaul 88980219Swpaul sc = device_get_softc(dev); 89080219Swpaul 891151772Sjhb TXP_LOCK(sc); 892151772Sjhb 89380219Swpaul /* mask all interrupts */ 89480219Swpaul WRITE_REG(sc, TXP_IMR, 89580219Swpaul TXP_INT_SELF | TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT | 89680219Swpaul TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 | 89780219Swpaul TXP_INT_LATCH); 89880219Swpaul 89980219Swpaul txp_command(sc, TXP_CMD_TX_DISABLE, 0, 0, 0, NULL, NULL, NULL, 0); 90080219Swpaul txp_command(sc, TXP_CMD_RX_DISABLE, 0, 0, 0, NULL, NULL, NULL, 0); 90180219Swpaul txp_command(sc, TXP_CMD_HALT, 0, 0, 0, NULL, NULL, NULL, 0); 902151772Sjhb TXP_UNLOCK(sc); 90380219Swpaul 90480219Swpaul return(0); 90580219Swpaul} 90680219Swpaul 90780219Swpaulstatic int 908189685Syongaritxp_alloc_rings(struct txp_softc *sc) 90980219Swpaul{ 91080219Swpaul struct txp_boot_record *boot; 91180219Swpaul struct txp_ldata *ld; 91280219Swpaul u_int32_t r; 91380219Swpaul int i; 91480219Swpaul 91592643Sjeff r = 0; 91680219Swpaul ld = sc->sc_ldata; 91780219Swpaul boot = &ld->txp_boot; 91880219Swpaul 91980219Swpaul /* boot record */ 92080219Swpaul sc->sc_boot = boot; 92180219Swpaul 92280219Swpaul /* host variables */ 92380219Swpaul bzero(&ld->txp_hostvar, sizeof(struct txp_hostvar)); 92480219Swpaul boot->br_hostvar_lo = vtophys(&ld->txp_hostvar); 92580219Swpaul boot->br_hostvar_hi = 0; 92680219Swpaul sc->sc_hostvar = (struct txp_hostvar *)&ld->txp_hostvar; 92780219Swpaul 92880219Swpaul /* hi priority tx ring */ 92980219Swpaul boot->br_txhipri_lo = vtophys(&ld->txp_txhiring);; 93080219Swpaul boot->br_txhipri_hi = 0; 93180219Swpaul boot->br_txhipri_siz = TX_ENTRIES * sizeof(struct txp_tx_desc); 93280219Swpaul sc->sc_txhir.r_reg = TXP_H2A_1; 93380219Swpaul sc->sc_txhir.r_desc = (struct txp_tx_desc *)&ld->txp_txhiring; 93480219Swpaul sc->sc_txhir.r_cons = sc->sc_txhir.r_prod = sc->sc_txhir.r_cnt = 0; 93580219Swpaul sc->sc_txhir.r_off = &sc->sc_hostvar->hv_tx_hi_desc_read_idx; 93680219Swpaul 93780219Swpaul /* lo priority tx ring */ 93880219Swpaul boot->br_txlopri_lo = vtophys(&ld->txp_txloring); 93980219Swpaul boot->br_txlopri_hi = 0; 94080219Swpaul boot->br_txlopri_siz = TX_ENTRIES * sizeof(struct txp_tx_desc); 94180219Swpaul sc->sc_txlor.r_reg = TXP_H2A_3; 94280219Swpaul sc->sc_txlor.r_desc = (struct txp_tx_desc *)&ld->txp_txloring; 94380219Swpaul sc->sc_txlor.r_cons = sc->sc_txlor.r_prod = sc->sc_txlor.r_cnt = 0; 94480219Swpaul sc->sc_txlor.r_off = &sc->sc_hostvar->hv_tx_lo_desc_read_idx; 94580219Swpaul 94680219Swpaul /* high priority rx ring */ 94780219Swpaul boot->br_rxhipri_lo = vtophys(&ld->txp_rxhiring); 94880219Swpaul boot->br_rxhipri_hi = 0; 94980219Swpaul boot->br_rxhipri_siz = RX_ENTRIES * sizeof(struct txp_rx_desc); 95080219Swpaul sc->sc_rxhir.r_desc = (struct txp_rx_desc *)&ld->txp_rxhiring; 95180219Swpaul sc->sc_rxhir.r_roff = &sc->sc_hostvar->hv_rx_hi_read_idx; 95280219Swpaul sc->sc_rxhir.r_woff = &sc->sc_hostvar->hv_rx_hi_write_idx; 95380219Swpaul 95480219Swpaul /* low priority rx ring */ 95580219Swpaul boot->br_rxlopri_lo = vtophys(&ld->txp_rxloring); 95680219Swpaul boot->br_rxlopri_hi = 0; 95780219Swpaul boot->br_rxlopri_siz = RX_ENTRIES * sizeof(struct txp_rx_desc); 95880219Swpaul sc->sc_rxlor.r_desc = (struct txp_rx_desc *)&ld->txp_rxloring; 95980219Swpaul sc->sc_rxlor.r_roff = &sc->sc_hostvar->hv_rx_lo_read_idx; 96080219Swpaul sc->sc_rxlor.r_woff = &sc->sc_hostvar->hv_rx_lo_write_idx; 96180219Swpaul 96280219Swpaul /* command ring */ 96380219Swpaul bzero(&ld->txp_cmdring, sizeof(struct txp_cmd_desc) * CMD_ENTRIES); 96480219Swpaul boot->br_cmd_lo = vtophys(&ld->txp_cmdring); 96580219Swpaul boot->br_cmd_hi = 0; 96680219Swpaul boot->br_cmd_siz = CMD_ENTRIES * sizeof(struct txp_cmd_desc); 96780219Swpaul sc->sc_cmdring.base = (struct txp_cmd_desc *)&ld->txp_cmdring; 96880219Swpaul sc->sc_cmdring.size = CMD_ENTRIES * sizeof(struct txp_cmd_desc); 96980219Swpaul sc->sc_cmdring.lastwrite = 0; 97080219Swpaul 97180219Swpaul /* response ring */ 97280219Swpaul bzero(&ld->txp_rspring, sizeof(struct txp_rsp_desc) * RSP_ENTRIES); 97380219Swpaul boot->br_resp_lo = vtophys(&ld->txp_rspring); 97480219Swpaul boot->br_resp_hi = 0; 97580219Swpaul boot->br_resp_siz = CMD_ENTRIES * sizeof(struct txp_rsp_desc); 97680219Swpaul sc->sc_rspring.base = (struct txp_rsp_desc *)&ld->txp_rspring; 97780219Swpaul sc->sc_rspring.size = RSP_ENTRIES * sizeof(struct txp_rsp_desc); 97880219Swpaul sc->sc_rspring.lastwrite = 0; 97980219Swpaul 98080219Swpaul /* receive buffer ring */ 98180219Swpaul boot->br_rxbuf_lo = vtophys(&ld->txp_rxbufs); 98280219Swpaul boot->br_rxbuf_hi = 0; 98380219Swpaul boot->br_rxbuf_siz = RXBUF_ENTRIES * sizeof(struct txp_rxbuf_desc); 98480219Swpaul sc->sc_rxbufs = (struct txp_rxbuf_desc *)&ld->txp_rxbufs; 98580219Swpaul 98680219Swpaul for (i = 0; i < RXBUF_ENTRIES; i++) { 98780457Swpaul struct txp_swdesc *sd; 98880219Swpaul if (sc->sc_rxbufs[i].rb_sd != NULL) 98980219Swpaul continue; 99080219Swpaul sc->sc_rxbufs[i].rb_sd = malloc(sizeof(struct txp_swdesc), 99180219Swpaul M_DEVBUF, M_NOWAIT); 99280219Swpaul if (sc->sc_rxbufs[i].rb_sd == NULL) 99380219Swpaul return(ENOBUFS); 99480457Swpaul sd = sc->sc_rxbufs[i].rb_sd; 99580457Swpaul sd->sd_mbuf = NULL; 99680219Swpaul } 99780219Swpaul sc->sc_rxbufprod = 0; 99880219Swpaul 99980219Swpaul /* zero dma */ 100080219Swpaul bzero(&ld->txp_zero, sizeof(u_int32_t)); 100180219Swpaul boot->br_zero_lo = vtophys(&ld->txp_zero); 100280219Swpaul boot->br_zero_hi = 0; 100380219Swpaul 100480219Swpaul /* See if it's waiting for boot, and try to boot it */ 100580219Swpaul for (i = 0; i < 10000; i++) { 100680219Swpaul r = READ_REG(sc, TXP_A2H_0); 100780219Swpaul if (r == STAT_WAITING_FOR_BOOT) 100880219Swpaul break; 100980219Swpaul DELAY(50); 101080219Swpaul } 101180219Swpaul 101280219Swpaul if (r != STAT_WAITING_FOR_BOOT) { 101380219Swpaul device_printf(sc->sc_dev, "not waiting for boot\n"); 101480455Swpaul return(ENXIO); 101580219Swpaul } 101680219Swpaul 101780219Swpaul WRITE_REG(sc, TXP_H2A_2, 0); 101880219Swpaul WRITE_REG(sc, TXP_H2A_1, vtophys(sc->sc_boot)); 101980219Swpaul WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_REGISTER_BOOT_RECORD); 102080219Swpaul 102180219Swpaul /* See if it booted */ 102280219Swpaul for (i = 0; i < 10000; i++) { 102380219Swpaul r = READ_REG(sc, TXP_A2H_0); 102480219Swpaul if (r == STAT_RUNNING) 102580219Swpaul break; 102680219Swpaul DELAY(50); 102780219Swpaul } 102880219Swpaul if (r != STAT_RUNNING) { 102980219Swpaul device_printf(sc->sc_dev, "fw not running\n"); 103080219Swpaul return(ENXIO); 103180219Swpaul } 103280219Swpaul 103380219Swpaul /* Clear TX and CMD ring write registers */ 103480219Swpaul WRITE_REG(sc, TXP_H2A_1, TXP_BOOTCMD_NULL); 103580219Swpaul WRITE_REG(sc, TXP_H2A_2, TXP_BOOTCMD_NULL); 103680219Swpaul WRITE_REG(sc, TXP_H2A_3, TXP_BOOTCMD_NULL); 103780219Swpaul WRITE_REG(sc, TXP_H2A_0, TXP_BOOTCMD_NULL); 103880219Swpaul 103980219Swpaul return (0); 104080219Swpaul} 104180219Swpaul 104280219Swpaulstatic int 1043189685Syongaritxp_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 104480219Swpaul{ 104580219Swpaul struct txp_softc *sc = ifp->if_softc; 104680219Swpaul struct ifreq *ifr = (struct ifreq *)data; 1047151772Sjhb int error = 0; 104880219Swpaul 104980219Swpaul switch(command) { 105080219Swpaul case SIOCSIFFLAGS: 1051151772Sjhb TXP_LOCK(sc); 105280219Swpaul if (ifp->if_flags & IFF_UP) { 1053151772Sjhb txp_init_locked(sc); 105480219Swpaul } else { 1055148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 105680219Swpaul txp_stop(sc); 105780219Swpaul } 1058151772Sjhb TXP_UNLOCK(sc); 105980219Swpaul break; 106080219Swpaul case SIOCADDMULTI: 106180219Swpaul case SIOCDELMULTI: 106280219Swpaul /* 106380219Swpaul * Multicast list has changed; set the hardware 106480219Swpaul * filter accordingly. 106580219Swpaul */ 1066151772Sjhb TXP_LOCK(sc); 106780219Swpaul txp_set_filter(sc); 1068151772Sjhb TXP_UNLOCK(sc); 106980219Swpaul error = 0; 107080219Swpaul break; 107180219Swpaul case SIOCGIFMEDIA: 107280219Swpaul case SIOCSIFMEDIA: 107380219Swpaul error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, command); 107480219Swpaul break; 107580219Swpaul default: 1076106937Ssam error = ether_ioctl(ifp, command, data); 107780219Swpaul break; 107880219Swpaul } 107980219Swpaul 108080219Swpaul return(error); 108180219Swpaul} 108280219Swpaul 108380219Swpaulstatic int 1084189685Syongaritxp_rxring_fill(struct txp_softc *sc) 108580219Swpaul{ 108680219Swpaul int i; 108780219Swpaul struct ifnet *ifp; 108880219Swpaul struct txp_swdesc *sd; 108980219Swpaul 1090151772Sjhb TXP_LOCK_ASSERT(sc); 1091147256Sbrooks ifp = sc->sc_ifp; 109280219Swpaul 109380219Swpaul for (i = 0; i < RXBUF_ENTRIES; i++) { 109480219Swpaul sd = sc->sc_rxbufs[i].rb_sd; 1095151772Sjhb sd->sd_mbuf = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 109680219Swpaul if (sd->sd_mbuf == NULL) 109780219Swpaul return(ENOBUFS); 109880219Swpaul 109980219Swpaul sd->sd_mbuf->m_pkthdr.len = sd->sd_mbuf->m_len = MCLBYTES; 110080219Swpaul sd->sd_mbuf->m_pkthdr.rcvif = ifp; 110180219Swpaul 110280219Swpaul sc->sc_rxbufs[i].rb_paddrlo = 110380219Swpaul vtophys(mtod(sd->sd_mbuf, vm_offset_t)); 110480219Swpaul sc->sc_rxbufs[i].rb_paddrhi = 0; 110580219Swpaul } 110680219Swpaul 110780219Swpaul sc->sc_hostvar->hv_rx_buf_write_idx = (RXBUF_ENTRIES - 1) * 110880219Swpaul sizeof(struct txp_rxbuf_desc); 110980219Swpaul 111080219Swpaul return(0); 111180219Swpaul} 111280219Swpaul 111380219Swpaulstatic void 1114189685Syongaritxp_rxring_empty(struct txp_softc *sc) 111580219Swpaul{ 111680219Swpaul int i; 111780219Swpaul struct txp_swdesc *sd; 111880219Swpaul 1119151772Sjhb TXP_LOCK_ASSERT(sc); 112080219Swpaul if (sc->sc_rxbufs == NULL) 112180219Swpaul return; 112280219Swpaul 112380219Swpaul for (i = 0; i < RXBUF_ENTRIES; i++) { 112480219Swpaul if (&sc->sc_rxbufs[i] == NULL) 112580219Swpaul continue; 112680219Swpaul sd = sc->sc_rxbufs[i].rb_sd; 112780219Swpaul if (sd == NULL) 112880219Swpaul continue; 112980219Swpaul if (sd->sd_mbuf != NULL) { 113080219Swpaul m_freem(sd->sd_mbuf); 113180219Swpaul sd->sd_mbuf = NULL; 113280219Swpaul } 113380219Swpaul } 113480219Swpaul} 113580219Swpaul 113680219Swpaulstatic void 1137189685Syongaritxp_init(void *xsc) 113880219Swpaul{ 113980219Swpaul struct txp_softc *sc; 1140151772Sjhb 1141151772Sjhb sc = xsc; 1142151772Sjhb TXP_LOCK(sc); 1143151772Sjhb txp_init_locked(sc); 1144151772Sjhb TXP_UNLOCK(sc); 1145151772Sjhb} 1146151772Sjhb 1147151772Sjhbstatic void 1148189685Syongaritxp_init_locked(struct txp_softc *sc) 1149151772Sjhb{ 115080219Swpaul struct ifnet *ifp; 115180219Swpaul u_int16_t p1; 115280219Swpaul u_int32_t p2; 115380219Swpaul 1154151772Sjhb TXP_LOCK_ASSERT(sc); 1155147256Sbrooks ifp = sc->sc_ifp; 115680219Swpaul 1157148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 115880219Swpaul return; 115980219Swpaul 116080219Swpaul txp_stop(sc); 116180219Swpaul 116280219Swpaul txp_command(sc, TXP_CMD_MAX_PKT_SIZE_WRITE, TXP_MAX_PKTLEN, 0, 0, 116380219Swpaul NULL, NULL, NULL, 1); 116480219Swpaul 116580219Swpaul /* Set station address. */ 1166152315Sru ((u_int8_t *)&p1)[1] = IF_LLADDR(sc->sc_ifp)[0]; 1167152315Sru ((u_int8_t *)&p1)[0] = IF_LLADDR(sc->sc_ifp)[1]; 1168152315Sru ((u_int8_t *)&p2)[3] = IF_LLADDR(sc->sc_ifp)[2]; 1169152315Sru ((u_int8_t *)&p2)[2] = IF_LLADDR(sc->sc_ifp)[3]; 1170152315Sru ((u_int8_t *)&p2)[1] = IF_LLADDR(sc->sc_ifp)[4]; 1171152315Sru ((u_int8_t *)&p2)[0] = IF_LLADDR(sc->sc_ifp)[5]; 117280219Swpaul txp_command(sc, TXP_CMD_STATION_ADDRESS_WRITE, p1, p2, 0, 117380219Swpaul NULL, NULL, NULL, 1); 117480219Swpaul 117580219Swpaul txp_set_filter(sc); 117680219Swpaul 117780219Swpaul txp_rxring_fill(sc); 117880219Swpaul 117980219Swpaul txp_command(sc, TXP_CMD_TX_ENABLE, 0, 0, 0, NULL, NULL, NULL, 1); 118080219Swpaul txp_command(sc, TXP_CMD_RX_ENABLE, 0, 0, 0, NULL, NULL, NULL, 1); 118180219Swpaul 118280219Swpaul WRITE_REG(sc, TXP_IER, TXP_INT_RESERVED | TXP_INT_SELF | 118380219Swpaul TXP_INT_A2H_7 | TXP_INT_A2H_6 | TXP_INT_A2H_5 | TXP_INT_A2H_4 | 118480219Swpaul TXP_INT_A2H_2 | TXP_INT_A2H_1 | TXP_INT_A2H_0 | 118580219Swpaul TXP_INT_DMA3 | TXP_INT_DMA2 | TXP_INT_DMA1 | TXP_INT_DMA0 | 118680219Swpaul TXP_INT_PCI_TABORT | TXP_INT_PCI_MABORT | TXP_INT_LATCH); 118780219Swpaul WRITE_REG(sc, TXP_IMR, TXP_INT_A2H_3); 118880219Swpaul 1189148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 1190148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 119180219Swpaul ifp->if_timer = 0; 119280219Swpaul 1193151772Sjhb callout_reset(&sc->sc_tick, hz, txp_tick, sc); 119480219Swpaul} 119580219Swpaul 119680219Swpaulstatic void 1197189685Syongaritxp_tick(void *vsc) 119880219Swpaul{ 119980219Swpaul struct txp_softc *sc = vsc; 1200147256Sbrooks struct ifnet *ifp = sc->sc_ifp; 120180219Swpaul struct txp_rsp_desc *rsp = NULL; 120280219Swpaul struct txp_ext_desc *ext; 120380219Swpaul 1204151772Sjhb TXP_LOCK_ASSERT(sc); 120580219Swpaul txp_rxbuf_reclaim(sc); 120680219Swpaul 120780219Swpaul if (txp_command2(sc, TXP_CMD_READ_STATISTICS, 0, 0, 0, NULL, 0, 120880219Swpaul &rsp, 1)) 120980219Swpaul goto out; 121080219Swpaul if (rsp->rsp_numdesc != 6) 121180219Swpaul goto out; 121280219Swpaul if (txp_command(sc, TXP_CMD_CLEAR_STATISTICS, 0, 0, 0, 121380219Swpaul NULL, NULL, NULL, 1)) 121480219Swpaul goto out; 121580219Swpaul ext = (struct txp_ext_desc *)(rsp + 1); 121680219Swpaul 121780219Swpaul ifp->if_ierrors += ext[3].ext_2 + ext[3].ext_3 + ext[3].ext_4 + 121880219Swpaul ext[4].ext_1 + ext[4].ext_4; 121980219Swpaul ifp->if_oerrors += ext[0].ext_1 + ext[1].ext_1 + ext[1].ext_4 + 122080219Swpaul ext[2].ext_1; 122180219Swpaul ifp->if_collisions += ext[0].ext_2 + ext[0].ext_3 + ext[1].ext_2 + 122280219Swpaul ext[1].ext_3; 122380219Swpaul ifp->if_opackets += rsp->rsp_par2; 122480219Swpaul ifp->if_ipackets += ext[2].ext_3; 122580219Swpaul 122680219Swpaulout: 122780219Swpaul if (rsp != NULL) 122880219Swpaul free(rsp, M_DEVBUF); 122980219Swpaul 1230151772Sjhb callout_reset(&sc->sc_tick, hz, txp_tick, sc); 123180219Swpaul} 123280219Swpaul 123380219Swpaulstatic void 1234189685Syongaritxp_start(struct ifnet *ifp) 123580219Swpaul{ 1236151772Sjhb struct txp_softc *sc; 1237151772Sjhb 1238151772Sjhb sc = ifp->if_softc; 1239151772Sjhb TXP_LOCK(sc); 1240151772Sjhb txp_start_locked(ifp); 1241151772Sjhb TXP_UNLOCK(sc); 1242151772Sjhb} 1243151772Sjhb 1244151772Sjhbstatic void 1245189685Syongaritxp_start_locked(struct ifnet *ifp) 1246151772Sjhb{ 124780219Swpaul struct txp_softc *sc = ifp->if_softc; 124880219Swpaul struct txp_tx_ring *r = &sc->sc_txhir; 124980219Swpaul struct txp_tx_desc *txd; 125080219Swpaul struct txp_frag_desc *fxd; 125180219Swpaul struct mbuf *m, *m0; 125280219Swpaul struct txp_swdesc *sd; 125380219Swpaul u_int32_t firstprod, firstcnt, prod, cnt; 125480219Swpaul 1255151772Sjhb TXP_LOCK_ASSERT(sc); 1256148887Srwatson if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1257148887Srwatson IFF_DRV_RUNNING) 125880219Swpaul return; 125980219Swpaul 126080219Swpaul prod = r->r_prod; 126180219Swpaul cnt = r->r_cnt; 126280219Swpaul 126380219Swpaul while (1) { 126480219Swpaul IF_DEQUEUE(&ifp->if_snd, m); 126580219Swpaul if (m == NULL) 126680219Swpaul break; 126780219Swpaul 126880219Swpaul firstprod = prod; 126980219Swpaul firstcnt = cnt; 127080219Swpaul 127180219Swpaul sd = sc->sc_txd + prod; 127280219Swpaul sd->sd_mbuf = m; 127380219Swpaul 127480219Swpaul if ((TX_ENTRIES - cnt) < 4) 127580219Swpaul goto oactive; 127680219Swpaul 127780219Swpaul txd = r->r_desc + prod; 127880219Swpaul 127980219Swpaul txd->tx_flags = TX_FLAGS_TYPE_DATA; 128080219Swpaul txd->tx_numdesc = 0; 128180219Swpaul txd->tx_addrlo = 0; 128280219Swpaul txd->tx_addrhi = 0; 128380219Swpaul txd->tx_totlen = 0; 128480219Swpaul txd->tx_pflags = 0; 128580219Swpaul 128680219Swpaul if (++prod == TX_ENTRIES) 128780219Swpaul prod = 0; 128880219Swpaul 128980219Swpaul if (++cnt >= (TX_ENTRIES - 4)) 129080219Swpaul goto oactive; 129180219Swpaul 1292162375Sandre if (m->m_flags & M_VLANTAG) { 129380219Swpaul txd->tx_pflags = TX_PFLAGS_VLAN | 1294162375Sandre (htons(m->m_pkthdr.ether_vtag) << TX_PFLAGS_VLANTAG_S); 129580219Swpaul } 129683115Sbrooks 129780219Swpaul if (m->m_pkthdr.csum_flags & CSUM_IP) 129880219Swpaul txd->tx_pflags |= TX_PFLAGS_IPCKSUM; 129980219Swpaul 130080219Swpaul#if 0 130180219Swpaul if (m->m_pkthdr.csum_flags & CSUM_TCP) 130280219Swpaul txd->tx_pflags |= TX_PFLAGS_TCPCKSUM; 130380219Swpaul if (m->m_pkthdr.csum_flags & CSUM_UDP) 130480219Swpaul txd->tx_pflags |= TX_PFLAGS_UDPCKSUM; 130580219Swpaul#endif 130680219Swpaul 130780219Swpaul fxd = (struct txp_frag_desc *)(r->r_desc + prod); 130880219Swpaul for (m0 = m; m0 != NULL; m0 = m0->m_next) { 130980219Swpaul if (m0->m_len == 0) 131080219Swpaul continue; 131180219Swpaul if (++cnt >= (TX_ENTRIES - 4)) 131280219Swpaul goto oactive; 131380219Swpaul 131480219Swpaul txd->tx_numdesc++; 131580219Swpaul 131680219Swpaul fxd->frag_flags = FRAG_FLAGS_TYPE_FRAG; 131780219Swpaul fxd->frag_rsvd1 = 0; 131880219Swpaul fxd->frag_len = m0->m_len; 131980219Swpaul fxd->frag_addrlo = vtophys(mtod(m0, vm_offset_t)); 132080219Swpaul fxd->frag_addrhi = 0; 132180219Swpaul fxd->frag_rsvd2 = 0; 132280219Swpaul 132380219Swpaul if (++prod == TX_ENTRIES) { 132480219Swpaul fxd = (struct txp_frag_desc *)r->r_desc; 132580219Swpaul prod = 0; 132680219Swpaul } else 132780219Swpaul fxd++; 132880219Swpaul 132980219Swpaul } 133080219Swpaul 133180219Swpaul ifp->if_timer = 5; 133280219Swpaul 1333167190Scsjp ETHER_BPF_MTAP(ifp, m); 133480219Swpaul WRITE_REG(sc, r->r_reg, TXP_IDX2OFFSET(prod)); 133580219Swpaul } 133680219Swpaul 133780219Swpaul r->r_prod = prod; 133880219Swpaul r->r_cnt = cnt; 133980219Swpaul return; 134080219Swpaul 134180219Swpauloactive: 1342148887Srwatson ifp->if_drv_flags |= IFF_DRV_OACTIVE; 134380219Swpaul r->r_prod = firstprod; 134480219Swpaul r->r_cnt = firstcnt; 134580219Swpaul IF_PREPEND(&ifp->if_snd, m); 134680219Swpaul} 134780219Swpaul 134880219Swpaul/* 134980219Swpaul * Handle simple commands sent to the typhoon 135080219Swpaul */ 135180219Swpaulstatic int 1352189004Srdivackytxp_command(struct txp_softc *sc, u_int16_t id, u_int16_t in1, u_int32_t in2, 1353189004Srdivacky u_int32_t in3, u_int16_t *out1, u_int32_t *out2, u_int32_t *out3, int wait) 135480219Swpaul{ 135580219Swpaul struct txp_rsp_desc *rsp = NULL; 135680219Swpaul 135780219Swpaul if (txp_command2(sc, id, in1, in2, in3, NULL, 0, &rsp, wait)) 135880219Swpaul return (-1); 135980219Swpaul 136080219Swpaul if (!wait) 136180219Swpaul return (0); 136280219Swpaul 136380219Swpaul if (out1 != NULL) 136480219Swpaul *out1 = rsp->rsp_par1; 136580219Swpaul if (out2 != NULL) 136680219Swpaul *out2 = rsp->rsp_par2; 136780219Swpaul if (out3 != NULL) 136880219Swpaul *out3 = rsp->rsp_par3; 136980219Swpaul free(rsp, M_DEVBUF); 137080219Swpaul return (0); 137180219Swpaul} 137280219Swpaul 137380219Swpaulstatic int 1374189004Srdivackytxp_command2(struct txp_softc *sc, u_int16_t id, u_int16_t in1, u_int32_t in2, 1375189004Srdivacky u_int32_t in3, struct txp_ext_desc *in_extp, u_int8_t in_extn, 1376189004Srdivacky struct txp_rsp_desc **rspp, int wait) 137780219Swpaul{ 137880219Swpaul struct txp_hostvar *hv = sc->sc_hostvar; 137980219Swpaul struct txp_cmd_desc *cmd; 138080219Swpaul struct txp_ext_desc *ext; 138180219Swpaul u_int32_t idx, i; 138280219Swpaul u_int16_t seq; 138380219Swpaul 138480219Swpaul if (txp_cmd_desc_numfree(sc) < (in_extn + 1)) { 138580219Swpaul device_printf(sc->sc_dev, "no free cmd descriptors\n"); 138680219Swpaul return (-1); 138780219Swpaul } 138880219Swpaul 138980219Swpaul idx = sc->sc_cmdring.lastwrite; 139080219Swpaul cmd = (struct txp_cmd_desc *)(((u_int8_t *)sc->sc_cmdring.base) + idx); 139180219Swpaul bzero(cmd, sizeof(*cmd)); 139280219Swpaul 139380219Swpaul cmd->cmd_numdesc = in_extn; 139480219Swpaul cmd->cmd_seq = seq = sc->sc_seq++; 139580219Swpaul cmd->cmd_id = id; 139680219Swpaul cmd->cmd_par1 = in1; 139780219Swpaul cmd->cmd_par2 = in2; 139880219Swpaul cmd->cmd_par3 = in3; 139980219Swpaul cmd->cmd_flags = CMD_FLAGS_TYPE_CMD | 140080219Swpaul (wait ? CMD_FLAGS_RESP : 0) | CMD_FLAGS_VALID; 140180219Swpaul 140280219Swpaul idx += sizeof(struct txp_cmd_desc); 140380219Swpaul if (idx == sc->sc_cmdring.size) 140480219Swpaul idx = 0; 140580219Swpaul 140680219Swpaul for (i = 0; i < in_extn; i++) { 140780219Swpaul ext = (struct txp_ext_desc *)(((u_int8_t *)sc->sc_cmdring.base) + idx); 140880219Swpaul bcopy(in_extp, ext, sizeof(struct txp_ext_desc)); 140980219Swpaul in_extp++; 141080219Swpaul idx += sizeof(struct txp_cmd_desc); 141180219Swpaul if (idx == sc->sc_cmdring.size) 141280219Swpaul idx = 0; 141380219Swpaul } 141480219Swpaul 141580219Swpaul sc->sc_cmdring.lastwrite = idx; 141680219Swpaul 141780219Swpaul WRITE_REG(sc, TXP_H2A_2, sc->sc_cmdring.lastwrite); 141880219Swpaul 141980219Swpaul if (!wait) 142080219Swpaul return (0); 142180219Swpaul 142280219Swpaul for (i = 0; i < 10000; i++) { 142380219Swpaul idx = hv->hv_resp_read_idx; 142480219Swpaul if (idx != hv->hv_resp_write_idx) { 142580219Swpaul *rspp = NULL; 142680219Swpaul if (txp_response(sc, idx, id, seq, rspp)) 142780219Swpaul return (-1); 142880219Swpaul if (*rspp != NULL) 142980219Swpaul break; 143080219Swpaul } 143180219Swpaul DELAY(50); 143280219Swpaul } 143380219Swpaul if (i == 1000 || (*rspp) == NULL) { 143480219Swpaul device_printf(sc->sc_dev, "0x%x command failed\n", id); 143580219Swpaul return (-1); 143680219Swpaul } 143780219Swpaul 143880219Swpaul return (0); 143980219Swpaul} 144080219Swpaul 144180219Swpaulstatic int 1442189004Srdivackytxp_response(struct txp_softc *sc, u_int32_t ridx, u_int16_t id, u_int16_t seq, 1443189004Srdivacky struct txp_rsp_desc **rspp) 144480219Swpaul{ 144580219Swpaul struct txp_hostvar *hv = sc->sc_hostvar; 144680219Swpaul struct txp_rsp_desc *rsp; 144780219Swpaul 144880219Swpaul while (ridx != hv->hv_resp_write_idx) { 144980219Swpaul rsp = (struct txp_rsp_desc *)(((u_int8_t *)sc->sc_rspring.base) + ridx); 145080219Swpaul 145180219Swpaul if (id == rsp->rsp_id && rsp->rsp_seq == seq) { 145280219Swpaul *rspp = (struct txp_rsp_desc *)malloc( 145380219Swpaul sizeof(struct txp_rsp_desc) * (rsp->rsp_numdesc + 1), 145480219Swpaul M_DEVBUF, M_NOWAIT); 145580219Swpaul if ((*rspp) == NULL) 145680219Swpaul return (-1); 145780219Swpaul txp_rsp_fixup(sc, rsp, *rspp); 145880219Swpaul return (0); 145980219Swpaul } 146080219Swpaul 146180219Swpaul if (rsp->rsp_flags & RSP_FLAGS_ERROR) { 146280219Swpaul device_printf(sc->sc_dev, "response error!\n"); 146380219Swpaul txp_rsp_fixup(sc, rsp, NULL); 146480219Swpaul ridx = hv->hv_resp_read_idx; 146580219Swpaul continue; 146680219Swpaul } 146780219Swpaul 146880219Swpaul switch (rsp->rsp_id) { 146980219Swpaul case TXP_CMD_CYCLE_STATISTICS: 147080219Swpaul case TXP_CMD_MEDIA_STATUS_READ: 147180219Swpaul break; 147280219Swpaul case TXP_CMD_HELLO_RESPONSE: 147380219Swpaul device_printf(sc->sc_dev, "hello\n"); 147480219Swpaul break; 147580219Swpaul default: 147680219Swpaul device_printf(sc->sc_dev, "unknown id(0x%x)\n", 147780219Swpaul rsp->rsp_id); 147880219Swpaul } 147980219Swpaul 148080219Swpaul txp_rsp_fixup(sc, rsp, NULL); 148180219Swpaul ridx = hv->hv_resp_read_idx; 148280219Swpaul hv->hv_resp_read_idx = ridx; 148380219Swpaul } 148480219Swpaul 148580219Swpaul return (0); 148680219Swpaul} 148780219Swpaul 148880219Swpaulstatic void 1489189685Syongaritxp_rsp_fixup(struct txp_softc *sc, struct txp_rsp_desc *rsp, 1490189685Syongari struct txp_rsp_desc *dst) 149180219Swpaul{ 149280219Swpaul struct txp_rsp_desc *src = rsp; 149380219Swpaul struct txp_hostvar *hv = sc->sc_hostvar; 149480219Swpaul u_int32_t i, ridx; 149580219Swpaul 149680219Swpaul ridx = hv->hv_resp_read_idx; 149780219Swpaul 149880219Swpaul for (i = 0; i < rsp->rsp_numdesc + 1; i++) { 149980219Swpaul if (dst != NULL) 150080219Swpaul bcopy(src, dst++, sizeof(struct txp_rsp_desc)); 150180219Swpaul ridx += sizeof(struct txp_rsp_desc); 150280219Swpaul if (ridx == sc->sc_rspring.size) { 150380219Swpaul src = sc->sc_rspring.base; 150480219Swpaul ridx = 0; 150580219Swpaul } else 150680219Swpaul src++; 150780219Swpaul sc->sc_rspring.lastwrite = hv->hv_resp_read_idx = ridx; 150880219Swpaul } 1509189686Syongari 151080219Swpaul hv->hv_resp_read_idx = ridx; 151180219Swpaul} 151280219Swpaul 151380219Swpaulstatic int 1514189685Syongaritxp_cmd_desc_numfree(struct txp_softc *sc) 151580219Swpaul{ 151680219Swpaul struct txp_hostvar *hv = sc->sc_hostvar; 151780219Swpaul struct txp_boot_record *br = sc->sc_boot; 151880219Swpaul u_int32_t widx, ridx, nfree; 151980219Swpaul 152080219Swpaul widx = sc->sc_cmdring.lastwrite; 152180219Swpaul ridx = hv->hv_cmd_read_idx; 152280219Swpaul 152380219Swpaul if (widx == ridx) { 152480219Swpaul /* Ring is completely free */ 152580219Swpaul nfree = br->br_cmd_siz - sizeof(struct txp_cmd_desc); 152680219Swpaul } else { 152780219Swpaul if (widx > ridx) 152880219Swpaul nfree = br->br_cmd_siz - 152980219Swpaul (widx - ridx + sizeof(struct txp_cmd_desc)); 153080219Swpaul else 153180219Swpaul nfree = ridx - widx - sizeof(struct txp_cmd_desc); 153280219Swpaul } 153380219Swpaul 153480219Swpaul return (nfree / sizeof(struct txp_cmd_desc)); 153580219Swpaul} 153680219Swpaul 153780219Swpaulstatic void 1538189685Syongaritxp_stop(struct txp_softc *sc) 153980219Swpaul{ 154080219Swpaul struct ifnet *ifp; 154180219Swpaul 1542151772Sjhb TXP_LOCK_ASSERT(sc); 1543147256Sbrooks ifp = sc->sc_ifp; 154480219Swpaul 1545148887Srwatson ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 154680219Swpaul 1547151772Sjhb callout_stop(&sc->sc_tick); 154880219Swpaul 154980219Swpaul txp_command(sc, TXP_CMD_TX_DISABLE, 0, 0, 0, NULL, NULL, NULL, 1); 155080219Swpaul txp_command(sc, TXP_CMD_RX_DISABLE, 0, 0, 0, NULL, NULL, NULL, 1); 155180219Swpaul 155280219Swpaul txp_rxring_empty(sc); 155380219Swpaul} 155480219Swpaul 155580219Swpaulstatic void 1556189685Syongaritxp_watchdog(struct ifnet *ifp) 155780219Swpaul{ 1558189687Syongari 155980219Swpaul} 156080219Swpaul 156180219Swpaulstatic int 1562189685Syongaritxp_ifmedia_upd(struct ifnet *ifp) 156380219Swpaul{ 156480219Swpaul struct txp_softc *sc = ifp->if_softc; 156580219Swpaul struct ifmedia *ifm = &sc->sc_ifmedia; 156680219Swpaul u_int16_t new_xcvr; 156780219Swpaul 1568151772Sjhb TXP_LOCK(sc); 1569151772Sjhb if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) { 1570151772Sjhb TXP_UNLOCK(sc); 157180219Swpaul return (EINVAL); 1572151772Sjhb } 157380219Swpaul 157480219Swpaul if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_T) { 157580219Swpaul if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) 157680219Swpaul new_xcvr = TXP_XCVR_10_FDX; 157780219Swpaul else 157880219Swpaul new_xcvr = TXP_XCVR_10_HDX; 157980219Swpaul } else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_TX) { 158080219Swpaul if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) 158180219Swpaul new_xcvr = TXP_XCVR_100_FDX; 158280219Swpaul else 158380219Swpaul new_xcvr = TXP_XCVR_100_HDX; 158480219Swpaul } else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) { 158580219Swpaul new_xcvr = TXP_XCVR_AUTO; 1586151772Sjhb } else { 1587151772Sjhb TXP_UNLOCK(sc); 158880219Swpaul return (EINVAL); 1589151772Sjhb } 159080219Swpaul 159180219Swpaul /* nothing to do */ 1592151772Sjhb if (sc->sc_xcvr == new_xcvr) { 1593151772Sjhb TXP_UNLOCK(sc); 159480219Swpaul return (0); 1595151772Sjhb } 159680219Swpaul 159780219Swpaul txp_command(sc, TXP_CMD_XCVR_SELECT, new_xcvr, 0, 0, 159880219Swpaul NULL, NULL, NULL, 0); 159980219Swpaul sc->sc_xcvr = new_xcvr; 1600151772Sjhb TXP_UNLOCK(sc); 160180219Swpaul 160280219Swpaul return (0); 160380219Swpaul} 160480219Swpaul 160580219Swpaulstatic void 1606189685Syongaritxp_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) 160780219Swpaul{ 160880219Swpaul struct txp_softc *sc = ifp->if_softc; 160980219Swpaul struct ifmedia *ifm = &sc->sc_ifmedia; 1610173666Syongari u_int16_t bmsr, bmcr, anar, anlpar; 161180219Swpaul 161280219Swpaul ifmr->ifm_status = IFM_AVALID; 161380219Swpaul ifmr->ifm_active = IFM_ETHER; 161480219Swpaul 1615151772Sjhb TXP_LOCK(sc); 161680219Swpaul if (txp_command(sc, TXP_CMD_PHY_MGMT_READ, 0, MII_BMSR, 0, 161780219Swpaul &bmsr, NULL, NULL, 1)) 161880219Swpaul goto bail; 161980219Swpaul if (txp_command(sc, TXP_CMD_PHY_MGMT_READ, 0, MII_BMSR, 0, 162080219Swpaul &bmsr, NULL, NULL, 1)) 162180219Swpaul goto bail; 162280219Swpaul 162380219Swpaul if (txp_command(sc, TXP_CMD_PHY_MGMT_READ, 0, MII_BMCR, 0, 162480219Swpaul &bmcr, NULL, NULL, 1)) 162580219Swpaul goto bail; 162680219Swpaul 162780219Swpaul if (txp_command(sc, TXP_CMD_PHY_MGMT_READ, 0, MII_ANLPAR, 0, 162880219Swpaul &anlpar, NULL, NULL, 1)) 162980219Swpaul goto bail; 1630173666Syongari 1631173666Syongari if (txp_command(sc, TXP_CMD_PHY_MGMT_READ, 0, MII_ANAR, 0, 1632173666Syongari &anar, NULL, NULL, 1)) 1633173666Syongari goto bail; 1634151772Sjhb TXP_UNLOCK(sc); 163580219Swpaul 163680219Swpaul if (bmsr & BMSR_LINK) 163780219Swpaul ifmr->ifm_status |= IFM_ACTIVE; 163880219Swpaul 163980219Swpaul if (bmcr & BMCR_ISO) { 164080219Swpaul ifmr->ifm_active |= IFM_NONE; 164180219Swpaul ifmr->ifm_status = 0; 164280219Swpaul return; 164380219Swpaul } 164480219Swpaul 164580219Swpaul if (bmcr & BMCR_LOOP) 164680219Swpaul ifmr->ifm_active |= IFM_LOOP; 164780219Swpaul 164880219Swpaul if (bmcr & BMCR_AUTOEN) { 164980219Swpaul if ((bmsr & BMSR_ACOMP) == 0) { 165080219Swpaul ifmr->ifm_active |= IFM_NONE; 165180219Swpaul return; 165280219Swpaul } 165380219Swpaul 1654173666Syongari anlpar &= anar; 1655173665Syongari if (anlpar & ANLPAR_TX_FD) 1656173665Syongari ifmr->ifm_active |= IFM_100_TX|IFM_FDX; 1657173665Syongari else if (anlpar & ANLPAR_T4) 165880219Swpaul ifmr->ifm_active |= IFM_100_T4; 165980219Swpaul else if (anlpar & ANLPAR_TX) 166080219Swpaul ifmr->ifm_active |= IFM_100_TX; 166180219Swpaul else if (anlpar & ANLPAR_10_FD) 166280219Swpaul ifmr->ifm_active |= IFM_10_T|IFM_FDX; 166380219Swpaul else if (anlpar & ANLPAR_10) 166480219Swpaul ifmr->ifm_active |= IFM_10_T; 166580219Swpaul else 166680219Swpaul ifmr->ifm_active |= IFM_NONE; 166780219Swpaul } else 166880219Swpaul ifmr->ifm_active = ifm->ifm_cur->ifm_media; 166980219Swpaul return; 167080219Swpaul 167180219Swpaulbail: 1672151772Sjhb TXP_UNLOCK(sc); 167380219Swpaul ifmr->ifm_active |= IFM_NONE; 167480219Swpaul ifmr->ifm_status &= ~IFM_AVALID; 167580219Swpaul} 167680219Swpaul 167780219Swpaul#ifdef TXP_DEBUG 167880219Swpaulstatic void 1679189685Syongaritxp_show_descriptor(void *d) 168080219Swpaul{ 168180219Swpaul struct txp_cmd_desc *cmd = d; 168280219Swpaul struct txp_rsp_desc *rsp = d; 168380219Swpaul struct txp_tx_desc *txd = d; 168480219Swpaul struct txp_frag_desc *frgd = d; 168580219Swpaul 168680219Swpaul switch (cmd->cmd_flags & CMD_FLAGS_TYPE_M) { 168780219Swpaul case CMD_FLAGS_TYPE_CMD: 168880219Swpaul /* command descriptor */ 168980219Swpaul printf("[cmd flags 0x%x num %d id %d seq %d par1 0x%x par2 0x%x par3 0x%x]\n", 169080219Swpaul cmd->cmd_flags, cmd->cmd_numdesc, cmd->cmd_id, cmd->cmd_seq, 169180219Swpaul cmd->cmd_par1, cmd->cmd_par2, cmd->cmd_par3); 169280219Swpaul break; 169380219Swpaul case CMD_FLAGS_TYPE_RESP: 169480219Swpaul /* response descriptor */ 169580219Swpaul printf("[rsp flags 0x%x num %d id %d seq %d par1 0x%x par2 0x%x par3 0x%x]\n", 169680219Swpaul rsp->rsp_flags, rsp->rsp_numdesc, rsp->rsp_id, rsp->rsp_seq, 169780219Swpaul rsp->rsp_par1, rsp->rsp_par2, rsp->rsp_par3); 169880219Swpaul break; 169980219Swpaul case CMD_FLAGS_TYPE_DATA: 170080219Swpaul /* data header (assuming tx for now) */ 170180219Swpaul printf("[data flags 0x%x num %d totlen %d addr 0x%x/0x%x pflags 0x%x]", 170280219Swpaul txd->tx_flags, txd->tx_numdesc, txd->tx_totlen, 170380219Swpaul txd->tx_addrlo, txd->tx_addrhi, txd->tx_pflags); 170480219Swpaul break; 170580219Swpaul case CMD_FLAGS_TYPE_FRAG: 170680219Swpaul /* fragment descriptor */ 170780219Swpaul printf("[frag flags 0x%x rsvd1 0x%x len %d addr 0x%x/0x%x rsvd2 0x%x]", 170880219Swpaul frgd->frag_flags, frgd->frag_rsvd1, frgd->frag_len, 170980219Swpaul frgd->frag_addrlo, frgd->frag_addrhi, frgd->frag_rsvd2); 171080219Swpaul break; 171180219Swpaul default: 171280219Swpaul printf("[unknown(%x) flags 0x%x num %d id %d seq %d par1 0x%x par2 0x%x par3 0x%x]\n", 171380219Swpaul cmd->cmd_flags & CMD_FLAGS_TYPE_M, 171480219Swpaul cmd->cmd_flags, cmd->cmd_numdesc, cmd->cmd_id, cmd->cmd_seq, 171580219Swpaul cmd->cmd_par1, cmd->cmd_par2, cmd->cmd_par3); 171680219Swpaul break; 171780219Swpaul } 171880219Swpaul} 171980219Swpaul#endif 172080219Swpaul 172180219Swpaulstatic void 1722189685Syongaritxp_set_filter(struct txp_softc *sc) 172380219Swpaul{ 1724147256Sbrooks struct ifnet *ifp = sc->sc_ifp; 172580219Swpaul u_int32_t crc, carry, hashbit, hash[2]; 172680219Swpaul u_int16_t filter; 172780219Swpaul u_int8_t octet; 172880219Swpaul int i, j, mcnt = 0; 172980219Swpaul struct ifmultiaddr *ifma; 173080219Swpaul char *enm; 173180219Swpaul 173280219Swpaul if (ifp->if_flags & IFF_PROMISC) { 173380219Swpaul filter = TXP_RXFILT_PROMISC; 173480219Swpaul goto setit; 173580219Swpaul } 173680219Swpaul 173780219Swpaul filter = TXP_RXFILT_DIRECT; 173880219Swpaul 173980219Swpaul if (ifp->if_flags & IFF_BROADCAST) 174080219Swpaul filter |= TXP_RXFILT_BROADCAST; 174180219Swpaul 174280219Swpaul if (ifp->if_flags & IFF_ALLMULTI) 174380219Swpaul filter |= TXP_RXFILT_ALLMULTI; 174480219Swpaul else { 174580219Swpaul hash[0] = hash[1] = 0; 174680219Swpaul 1747148654Srwatson IF_ADDR_LOCK(ifp); 174880219Swpaul TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 174980219Swpaul if (ifma->ifma_addr->sa_family != AF_LINK) 175080219Swpaul continue; 175180219Swpaul 175280219Swpaul enm = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 175380219Swpaul mcnt++; 175480219Swpaul crc = 0xffffffff; 175580219Swpaul 175680219Swpaul for (i = 0; i < ETHER_ADDR_LEN; i++) { 175780219Swpaul octet = enm[i]; 175880219Swpaul for (j = 0; j < 8; j++) { 175980219Swpaul carry = ((crc & 0x80000000) ? 1 : 0) ^ 176080219Swpaul (octet & 1); 176180219Swpaul crc <<= 1; 176280219Swpaul octet >>= 1; 176380219Swpaul if (carry) 176480219Swpaul crc = (crc ^ TXP_POLYNOMIAL) | 176580219Swpaul carry; 176680219Swpaul } 176780219Swpaul } 176880219Swpaul hashbit = (u_int16_t)(crc & (64 - 1)); 176980219Swpaul hash[hashbit / 32] |= (1 << hashbit % 32); 177080219Swpaul } 1771148654Srwatson IF_ADDR_UNLOCK(ifp); 177280219Swpaul 177380219Swpaul if (mcnt > 0) { 177480219Swpaul filter |= TXP_RXFILT_HASHMULTI; 177580219Swpaul txp_command(sc, TXP_CMD_MCAST_HASH_MASK_WRITE, 177680219Swpaul 2, hash[0], hash[1], NULL, NULL, NULL, 0); 177780219Swpaul } 177880219Swpaul } 177980219Swpaul 178080219Swpaulsetit: 178180219Swpaul 178280219Swpaul txp_command(sc, TXP_CMD_RX_FILTER_WRITE, filter, 0, 0, 178380219Swpaul NULL, NULL, NULL, 1); 178480219Swpaul} 178580219Swpaul 178680219Swpaulstatic void 1787189685Syongaritxp_capabilities(struct txp_softc *sc) 178880219Swpaul{ 1789147256Sbrooks struct ifnet *ifp = sc->sc_ifp; 179080219Swpaul struct txp_rsp_desc *rsp = NULL; 179180219Swpaul struct txp_ext_desc *ext; 179280219Swpaul 179380219Swpaul if (txp_command2(sc, TXP_CMD_OFFLOAD_READ, 0, 0, 0, NULL, 0, &rsp, 1)) 179480219Swpaul goto out; 179580219Swpaul 179680219Swpaul if (rsp->rsp_numdesc != 1) 179780219Swpaul goto out; 179880219Swpaul ext = (struct txp_ext_desc *)(rsp + 1); 179980219Swpaul 180080219Swpaul sc->sc_tx_capability = ext->ext_1 & OFFLOAD_MASK; 180180219Swpaul sc->sc_rx_capability = ext->ext_2 & OFFLOAD_MASK; 180283631Sjlemon ifp->if_capabilities = 0; 180380219Swpaul 180480219Swpaul if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_VLAN) { 180580219Swpaul sc->sc_tx_capability |= OFFLOAD_VLAN; 180680219Swpaul sc->sc_rx_capability |= OFFLOAD_VLAN; 1807106937Ssam ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 180880219Swpaul } 180980219Swpaul 181080219Swpaul#if 0 181180219Swpaul /* not ready yet */ 181280219Swpaul if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_IPSEC) { 181380219Swpaul sc->sc_tx_capability |= OFFLOAD_IPSEC; 181480219Swpaul sc->sc_rx_capability |= OFFLOAD_IPSEC; 181580219Swpaul ifp->if_capabilities |= IFCAP_IPSEC; 181680219Swpaul } 181780219Swpaul#endif 181880219Swpaul 181980219Swpaul if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_IPCKSUM) { 182080219Swpaul sc->sc_tx_capability |= OFFLOAD_IPCKSUM; 182180219Swpaul sc->sc_rx_capability |= OFFLOAD_IPCKSUM; 182283631Sjlemon ifp->if_capabilities |= IFCAP_HWCSUM; 182380219Swpaul ifp->if_hwassist |= CSUM_IP; 182480219Swpaul } 182580219Swpaul 182680219Swpaul if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_TCPCKSUM) { 182780219Swpaul#if 0 182880219Swpaul sc->sc_tx_capability |= OFFLOAD_TCPCKSUM; 182980219Swpaul#endif 183080219Swpaul sc->sc_rx_capability |= OFFLOAD_TCPCKSUM; 183183631Sjlemon ifp->if_capabilities |= IFCAP_HWCSUM; 183280219Swpaul } 183380219Swpaul 183480219Swpaul if (rsp->rsp_par2 & rsp->rsp_par3 & OFFLOAD_UDPCKSUM) { 183580219Swpaul#if 0 183680219Swpaul sc->sc_tx_capability |= OFFLOAD_UDPCKSUM; 183780219Swpaul#endif 183880219Swpaul sc->sc_rx_capability |= OFFLOAD_UDPCKSUM; 183983631Sjlemon ifp->if_capabilities |= IFCAP_HWCSUM; 184080219Swpaul } 184183631Sjlemon ifp->if_capenable = ifp->if_capabilities; 184280219Swpaul 184380219Swpaul if (txp_command(sc, TXP_CMD_OFFLOAD_WRITE, 0, 184480219Swpaul sc->sc_tx_capability, sc->sc_rx_capability, NULL, NULL, NULL, 1)) 184580219Swpaul goto out; 184680219Swpaul 184780219Swpaulout: 184880219Swpaul if (rsp != NULL) 184980219Swpaul free(rsp, M_DEVBUF); 185080219Swpaul} 1851