147133Sobrien/*- 2121099Srsm * Copyright (c) 1998, 1999, 2003 Scott Mitchell 347133Sobrien * All rights reserved. 447133Sobrien * 547133Sobrien * Redistribution and use in source and binary forms, with or without 647133Sobrien * modification, are permitted provided that the following conditions 747133Sobrien * are met: 847133Sobrien * 1. Redistributions of source code must retain the above copyright 947133Sobrien * notice, this list of conditions and the following disclaimer. 1047133Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1147133Sobrien * notice, this list of conditions and the following disclaimer in the 1247133Sobrien * documentation and/or other materials provided with the distribution. 1347133Sobrien * 1447133Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1547133Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1647133Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1747133Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1847133Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1947133Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2047133Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2147133Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2247133Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2347133Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2447133Sobrien * SUCH DAMAGE. 2547133Sobrien */ 26139749Simp/*- 2747133Sobrien * Portions of this software were derived from Werner Koch's xirc2ps driver 2847133Sobrien * for Linux under the terms of the following license (from v1.30 of the 2947133Sobrien * xirc2ps driver): 3047133Sobrien * 3147133Sobrien * Copyright (c) 1997 by Werner Koch (dd9jn) 3247133Sobrien * 3347133Sobrien * Redistribution and use in source and binary forms, with or without 3447133Sobrien * modification, are permitted provided that the following conditions 3547133Sobrien * are met: 3647133Sobrien * 1. Redistributions of source code must retain the above copyright 3747133Sobrien * notice, and the entire permission notice in its entirety, 3847133Sobrien * including the disclaimer of warranties. 3947133Sobrien * 2. Redistributions in binary form must reproduce the above copyright 4047133Sobrien * notice, this list of conditions and the following disclaimer in the 4147133Sobrien * documentation and/or other materials provided with the distribution. 4247133Sobrien * 3. The name of the author may not be used to endorse or promote 4347133Sobrien * products derived from this software without specific prior 4447133Sobrien * written permission. 4547133Sobrien * 4647133Sobrien * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 4747133Sobrien * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 4847133Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 4947133Sobrien * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 5047133Sobrien * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 5147133Sobrien * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 5247133Sobrien * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5347133Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 5447133Sobrien * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 5547133Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 5647133Sobrien * OF THE POSSIBILITY OF SUCH DAMAGE. 5747133Sobrien */ 5847133Sobrien 59122625Sobrien#include <sys/cdefs.h> 60122625Sobrien__FBSDID("$FreeBSD$"); 61122625Sobrien 6247133Sobrien/* 6347145Sobrien * FreeBSD device driver for Xircom CreditCard PCMCIA Ethernet adapters. The 6447151Sobrien * following cards are currently known to work with the driver: 6547151Sobrien * Xircom CreditCard 10/100 (CE3) 6648117Sobrien * Xircom CreditCard Ethernet + Modem 28 (CEM28) 6747151Sobrien * Xircom CreditCard Ethernet 10/100 + Modem 56 (CEM56) 6848117Sobrien * Xircom RealPort Ethernet 10 6947151Sobrien * Xircom RealPort Ethernet 10/100 7047151Sobrien * Xircom RealPort Ethernet 10/100 + Modem 56 (REM56, REM56G) 7147151Sobrien * Intel EtherExpress Pro/100 PC Card Mobile Adapter 16 (Pro/100 M16A) 7247151Sobrien * Compaq Netelligent 10/100 PC Card (CPQ-10/100) 7347133Sobrien * 7447151Sobrien * Some other cards *should* work, but support for them is either broken or in 7547151Sobrien * an unknown state at the moment. I'm always interested in hearing from 7647151Sobrien * people who own any of these cards: 7747151Sobrien * Xircom CreditCard 10Base-T (PS-CE2-10) 7847151Sobrien * Xircom CreditCard Ethernet + ModemII (CEM2) 7947151Sobrien * Xircom CEM28 and CEM33 Ethernet/Modem cards (may be variants of CEM2?) 8047151Sobrien * 8147145Sobrien * Thanks to all who assisted with the development and testing of the driver, 8247151Sobrien * especially: Werner Koch, Duke Kamstra, Duncan Barclay, Jason George, Dru 8347151Sobrien * Nelson, Mike Kephart, Bill Rainey and Douglas Rand. Apologies if I've left 8447151Sobrien * out anyone who deserves a mention here. 8547133Sobrien * 8647151Sobrien * Special thanks to Ade Lovett for both hosting the mailing list and doing 8747151Sobrien * the CEM56/REM56 support code; and the FreeBSD UK Users' Group for hosting 8847151Sobrien * the web pages. 8947136Sobrien * 90121099Srsm * Author email: <scott@uk.freebsd.org> 9147151Sobrien * Driver web page: http://ukug.uk.freebsd.org/~scott/xe_drv/ 9247133Sobrien */ 9347133Sobrien 9447151Sobrien 9547133Sobrien#include <sys/param.h> 9647133Sobrien#include <sys/cdefs.h> 9747133Sobrien#include <sys/errno.h> 9847133Sobrien#include <sys/kernel.h> 9947133Sobrien#include <sys/mbuf.h> 10047133Sobrien#include <sys/socket.h> 10147133Sobrien#include <sys/sockio.h> 10247133Sobrien#include <sys/systm.h> 10347133Sobrien#include <sys/uio.h> 104122081Srsm#include <sys/sysctl.h> 10547133Sobrien 10655723Simp#include <sys/module.h> 10755723Simp#include <sys/bus.h> 10855723Simp 10955723Simp#include <machine/bus.h> 11055723Simp#include <machine/resource.h> 11155723Simp#include <sys/rman.h> 11255723Simp 11347133Sobrien#include <net/ethernet.h> 11447133Sobrien#include <net/if.h> 11547133Sobrien#include <net/if_arp.h> 11647133Sobrien#include <net/if_dl.h> 11747133Sobrien#include <net/if_media.h> 11847133Sobrien#include <net/if_mib.h> 11947133Sobrien#include <net/bpf.h> 120147256Sbrooks#include <net/if_types.h> 12147133Sobrien 12255723Simp#include <dev/xe/if_xereg.h> 12355723Simp#include <dev/xe/if_xevar.h> 12455723Simp 12547133Sobrien/* 12647136Sobrien * MII command structure 12747136Sobrien */ 12847136Sobrienstruct xe_mii_frame { 129179551Sjhb uint8_t mii_stdelim; 130179551Sjhb uint8_t mii_opcode; 131179551Sjhb uint8_t mii_phyaddr; 132179551Sjhb uint8_t mii_regaddr; 133179551Sjhb uint8_t mii_turnaround; 134179551Sjhb uint16_t mii_data; 13547136Sobrien}; 13647133Sobrien 13747133Sobrien/* 13847136Sobrien * Media autonegotiation progress constants 13947133Sobrien */ 140179551Sjhb#define XE_AUTONEG_NONE 0 /* No autonegotiation in progress */ 141179551Sjhb#define XE_AUTONEG_WAITING 1 /* Waiting for transmitter to go idle */ 142179551Sjhb#define XE_AUTONEG_STARTED 2 /* Waiting for autonegotiation to complete */ 143179551Sjhb#define XE_AUTONEG_100TX 3 /* Trying to force 100baseTX link */ 144179551Sjhb#define XE_AUTONEG_FAIL 4 /* Autonegotiation failed */ 14547133Sobrien 146121099Srsm/* 14747136Sobrien * Prototypes start here 14847133Sobrien */ 149179551Sjhbstatic void xe_init(void *xscp); 150179551Sjhbstatic void xe_init_locked(struct xe_softc *scp); 151179551Sjhbstatic void xe_start(struct ifnet *ifp); 152179551Sjhbstatic void xe_start_locked(struct ifnet *ifp); 153179551Sjhbstatic int xe_ioctl(struct ifnet *ifp, u_long command, caddr_t data); 154179551Sjhbstatic void xe_watchdog(void *arg); 155179551Sjhbstatic void xe_intr(void *xscp); 156179551Sjhbstatic void xe_txintr(struct xe_softc *scp, uint8_t txst1); 157179551Sjhbstatic void xe_macintr(struct xe_softc *scp, uint8_t rst0, uint8_t txst0, 158179551Sjhb uint8_t txst1); 159179551Sjhbstatic void xe_rxintr(struct xe_softc *scp, uint8_t rst0); 160179551Sjhbstatic int xe_media_change(struct ifnet *ifp); 161179551Sjhbstatic void xe_media_status(struct ifnet *ifp, struct ifmediareq *mrp); 162179551Sjhbstatic void xe_setmedia(void *arg); 163179551Sjhbstatic void xe_reset(struct xe_softc *scp); 164179551Sjhbstatic void xe_enable_intr(struct xe_softc *scp); 165179551Sjhbstatic void xe_disable_intr(struct xe_softc *scp); 166179551Sjhbstatic void xe_set_multicast(struct xe_softc *scp); 167179551Sjhbstatic void xe_set_addr(struct xe_softc *scp, uint8_t* addr, unsigned idx); 168179551Sjhbstatic void xe_mchash(struct xe_softc *scp, const uint8_t *addr); 169179551Sjhbstatic int xe_pio_write_packet(struct xe_softc *scp, struct mbuf *mbp); 17047133Sobrien 17147133Sobrien/* 17247136Sobrien * MII functions 17347133Sobrien */ 174179551Sjhbstatic void xe_mii_sync(struct xe_softc *scp); 175179551Sjhbstatic int xe_mii_init(struct xe_softc *scp); 176179551Sjhbstatic void xe_mii_send(struct xe_softc *scp, uint32_t bits, int cnt); 177179551Sjhbstatic int xe_mii_readreg(struct xe_softc *scp, 178179551Sjhb struct xe_mii_frame *frame); 179179551Sjhbstatic int xe_mii_writereg(struct xe_softc *scp, 180179551Sjhb struct xe_mii_frame *frame); 181179551Sjhbstatic uint16_t xe_phy_readreg(struct xe_softc *scp, uint16_t reg); 182179551Sjhbstatic void xe_phy_writereg(struct xe_softc *scp, uint16_t reg, 183179551Sjhb uint16_t data); 18447133Sobrien 185122081Srsm/* 186122081Srsm * Debugging functions 187122081Srsm */ 188179551Sjhbstatic void xe_mii_dump(struct xe_softc *scp); 189122170Srsm#if 0 190179551Sjhbstatic void xe_reg_dump(struct xe_softc *scp); 191122170Srsm#endif 192121099Srsm 19347133Sobrien/* 194122081Srsm * Debug logging levels - set with hw.xe.debug sysctl 195122081Srsm * 0 = None 196122081Srsm * 1 = More hardware details, probe/attach progress 197122081Srsm * 2 = Most function calls, ioctls and media selection progress 198122081Srsm * 3 = Everything - interrupts, packets in/out and multicast address setup 19947133Sobrien */ 200179551Sjhb#define XE_DEBUG 201122081Srsm#ifdef XE_DEBUG 202121099Srsm 203122081Srsm/* sysctl vars */ 204227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, xe, CTLFLAG_RD, 0, "if_xe parameters"); 205122081Srsm 206122081Srsmint xe_debug = 0; 207179551SjhbSYSCTL_INT(_hw_xe, OID_AUTO, debug, CTLFLAG_RW, &xe_debug, 0, 208179551Sjhb "if_xe debug level"); 209122081Srsm 210179551Sjhb#define DEVPRINTF(level, arg) if (xe_debug >= (level)) device_printf arg 211179551Sjhb#define DPRINTF(level, arg) if (xe_debug >= (level)) printf arg 212179551Sjhb#define XE_MII_DUMP(scp) if (xe_debug >= 3) xe_mii_dump(scp) 213122170Srsm#if 0 214179551Sjhb#define XE_REG_DUMP(scp) if (xe_debug >= 3) xe_reg_dump(scp) 215122170Srsm#endif 21647136Sobrien#else 217179551Sjhb#define DEVPRINTF(level, arg) 218179551Sjhb#define DPRINTF(level, arg) 219179551Sjhb#define XE_MII_DUMP(scp) 220122170Srsm#if 0 221179551Sjhb#define XE_REG_DUMP(scp) 22247133Sobrien#endif 223122170Srsm#endif 22447133Sobrien 22547133Sobrien/* 22690962Sshiba * Attach a device. 22747148Sobrien */ 22890962Sshibaint 229179551Sjhbxe_attach(device_t dev) 23047148Sobrien{ 231179551Sjhb struct xe_softc *scp = device_get_softc(dev); 232179551Sjhb int err; 23355723Simp 234179551Sjhb DEVPRINTF(2, (dev, "attach\n")); 23555723Simp 236179551Sjhb /* Initialise stuff... */ 237179551Sjhb scp->dev = dev; 238179551Sjhb scp->ifp = if_alloc(IFT_ETHER); 239179551Sjhb if (scp->ifp == NULL) 240179551Sjhb return (ENOSPC); 241179551Sjhb scp->ifm = &scp->ifmedia; 242179551Sjhb scp->autoneg_status = XE_AUTONEG_NONE; 243179551Sjhb mtx_init(&scp->lock, device_get_nameunit(dev), MTX_NETWORK_LOCK, 244179551Sjhb MTX_DEF); 245179551Sjhb callout_init_mtx(&scp->wdog_timer, &scp->lock, 0); 24647136Sobrien 247179551Sjhb /* Initialise the ifnet structure */ 248179551Sjhb scp->ifp->if_softc = scp; 249179551Sjhb if_initname(scp->ifp, device_get_name(dev), device_get_unit(dev)); 250179551Sjhb scp->ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 251179551Sjhb scp->ifp->if_linkmib = &scp->mibdata; 252179551Sjhb scp->ifp->if_linkmiblen = sizeof(scp->mibdata); 253179551Sjhb scp->ifp->if_start = xe_start; 254179551Sjhb scp->ifp->if_ioctl = xe_ioctl; 255179551Sjhb scp->ifp->if_init = xe_init; 256179551Sjhb scp->ifp->if_baudrate = 100000000; 257207554Ssobomax IFQ_SET_MAXLEN(&scp->ifp->if_snd, ifqmaxlen); 25847136Sobrien 259179551Sjhb /* Initialise the ifmedia structure */ 260179551Sjhb ifmedia_init(scp->ifm, 0, xe_media_change, xe_media_status); 261179551Sjhb callout_init_mtx(&scp->media_timer, &scp->lock, 0); 26247136Sobrien 263179551Sjhb /* Add supported media types */ 264179551Sjhb if (scp->mohawk) { 265179551Sjhb ifmedia_add(scp->ifm, IFM_ETHER|IFM_100_TX, 0, NULL); 266179551Sjhb ifmedia_add(scp->ifm, IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); 267179551Sjhb ifmedia_add(scp->ifm, IFM_ETHER|IFM_10_T|IFM_HDX, 0, NULL); 268179551Sjhb } 269179551Sjhb ifmedia_add(scp->ifm, IFM_ETHER|IFM_10_T, 0, NULL); 270179551Sjhb if (scp->ce2) 271179551Sjhb ifmedia_add(scp->ifm, IFM_ETHER|IFM_10_2, 0, NULL); 272179551Sjhb ifmedia_add(scp->ifm, IFM_ETHER|IFM_AUTO, 0, NULL); 27347136Sobrien 274179551Sjhb /* Default is to autoselect best supported media type */ 275179551Sjhb ifmedia_set(scp->ifm, IFM_ETHER|IFM_AUTO); 27647136Sobrien 277179551Sjhb /* Get the hardware into a known state */ 278179551Sjhb XE_LOCK(scp); 279179551Sjhb xe_reset(scp); 280179551Sjhb XE_UNLOCK(scp); 281121099Srsm 282179551Sjhb /* Get hardware version numbers */ 283179551Sjhb XE_SELECT_PAGE(4); 284179551Sjhb scp->version = XE_INB(XE_BOV); 285179551Sjhb if (scp->mohawk) 286179551Sjhb scp->srev = (XE_INB(XE_BOV) & 0x70) >> 4; 287179551Sjhb else 288179551Sjhb scp->srev = (XE_INB(XE_BOV) & 0x30) >> 4; 289121099Srsm 290179551Sjhb /* Print some useful information */ 291179551Sjhb device_printf(dev, "version 0x%02x/0x%02x%s%s\n", scp->version, 292179551Sjhb scp->srev, scp->mohawk ? ", 100Mbps capable" : "", 293179551Sjhb scp->modem ? ", with modem" : ""); 294179551Sjhb if (scp->mohawk) { 295179551Sjhb XE_SELECT_PAGE(0x10); 296179551Sjhb DEVPRINTF(1, (dev, 297179551Sjhb "DingoID=0x%04x, RevisionID=0x%04x, VendorID=0x%04x\n", 298179551Sjhb XE_INW(XE_DINGOID), XE_INW(XE_RevID), XE_INW(XE_VendorID))); 299179551Sjhb } 300179551Sjhb if (scp->ce2) { 301179551Sjhb XE_SELECT_PAGE(0x45); 302179551Sjhb DEVPRINTF(1, (dev, "CE2 version = 0x%02x\n", XE_INB(XE_REV))); 303179551Sjhb } 30447133Sobrien 305179551Sjhb /* Attach the interface */ 306179551Sjhb ether_ifattach(scp->ifp, scp->enaddr); 30747133Sobrien 308179551Sjhb err = bus_setup_intr(dev, scp->irq_res, INTR_TYPE_NET | INTR_MPSAFE, 309179551Sjhb NULL, xe_intr, scp, &scp->intrhand); 310179551Sjhb if (err) { 311179551Sjhb ether_ifdetach(scp->ifp); 312179551Sjhb mtx_destroy(&scp->lock); 313179551Sjhb return (err); 314179551Sjhb } 315179492Sjhb 316179551Sjhb /* Done */ 317179551Sjhb return (0); 31847133Sobrien} 31947133Sobrien 32047133Sobrien/* 321121099Srsm * Complete hardware intitialisation and enable output. Exits without doing 322121099Srsm * anything if there's no address assigned to the card, or if media selection 323121099Srsm * is in progress (the latter implies we've already run this function). 32447133Sobrien */ 32547133Sobrienstatic void 326179551Sjhbxe_init(void *xscp) 327179551Sjhb{ 328179551Sjhb struct xe_softc *scp = xscp; 329179492Sjhb 330179551Sjhb XE_LOCK(scp); 331179551Sjhb xe_init_locked(scp); 332179551Sjhb XE_UNLOCK(scp); 333179492Sjhb} 334179492Sjhb 335179492Sjhbstatic void 336179551Sjhbxe_init_locked(struct xe_softc *scp) 337179551Sjhb{ 338179551Sjhb unsigned i; 33947133Sobrien 340179551Sjhb if (scp->autoneg_status != XE_AUTONEG_NONE) 341179551Sjhb return; 342121099Srsm 343179551Sjhb DEVPRINTF(2, (scp->dev, "init\n")); 34447133Sobrien 345179551Sjhb /* Reset transmitter flags */ 346179551Sjhb scp->tx_queued = 0; 347179551Sjhb scp->tx_tpr = 0; 348179551Sjhb scp->tx_timeouts = 0; 349179551Sjhb scp->tx_thres = 64; 350179551Sjhb scp->tx_min = ETHER_MIN_LEN - ETHER_CRC_LEN; 351179551Sjhb scp->tx_timeout = 0; 35247133Sobrien 353179551Sjhb /* Soft reset the card */ 354179551Sjhb XE_SELECT_PAGE(0); 355179551Sjhb XE_OUTB(XE_CR, XE_CR_SOFT_RESET); 356179551Sjhb DELAY(40000); 357179551Sjhb XE_OUTB(XE_CR, 0); 358179551Sjhb DELAY(40000); 35947133Sobrien 360179551Sjhb if (scp->mohawk) { 361179551Sjhb /* 362179551Sjhb * set GP1 and GP2 as outputs (bits 2 & 3) 363179551Sjhb * set GP1 low to power on the ML6692 (bit 0) 364179551Sjhb * set GP2 high to power on the 10Mhz chip (bit 1) 365179551Sjhb */ 366179551Sjhb XE_SELECT_PAGE(4); 367179551Sjhb XE_OUTB(XE_GPR0, XE_GPR0_GP2_SELECT | XE_GPR0_GP1_SELECT | 368179551Sjhb XE_GPR0_GP2_OUT); 369179551Sjhb } 370121099Srsm 371179551Sjhb /* Shut off interrupts */ 372179551Sjhb xe_disable_intr(scp); 373121099Srsm 374179551Sjhb /* Wait for everything to wake up */ 375179551Sjhb DELAY(500000); 376121099Srsm 377179551Sjhb /* Check for PHY */ 378179551Sjhb if (scp->mohawk) 379179551Sjhb scp->phy_ok = xe_mii_init(scp); 380121099Srsm 381179551Sjhb /* Disable 'source insertion' (not sure what that means) */ 382179551Sjhb XE_SELECT_PAGE(0x42); 383179551Sjhb XE_OUTB(XE_SWC0, XE_SWC0_NO_SRC_INSERT); 38447133Sobrien 385179551Sjhb /* Set 8K/24K Tx/Rx buffer split */ 386179551Sjhb if (scp->srev != 1) { 387179551Sjhb XE_SELECT_PAGE(2); 388179551Sjhb XE_OUTW(XE_RBS, 0x2000); 389179551Sjhb } 39047133Sobrien 391179551Sjhb /* Enable early transmit mode on Mohawk/Dingo */ 392179551Sjhb if (scp->mohawk) { 393179551Sjhb XE_SELECT_PAGE(0x03); 394179551Sjhb XE_OUTW(XE_TPT, scp->tx_thres); 395179551Sjhb XE_SELECT_PAGE(0x01); 396179551Sjhb XE_OUTB(XE_ECR, XE_INB(XE_ECR) | XE_ECR_EARLY_TX); 397179551Sjhb } 398121099Srsm 399179551Sjhb /* Put MAC address in first 'individual address' register */ 400179551Sjhb XE_SELECT_PAGE(0x50); 401179551Sjhb for (i = 0; i < ETHER_ADDR_LEN; i++) 402179551Sjhb XE_OUTB(0x08 + i, IF_LLADDR(scp->ifp)[scp->mohawk ? 5 - i : i]); 403121099Srsm 404179551Sjhb /* Set up multicast addresses */ 405179551Sjhb xe_set_multicast(scp); 40647133Sobrien 407179551Sjhb /* Fix the receive data offset -- reset can leave it off-by-one */ 408179551Sjhb XE_SELECT_PAGE(0); 409179551Sjhb XE_OUTW(XE_DO, 0x2000); 41047133Sobrien 411179551Sjhb /* Set interrupt masks */ 412179551Sjhb XE_SELECT_PAGE(1); 413179551Sjhb XE_OUTB(XE_IMR0, XE_IMR0_TX_PACKET | XE_IMR0_MAC_INTR | 414179551Sjhb XE_IMR0_RX_PACKET); 41547133Sobrien 416179551Sjhb /* Set MAC interrupt masks */ 417179551Sjhb XE_SELECT_PAGE(0x40); 418179551Sjhb XE_OUTB(XE_RX0Msk, 419179551Sjhb ~(XE_RX0M_RX_OVERRUN | XE_RX0M_CRC_ERROR | XE_RX0M_ALIGN_ERROR | 420179551Sjhb XE_RX0M_LONG_PACKET)); 421179551Sjhb XE_OUTB(XE_TX0Msk, 422179551Sjhb ~(XE_TX0M_SQE_FAIL | XE_TX0M_LATE_COLLISION | XE_TX0M_TX_UNDERRUN | 423179551Sjhb XE_TX0M_16_COLLISIONS | XE_TX0M_NO_CARRIER)); 42447133Sobrien 425179551Sjhb /* Clear MAC status registers */ 426179551Sjhb XE_SELECT_PAGE(0x40); 427179551Sjhb XE_OUTB(XE_RST0, 0x00); 428179551Sjhb XE_OUTB(XE_TXST0, 0x00); 42947133Sobrien 430179551Sjhb /* Enable receiver and put MAC online */ 431179551Sjhb XE_SELECT_PAGE(0x40); 432179551Sjhb XE_OUTB(XE_CMD0, XE_CMD0_RX_ENABLE|XE_CMD0_ONLINE); 43347133Sobrien 434179551Sjhb /* Set up IMR, enable interrupts */ 435179551Sjhb xe_enable_intr(scp); 436121099Srsm 437179551Sjhb /* Start media selection */ 438179551Sjhb xe_setmedia(scp); 439121099Srsm 440179551Sjhb /* Enable output */ 441179551Sjhb scp->ifp->if_drv_flags |= IFF_DRV_RUNNING; 442179551Sjhb scp->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 443179551Sjhb callout_reset(&scp->wdog_timer, hz, xe_watchdog, scp); 44447133Sobrien} 44547133Sobrien 44647133Sobrien/* 447121099Srsm * Start output on interface. Should be called at splimp() priority. Check 448148887Srwatson * that the output is idle (ie, IFF_DRV_OACTIVE is not set) before calling this 449148887Srwatson * function. If media selection is in progress we set IFF_DRV_OACTIVE ourselves 450121099Srsm * and return immediately. 45147133Sobrien */ 45247133Sobrienstatic void 453179551Sjhbxe_start(struct ifnet *ifp) 454179551Sjhb{ 455179551Sjhb struct xe_softc *scp = ifp->if_softc; 456179492Sjhb 457179551Sjhb XE_LOCK(scp); 458179551Sjhb xe_start_locked(ifp); 459179551Sjhb XE_UNLOCK(scp); 460179492Sjhb} 461179492Sjhb 462179492Sjhbstatic void 463179551Sjhbxe_start_locked(struct ifnet *ifp) 464179551Sjhb{ 465179551Sjhb struct xe_softc *scp = ifp->if_softc; 466179551Sjhb struct mbuf *mbp; 46747133Sobrien 468179551Sjhb if (scp->autoneg_status != XE_AUTONEG_NONE) { 469179551Sjhb ifp->if_drv_flags |= IFF_DRV_OACTIVE; 470179551Sjhb return; 471179551Sjhb } 472121099Srsm 473179551Sjhb DEVPRINTF(3, (scp->dev, "start\n")); 474121099Srsm 475179551Sjhb /* 476179551Sjhb * Loop while there are packets to be sent, and space to send 477179551Sjhb * them. 478179551Sjhb */ 479179551Sjhb for (;;) { 480179551Sjhb /* Suck a packet off the send queue */ 481179551Sjhb IF_DEQUEUE(&ifp->if_snd, mbp); 48247133Sobrien 483179551Sjhb if (mbp == NULL) { 484179551Sjhb /* 485179551Sjhb * We are using the !OACTIVE flag to indicate 486179551Sjhb * to the outside world that we can accept an 487179551Sjhb * additional packet rather than that the 488179551Sjhb * transmitter is _actually_ active. Indeed, 489179551Sjhb * the transmitter may be active, but if we 490179551Sjhb * haven't filled all the buffers with data 491179551Sjhb * then we still want to accept more. 492179551Sjhb */ 493179551Sjhb ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 494179551Sjhb return; 495179551Sjhb } 49647133Sobrien 497179551Sjhb if (xe_pio_write_packet(scp, mbp) != 0) { 498179551Sjhb /* Push the packet back onto the queue */ 499179551Sjhb IF_PREPEND(&ifp->if_snd, mbp); 500179551Sjhb ifp->if_drv_flags |= IFF_DRV_OACTIVE; 501179551Sjhb return; 502179551Sjhb } 50347133Sobrien 504179551Sjhb /* Tap off here if there is a bpf listener */ 505179551Sjhb BPF_MTAP(ifp, mbp); 50647133Sobrien 507179551Sjhb /* In case we don't hear from the card again... */ 508179551Sjhb scp->tx_timeout = 5; 509179551Sjhb scp->tx_queued++; 51047133Sobrien 511179551Sjhb m_freem(mbp); 512179551Sjhb } 51347133Sobrien} 51447133Sobrien 51547133Sobrien/* 51647133Sobrien * Process an ioctl request. Adapted from the ed driver. 51747133Sobrien */ 51847133Sobrienstatic int 519179551Sjhbxe_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 520179551Sjhb{ 521179551Sjhb struct xe_softc *scp; 522179551Sjhb int error; 52347133Sobrien 524179551Sjhb scp = ifp->if_softc; 525179551Sjhb error = 0; 52647133Sobrien 527179551Sjhb switch (command) { 528179551Sjhb case SIOCSIFFLAGS: 529179551Sjhb DEVPRINTF(2, (scp->dev, "ioctl: SIOCSIFFLAGS: 0x%04x\n", 530179551Sjhb ifp->if_flags)); 531179551Sjhb /* 532179551Sjhb * If the interface is marked up and stopped, then 533179551Sjhb * start it. If it is marked down and running, then 534179551Sjhb * stop it. 535179551Sjhb */ 536179551Sjhb XE_LOCK(scp); 537179551Sjhb if (ifp->if_flags & IFF_UP) { 538179551Sjhb if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 539179551Sjhb xe_reset(scp); 540179551Sjhb xe_init_locked(scp); 541179551Sjhb } 542179551Sjhb } else { 543179551Sjhb if (ifp->if_drv_flags & IFF_DRV_RUNNING) 544179551Sjhb xe_stop(scp); 545179551Sjhb } 54647133Sobrien 547179551Sjhb /* handle changes to PROMISC/ALLMULTI flags */ 548179551Sjhb xe_set_multicast(scp); 549179551Sjhb XE_UNLOCK(scp); 550179551Sjhb error = 0; 551179551Sjhb break; 552179551Sjhb case SIOCADDMULTI: 553179551Sjhb case SIOCDELMULTI: 554179551Sjhb DEVPRINTF(2, (scp->dev, "ioctl: SIOC{ADD,DEL}MULTI\n")); 555179551Sjhb /* 556179551Sjhb * Multicast list has (maybe) changed; set the 557179551Sjhb * hardware filters accordingly. 558179551Sjhb */ 559179551Sjhb XE_LOCK(scp); 560179551Sjhb xe_set_multicast(scp); 561179551Sjhb XE_UNLOCK(scp); 562179551Sjhb error = 0; 563179551Sjhb break; 564179551Sjhb case SIOCSIFMEDIA: 565179551Sjhb case SIOCGIFMEDIA: 566179551Sjhb DEVPRINTF(3, (scp->dev, "ioctl: bounce to ifmedia_ioctl\n")); 567179551Sjhb /* 568179551Sjhb * Someone wants to get/set media options. 569179551Sjhb */ 570179551Sjhb error = ifmedia_ioctl(ifp, (struct ifreq *)data, &scp->ifmedia, 571179551Sjhb command); 572179551Sjhb break; 573179551Sjhb default: 574179551Sjhb DEVPRINTF(3, (scp->dev, "ioctl: bounce to ether_ioctl\n")); 575179551Sjhb error = ether_ioctl(ifp, command, data); 576179551Sjhb } 577121099Srsm 578179551Sjhb return (error); 57947133Sobrien} 58047133Sobrien 58147133Sobrien/* 58255723Simp * Card interrupt handler. 58347136Sobrien * 58447136Sobrien * This function is probably more complicated than it needs to be, as it 58547136Sobrien * attempts to deal with the case where multiple packets get sent between 58647136Sobrien * interrupts. This is especially annoying when working out the collision 58747136Sobrien * stats. Not sure whether this case ever really happens or not (maybe on a 58847136Sobrien * slow/heavily loaded machine?) so it's probably best to leave this like it 58947136Sobrien * is. 59047136Sobrien * 59147136Sobrien * Note that the crappy PIO used to get packets on and off the card means that 59247136Sobrien * you will spend a lot of time in this routine -- I can get my P150 to spend 59347136Sobrien * 90% of its time servicing interrupts if I really hammer the network. Could 59447136Sobrien * fix this, but then you'd start dropping/losing packets. The moral of this 59547136Sobrien * story? If you want good network performance _and_ some cycles left over to 59647136Sobrien * get your work done, don't buy a Xircom card. Or convince them to tell me 59747136Sobrien * how to do memory-mapped I/O :) 59847136Sobrien */ 59955723Simpstatic void 600179551Sjhbxe_txintr(struct xe_softc *scp, uint8_t txst1) 60155723Simp{ 602179551Sjhb struct ifnet *ifp; 603179551Sjhb uint8_t tpr, sent, coll; 60447136Sobrien 605179551Sjhb ifp = scp->ifp; 60647136Sobrien 607179551Sjhb /* Update packet count, accounting for rollover */ 608179551Sjhb tpr = XE_INB(XE_TPR); 609179551Sjhb sent = -scp->tx_tpr + tpr; 610121099Srsm 611179551Sjhb /* Update statistics if we actually sent anything */ 612179551Sjhb if (sent > 0) { 613179551Sjhb coll = txst1 & XE_TXST1_RETRY_COUNT; 614179551Sjhb scp->tx_tpr = tpr; 615179551Sjhb scp->tx_queued -= sent; 616179551Sjhb ifp->if_opackets += sent; 617179551Sjhb ifp->if_collisions += coll; 61847136Sobrien 619179551Sjhb /* 620179551Sjhb * According to the Xircom manual, Dingo will 621179551Sjhb * sometimes manage to transmit a packet with 622179551Sjhb * triggering an interrupt. If this happens, we have 623179551Sjhb * sent > 1 and the collision count only reflects 624179551Sjhb * collisions on the last packet sent (the one that 625179551Sjhb * triggered the interrupt). Collision stats might 626179551Sjhb * therefore be a bit low, but there doesn't seem to 627179551Sjhb * be anything we can do about that. 628179551Sjhb */ 629179551Sjhb switch (coll) { 630179551Sjhb case 0: 631179551Sjhb break; 632179551Sjhb case 1: 633179551Sjhb scp->mibdata.dot3StatsSingleCollisionFrames++; 634179551Sjhb scp->mibdata.dot3StatsCollFrequencies[0]++; 635179551Sjhb break; 636179551Sjhb default: 637179551Sjhb scp->mibdata.dot3StatsMultipleCollisionFrames++; 638179551Sjhb scp->mibdata.dot3StatsCollFrequencies[coll-1]++; 639179551Sjhb } 64047136Sobrien } 641179551Sjhb scp->tx_timeout = 0; 642179551Sjhb ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 643179543Sjhb} 644121099Srsm 645179543Sjhb/* Handle most MAC interrupts */ 646179543Sjhbstatic void 647179551Sjhbxe_macintr(struct xe_softc *scp, uint8_t rst0, uint8_t txst0, uint8_t txst1) 648179543Sjhb{ 649179551Sjhb struct ifnet *ifp; 650121099Srsm 651179551Sjhb ifp = scp->ifp; 652179543Sjhb 653121099Srsm#if 0 654179551Sjhb /* Carrier sense lost -- only in 10Mbit HDX mode */ 655179551Sjhb if (txst0 & XE_TXST0_NO_CARRIER || !(txst1 & XE_TXST1_LINK_STATUS)) { 656179551Sjhb /* XXX - Need to update media status here */ 657179551Sjhb device_printf(scp->dev, "no carrier\n"); 658179551Sjhb ifp->if_oerrors++; 659179551Sjhb scp->mibdata.dot3StatsCarrierSenseErrors++; 660179551Sjhb } 661121099Srsm#endif 662179551Sjhb /* Excessive collisions -- try sending again */ 663179551Sjhb if (txst0 & XE_TXST0_16_COLLISIONS) { 664179551Sjhb ifp->if_collisions += 16; 665179551Sjhb ifp->if_oerrors++; 666179551Sjhb scp->mibdata.dot3StatsExcessiveCollisions++; 667179551Sjhb scp->mibdata.dot3StatsMultipleCollisionFrames++; 668179551Sjhb scp->mibdata.dot3StatsCollFrequencies[15]++; 669179551Sjhb XE_OUTB(XE_CR, XE_CR_RESTART_TX); 670121099Srsm } 671179551Sjhb 672179551Sjhb /* Transmit underrun -- increase early transmit threshold */ 673179551Sjhb if (txst0 & XE_TXST0_TX_UNDERRUN && scp->mohawk) { 674179551Sjhb DEVPRINTF(1, (scp->dev, "transmit underrun")); 675179551Sjhb if (scp->tx_thres < ETHER_MAX_LEN) { 676179551Sjhb if ((scp->tx_thres += 64) > ETHER_MAX_LEN) 677179551Sjhb scp->tx_thres = ETHER_MAX_LEN; 678179551Sjhb DPRINTF(1, (": increasing transmit threshold to %u", 679179551Sjhb scp->tx_thres)); 680179551Sjhb XE_SELECT_PAGE(0x3); 681179551Sjhb XE_OUTW(XE_TPT, scp->tx_thres); 682179551Sjhb XE_SELECT_PAGE(0x0); 683179551Sjhb } 684179551Sjhb DPRINTF(1, ("\n")); 685179551Sjhb ifp->if_oerrors++; 686179551Sjhb scp->mibdata.dot3StatsInternalMacTransmitErrors++; 687179551Sjhb } 688179551Sjhb 689179551Sjhb /* Late collision -- just complain about it */ 690179551Sjhb if (txst0 & XE_TXST0_LATE_COLLISION) { 691179551Sjhb device_printf(scp->dev, "late collision\n"); 692179551Sjhb ifp->if_oerrors++; 693179551Sjhb scp->mibdata.dot3StatsLateCollisions++; 694179551Sjhb } 695179551Sjhb 696179551Sjhb /* SQE test failure -- just complain about it */ 697179551Sjhb if (txst0 & XE_TXST0_SQE_FAIL) { 698179551Sjhb device_printf(scp->dev, "SQE test failure\n"); 699179551Sjhb ifp->if_oerrors++; 700179551Sjhb scp->mibdata.dot3StatsSQETestErrors++; 701179551Sjhb } 702179551Sjhb 703179551Sjhb /* Packet too long -- what happens to these */ 704179551Sjhb if (rst0 & XE_RST0_LONG_PACKET) { 705179551Sjhb device_printf(scp->dev, "received giant packet\n"); 706179551Sjhb ifp->if_ierrors++; 707179551Sjhb scp->mibdata.dot3StatsFrameTooLongs++; 708179551Sjhb } 709179551Sjhb 710179551Sjhb /* CRC error -- packet dropped */ 711179551Sjhb if (rst0 & XE_RST0_CRC_ERROR) { 712179551Sjhb device_printf(scp->dev, "CRC error\n"); 713179551Sjhb ifp->if_ierrors++; 714179551Sjhb scp->mibdata.dot3StatsFCSErrors++; 715179551Sjhb } 716179543Sjhb} 71747136Sobrien 718179543Sjhbstatic void 719179551Sjhbxe_rxintr(struct xe_softc *scp, uint8_t rst0) 720179543Sjhb{ 721179551Sjhb struct ifnet *ifp; 722179551Sjhb uint8_t esr, rsr; 723179543Sjhb 724179551Sjhb ifp = scp->ifp; 725179543Sjhb 726179551Sjhb /* Handle received packet(s) */ 727179551Sjhb while ((esr = XE_INB(XE_ESR)) & XE_ESR_FULL_PACKET_RX) { 728179551Sjhb rsr = XE_INB(XE_RSR); 72947136Sobrien 730179551Sjhb DEVPRINTF(3, (scp->dev, "intr: ESR=0x%02x, RSR=0x%02x\n", esr, 731179551Sjhb rsr)); 732121099Srsm 733179551Sjhb /* Make sure packet is a good one */ 734179551Sjhb if (rsr & XE_RSR_RX_OK) { 735179551Sjhb struct ether_header *ehp; 736179551Sjhb struct mbuf *mbp; 737179551Sjhb uint16_t len; 73847136Sobrien 739179551Sjhb len = XE_INW(XE_RBC) - ETHER_CRC_LEN; 74047136Sobrien 741179551Sjhb DEVPRINTF(3, (scp->dev, "intr: receive length = %d\n", 742179551Sjhb len)); 743121099Srsm 744179551Sjhb if (len == 0) { 745179551Sjhb ifp->if_iqdrops++; 746179551Sjhb continue; 747179551Sjhb } 74847136Sobrien 749179551Sjhb /* 750179551Sjhb * Allocate mbuf to hold received packet. If 751179551Sjhb * the mbuf header isn't big enough, we attach 752179551Sjhb * an mbuf cluster to hold the packet. Note 753179551Sjhb * the +=2 to align the packet data on a 754179551Sjhb * 32-bit boundary, and the +3 to allow for 755179551Sjhb * the possibility of reading one more byte 756179551Sjhb * than the actual packet length (we always 757179551Sjhb * read 16-bit words). XXX - Surely there's a 758179551Sjhb * better way to do this alignment? 759179551Sjhb */ 760243857Sglebius MGETHDR(mbp, M_NOWAIT, MT_DATA); 761179551Sjhb if (mbp == NULL) { 762179551Sjhb ifp->if_iqdrops++; 763179551Sjhb continue; 764179551Sjhb } 76547136Sobrien 766179551Sjhb if (len + 3 > MHLEN) { 767243857Sglebius MCLGET(mbp, M_NOWAIT); 768179551Sjhb if ((mbp->m_flags & M_EXT) == 0) { 769179551Sjhb m_freem(mbp); 770179551Sjhb ifp->if_iqdrops++; 771179551Sjhb continue; 772179551Sjhb } 773179551Sjhb } 77447136Sobrien 775179551Sjhb mbp->m_data += 2; 776179551Sjhb ehp = mtod(mbp, struct ether_header *); 77747136Sobrien 778179551Sjhb /* 779179551Sjhb * Now get the packet in PIO mode, including 780179551Sjhb * the Ethernet header but omitting the 781179551Sjhb * trailing CRC. 782179551Sjhb */ 78347136Sobrien 784179551Sjhb /* 785179551Sjhb * Work around a bug in CE2 cards. There 786179551Sjhb * seems to be a problem with duplicated and 787179551Sjhb * extraneous bytes in the receive buffer, but 788179551Sjhb * without any real documentation for the CE2 789179551Sjhb * it's hard to tell for sure. XXX - Needs 790179551Sjhb * testing on CE2 hardware 791179551Sjhb */ 792179551Sjhb if (scp->srev == 0) { 793179551Sjhb u_short rhs; 79447136Sobrien 795179551Sjhb XE_SELECT_PAGE(5); 796179551Sjhb rhs = XE_INW(XE_RHSA); 797179551Sjhb XE_SELECT_PAGE(0); 79847136Sobrien 799179551Sjhb rhs += 3; /* Skip control info */ 80047136Sobrien 801179551Sjhb if (rhs >= 0x8000) 802179551Sjhb rhs = 0; 80347136Sobrien 804179551Sjhb if (rhs + len > 0x8000) { 805179551Sjhb int i; 806121099Srsm 807179551Sjhb for (i = 0; i < len; i++, rhs++) { 808179551Sjhb ((char *)ehp)[i] = 809179551Sjhb XE_INB(XE_EDP); 810179551Sjhb if (rhs == 0x8000) { 811179551Sjhb rhs = 0; 812179551Sjhb i--; 813179551Sjhb } 814179551Sjhb } 815179551Sjhb } else 816179551Sjhb bus_read_multi_2(scp->port_res, XE_EDP, 817179551Sjhb (uint16_t *)ehp, (len + 1) >> 1); 818179551Sjhb } else 819179551Sjhb bus_read_multi_2(scp->port_res, XE_EDP, 820179551Sjhb (uint16_t *)ehp, (len + 1) >> 1); 82147136Sobrien 822179551Sjhb /* Deliver packet to upper layers */ 823179551Sjhb mbp->m_pkthdr.rcvif = ifp; 824179551Sjhb mbp->m_pkthdr.len = mbp->m_len = len; 825179551Sjhb XE_UNLOCK(scp); 826179551Sjhb (*ifp->if_input)(ifp, mbp); 827179551Sjhb XE_LOCK(scp); 828179551Sjhb ifp->if_ipackets++; 829121099Srsm 830179551Sjhb } else if (rsr & XE_RSR_ALIGN_ERROR) { 831179551Sjhb /* Packet alignment error -- drop packet */ 832179551Sjhb device_printf(scp->dev, "alignment error\n"); 833179551Sjhb scp->mibdata.dot3StatsAlignmentErrors++; 834179551Sjhb ifp->if_ierrors++; 835179551Sjhb } 836121099Srsm 837179551Sjhb /* Skip to next packet, if there is one */ 838179551Sjhb XE_OUTW(XE_DO, 0x8000); 839179551Sjhb } 840121099Srsm 841179551Sjhb /* Clear receiver overruns now we have some free buffer space */ 842179551Sjhb if (rst0 & XE_RST0_RX_OVERRUN) { 843179551Sjhb DEVPRINTF(1, (scp->dev, "receive overrun\n")); 844179551Sjhb ifp->if_ierrors++; 845179551Sjhb scp->mibdata.dot3StatsInternalMacReceiveErrors++; 846179551Sjhb XE_OUTB(XE_CR, XE_CR_CLEAR_OVERRUN); 847179551Sjhb } 848179543Sjhb} 849179543Sjhb 850179543Sjhbstatic void 851179551Sjhbxe_intr(void *xscp) 852179543Sjhb{ 853179551Sjhb struct xe_softc *scp = (struct xe_softc *) xscp; 854179551Sjhb struct ifnet *ifp; 855179551Sjhb uint8_t psr, isr, rst0, txst0, txst1; 856179543Sjhb 857179551Sjhb ifp = scp->ifp; 858179551Sjhb XE_LOCK(scp); 859179543Sjhb 860179551Sjhb /* Disable interrupts */ 861179551Sjhb if (scp->mohawk) 862179551Sjhb XE_OUTB(XE_CR, 0); 863179543Sjhb 864179551Sjhb /* Cache current register page */ 865179551Sjhb psr = XE_INB(XE_PR); 866179543Sjhb 867179551Sjhb /* Read ISR to see what caused this interrupt */ 868179551Sjhb while ((isr = XE_INB(XE_ISR)) != 0) { 869179543Sjhb 870179551Sjhb /* 0xff might mean the card is no longer around */ 871179551Sjhb if (isr == 0xff) { 872179551Sjhb DEVPRINTF(3, (scp->dev, 873179551Sjhb "intr: interrupt received for missing card?\n")); 874179551Sjhb break; 875179551Sjhb } 876179543Sjhb 877179551Sjhb /* Read other status registers */ 878179551Sjhb XE_SELECT_PAGE(0x40); 879179551Sjhb rst0 = XE_INB(XE_RST0); 880179551Sjhb XE_OUTB(XE_RST0, 0); 881179551Sjhb txst0 = XE_INB(XE_TXST0); 882179551Sjhb txst1 = XE_INB(XE_TXST1); 883179551Sjhb XE_OUTB(XE_TXST0, 0); 884179551Sjhb XE_OUTB(XE_TXST1, 0); 885179551Sjhb XE_SELECT_PAGE(0); 886179543Sjhb 887179551Sjhb DEVPRINTF(3, (scp->dev, 888179551Sjhb "intr: ISR=0x%02x, RST=0x%02x, TXT=0x%02x%02x\n", isr, 889179551Sjhb rst0, txst1, txst0)); 890179543Sjhb 891179551Sjhb if (isr & XE_ISR_TX_PACKET) 892179551Sjhb xe_txintr(scp, txst1); 893179543Sjhb 894179551Sjhb if (isr & XE_ISR_MAC_INTR) 895179551Sjhb xe_macintr(scp, rst0, txst0, txst1); 896179543Sjhb 897179551Sjhb xe_rxintr(scp, rst0); 898179551Sjhb } 89947136Sobrien 900179551Sjhb /* Restore saved page */ 901179551Sjhb XE_SELECT_PAGE(psr); 90247136Sobrien 903179551Sjhb /* Re-enable interrupts */ 904179551Sjhb XE_OUTB(XE_CR, XE_CR_ENABLE_INTR); 90547136Sobrien 906179551Sjhb XE_UNLOCK(scp); 90747136Sobrien} 90847136Sobrien 90947136Sobrien/* 91047133Sobrien * Device timeout/watchdog routine. Called automatically if we queue a packet 91147133Sobrien * for transmission but don't get an interrupt within a specified timeout 91247133Sobrien * (usually 5 seconds). When this happens we assume the worst and reset the 91347133Sobrien * card. 91447133Sobrien */ 91547133Sobrienstatic void 916179551Sjhbxe_watchdog(void *arg) 917179551Sjhb{ 918179551Sjhb struct xe_softc *scp = arg; 91947133Sobrien 920179551Sjhb XE_ASSERT_LOCKED(scp); 921179527Sjhb 922179551Sjhb if (scp->tx_timeout && --scp->tx_timeout == 0) { 923179551Sjhb device_printf(scp->dev, "watchdog timeout: resetting card\n"); 924179551Sjhb scp->tx_timeouts++; 925179551Sjhb scp->ifp->if_oerrors += scp->tx_queued; 926179551Sjhb xe_stop(scp); 927179551Sjhb xe_reset(scp); 928179551Sjhb xe_init_locked(scp); 929179551Sjhb } 930179551Sjhb callout_reset(&scp->wdog_timer, hz, xe_watchdog, scp); 93147133Sobrien} 93247133Sobrien 93347133Sobrien/* 93447136Sobrien * Change media selection. 93547133Sobrien */ 93647136Sobrienstatic int 937179551Sjhbxe_media_change(struct ifnet *ifp) 938179551Sjhb{ 939179551Sjhb struct xe_softc *scp = ifp->if_softc; 94047136Sobrien 941179551Sjhb DEVPRINTF(2, (scp->dev, "media_change\n")); 94247136Sobrien 943179551Sjhb XE_LOCK(scp); 944179551Sjhb if (IFM_TYPE(scp->ifm->ifm_media) != IFM_ETHER) { 945179551Sjhb XE_UNLOCK(scp); 946179551Sjhb return(EINVAL); 947179551Sjhb } 94847136Sobrien 949179551Sjhb /* 950179551Sjhb * Some card/media combos aren't always possible -- filter 951179551Sjhb * those out here. 952179551Sjhb */ 953179551Sjhb if ((IFM_SUBTYPE(scp->ifm->ifm_media) == IFM_AUTO || 954179551Sjhb IFM_SUBTYPE(scp->ifm->ifm_media) == IFM_100_TX) && !scp->phy_ok) { 955179551Sjhb XE_UNLOCK(scp); 956179551Sjhb return (EINVAL); 957179551Sjhb } 95847136Sobrien 959179551Sjhb xe_setmedia(scp); 960179551Sjhb XE_UNLOCK(scp); 96147136Sobrien 962179551Sjhb return (0); 96347136Sobrien} 96447136Sobrien 96547136Sobrien/* 96647136Sobrien * Return current media selection. 96747136Sobrien */ 96847133Sobrienstatic void 969179551Sjhbxe_media_status(struct ifnet *ifp, struct ifmediareq *mrp) 970179551Sjhb{ 971179551Sjhb struct xe_softc *scp = ifp->if_softc; 97247133Sobrien 973179551Sjhb DEVPRINTF(3, (scp->dev, "media_status\n")); 97447133Sobrien 975179551Sjhb /* XXX - This is clearly wrong. Will fix once I have CE2 working */ 976179551Sjhb XE_LOCK(scp); 977179551Sjhb mrp->ifm_status = IFM_AVALID | IFM_ACTIVE; 978179551Sjhb mrp->ifm_active = ((struct xe_softc *)ifp->if_softc)->media; 979179551Sjhb XE_UNLOCK(scp); 98047136Sobrien} 98147136Sobrien 98247136Sobrien/* 98347136Sobrien * Select active media. 98447136Sobrien */ 985179551Sjhbstatic void 986179551Sjhbxe_setmedia(void *xscp) 987179551Sjhb{ 988179551Sjhb struct xe_softc *scp = xscp; 989179551Sjhb uint16_t bmcr, bmsr, anar, lpar; 99047136Sobrien 991179551Sjhb DEVPRINTF(2, (scp->dev, "setmedia\n")); 99247136Sobrien 993179551Sjhb XE_ASSERT_LOCKED(scp); 994179492Sjhb 995179551Sjhb /* Cancel any pending timeout */ 996179551Sjhb callout_stop(&scp->media_timer); 997179551Sjhb xe_disable_intr(scp); 99847136Sobrien 999179551Sjhb /* Select media */ 1000179551Sjhb scp->media = IFM_ETHER; 1001179551Sjhb switch (IFM_SUBTYPE(scp->ifm->ifm_media)) { 100247136Sobrien 1003179551Sjhb case IFM_AUTO: /* Autoselect media */ 1004179551Sjhb scp->media = IFM_ETHER|IFM_AUTO; 100547136Sobrien 1006179551Sjhb /* 1007179551Sjhb * Autoselection is really awful. It goes something like this: 1008179551Sjhb * 1009179551Sjhb * Wait until the transmitter goes idle (2sec timeout). 1010179551Sjhb * Reset card 1011179551Sjhb * IF a 100Mbit PHY exists 1012179551Sjhb * Start NWAY autonegotiation (3.5sec timeout) 1013179551Sjhb * IF that succeeds 1014179551Sjhb * Select 100baseTX or 10baseT, whichever was detected 1015179551Sjhb * ELSE 1016179551Sjhb * Reset card 1017179551Sjhb * IF a 100Mbit PHY exists 1018179551Sjhb * Try to force a 100baseTX link (3sec timeout) 1019179551Sjhb * IF that succeeds 1020179551Sjhb * Select 100baseTX 1021179551Sjhb * ELSE 1022179551Sjhb * Disable the PHY 1023179551Sjhb * ENDIF 1024179551Sjhb * ENDIF 1025179551Sjhb * ENDIF 1026179551Sjhb * ENDIF 1027179551Sjhb * IF nothing selected so far 1028179551Sjhb * IF a 100Mbit PHY exists 1029179551Sjhb * Select 10baseT 1030179551Sjhb * ELSE 1031179551Sjhb * Select 10baseT or 10base2, whichever is connected 1032179551Sjhb * ENDIF 1033179551Sjhb * ENDIF 1034179551Sjhb */ 1035179551Sjhb switch (scp->autoneg_status) { 1036179551Sjhb case XE_AUTONEG_NONE: 1037179551Sjhb DEVPRINTF(2, (scp->dev, 1038179551Sjhb "Waiting for idle transmitter\n")); 1039179551Sjhb scp->ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1040179551Sjhb scp->autoneg_status = XE_AUTONEG_WAITING; 1041179551Sjhb /* FALL THROUGH */ 1042179551Sjhb case XE_AUTONEG_WAITING: 1043179551Sjhb if (scp->tx_queued != 0) { 1044179551Sjhb callout_reset(&scp->media_timer, hz / 2, 1045179551Sjhb xe_setmedia, scp); 1046179551Sjhb return; 1047179551Sjhb } 1048179551Sjhb if (scp->phy_ok) { 1049179551Sjhb DEVPRINTF(2, (scp->dev, 1050179551Sjhb "Starting autonegotiation\n")); 1051179551Sjhb bmcr = xe_phy_readreg(scp, PHY_BMCR); 1052179551Sjhb bmcr &= ~(PHY_BMCR_AUTONEGENBL); 1053179551Sjhb xe_phy_writereg(scp, PHY_BMCR, bmcr); 1054179551Sjhb anar = xe_phy_readreg(scp, PHY_ANAR); 1055179551Sjhb anar &= ~(PHY_ANAR_100BT4 | 1056179551Sjhb PHY_ANAR_100BTXFULL | PHY_ANAR_10BTFULL); 1057179551Sjhb anar |= PHY_ANAR_100BTXHALF | PHY_ANAR_10BTHALF; 1058179551Sjhb xe_phy_writereg(scp, PHY_ANAR, anar); 1059179551Sjhb bmcr |= PHY_BMCR_AUTONEGENBL | 1060179551Sjhb PHY_BMCR_AUTONEGRSTR; 1061179551Sjhb xe_phy_writereg(scp, PHY_BMCR, bmcr); 1062179551Sjhb scp->autoneg_status = XE_AUTONEG_STARTED; 1063179551Sjhb callout_reset(&scp->media_timer, hz * 7/2, 1064179551Sjhb xe_setmedia, scp); 1065179551Sjhb return; 1066179551Sjhb } else { 1067179551Sjhb scp->autoneg_status = XE_AUTONEG_FAIL; 1068179551Sjhb } 1069179551Sjhb break; 1070179551Sjhb case XE_AUTONEG_STARTED: 1071179551Sjhb bmsr = xe_phy_readreg(scp, PHY_BMSR); 1072179551Sjhb lpar = xe_phy_readreg(scp, PHY_LPAR); 1073179551Sjhb if (bmsr & (PHY_BMSR_AUTONEGCOMP | PHY_BMSR_LINKSTAT)) { 1074179551Sjhb DEVPRINTF(2, (scp->dev, 1075179551Sjhb "Autonegotiation complete!\n")); 107647136Sobrien 1077179551Sjhb /* 1078179551Sjhb * XXX - Shouldn't have to do this, 1079179551Sjhb * but (on my hub at least) the 1080179551Sjhb * transmitter won't work after a 1081179551Sjhb * successful autoneg. So we see what 1082179551Sjhb * the negotiation result was and 1083179551Sjhb * force that mode. I'm sure there is 1084179551Sjhb * an easy fix for this. 1085179551Sjhb */ 1086179551Sjhb if (lpar & PHY_LPAR_100BTXHALF) { 1087179551Sjhb xe_phy_writereg(scp, PHY_BMCR, 1088179551Sjhb PHY_BMCR_SPEEDSEL); 1089179551Sjhb XE_MII_DUMP(scp); 1090179551Sjhb XE_SELECT_PAGE(2); 1091179551Sjhb XE_OUTB(XE_MSR, XE_INB(XE_MSR) | 0x08); 1092179551Sjhb scp->media = IFM_ETHER | IFM_100_TX; 1093179551Sjhb scp->autoneg_status = XE_AUTONEG_NONE; 1094179551Sjhb } else { 1095179551Sjhb /* 1096179551Sjhb * XXX - Bit of a hack going 1097179551Sjhb * on in here. This is 1098179551Sjhb * derived from Ken Hughes 1099179551Sjhb * patch to the Linux driver 1100179551Sjhb * to make it work with 10Mbit 1101179551Sjhb * _autonegotiated_ links on 1102179551Sjhb * CE3B cards. What's a CE3B 1103179551Sjhb * and how's it differ from a 1104179551Sjhb * plain CE3? these are the 1105179551Sjhb * things we need to find out. 1106179551Sjhb */ 1107179551Sjhb xe_phy_writereg(scp, PHY_BMCR, 0x0000); 1108179551Sjhb XE_SELECT_PAGE(2); 1109179551Sjhb /* BEGIN HACK */ 1110179551Sjhb XE_OUTB(XE_MSR, XE_INB(XE_MSR) | 0x08); 1111179551Sjhb XE_SELECT_PAGE(0x42); 1112179551Sjhb XE_OUTB(XE_SWC1, 0x80); 1113179551Sjhb scp->media = IFM_ETHER | IFM_10_T; 1114179551Sjhb scp->autoneg_status = XE_AUTONEG_NONE; 1115179551Sjhb /* END HACK */ 1116179551Sjhb#if 0 1117179551Sjhb /* Display PHY? */ 1118179551Sjhb XE_OUTB(XE_MSR, XE_INB(XE_MSR) & ~0x08); 1119179551Sjhb scp->autoneg_status = XE_AUTONEG_FAIL; 1120179551Sjhb#endif 1121179551Sjhb } 1122179551Sjhb } else { 1123179551Sjhb DEVPRINTF(2, (scp->dev, 1124179551Sjhb "Autonegotiation failed; trying 100baseTX\n")); 1125179551Sjhb XE_MII_DUMP(scp); 1126179551Sjhb if (scp->phy_ok) { 1127179551Sjhb xe_phy_writereg(scp, PHY_BMCR, 1128179551Sjhb PHY_BMCR_SPEEDSEL); 1129179551Sjhb scp->autoneg_status = XE_AUTONEG_100TX; 1130179551Sjhb callout_reset(&scp->media_timer, hz * 3, 1131179551Sjhb xe_setmedia, scp); 1132179551Sjhb return; 1133179551Sjhb } else { 1134179551Sjhb scp->autoneg_status = XE_AUTONEG_FAIL; 1135179551Sjhb } 1136179551Sjhb } 1137179551Sjhb break; 1138179551Sjhb case XE_AUTONEG_100TX: 1139179551Sjhb (void)xe_phy_readreg(scp, PHY_BMSR); 1140179551Sjhb bmsr = xe_phy_readreg(scp, PHY_BMSR); 1141179551Sjhb if (bmsr & PHY_BMSR_LINKSTAT) { 1142179551Sjhb DEVPRINTF(2, (scp->dev, 1143179551Sjhb "Got 100baseTX link!\n")); 1144179551Sjhb XE_MII_DUMP(scp); 1145179551Sjhb XE_SELECT_PAGE(2); 1146179551Sjhb XE_OUTB(XE_MSR, XE_INB(XE_MSR) | 0x08); 1147179551Sjhb scp->media = IFM_ETHER | IFM_100_TX; 1148179551Sjhb scp->autoneg_status = XE_AUTONEG_NONE; 1149179551Sjhb } else { 1150179551Sjhb DEVPRINTF(2, (scp->dev, 1151179551Sjhb "Autonegotiation failed; disabling PHY\n")); 1152179551Sjhb XE_MII_DUMP(scp); 1153179551Sjhb xe_phy_writereg(scp, PHY_BMCR, 0x0000); 1154179551Sjhb XE_SELECT_PAGE(2); 115547136Sobrien 1156179551Sjhb /* Disable PHY? */ 1157179551Sjhb XE_OUTB(XE_MSR, XE_INB(XE_MSR) & ~0x08); 1158179551Sjhb scp->autoneg_status = XE_AUTONEG_FAIL; 1159179551Sjhb } 1160179551Sjhb break; 1161179551Sjhb } 116247136Sobrien 1163179551Sjhb /* 1164179551Sjhb * If we got down here _and_ autoneg_status is 1165179551Sjhb * XE_AUTONEG_FAIL, then either autonegotiation 1166179551Sjhb * failed, or never got started to begin with. In 1167179551Sjhb * either case, select a suitable 10Mbit media and 1168179551Sjhb * hope it works. We don't need to reset the card 1169179551Sjhb * again, since it will have been done already by the 1170179551Sjhb * big switch above. 1171179551Sjhb */ 1172179551Sjhb if (scp->autoneg_status == XE_AUTONEG_FAIL) { 1173179551Sjhb DEVPRINTF(2, (scp->dev, "Selecting 10baseX\n")); 1174179551Sjhb if (scp->mohawk) { 1175179551Sjhb XE_SELECT_PAGE(0x42); 1176179551Sjhb XE_OUTB(XE_SWC1, 0x80); 1177179551Sjhb scp->media = IFM_ETHER | IFM_10_T; 1178179551Sjhb scp->autoneg_status = XE_AUTONEG_NONE; 1179179551Sjhb } else { 1180179551Sjhb XE_SELECT_PAGE(4); 1181179551Sjhb XE_OUTB(XE_GPR0, 4); 1182179551Sjhb DELAY(50000); 1183179551Sjhb XE_SELECT_PAGE(0x42); 1184179551Sjhb XE_OUTB(XE_SWC1, 1185179551Sjhb (XE_INB(XE_ESR) & XE_ESR_MEDIA_SELECT) ? 1186179551Sjhb 0x80 : 0xc0); 1187179551Sjhb scp->media = IFM_ETHER | ((XE_INB(XE_ESR) & 1188179551Sjhb XE_ESR_MEDIA_SELECT) ? IFM_10_T : IFM_10_2); 1189179551Sjhb scp->autoneg_status = XE_AUTONEG_NONE; 1190179551Sjhb } 1191179551Sjhb } 1192179551Sjhb break; 1193179551Sjhb 119447136Sobrien /* 1195179551Sjhb * If a specific media has been requested, we just reset the 1196179551Sjhb * card and select it (one small exception -- if 100baseTX is 1197179551Sjhb * requested but there is no PHY, we fall back to 10baseT 1198179551Sjhb * operation). 119947136Sobrien */ 1200179551Sjhb case IFM_100_TX: /* Force 100baseTX */ 1201179551Sjhb if (scp->phy_ok) { 1202179551Sjhb DEVPRINTF(2, (scp->dev, "Selecting 100baseTX\n")); 1203179551Sjhb XE_SELECT_PAGE(0x42); 1204179551Sjhb XE_OUTB(XE_SWC1, 0); 1205179551Sjhb xe_phy_writereg(scp, PHY_BMCR, PHY_BMCR_SPEEDSEL); 1206179551Sjhb XE_SELECT_PAGE(2); 1207179551Sjhb XE_OUTB(XE_MSR, XE_INB(XE_MSR) | 0x08); 1208179551Sjhb scp->media |= IFM_100_TX; 1209179551Sjhb break; 1210179551Sjhb } 1211179551Sjhb /* FALLTHROUGH */ 1212179551Sjhb case IFM_10_T: /* Force 10baseT */ 1213179551Sjhb DEVPRINTF(2, (scp->dev, "Selecting 10baseT\n")); 1214179551Sjhb if (scp->phy_ok) { 1215179551Sjhb xe_phy_writereg(scp, PHY_BMCR, 0x0000); 1216179551Sjhb XE_SELECT_PAGE(2); 1217179551Sjhb 1218179551Sjhb /* Disable PHY */ 1219179551Sjhb XE_OUTB(XE_MSR, XE_INB(XE_MSR) & ~0x08); 1220179551Sjhb } 1221179551Sjhb XE_SELECT_PAGE(0x42); 1222179551Sjhb XE_OUTB(XE_SWC1, 0x80); 1223179551Sjhb scp->media |= IFM_10_T; 1224179551Sjhb break; 1225179551Sjhb case IFM_10_2: 1226179551Sjhb DEVPRINTF(2, (scp->dev, "Selecting 10base2\n")); 1227179551Sjhb XE_SELECT_PAGE(0x42); 1228179551Sjhb XE_OUTB(XE_SWC1, 0xc0); 1229179551Sjhb scp->media |= IFM_10_2; 1230179551Sjhb break; 123147136Sobrien } 123247136Sobrien 1233179551Sjhb /* 1234179551Sjhb * Finally, the LEDs are set to match whatever media was 1235179551Sjhb * chosen and the transmitter is unblocked. 1236179551Sjhb */ 1237179551Sjhb DEVPRINTF(2, (scp->dev, "Setting LEDs\n")); 123847136Sobrien XE_SELECT_PAGE(2); 1239179551Sjhb switch (IFM_SUBTYPE(scp->media)) { 1240179551Sjhb case IFM_100_TX: 1241179551Sjhb case IFM_10_T: 1242179551Sjhb XE_OUTB(XE_LED, 0x3b); 1243179551Sjhb if (scp->dingo) 1244179551Sjhb XE_OUTB(0x0b, 0x04); /* 100Mbit LED */ 1245179551Sjhb break; 1246179551Sjhb case IFM_10_2: 1247179551Sjhb XE_OUTB(XE_LED, 0x3a); 1248179551Sjhb break; 1249179551Sjhb } 125047136Sobrien 1251179551Sjhb /* Restart output? */ 1252179551Sjhb xe_enable_intr(scp); 1253179551Sjhb scp->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1254179551Sjhb xe_start_locked(scp->ifp); 125547136Sobrien} 125647136Sobrien 125747136Sobrien/* 125847136Sobrien * Hard reset (power cycle) the card. 125947136Sobrien */ 126047136Sobrienstatic void 1261179551Sjhbxe_reset(struct xe_softc *scp) 1262179551Sjhb{ 126347136Sobrien 1264179551Sjhb DEVPRINTF(2, (scp->dev, "reset\n")); 126547136Sobrien 1266179551Sjhb XE_ASSERT_LOCKED(scp); 126747136Sobrien 1268179551Sjhb /* Power down */ 1269179551Sjhb XE_SELECT_PAGE(4); 1270179551Sjhb XE_OUTB(XE_GPR1, 0); 1271179551Sjhb DELAY(40000); 127247136Sobrien 1273179551Sjhb /* Power up again */ 1274179551Sjhb if (scp->mohawk) 1275179551Sjhb XE_OUTB(XE_GPR1, XE_GPR1_POWER_DOWN); 1276179551Sjhb else 1277179551Sjhb XE_OUTB(XE_GPR1, XE_GPR1_POWER_DOWN | XE_GPR1_AIC); 127847136Sobrien 1279179551Sjhb DELAY(40000); 1280179551Sjhb XE_SELECT_PAGE(0); 128147133Sobrien} 128247133Sobrien 128347133Sobrien/* 128447136Sobrien * Take interface offline. This is done by powering down the device, which I 128547136Sobrien * assume means just shutting down the transceiver and Ethernet logic. This 128647136Sobrien * requires a _hard_ reset to recover from, as we need to power up again. 128747133Sobrien */ 1288179492Sjhbvoid 1289179551Sjhbxe_stop(struct xe_softc *scp) 1290179551Sjhb{ 129147133Sobrien 1292179551Sjhb DEVPRINTF(2, (scp->dev, "stop\n")); 129347133Sobrien 1294179551Sjhb XE_ASSERT_LOCKED(scp); 129547133Sobrien 1296179551Sjhb /* 1297179551Sjhb * Shut off interrupts. 1298179551Sjhb */ 1299179551Sjhb xe_disable_intr(scp); 130047133Sobrien 1301179551Sjhb /* 1302179551Sjhb * Power down. 1303179551Sjhb */ 1304179551Sjhb XE_SELECT_PAGE(4); 1305179551Sjhb XE_OUTB(XE_GPR1, 0); 1306179551Sjhb XE_SELECT_PAGE(0); 1307179551Sjhb if (scp->mohawk) { 1308179551Sjhb /* 1309179551Sjhb * set GP1 and GP2 as outputs (bits 2 & 3) 1310179551Sjhb * set GP1 high to power on the ML6692 (bit 0) 1311179551Sjhb * set GP2 low to power on the 10Mhz chip (bit 1) 1312179551Sjhb */ 1313179551Sjhb XE_SELECT_PAGE(4); 1314179551Sjhb XE_OUTB(XE_GPR0, XE_GPR0_GP2_SELECT | XE_GPR0_GP1_SELECT | 1315179551Sjhb XE_GPR0_GP1_OUT); 1316179551Sjhb } 131747136Sobrien 1318179551Sjhb /* 1319179551Sjhb * ~IFF_DRV_RUNNING == interface down. 1320179551Sjhb */ 1321179551Sjhb scp->ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1322179551Sjhb scp->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1323179551Sjhb scp->tx_timeout = 0; 1324179551Sjhb callout_stop(&scp->wdog_timer); 1325179551Sjhb callout_stop(&scp->media_timer); 132647133Sobrien} 132747133Sobrien 132847133Sobrien/* 1329121099Srsm * Enable interrupts from the card. 133047136Sobrien */ 133147136Sobrienstatic void 1332179551Sjhbxe_enable_intr(struct xe_softc *scp) 1333179551Sjhb{ 1334121099Srsm 1335179551Sjhb DEVPRINTF(2, (scp->dev, "enable_intr\n")); 133647136Sobrien 1337179551Sjhb XE_SELECT_PAGE(0); 1338179551Sjhb XE_OUTB(XE_CR, XE_CR_ENABLE_INTR); /* Enable interrupts */ 1339179551Sjhb if (scp->modem && !scp->dingo) { /* This bit is just magic */ 1340179551Sjhb if (!(XE_INB(0x10) & 0x01)) { 1341179551Sjhb XE_OUTB(0x10, 0x11); /* Unmask master int enable */ 1342179551Sjhb } 1343179551Sjhb } 134447136Sobrien} 134547136Sobrien 134647136Sobrien/* 1347121099Srsm * Disable interrupts from the card. 134847136Sobrien */ 134947136Sobrienstatic void 1350179551Sjhbxe_disable_intr(struct xe_softc *scp) 1351179551Sjhb{ 1352121099Srsm 1353179551Sjhb DEVPRINTF(2, (scp->dev, "disable_intr\n")); 135447136Sobrien 1355179551Sjhb XE_SELECT_PAGE(0); 1356179551Sjhb XE_OUTB(XE_CR, 0); /* Disable interrupts */ 1357179551Sjhb if (scp->modem && !scp->dingo) { /* More magic */ 1358179551Sjhb XE_OUTB(0x10, 0x10); /* Mask the master int enable */ 1359179551Sjhb } 136047136Sobrien} 136147136Sobrien 136247136Sobrien/* 1363121099Srsm * Set up multicast filter and promiscuous modes. 136447133Sobrien */ 136547133Sobrienstatic void 1366179551Sjhbxe_set_multicast(struct xe_softc *scp) 1367179551Sjhb{ 1368179551Sjhb struct ifnet *ifp; 1369179551Sjhb struct ifmultiaddr *maddr; 1370179551Sjhb unsigned count, i; 137147133Sobrien 1372179551Sjhb DEVPRINTF(2, (scp->dev, "set_multicast\n")); 1373121099Srsm 1374179551Sjhb ifp = scp->ifp; 1375179551Sjhb XE_SELECT_PAGE(0x42); 137647133Sobrien 1377179551Sjhb /* Handle PROMISC flag */ 1378179551Sjhb if (ifp->if_flags & IFF_PROMISC) { 1379179551Sjhb XE_OUTB(XE_SWC1, XE_INB(XE_SWC1) | XE_SWC1_PROMISCUOUS); 1380179551Sjhb return; 1381179551Sjhb } else 1382179551Sjhb XE_OUTB(XE_SWC1, XE_INB(XE_SWC1) & ~XE_SWC1_PROMISCUOUS); 138347133Sobrien 1384179551Sjhb /* Handle ALLMULTI flag */ 1385179551Sjhb if (ifp->if_flags & IFF_ALLMULTI) { 1386179551Sjhb XE_OUTB(XE_SWC1, XE_INB(XE_SWC1) | XE_SWC1_ALLMULTI); 1387179551Sjhb return; 1388179551Sjhb } else 1389179551Sjhb XE_OUTB(XE_SWC1, XE_INB(XE_SWC1) & ~XE_SWC1_ALLMULTI); 1390121099Srsm 1391179551Sjhb /* Iterate over multicast address list */ 1392179551Sjhb count = 0; 1393195049Srwatson if_maddr_rlock(ifp); 1394179551Sjhb TAILQ_FOREACH(maddr, &ifp->if_multiaddrs, ifma_link) { 1395179551Sjhb if (maddr->ifma_addr->sa_family != AF_LINK) 1396179551Sjhb continue; 1397121099Srsm 1398179551Sjhb count++; 1399121099Srsm 1400179551Sjhb if (count < 10) 1401179551Sjhb /* 1402179551Sjhb * First 9 use Individual Addresses for exact 1403179551Sjhb * matching. 1404179551Sjhb */ 1405179551Sjhb xe_set_addr(scp, 1406179551Sjhb LLADDR((struct sockaddr_dl *)maddr->ifma_addr), 1407179551Sjhb count); 1408179551Sjhb else if (scp->mohawk) 1409179551Sjhb /* Use hash filter on Mohawk and Dingo */ 1410179551Sjhb xe_mchash(scp, 1411179551Sjhb LLADDR((struct sockaddr_dl *)maddr->ifma_addr)); 1412179551Sjhb else 1413179551Sjhb /* Nowhere else to put them on CE2 */ 1414179551Sjhb break; 1415179551Sjhb } 1416195049Srwatson if_maddr_runlock(ifp); 1417121099Srsm 1418179551Sjhb DEVPRINTF(2, (scp->dev, "set_multicast: count = %u\n", count)); 1419121099Srsm 1420179551Sjhb /* Now do some cleanup and enable multicast handling as needed */ 1421179551Sjhb if (count == 0) { 1422179551Sjhb /* Disable all multicast handling */ 1423179551Sjhb XE_SELECT_PAGE(0x42); 1424179551Sjhb XE_OUTB(XE_SWC1, XE_INB(XE_SWC1) & 1425179551Sjhb ~(XE_SWC1_IA_ENABLE | XE_SWC1_ALLMULTI)); 1426179551Sjhb if (scp->mohawk) { 1427179551Sjhb XE_SELECT_PAGE(0x02); 1428179551Sjhb XE_OUTB(XE_MSR, XE_INB(XE_MSR) & ~XE_MSR_HASH_TABLE); 1429179551Sjhb } 1430179551Sjhb } else if (count < 10) { 1431179551Sjhb /* 1432179551Sjhb * Full in any unused Individual Addresses with our 1433179551Sjhb * MAC address. 1434179551Sjhb */ 1435179551Sjhb for (i = count + 1; i < 10; i++) 1436179551Sjhb xe_set_addr(scp, IF_LLADDR(scp->ifp), i); 1437121099Srsm 1438179551Sjhb /* Enable Individual Address matching only */ 1439179551Sjhb XE_SELECT_PAGE(0x42); 1440179551Sjhb XE_OUTB(XE_SWC1, (XE_INB(XE_SWC1) & ~XE_SWC1_ALLMULTI) | 1441179551Sjhb XE_SWC1_IA_ENABLE); 1442179551Sjhb if (scp->mohawk) { 1443179551Sjhb XE_SELECT_PAGE(0x02); 1444179551Sjhb XE_OUTB(XE_MSR, XE_INB(XE_MSR) & ~XE_MSR_HASH_TABLE); 1445179551Sjhb } 1446179551Sjhb } else if (scp->mohawk) { 1447179551Sjhb /* Check whether hash table is full */ 1448179551Sjhb XE_SELECT_PAGE(0x58); 1449179551Sjhb for (i = 0x08; i < 0x10; i++) 1450179551Sjhb if (XE_INB(i) != 0xff) 1451179551Sjhb break; 1452179551Sjhb if (i == 0x10) { 1453179551Sjhb /* 1454179551Sjhb * Hash table full - enable 1455179551Sjhb * promiscuous multicast matching 1456179551Sjhb */ 1457179551Sjhb XE_SELECT_PAGE(0x42); 1458179551Sjhb XE_OUTB(XE_SWC1, (XE_INB(XE_SWC1) & 1459179551Sjhb ~XE_SWC1_IA_ENABLE) | XE_SWC1_ALLMULTI); 1460179551Sjhb XE_SELECT_PAGE(0x02); 1461179551Sjhb XE_OUTB(XE_MSR, XE_INB(XE_MSR) & ~XE_MSR_HASH_TABLE); 1462179551Sjhb } else { 1463179551Sjhb /* Enable hash table and Individual Address matching */ 1464179551Sjhb XE_SELECT_PAGE(0x42); 1465179551Sjhb XE_OUTB(XE_SWC1, (XE_INB(XE_SWC1) & ~XE_SWC1_ALLMULTI) | 1466179551Sjhb XE_SWC1_IA_ENABLE); 1467179551Sjhb XE_SELECT_PAGE(0x02); 1468179551Sjhb XE_OUTB(XE_MSR, XE_INB(XE_MSR) | XE_MSR_HASH_TABLE); 1469179551Sjhb } 1470179551Sjhb } else { 1471179551Sjhb /* Enable promiscuous multicast matching */ 1472179551Sjhb XE_SELECT_PAGE(0x42); 1473179551Sjhb XE_OUTB(XE_SWC1, (XE_INB(XE_SWC1) & ~XE_SWC1_IA_ENABLE) | 1474179551Sjhb XE_SWC1_ALLMULTI); 1475179551Sjhb } 1476179551Sjhb 1477179551Sjhb XE_SELECT_PAGE(0); 147847133Sobrien} 147947133Sobrien 148047133Sobrien/* 1481121099Srsm * Copy the Ethernet multicast address in addr to the on-chip registers for 1482121099Srsm * Individual Address idx. Assumes that addr is really a multicast address 1483121099Srsm * and that idx > 0 (slot 0 is always used for the card MAC address). 148447133Sobrien */ 148547133Sobrienstatic void 1486179551Sjhbxe_set_addr(struct xe_softc *scp, uint8_t* addr, unsigned idx) 1487179551Sjhb{ 1488179551Sjhb uint8_t page, reg; 1489179551Sjhb unsigned i; 149047133Sobrien 1491179551Sjhb /* 1492179551Sjhb * Individual Addresses are stored in registers 8-F of pages 1493179551Sjhb * 0x50-0x57. IA1 therefore starts at register 0xE on page 1494179551Sjhb * 0x50. The expressions below compute the starting page and 1495179551Sjhb * register for any IA index > 0. 1496179551Sjhb */ 1497179551Sjhb --idx; 1498179551Sjhb page = 0x50 + idx % 4 + idx / 4 * 3; 1499179551Sjhb reg = 0x0e - 2 * (idx % 4); 150047133Sobrien 1501179551Sjhb DEVPRINTF(3, (scp->dev, 1502179551Sjhb "set_addr: idx = %u, page = 0x%02x, reg = 0x%02x\n", idx + 1, page, 1503179551Sjhb reg)); 150447133Sobrien 1505179551Sjhb /* 1506179551Sjhb * Copy the IA bytes. Note that the byte order is reversed 1507179551Sjhb * for Mohawk and Dingo wrt. CE2 hardware. 1508179551Sjhb */ 1509179551Sjhb XE_SELECT_PAGE(page); 1510179551Sjhb for (i = 0; i < ETHER_ADDR_LEN; i++) { 1511179551Sjhb if (i > 0) { 1512179551Sjhb DPRINTF(3, (":%02x", addr[i])); 1513179551Sjhb } else { 1514179551Sjhb DEVPRINTF(3, (scp->dev, "set_addr: %02x", addr[0])); 1515179551Sjhb } 1516179551Sjhb XE_OUTB(reg, addr[scp->mohawk ? 5 - i : i]); 1517179551Sjhb if (++reg == 0x10) { 1518179551Sjhb reg = 0x08; 1519179551Sjhb XE_SELECT_PAGE(++page); 1520179551Sjhb } 1521179551Sjhb } 1522179551Sjhb DPRINTF(3, ("\n")); 1523121099Srsm} 152447133Sobrien 1525121099Srsm/* 1526121099Srsm * Set the appropriate bit in the multicast hash table for the supplied 1527121099Srsm * Ethernet multicast address addr. Assumes that addr is really a multicast 1528121099Srsm * address. 1529121099Srsm */ 1530121099Srsmstatic void 1531179551Sjhbxe_mchash(struct xe_softc* scp, const uint8_t *addr) 1532179551Sjhb{ 1533179551Sjhb int bit; 1534179551Sjhb uint8_t byte, hash; 1535121099Srsm 1536179551Sjhb hash = ether_crc32_le(addr, ETHER_ADDR_LEN) & 0x3F; 153747133Sobrien 1538179551Sjhb /* 1539179551Sjhb * Top 3 bits of hash give register - 8, bottom 3 give bit 1540179551Sjhb * within register. 1541179551Sjhb */ 1542179551Sjhb byte = hash >> 3 | 0x08; 1543179551Sjhb bit = 0x01 << (hash & 0x07); 1544121099Srsm 1545179551Sjhb DEVPRINTF(3, (scp->dev, 1546179551Sjhb "set_hash: hash = 0x%02x, byte = 0x%02x, bit = 0x%02x\n", hash, 1547179551Sjhb byte, bit)); 1548121099Srsm 1549179551Sjhb XE_SELECT_PAGE(0x58); 1550179551Sjhb XE_OUTB(byte, XE_INB(byte) | bit); 155147133Sobrien} 155247133Sobrien 155347133Sobrien/* 155447133Sobrien * Write an outgoing packet to the card using programmed I/O. 155547133Sobrien */ 155647133Sobrienstatic int 1557179551Sjhbxe_pio_write_packet(struct xe_softc *scp, struct mbuf *mbp) 1558179551Sjhb{ 1559179551Sjhb unsigned len, pad; 1560179551Sjhb unsigned char wantbyte; 1561179551Sjhb uint8_t *data; 1562179551Sjhb uint8_t savebyte[2]; 156347133Sobrien 1564179551Sjhb /* Get total packet length */ 1565179551Sjhb if (mbp->m_flags & M_PKTHDR) 1566179551Sjhb len = mbp->m_pkthdr.len; 1567179551Sjhb else { 1568179551Sjhb struct mbuf* mbp2 = mbp; 1569179551Sjhb for (len = 0; mbp2 != NULL; 1570179551Sjhb len += mbp2->m_len, mbp2 = mbp2->m_next); 1571179551Sjhb } 157247133Sobrien 1573179551Sjhb DEVPRINTF(3, (scp->dev, "pio_write_packet: len = %u\n", len)); 1574121099Srsm 1575179551Sjhb /* Packets < minimum length may need to be padded out */ 1576179551Sjhb pad = 0; 1577179551Sjhb if (len < scp->tx_min) { 1578179551Sjhb pad = scp->tx_min - len; 1579179551Sjhb len = scp->tx_min; 1580179551Sjhb } 158147133Sobrien 1582179551Sjhb /* Check transmit buffer space */ 1583179551Sjhb XE_SELECT_PAGE(0); 1584179551Sjhb XE_OUTW(XE_TRS, len + 2); /* Only effective on rev. 1 CE2 cards */ 1585179551Sjhb if ((XE_INW(XE_TSO) & 0x7fff) <= len + 2) 1586179551Sjhb return (1); 158747133Sobrien 1588179551Sjhb /* Send packet length to card */ 1589179551Sjhb XE_OUTW(XE_EDP, len); 159047133Sobrien 1591179551Sjhb /* 1592179551Sjhb * Write packet to card using PIO (code stolen from the ed driver) 1593179551Sjhb */ 159447133Sobrien wantbyte = 0; 1595179551Sjhb while (mbp != NULL) { 1596179551Sjhb len = mbp->m_len; 1597179551Sjhb if (len > 0) { 1598179551Sjhb data = mtod(mbp, caddr_t); 1599179551Sjhb if (wantbyte) { /* Finish the last word */ 1600179551Sjhb savebyte[1] = *data; 1601179551Sjhb XE_OUTW(XE_EDP, *(u_short *)savebyte); 1602179551Sjhb data++; 1603179551Sjhb len--; 1604179551Sjhb wantbyte = 0; 1605179551Sjhb } 1606179551Sjhb if (len > 1) { /* Output contiguous words */ 1607179551Sjhb bus_write_multi_2(scp->port_res, XE_EDP, 1608179551Sjhb (uint16_t *)data, len >> 1); 1609179551Sjhb data += len & ~1; 1610179551Sjhb len &= 1; 1611179551Sjhb } 1612179551Sjhb if (len == 1) { /* Save last byte, if needed */ 1613179551Sjhb savebyte[0] = *data; 1614179551Sjhb wantbyte = 1; 1615179551Sjhb } 1616179551Sjhb } 1617179551Sjhb mbp = mbp->m_next; 1618179551Sjhb } 161947133Sobrien 1620179551Sjhb /* 1621179551Sjhb * Send last byte of odd-length packets 1622179551Sjhb */ 1623179551Sjhb if (wantbyte) 1624179551Sjhb XE_OUTB(XE_EDP, savebyte[0]); 1625121099Srsm 1626179551Sjhb /* 1627179551Sjhb * Can just tell CE3 cards to send; short packets will be 1628179551Sjhb * padded out with random cruft automatically. For CE2, 1629179551Sjhb * manually pad the packet with garbage; it will be sent when 1630179551Sjhb * the required number of bytes have been delivered to the 1631179551Sjhb * card. 1632179551Sjhb */ 1633179551Sjhb if (scp->mohawk) 1634179551Sjhb XE_OUTB(XE_CR, XE_CR_TX_PACKET | XE_CR_RESTART_TX | 1635179551Sjhb XE_CR_ENABLE_INTR); 1636179551Sjhb else if (pad > 0) { 1637179551Sjhb if (pad & 0x01) 1638179551Sjhb XE_OUTB(XE_EDP, 0xaa); 1639179551Sjhb pad >>= 1; 1640179551Sjhb while (pad > 0) { 1641179551Sjhb XE_OUTW(XE_EDP, 0xdead); 1642179551Sjhb pad--; 1643179551Sjhb } 1644179551Sjhb } 164547133Sobrien 1646179551Sjhb return (0); 164747133Sobrien} 164847133Sobrien 164947133Sobrien/************************************************************** 165047133Sobrien * * 165147133Sobrien * M I I F U N C T I O N S * 165247133Sobrien * * 165347133Sobrien **************************************************************/ 165447133Sobrien 165547133Sobrien/* 165647133Sobrien * Alternative MII/PHY handling code adapted from the xl driver. It doesn't 165747133Sobrien * seem to work any better than the xirc2_ps stuff, but it's cleaner code. 165848117Sobrien * XXX - this stuff shouldn't be here. It should all be abstracted off to 165948117Sobrien * XXX - some kind of common MII-handling code, shared by all drivers. But 166048117Sobrien * XXX - that's a whole other mission. 166147133Sobrien */ 1662179551Sjhb#define XE_MII_SET(x) XE_OUTB(XE_GPR2, (XE_INB(XE_GPR2) | 0x04) | (x)) 1663179551Sjhb#define XE_MII_CLR(x) XE_OUTB(XE_GPR2, (XE_INB(XE_GPR2) | 0x04) & ~(x)) 166447133Sobrien 166547133Sobrien/* 166647133Sobrien * Sync the PHYs by setting data bit and strobing the clock 32 times. 166747133Sobrien */ 166847133Sobrienstatic void 1669179551Sjhbxe_mii_sync(struct xe_softc *scp) 1670179551Sjhb{ 1671179551Sjhb int i; 167247133Sobrien 1673179551Sjhb XE_SELECT_PAGE(2); 1674179551Sjhb XE_MII_SET(XE_MII_DIR|XE_MII_WRD); 167547133Sobrien 1676179551Sjhb for (i = 0; i < 32; i++) { 1677179551Sjhb XE_MII_SET(XE_MII_CLK); 1678179551Sjhb DELAY(1); 1679179551Sjhb XE_MII_CLR(XE_MII_CLK); 1680179551Sjhb DELAY(1); 1681179551Sjhb } 168247133Sobrien} 168347133Sobrien 168447133Sobrien/* 168547136Sobrien * Look for a MII-compliant PHY. If we find one, reset it. 168647136Sobrien */ 168747136Sobrienstatic int 1688179551Sjhbxe_mii_init(struct xe_softc *scp) 1689179551Sjhb{ 1690179551Sjhb uint16_t status; 169147136Sobrien 1692179551Sjhb status = xe_phy_readreg(scp, PHY_BMSR); 1693179551Sjhb if ((status & 0xff00) != 0x7800) { 1694179551Sjhb DEVPRINTF(2, (scp->dev, "no PHY found, %0x\n", status)); 1695179551Sjhb return (0); 1696179551Sjhb } else { 1697179551Sjhb DEVPRINTF(2, (scp->dev, "PHY OK!\n")); 169847136Sobrien 1699179551Sjhb /* Reset the PHY */ 1700179551Sjhb xe_phy_writereg(scp, PHY_BMCR, PHY_BMCR_RESET); 1701179551Sjhb DELAY(500); 1702179551Sjhb while(xe_phy_readreg(scp, PHY_BMCR) & PHY_BMCR_RESET) 1703179551Sjhb ; /* nothing */ 1704179551Sjhb XE_MII_DUMP(scp); 1705179551Sjhb return (1); 1706179551Sjhb } 170747136Sobrien} 170847136Sobrien 170947136Sobrien/* 171047133Sobrien * Clock a series of bits through the MII. 171147133Sobrien */ 171247133Sobrienstatic void 1713179551Sjhbxe_mii_send(struct xe_softc *scp, uint32_t bits, int cnt) 1714179551Sjhb{ 1715179551Sjhb int i; 171647133Sobrien 1717179551Sjhb XE_SELECT_PAGE(2); 1718179551Sjhb XE_MII_CLR(XE_MII_CLK); 171947133Sobrien 1720179551Sjhb for (i = (0x1 << (cnt - 1)); i; i >>= 1) { 1721179551Sjhb if (bits & i) { 1722179551Sjhb XE_MII_SET(XE_MII_WRD); 1723179551Sjhb } else { 1724179551Sjhb XE_MII_CLR(XE_MII_WRD); 1725179551Sjhb } 1726179551Sjhb DELAY(1); 1727179551Sjhb XE_MII_CLR(XE_MII_CLK); 1728179551Sjhb DELAY(1); 1729179551Sjhb XE_MII_SET(XE_MII_CLK); 1730179551Sjhb } 173147133Sobrien} 173247133Sobrien 173347133Sobrien/* 173447133Sobrien * Read an PHY register through the MII. 173547133Sobrien */ 173647133Sobrienstatic int 1737179551Sjhbxe_mii_readreg(struct xe_softc *scp, struct xe_mii_frame *frame) 1738179551Sjhb{ 1739179551Sjhb int i, ack; 174047133Sobrien 1741179551Sjhb XE_ASSERT_LOCKED(scp); 174247133Sobrien 1743179551Sjhb /* 1744179551Sjhb * Set up frame for RX. 1745179551Sjhb */ 1746179551Sjhb frame->mii_stdelim = XE_MII_STARTDELIM; 1747179551Sjhb frame->mii_opcode = XE_MII_READOP; 1748179551Sjhb frame->mii_turnaround = 0; 1749179551Sjhb frame->mii_data = 0; 175047133Sobrien 1751179551Sjhb XE_SELECT_PAGE(2); 1752179551Sjhb XE_OUTB(XE_GPR2, 0); 175347133Sobrien 1754179551Sjhb /* 1755179551Sjhb * Turn on data xmit. 1756179551Sjhb */ 1757179551Sjhb XE_MII_SET(XE_MII_DIR); 175847133Sobrien 1759179551Sjhb xe_mii_sync(scp); 176047133Sobrien 1761179551Sjhb /* 1762179551Sjhb * Send command/address info. 1763179551Sjhb */ 1764179551Sjhb xe_mii_send(scp, frame->mii_stdelim, 2); 1765179551Sjhb xe_mii_send(scp, frame->mii_opcode, 2); 1766179551Sjhb xe_mii_send(scp, frame->mii_phyaddr, 5); 1767179551Sjhb xe_mii_send(scp, frame->mii_regaddr, 5); 176847133Sobrien 1769179551Sjhb /* Idle bit */ 1770179551Sjhb XE_MII_CLR((XE_MII_CLK|XE_MII_WRD)); 1771179551Sjhb DELAY(1); 1772179551Sjhb XE_MII_SET(XE_MII_CLK); 1773179551Sjhb DELAY(1); 177447133Sobrien 1775179551Sjhb /* Turn off xmit. */ 1776179551Sjhb XE_MII_CLR(XE_MII_DIR); 177747133Sobrien 1778179551Sjhb /* Check for ack */ 1779179551Sjhb XE_MII_CLR(XE_MII_CLK); 1780179551Sjhb DELAY(1); 1781179551Sjhb ack = XE_INB(XE_GPR2) & XE_MII_RDD; 1782179551Sjhb XE_MII_SET(XE_MII_CLK); 1783179551Sjhb DELAY(1); 178447133Sobrien 1785179551Sjhb /* 1786179551Sjhb * Now try reading data bits. If the ack failed, we still 1787179551Sjhb * need to clock through 16 cycles to keep the PHY(s) in sync. 1788179551Sjhb */ 1789179551Sjhb if (ack) { 1790179551Sjhb for(i = 0; i < 16; i++) { 1791179551Sjhb XE_MII_CLR(XE_MII_CLK); 1792179551Sjhb DELAY(1); 1793179551Sjhb XE_MII_SET(XE_MII_CLK); 1794179551Sjhb DELAY(1); 1795179551Sjhb } 1796179551Sjhb goto fail; 1797179551Sjhb } 179847133Sobrien 1799179551Sjhb for (i = 0x8000; i; i >>= 1) { 1800179551Sjhb XE_MII_CLR(XE_MII_CLK); 1801179551Sjhb DELAY(1); 1802179551Sjhb if (!ack) { 1803179551Sjhb if (XE_INB(XE_GPR2) & XE_MII_RDD) 1804179551Sjhb frame->mii_data |= i; 1805179551Sjhb DELAY(1); 1806179551Sjhb } 1807179551Sjhb XE_MII_SET(XE_MII_CLK); 1808179551Sjhb DELAY(1); 1809179551Sjhb } 181047133Sobrien 181147133Sobrienfail: 1812179551Sjhb XE_MII_CLR(XE_MII_CLK); 1813179551Sjhb DELAY(1); 1814179551Sjhb XE_MII_SET(XE_MII_CLK); 1815179551Sjhb DELAY(1); 181647133Sobrien 1817179551Sjhb if (ack) 1818179551Sjhb return(1); 1819179551Sjhb return(0); 182047133Sobrien} 182147133Sobrien 182247133Sobrien/* 182347133Sobrien * Write to a PHY register through the MII. 182447133Sobrien */ 182547133Sobrienstatic int 1826179551Sjhbxe_mii_writereg(struct xe_softc *scp, struct xe_mii_frame *frame) 1827179551Sjhb{ 182847133Sobrien 1829179551Sjhb XE_ASSERT_LOCKED(scp); 183047133Sobrien 1831179551Sjhb /* 1832179551Sjhb * Set up frame for TX. 1833179551Sjhb */ 1834179551Sjhb frame->mii_stdelim = XE_MII_STARTDELIM; 1835179551Sjhb frame->mii_opcode = XE_MII_WRITEOP; 1836179551Sjhb frame->mii_turnaround = XE_MII_TURNAROUND; 183747133Sobrien 1838179551Sjhb XE_SELECT_PAGE(2); 183947133Sobrien 1840179551Sjhb /* 1841179551Sjhb * Turn on data output. 1842179551Sjhb */ 1843179551Sjhb XE_MII_SET(XE_MII_DIR); 184447133Sobrien 1845179551Sjhb xe_mii_sync(scp); 184647133Sobrien 1847179551Sjhb xe_mii_send(scp, frame->mii_stdelim, 2); 1848179551Sjhb xe_mii_send(scp, frame->mii_opcode, 2); 1849179551Sjhb xe_mii_send(scp, frame->mii_phyaddr, 5); 1850179551Sjhb xe_mii_send(scp, frame->mii_regaddr, 5); 1851179551Sjhb xe_mii_send(scp, frame->mii_turnaround, 2); 1852179551Sjhb xe_mii_send(scp, frame->mii_data, 16); 185347133Sobrien 1854179551Sjhb /* Idle bit. */ 1855179551Sjhb XE_MII_SET(XE_MII_CLK); 1856179551Sjhb DELAY(1); 1857179551Sjhb XE_MII_CLR(XE_MII_CLK); 1858179551Sjhb DELAY(1); 185947133Sobrien 1860179551Sjhb /* 1861179551Sjhb * Turn off xmit. 1862179551Sjhb */ 1863179551Sjhb XE_MII_CLR(XE_MII_DIR); 186447133Sobrien 1865179551Sjhb return(0); 186647133Sobrien} 186747133Sobrien 186847136Sobrien/* 186947136Sobrien * Read a register from the PHY. 187047136Sobrien */ 1871179551Sjhbstatic uint16_t 1872179551Sjhbxe_phy_readreg(struct xe_softc *scp, uint16_t reg) 1873179551Sjhb{ 1874179551Sjhb struct xe_mii_frame frame; 187547133Sobrien 1876179551Sjhb bzero((char *)&frame, sizeof(frame)); 187747133Sobrien 1878179551Sjhb frame.mii_phyaddr = 0; 1879179551Sjhb frame.mii_regaddr = reg; 1880179551Sjhb xe_mii_readreg(scp, &frame); 188147133Sobrien 1882179551Sjhb return (frame.mii_data); 188347133Sobrien} 188447133Sobrien 188547136Sobrien/* 188647136Sobrien * Write to a PHY register. 188747136Sobrien */ 188847133Sobrienstatic void 1889179551Sjhbxe_phy_writereg(struct xe_softc *scp, uint16_t reg, uint16_t data) 1890179551Sjhb{ 1891179551Sjhb struct xe_mii_frame frame; 189247133Sobrien 1893179551Sjhb bzero((char *)&frame, sizeof(frame)); 189447133Sobrien 1895179551Sjhb frame.mii_phyaddr = 0; 1896179551Sjhb frame.mii_regaddr = reg; 1897179551Sjhb frame.mii_data = data; 1898179551Sjhb xe_mii_writereg(scp, &frame); 189947133Sobrien} 190047133Sobrien 190147145Sobrien/* 190247145Sobrien * A bit of debugging code. 190347145Sobrien */ 190447133Sobrienstatic void 1905179551Sjhbxe_mii_dump(struct xe_softc *scp) 1906179551Sjhb{ 1907179551Sjhb int i; 190847133Sobrien 1909179551Sjhb device_printf(scp->dev, "MII registers: "); 1910179551Sjhb for (i = 0; i < 2; i++) { 1911179551Sjhb printf(" %d:%04x", i, xe_phy_readreg(scp, i)); 1912179551Sjhb } 1913179551Sjhb for (i = 4; i < 7; i++) { 1914179551Sjhb printf(" %d:%04x", i, xe_phy_readreg(scp, i)); 1915179551Sjhb } 1916179551Sjhb printf("\n"); 191747133Sobrien} 191847133Sobrien 1919122170Srsm#if 0 1920122106Simpvoid 1921179551Sjhbxe_reg_dump(struct xe_softc *scp) 1922179551Sjhb{ 1923179551Sjhb int page, i; 192447133Sobrien 1925179551Sjhb device_printf(scp->dev, "Common registers: "); 1926179551Sjhb for (i = 0; i < 8; i++) { 1927179551Sjhb printf(" %2.2x", XE_INB(i)); 1928179551Sjhb } 1929179551Sjhb printf("\n"); 193047133Sobrien 1931179551Sjhb for (page = 0; page <= 8; page++) { 1932179551Sjhb device_printf(scp->dev, "Register page %2.2x: ", page); 1933179551Sjhb XE_SELECT_PAGE(page); 1934179551Sjhb for (i = 8; i < 16; i++) { 1935179551Sjhb printf(" %2.2x", XE_INB(i)); 1936179551Sjhb } 1937179551Sjhb printf("\n"); 1938179551Sjhb } 193947133Sobrien 1940179551Sjhb for (page = 0x10; page < 0x5f; page++) { 1941179551Sjhb if ((page >= 0x11 && page <= 0x3f) || 1942179551Sjhb (page == 0x41) || 1943179551Sjhb (page >= 0x43 && page <= 0x4f) || 1944179551Sjhb (page >= 0x59)) 1945179551Sjhb continue; 1946179551Sjhb device_printf(scp->dev, "Register page %2.2x: ", page); 1947179551Sjhb XE_SELECT_PAGE(page); 1948179551Sjhb for (i = 8; i < 16; i++) { 1949179551Sjhb printf(" %2.2x", XE_INB(i)); 1950179551Sjhb } 1951179551Sjhb printf("\n"); 1952179551Sjhb } 195347133Sobrien} 1954122170Srsm#endif 195547133Sobrien 195655723Simpint 195755723Simpxe_activate(device_t dev) 195855723Simp{ 195955723Simp struct xe_softc *sc = device_get_softc(dev); 1960179492Sjhb int start, i; 196147133Sobrien 1962122081Srsm DEVPRINTF(2, (dev, "activate\n")); 1963121099Srsm 1964121099Srsm if (!sc->modem) { 196561084Simp sc->port_rid = 0; /* 0 is managed by pccard */ 196661084Simp sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, 1967179551Sjhb &sc->port_rid, 0ul, ~0ul, 16, RF_ACTIVE); 1968179551Sjhb } else if (sc->dingo) { 196961084Simp /* 197061084Simp * Find a 16 byte aligned ioport for the card. 197161084Simp */ 1972122081Srsm DEVPRINTF(1, (dev, "Finding an aligned port for RealPort\n")); 197361084Simp sc->port_rid = 1; /* 0 is managed by pccard */ 197461084Simp start = 0x100; 197561084Simp do { 1976179551Sjhb sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, 1977179551Sjhb &sc->port_rid, start, 0x3ff, 16, RF_ACTIVE); 1978179551Sjhb if (sc->port_res == NULL) 1979179551Sjhb break; 198061084Simp if ((rman_get_start(sc->port_res) & 0xf) == 0) 1981179551Sjhb break; 198261084Simp bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid, 198361084Simp sc->port_res); 198461084Simp start = (rman_get_start(sc->port_res) + 15) & ~0xf; 198561084Simp } while (1); 1986122081Srsm DEVPRINTF(1, (dev, "RealPort port 0x%0lx, size 0x%0lx\n", 1987121099Srsm bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid), 1988122081Srsm bus_get_resource_count(dev, SYS_RES_IOPORT, sc->port_rid))); 1989179551Sjhb } else if (sc->ce2) { 1990179551Sjhb /* 1991179551Sjhb * Find contiguous I/O port for the Ethernet function 1992179551Sjhb * on CEM2 and CEM3 cards. We allocate window 0 1993179551Sjhb * wherever pccard has decided it should be, then find 1994179551Sjhb * an available window adjacent to it for the second 1995179551Sjhb * function. Not sure that both windows are actually 1996179551Sjhb * needed. 1997179551Sjhb */ 1998179551Sjhb DEVPRINTF(1, (dev, "Finding I/O port for CEM2/CEM3\n")); 1999179551Sjhb sc->ce2_port_rid = 0; /* 0 is managed by pccard */ 2000179551Sjhb sc->ce2_port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, 2001179551Sjhb &sc->ce2_port_rid, 0ul, ~0ul, 8, RF_ACTIVE); 2002179551Sjhb if (sc->ce2_port_res == NULL) { 2003179551Sjhb DEVPRINTF(1, (dev, 2004179551Sjhb "Cannot allocate I/O port for modem\n")); 2005179551Sjhb xe_deactivate(dev); 2006179551Sjhb return (ENOMEM); 2007179551Sjhb } 2008121099Srsm 2009179551Sjhb sc->port_rid = 1; 2010179551Sjhb start = bus_get_resource_start(dev, SYS_RES_IOPORT, 2011179551Sjhb sc->ce2_port_rid); 2012179551Sjhb for (i = 0; i < 2; i++) { 2013179551Sjhb start += (i == 0 ? 8 : -24); 2014179551Sjhb sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, 2015179551Sjhb &sc->port_rid, start, start + 15, 16, RF_ACTIVE); 2016179551Sjhb if (sc->port_res == NULL) 2017179551Sjhb continue; 2018179551Sjhb if (bus_get_resource_start(dev, SYS_RES_IOPORT, 2019179551Sjhb sc->port_rid) == start) 2020179551Sjhb break; 2021121099Srsm 2022179551Sjhb bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid, 2023179551Sjhb sc->port_res); 2024179551Sjhb sc->port_res = NULL; 2025179551Sjhb } 2026122081Srsm DEVPRINTF(1, (dev, "CEM2/CEM3 port 0x%0lx, size 0x%0lx\n", 202761084Simp bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid), 2028122081Srsm bus_get_resource_count(dev, SYS_RES_IOPORT, sc->port_rid))); 202961084Simp } 2030121099Srsm 203155723Simp if (!sc->port_res) { 2032122081Srsm DEVPRINTF(1, (dev, "Cannot allocate ioport\n")); 2033148030Simp xe_deactivate(dev); 2034179551Sjhb return (ENOMEM); 203555723Simp } 203647133Sobrien 203755723Simp sc->irq_rid = 0; 2038127135Snjl sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, 2039127135Snjl RF_ACTIVE); 2040179551Sjhb if (sc->irq_res == NULL) { 2041122081Srsm DEVPRINTF(1, (dev, "Cannot allocate irq\n")); 204255723Simp xe_deactivate(dev); 2043179551Sjhb return (ENOMEM); 204455723Simp } 204559620Simp 204655723Simp return (0); 204755723Simp} 204847151Sobrien 204955723Simpvoid 205055723Simpxe_deactivate(device_t dev) 205155723Simp{ 205255723Simp struct xe_softc *sc = device_get_softc(dev); 205355723Simp 2054122081Srsm DEVPRINTF(2, (dev, "deactivate\n")); 205555723Simp if (sc->intrhand) 205655723Simp bus_teardown_intr(dev, sc->irq_res, sc->intrhand); 2057179551Sjhb sc->intrhand = NULL; 205855723Simp if (sc->port_res) 205955723Simp bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid, 206055723Simp sc->port_res); 2061179551Sjhb sc->port_res = NULL; 2062121099Srsm if (sc->ce2_port_res) 2063121099Srsm bus_release_resource(dev, SYS_RES_IOPORT, sc->ce2_port_rid, 2064179551Sjhb sc->ce2_port_res); 2065179551Sjhb sc->ce2_port_res = NULL; 206655723Simp if (sc->irq_res) 206755723Simp bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, 206855723Simp sc->irq_res); 2069179551Sjhb sc->irq_res = NULL; 2070179492Sjhb if (sc->ifp) 2071179492Sjhb if_free(sc->ifp); 2072179551Sjhb sc->ifp = NULL; 207347133Sobrien} 2074