From 90bba6bf72c1adb0eb71235c7b2e72e56d78bcf8 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Mon, 10 Jan 2000 08:05:53 +0000 Subject: [PATCH] Move xe driver from dev/pccard to dev/xe. Convert driver to newbus. Driver is not functional yet, but does compile. Tests with xe cards indicates that it doesn't panic the machine when they are present, but fail to probe. Interface help in the pcic/pccard layers are needed to complete this driver. --- sys/conf/files | 2 +- sys/conf/files.i386 | 1 - sys/dev/pccard/if_xe.c | 2500 ------------------------------------- sys/dev/pccard/if_xereg.h | 697 ----------- sys/dev/xe/if_xe.c | 864 +++++-------- sys/dev/xe/if_xereg.h | 10 +- sys/dev/xe/if_xevar.h | 85 ++ 7 files changed, 411 insertions(+), 3748 deletions(-) delete mode 100644 sys/dev/pccard/if_xe.c delete mode 100644 sys/dev/pccard/if_xereg.h create mode 100644 sys/dev/xe/if_xevar.h diff --git a/sys/conf/files b/sys/conf/files index fd7a87314497..6427b6e86d48 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -293,7 +293,7 @@ dev/vinum/vinumstate.c optional vinum dev/vinum/vinumutil.c optional vinum dev/vn/vn.c optional vn dev/vx/if_vx.c optional vx -#dev/xe/if_xe.c optional xe +dev/xe/if_xe.c optional xe gnu/ext2fs/ext2_alloc.c optional ext2fs gnu/ext2fs/ext2_balloc.c optional ext2fs gnu/ext2fs/ext2_inode.c optional ext2fs diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index 148d0bc73810..18b060afeead 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -83,7 +83,6 @@ dev/kbd/kbd.c optional kbd dev/kbd/kbd.c optional sc dev/kbd/kbd.c optional ukbd dev/kbd/kbd.c optional vt -dev/pccard/if_xe.c optional xe dev/sound/isa/ad1816.c optional pcm isa dev/sound/isa/es1888.c optional pcm isa dev/sound/isa/gusc.c optional gusc isa diff --git a/sys/dev/pccard/if_xe.c b/sys/dev/pccard/if_xe.c deleted file mode 100644 index 715ab79191de..000000000000 --- a/sys/dev/pccard/if_xe.c +++ /dev/null @@ -1,2500 +0,0 @@ -/*- - * Copyright (c) 1998, 1999 Scott Mitchell - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: if_xe.c,v 1.20 1999/06/13 19:17:40 scott Exp $ - * $FreeBSD$ - */ - -/* - * Portions of this software were derived from Werner Koch's xirc2ps driver - * for Linux under the terms of the following license (from v1.30 of the - * xirc2ps driver): - * - * Copyright (c) 1997 by Werner Koch (dd9jn) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * FreeBSD device driver for Xircom CreditCard PCMCIA Ethernet adapters. The - * following cards are currently known to work with the driver: - * Xircom CreditCard 10/100 (CE3) - * Xircom CreditCard Ethernet + Modem 28 (CEM28) - * Xircom CreditCard Ethernet 10/100 + Modem 56 (CEM56) - * Xircom RealPort Ethernet 10 - * Xircom RealPort Ethernet 10/100 - * Xircom RealPort Ethernet 10/100 + Modem 56 (REM56, REM56G) - * Intel EtherExpress Pro/100 PC Card Mobile Adapter 16 (Pro/100 M16A) - * Compaq Netelligent 10/100 PC Card (CPQ-10/100) - * - * Some other cards *should* work, but support for them is either broken or in - * an unknown state at the moment. I'm always interested in hearing from - * people who own any of these cards: - * Xircom CreditCard 10Base-T (PS-CE2-10) - * Xircom CreditCard Ethernet + ModemII (CEM2) - * Xircom CEM28 and CEM33 Ethernet/Modem cards (may be variants of CEM2?) - * - * Thanks to all who assisted with the development and testing of the driver, - * especially: Werner Koch, Duke Kamstra, Duncan Barclay, Jason George, Dru - * Nelson, Mike Kephart, Bill Rainey and Douglas Rand. Apologies if I've left - * out anyone who deserves a mention here. - * - * Special thanks to Ade Lovett for both hosting the mailing list and doing - * the CEM56/REM56 support code; and the FreeBSD UK Users' Group for hosting - * the web pages. - * - * Contact points: - * - * Driver web page: http://ukug.uk.freebsd.org/~scott/xe_drv/ - * - * Mailing list: http://www.lovett.com/lists/freebsd-xircom/ - * or send "subscribe freebsd-xircom" to - * - * Author email: - */ - - -#ifndef XE_DEBUG -#define XE_DEBUG 1 /* Increase for more voluminous output! */ -#endif - -#include "xe.h" -#include "card.h" -#include "apm.h" - -#if NXE > 0 - -#undef NCARD -#define NCARD 0 -#if NCARD > 0 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#if NAPM > 0 -#include -#endif /* NAPM > 0 */ - -#include -#include -#include -#include - - - -/* - * One of these structures per allocated device - */ -struct xe_softc { - struct arpcom arpcom; - struct ifmedia ifmedia; - struct ifmib_iso_8802_3 mibdata; - struct callout_handle chand; - struct isa_device *dev; - struct pccard_devinfo *crd; - struct ifnet *ifp; - struct ifmedia *ifm; - char *card_type; /* Card model name */ - char *vendor; /* Card manufacturer */ - int unit; /* Unit number, from dev->id_unit */ - int srev; /* Silicon revision */ - int tx_queued; /* Packets currently waiting to transmit */ - int tx_tpr; /* Last value of TPR reg on card */ - int tx_collisions; /* Collisions since last successful send */ - int tx_timeouts; /* Count of transmit timeouts */ - int autoneg_status; /* Autonegotiation progress state */ - int media; /* Private media word */ - u_char version; /* Bonding Version register from card */ - u_char modem; /* 1 = Card has a modem */ - u_char ce2; /* 1 = Card has CE2 silicon */ - u_char mohawk; /* 1 = Card has Mohawk (CE3) silicon */ - u_char dingo; /* 1 = Card has Dingo (CEM56) silicon */ - u_char phy_ok; /* 1 = MII-compliant PHY found and initialised */ - u_char gone; /* 1 = Card bailed out */ -#if NAPM > 0 - struct apmhook suspend_hook; - struct apmhook resume_hook; -#endif /* NAPM > 0 */ -}; - -static struct xe_softc *sca[MAXSLOT]; - - -/* - * MII command structure - */ -struct xe_mii_frame { - u_int8_t mii_stdelim; - u_int8_t mii_opcode; - u_int8_t mii_phyaddr; - u_int8_t mii_regaddr; - u_int8_t mii_turnaround; - u_int16_t mii_data; -}; - -/* - * For accessing card registers - */ -#define XE_INB(r) inb(scp->dev->id_iobase+(r)) -#define XE_INW(r) inw(scp->dev->id_iobase+(r)) -#define XE_OUTB(r, b) outb(scp->dev->id_iobase+(r), (b)) -#define XE_OUTW(r, w) outw(scp->dev->id_iobase+(r), (w)) -#define XE_SELECT_PAGE(p) XE_OUTB(XE_PR, (p)) - -/* - * Horrid stuff for accessing CIS tuples - */ -#define CARD_MAJOR 50 -#define CISTPL_BUFSIZE 512 -#define CISTPL_TYPE(tpl) tpl[0] -#define CISTPL_LEN(tpl) tpl[2] -#define CISTPL_DATA(tpl,pos) tpl[4 + ((pos)<<1)] - -/* - * Media autonegotiation progress constants - */ -#define XE_AUTONEG_NONE 0 /* No autonegotiation in progress */ -#define XE_AUTONEG_WAITING 1 /* Waiting for transmitter to go idle */ -#define XE_AUTONEG_STARTED 2 /* Waiting for autonegotiation to complete */ -#define XE_AUTONEG_100TX 3 /* Trying to force 100baseTX link */ -#define XE_AUTONEG_FAIL 4 /* Autonegotiation failed */ - - -/* - * Prototypes start here - */ -static int xe_probe (struct isa_device *dev); -static int xe_card_init (struct pccard_devinfo *devi); -static int xe_attach (struct isa_device *dev); -static void xe_init (void *xscp); -static void xe_start (struct ifnet *ifp); -static int xe_ioctl (struct ifnet *ifp, u_long command, caddr_t data); -static int xe_card_intr (struct pccard_devinfo *devi); -static void xe_watchdog (struct ifnet *ifp); -static int xe_media_change (struct ifnet *ifp); -static void xe_media_status (struct ifnet *ifp, struct ifmediareq *mrp); -static timeout_t xe_setmedia; -static void xe_hard_reset (struct xe_softc *scp); -static void xe_soft_reset (struct xe_softc *scp); -static void xe_stop (struct xe_softc *scp); -static void xe_enable_intr (struct xe_softc *scp); -static void xe_disable_intr (struct xe_softc *scp); -static void xe_setmulti (struct xe_softc *scp); -static void xe_setaddrs (struct xe_softc *scp); -static int xe_pio_write_packet (struct xe_softc *scp, struct mbuf *mbp); -static void xe_card_unload (struct pccard_devinfo *devi); -static u_int32_t xe_compute_crc (u_int8_t *data, int len); -static int xe_compute_hashbit (u_int32_t crc); - -/* - * MII functions - */ -static void xe_mii_sync (struct xe_softc *scp); -static int xe_mii_init (struct xe_softc *scp); -static void xe_mii_send (struct xe_softc *scp, u_int32_t bits, int cnt); -static int xe_mii_readreg (struct xe_softc *scp, struct xe_mii_frame *frame); -static int xe_mii_writereg (struct xe_softc *scp, struct xe_mii_frame *frame); -static u_int16_t xe_phy_readreg (struct xe_softc *scp, u_int16_t reg); -static void xe_phy_writereg (struct xe_softc *scp, u_int16_t reg, u_int16_t data); - -/* - * Debug functions - */ -#ifdef XE_DEBUG -#define XE_REG_DUMP(scp) xe_reg_dump((scp)) -#define XE_MII_DUMP(scp) xe_mii_dump((scp)) -static void xe_reg_dump (struct xe_softc *scp); -static void xe_mii_dump (struct xe_softc *scp); -#else -#define XE_REG_DUMP(scp) -#define XE_MII_DUMP(scp) -#endif - -#if NAPM > 0 -/* - * APM hook functions - */ -static int xe_suspend (void *xunit); -static int xe_resume (void *xunit); -#endif /* NAPM > 0 */ - - -/* - * PCMCIA driver hooks - */ -#ifdef PCCARD_MODULE -PCCARD_MODULE(xe, xe_card_init, xe_card_unload, xe_card_intr, 0, net_imask); -#else -static struct pccard_device xe_info = { /* For pre 3.1-STABLE code */ - "xe", - xe_card_init, - xe_card_unload, - xe_card_intr, - 0, - &net_imask -}; -DATA_SET(pccarddrv_set, xe_info); -#endif /* PCCARD_MODULE */ - - -/* - * ISA driver hooks. I'd like to do without these but the kernel config stuff - * seems to require them. - */ -struct isa_driver xedriver = { - xe_probe, - xe_attach, - "xe" -}; - - - -/* - * ISA probe routine. - * All of the supported devices are PCMCIA cards. I have no idea if it's even - * possible to successfully probe/attach these at boot time (pccardd normally - * does a lot of setup work) so I don't even bother trying. - */ -static int -xe_probe (struct isa_device *dev) { -#ifdef XE_DEBUG - printf("xe%d: probe\n", dev->id_unit); -#endif - bzero(sca, MAXSLOT * sizeof(sca[0])); - return 0; -} - - -/* - * Two routines to read from/write to the attribute memory - * the write portion is used only for fixing up the RealPort cards, - * the reader portion was needed for debugging info, and duplicated some - * code in xe_card_init(), so it appears here instead with suitable - * modifications to xe_card_init() - * -aDe Lovett - */ -static int -xe_memwrite(struct pccard_devinfo *devi, off_t offset, u_char byte) -{ - struct iovec iov; - struct uio uios; - - iov.iov_base = &byte; - iov.iov_len = sizeof(byte); - - uios.uio_iov = &iov; - uios.uio_iovcnt = 1; - uios.uio_offset = offset; - uios.uio_resid = sizeof(byte); - uios.uio_segflg = UIO_SYSSPACE; - uios.uio_rw = UIO_WRITE; - uios.uio_procp = 0; - -#if 0 /* THIS IS BOGUS */ - return cdevsw[CARD_MAJOR]->d_write(makedev(CARD_MAJOR, devi->slt->slotnum), &uios, 0); -#else - return (-1); -#endif -} - - -static int -xe_memread(struct pccard_devinfo *devi, off_t offset, u_char *buf, int size) -{ - struct iovec iov; - struct uio uios; - - iov.iov_base = buf; - iov.iov_len = size; - - uios.uio_iov = &iov; - uios.uio_iovcnt = 1; - uios.uio_offset = offset; - uios.uio_resid = size; - uios.uio_segflg = UIO_SYSSPACE; - uios.uio_rw = UIO_READ; - uios.uio_procp = 0; - -#if 0 /* THIS IS BOGUS */ - return cdevsw[CARD_MAJOR]->d_read(makedev(CARD_MAJOR, devi->slt->slotnum), &uios, 0); -#else - return (-1); -#endif -} - - -/* - * Hacking for RealPort cards - */ -static int -xe_cem56fix(struct xe_softc *scp) -{ - struct pccard_devinfo *devi; - struct slot *slt; - struct slot_ctrl *ctrl; - int ioport, fail; - - /* initialise a few variables */ - devi = scp->crd; - slt = devi->slt; - ctrl = slt->ctrl; - - /* allocate a new I/O slot for the ethernet */ - /* XXX: ctrl->mapio() always appears to return 0 (success), so - * this may cause problems if another device is listening - * on 0x300 already. In this case, you should choose a - * known free I/O port address in the kernel config line - * for the driver. It will be picked up here and used - * instead of the autodetected value. - */ - slt->io[1].window = 1; - slt->io[1].flags = IODF_WS|IODF_16BIT|IODF_ZEROWS|IODF_ACTIVE; - slt->io[1].size = 0x10; - -#ifdef XE_IOBASE - - printf( "xe%d: user requested ioport 0x%x\n", scp->unit, XE_IOBASE ); - ioport = XE_IOBASE; - slt->io[1].start = ioport; - fail = ctrl->mapio(slt, 1); - -#else - - for (ioport = 0x300; ioport < 0x400; ioport += 0x10) { - slt->io[1].start = ioport; - if ((fail = ctrl->mapio( slt, 1 )) == 0) - break; - } - -#endif - - /* did we find one? */ - if (fail) { - printf( "xe%d: xe_cem56fix: no free address space\n", scp->unit ); - return -1; - } - - - /* munge the id_iobase entry for use by the rest of the driver */ -#if XE_DEBUG > 1 - printf( "xe%d: using 0x%x for RealPort ethernet\n", scp->unit, ioport ); -#endif - scp->dev->id_iobase = ioport; - scp->dev->id_alive = 0x10; - - /* magic to set up the ethernet */ - xe_memwrite( devi, DINGO_ECOR, DINGO_ECOR_IRQ_LEVEL|DINGO_ECOR_INT_ENABLE| - DINGO_ECOR_IOB_ENABLE|DINGO_ECOR_ETH_ENABLE ); - xe_memwrite( devi, DINGO_EBAR0, ioport & 0xff ); - xe_memwrite( devi, DINGO_EBAR1, (ioport >> 8) & 0xff ); - - xe_memwrite( devi, DINGO_DCOR0, DINGO_DCOR0_SF_INT ); - xe_memwrite( devi, DINGO_DCOR1, DINGO_DCOR1_INT_LEVEL|DINGO_DCOR1_EEDIO ); - xe_memwrite( devi, DINGO_DCOR2, 0x00 ); - xe_memwrite( devi, DINGO_DCOR3, 0x00 ); - xe_memwrite( devi, DINGO_DCOR4, 0x00 ); - - /* success! */ - return 0; -} - - -/* - * PCMCIA probe routine. - * Probe and identify the device. Called by the slot manager when the card is - * inserted or the machine wakes up from suspend mode. Assmes that the slot - * structure has been initialised already. - */ -static int -xe_card_init(struct pccard_devinfo *devi) -{ - struct xe_softc *scp; - struct isa_device *dev; - u_char buf[CISTPL_BUFSIZE]; - u_char ver_str[CISTPL_BUFSIZE>>1]; - off_t offs; - int unit, success, rc, i; - - unit = devi->isahd.id_unit; - scp = sca[unit]; - dev = &devi->isahd; - success = 0; - -#ifdef XE_DEBUG - printf("xe: Probing for unit %d\n", unit); -#endif - - /* Check that unit number is OK */ - if (unit > MAXSLOT) { - printf("xe%d: bad unit\n", unit); - return (ENODEV); - } - - /* Don't attach an active device */ - if (scp && !scp->gone) { - printf("xe%d: already attached\n", unit); - return (EBUSY); - } - - /* Allocate per-instance storage */ - if (!scp) { - if ((scp = malloc(sizeof(*scp), M_DEVBUF, M_NOWAIT)) == NULL) { - printf("xe%d: failed to allocage driver storage\n", unit); - return (ENOMEM); - } - bzero(scp, sizeof(*scp)); - } - - /* Re-attach an existing device */ - if (scp->gone) { - scp->gone = 0; - return 0; - } - - /* Grep through CIS looking for relevant tuples */ - offs = 0; - do { - u_int16_t vendor; - u_int8_t rev, media, prod; - - /* - * Read tuples one at a time into buf. Sucks, but it only happens once. - * XXX - This assumes that attribute has been mapped by pccardd, which - * XXX - seems to be the default situation. If not, we're well and truly - * XXX - FUBAR. This is a general PCCARD problem, not our fault :) - */ - if ((rc = xe_memread( devi, offs, buf, CISTPL_BUFSIZE )) == 0) { - - switch (CISTPL_TYPE(buf)) { - - case 0x15: /* Grab version string (needed to ID some weird CE2's) */ -#if XE_DEBUG > 1 - printf("xe%d: Got version string (0x15)\n", unit); -#endif - for (i = 0; i < CISTPL_LEN(buf); ver_str[i] = CISTPL_DATA(buf, i++)); - ver_str[i] = '\0'; - ver_str[(CISTPL_BUFSIZE>>1) - 1] = CISTPL_LEN(buf); - success++; - break; - - case 0x20: /* Figure out what type of card we have */ -#if XE_DEBUG > 1 - printf("xe%d: Got card ID (0x20)\n", unit); -#endif - vendor = CISTPL_DATA(buf, 0) + (CISTPL_DATA(buf, 1) << 8); - rev = CISTPL_DATA(buf, 2); - media = CISTPL_DATA(buf, 3); - prod = CISTPL_DATA(buf, 4); - - switch (vendor) { /* Get vendor ID */ - case 0x0105: - scp->vendor = "Xircom"; break; - case 0x0138: - case 0x0183: - scp->vendor = "Compaq"; break; - case 0x0089: - scp->vendor = "Intel"; break; - default: - scp->vendor = "Unknown"; - } - - if (!((prod & 0x40) && (media & 0x01))) { -#if XE_DEBUG > 1 - printf("xe%d: Not a PCMCIA Ethernet card!\n", unit); -#endif - rc = ENODEV; /* Not a PCMCIA Ethernet device */ - } - else { - if (media & 0x10) { /* Ethernet/modem cards */ -#if XE_DEBUG > 1 - printf("xe%d: Card is Ethernet/modem combo\n", unit); -#endif - scp->modem = 1; - switch (prod & 0x0f) { - case 1: - scp->card_type = "CEM"; break; - case 2: - scp->ce2 = 1; - scp->card_type = "CEM2"; break; - case 3: - scp->ce2 = 1; - scp->card_type = "CEM3"; break; - case 4: - scp->ce2 = 1; - scp->card_type = "CEM33"; break; - case 5: - scp->mohawk = 1; - scp->card_type = "CEM56M"; break; - case 6: - case 7: /* Some kind of RealPort card */ - scp->mohawk = 1; - scp->dingo = 1; - scp->card_type = "CEM56"; break; - default: - rc = ENODEV; - } - } - else { /* Ethernet-only cards */ -#if XE_DEBUG > 1 - printf("xe%d: Card is Ethernet only\n", unit); -#endif - switch (prod & 0x0f) { - case 1: - scp->card_type = "CE"; break; - case 2: - scp->ce2 = 1; - scp->card_type = "CE2"; break; - case 3: - scp->mohawk = 1; - scp->card_type = "CE3"; break; - default: - rc = ENODEV; - } - } - } - success++; - break; - - case 0x22: /* Get MAC address */ - if ((CISTPL_LEN(buf) == 8) && - (CISTPL_DATA(buf, 0) == 0x04) && - (CISTPL_DATA(buf, 1) == ETHER_ADDR_LEN)) { -#if XE_DEBUG > 1 - printf("xe%d: Got MAC address (0x22)\n", unit); -#endif - for (i = 0; i < ETHER_ADDR_LEN; scp->arpcom.ac_enaddr[i] = CISTPL_DATA(buf, i+2), i++); - } - success++; - break; - default: - } - } - - /* Skip to next tuple */ - offs += ((CISTPL_LEN(buf) + 2) << 1); - - } while ((CISTPL_TYPE(buf) != 0xff) && (CISTPL_LEN(buf) != 0xff) && (rc == 0)); - - - /* Die now if something went wrong above */ - if ((rc != 0) || (success < 3)) { - free(scp, M_DEVBUF); - return rc; - } - - /* Check for certain strange CE2's that look like CE's */ - if (strcmp(scp->card_type, "CE") == 0) { - u_char *str = ver_str; -#if XE_DEBUG > 1 - printf("xe%d: Checking for weird CE2 string\n", unit); -#endif - str += strlen(str) + 1; /* Skip forward to 3rd version string */ - str += strlen(str) + 1; - str += strlen(str) + 1; - for (i = 0; i < strlen(str) - 2; i++) { - if (bcmp(&str[i], "CE2", 3) ==0) { /* Look for "CE2" string */ - scp->card_type = "CE2"; - } - } - } - - /* Reject unsupported cards */ - if (strcmp(scp->card_type, "CE") == 0 || strcmp(scp->card_type, "CEM") == 0) { - printf("xe%d: Sorry, your %s card is not supported :(\n", unit, scp->card_type); - free(scp, M_DEVBUF); - return ENODEV; - } - - /* Fill in some private data */ - sca[unit] = scp; - scp->dev = &devi->isahd; - scp->crd = devi; - scp->ifp = &scp->arpcom.ac_if; - scp->ifm = &scp->ifmedia; - scp->unit = unit; - scp->autoneg_status = 0; - - /* Hack RealPorts into submission */ - if (scp->dingo && xe_cem56fix(scp) < 0) { - printf( "xe%d: Unable to fix your RealPort\n", unit ); - sca[unit] = 0; - free(scp, M_DEVBUF); - return ENODEV; - } - - /* Hopefully safe to read this here */ - XE_SELECT_PAGE(4); - scp->version = XE_INB(XE_BOV); - - /* Attempt to attach the device */ - if (!xe_attach(scp->dev)) { - sca[unit] = 0; - free(scp, M_DEVBUF); - return ENXIO; - } - -#if NAPM > 0 - /* Establish APM hooks once device attached */ - scp->suspend_hook.ah_name = "xe_suspend"; - scp->suspend_hook.ah_fun = xe_suspend; - scp->suspend_hook.ah_arg = (void *)unit; - scp->suspend_hook.ah_order = APM_MIN_ORDER; - apm_hook_establish(APM_HOOK_SUSPEND, &scp->suspend_hook); - scp->resume_hook.ah_name = "xe_resume"; - scp->resume_hook.ah_fun = xe_resume; - scp->resume_hook.ah_arg = (void *)unit; - scp->resume_hook.ah_order = APM_MIN_ORDER; - apm_hook_establish(APM_HOOK_RESUME, &scp->resume_hook); -#endif /* NAPM > 0 */ - - /* Success */ - return 0; -} - - -/* - * Attach a device (called when xe_card_init succeeds). Assume that the probe - * routine has set up the softc structure correctly and that we can trust the - * unit number. - */ -static int -xe_attach (struct isa_device *dev) { - struct xe_softc *scp = sca[dev->id_unit]; - int i; - -#ifdef XE_DEBUG - printf("xe%d: attach\n", scp->unit); -#endif - - /* Initialise the ifnet structure */ - if (!scp->ifp->if_name) { - scp->ifp->if_softc = scp; - scp->ifp->if_name = "xe"; - scp->ifp->if_unit = scp->unit; - scp->ifp->if_timer = 0; - scp->ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); - scp->ifp->if_linkmib = &scp->mibdata; - scp->ifp->if_linkmiblen = sizeof scp->mibdata; - scp->ifp->if_output = ether_output; - scp->ifp->if_start = xe_start; - scp->ifp->if_ioctl = xe_ioctl; - scp->ifp->if_watchdog = xe_watchdog; - scp->ifp->if_init = xe_init; - scp->ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; - } - - /* Initialise the ifmedia structure */ - ifmedia_init(scp->ifm, 0, xe_media_change, xe_media_status); - callout_handle_init(&scp->chand); - - /* - * Fill in supported media types. Some cards _do_ support full duplex - * operation, but this driver doesn't, yet. Therefore we leave those modes - * out of the list. We support some form of autoselection in all cases. - */ - if (scp->mohawk) { - ifmedia_add(scp->ifm, IFM_ETHER|IFM_100_TX, 0, NULL); - ifmedia_add(scp->ifm, IFM_ETHER|IFM_10_T, 0, NULL); - } - else { - ifmedia_add(scp->ifm, IFM_ETHER|IFM_10_T, 0, NULL); - ifmedia_add(scp->ifm, IFM_ETHER|IFM_10_2, 0, NULL); - } - ifmedia_add(scp->ifm, IFM_ETHER|IFM_AUTO, 0, NULL); - - /* Default is to autoselect best supported media type */ - ifmedia_set(scp->ifm, IFM_ETHER|IFM_AUTO); - - /* Print some useful information */ - printf("\n"); - printf("xe%d: %s %s, bonding version %#x%s%s\n", - scp->unit, - scp->vendor, - scp->card_type, - scp->version, - scp->mohawk ? ", 100Mbps capable" : "", - scp->modem ? ", with modem" : ""); - if (scp->mohawk) { - XE_SELECT_PAGE(0x10); - printf("xe%d: DingoID = %#x, RevisionID = %#x, VendorID = %#x\n", - scp->unit, - XE_INW(XE_DINGOID), - XE_INW(XE_RevID), - XE_INW(XE_VendorID)); - } - if (scp->ce2) { - XE_SELECT_PAGE(0x45); - printf("xe%d: CE2 version = %#x\n", - scp->unit, - XE_INB(XE_REV)); - } - - /* Print MAC address */ - printf("xe%d: Ethernet address %02x", scp->unit, scp->arpcom.ac_enaddr[0]); - for (i = 1; i < ETHER_ADDR_LEN; i++) { - printf(":%02x", scp->arpcom.ac_enaddr[i]); - } - printf("\n"); - - /* Attach the interface */ - if_attach(scp->ifp); - ether_ifattach(scp->ifp); - - /* If BPF is in the kernel, call the attach for it */ -#if XE_DEBUG > 1 - printf("xe%d: BPF listener attached\n", scp->unit); -#endif - bpfattach(scp->ifp, DLT_EN10MB, sizeof(struct ether_header)); - - /* Done */ - return 1; -} - - -/* - * Initialize device. Completes the reset procedure on the card and starts - * output. If there's an autonegotiation in progress we DON'T do anything; - * the media selection code will call us again when it's done. - */ -static void -xe_init(void *xscp) { - struct xe_softc *scp = xscp; - int s; - -#ifdef XE_DEBUG - printf("xe%d: init\n", scp->unit); -#endif - - if (scp->gone) return; - - if (TAILQ_EMPTY(&scp->ifp->if_addrhead)) return; - - /* Reset transmitter flags */ - scp->tx_queued = 0; - scp->tx_tpr = 0; - scp->tx_collisions = 0; - scp->ifp->if_timer = 0; - - s = splimp(); - - XE_SELECT_PAGE(0x42); - XE_OUTB(XE_SWC0, 0x20); /* Disable source insertion (WTF is that?) */ - - /* - * Set the 'local memory dividing line' -- splits the 32K card memory into - * 8K for transmit buffers and 24K for receive. This is done automatically - * on newer revision cards. - */ - if (scp->srev != 1) { - XE_SELECT_PAGE(2); - XE_OUTW(XE_RBS, 0x2000); - } - - /* Set up multicast addresses */ - xe_setmulti(scp); - - /* Fix the data offset register -- reset leaves it off-by-one */ - XE_SELECT_PAGE(0); - XE_OUTW(XE_DO, 0x2000); - - /* - * Set MAC interrupt masks and clear status regs. The bit names are direct - * from the Linux code; I have no idea what most of them do. - */ - XE_SELECT_PAGE(0x40); /* Bit 7..0 */ - XE_OUTB(XE_RX0Msk, 0xff); /* ROK, RAB, rsv, RO, CRC, AE, PTL, MP */ - XE_OUTB(XE_TX0Msk, 0xff); /* TOK, TAB, SQE, LL, TU, JAB, EXC, CRS */ - XE_OUTB(XE_TX0Msk+1, 0xb0); /* rsv, rsv, PTD, EXT, rsv, rsv, rsv, rsv */ - XE_OUTB(XE_RST0, 0x00); /* ROK, RAB, REN, RO, CRC, AE, PTL, MP */ - XE_OUTB(XE_TXST0, 0x00); /* TOK, TAB, SQE, LL, TU, JAB, EXC, CRS */ - XE_OUTB(XE_TXST1, 0x00); /* TEN, rsv, PTD, EXT, retry_counter:4 */ - - /* - * Check for an in-progress autonegotiation. If one is active, just set - * IFF_RUNNING and return. The media selection code will call us again when - * it's done. - */ - if (scp->autoneg_status) { - scp->ifp->if_flags |= IFF_RUNNING; - } - else { - /* Enable receiver, put MAC online */ - XE_SELECT_PAGE(0x40); - XE_OUTB(XE_CMD0, XE_CMD0_RX_ENABLE|XE_CMD0_ONLINE); - - /* Set up IMR, enable interrupts */ - xe_enable_intr(scp); - - /* Attempt to start output */ - scp->ifp->if_flags |= IFF_RUNNING; - scp->ifp->if_flags &= ~IFF_OACTIVE; - xe_start(scp->ifp); - } - - (void)splx(s); -} - - -/* - * Start output on interface. We make two assumptions here: - * 1) that the current priority is set to splimp _before_ this code - * is called *and* is returned to the appropriate priority after - * return - * 2) that the IFF_OACTIVE flag is checked before this code is called - * (i.e. that the output part of the interface is idle) - */ -static void -xe_start(struct ifnet *ifp) { - struct xe_softc *scp = ifp->if_softc; - struct mbuf *mbp; - - if (scp->gone) return; - - /* - * Loop while there are packets to be sent, and space to send them. - */ - while (1) { - IF_DEQUEUE(&ifp->if_snd, mbp); /* Suck a packet off the send queue */ - - if (mbp == NULL) { - /* - * We are using the !OACTIVE flag to indicate to the outside world that - * we can accept an additional packet rather than that the transmitter - * is _actually_ active. Indeed, the transmitter may be active, but if - * we haven't filled all the buffers with data then we still want to - * accept more. - */ - ifp->if_flags &= ~IFF_OACTIVE; - return; - } - - if (xe_pio_write_packet(scp, mbp) != 0) { - IF_PREPEND(&ifp->if_snd, mbp); /* Push the packet back onto the queue */ - ifp->if_flags |= IFF_OACTIVE; - return; - } - - /* Tap off here if there is a bpf listener */ - if (ifp->if_bpf) { -#if XE_DEBUG > 1 - printf("xe%d: sending output packet to BPF\n", scp->unit); -#endif - bpf_mtap(ifp, mbp); - } - - ifp->if_timer = 5; /* In case we don't hear from the card again */ - scp->tx_queued++; - - m_freem(mbp); - } -} - - -/* - * Process an ioctl request. Adapted from the ed driver. - */ -static int -xe_ioctl (register struct ifnet *ifp, u_long command, caddr_t data) { - struct xe_softc *scp; - int s, error; - - scp = ifp->if_softc; - error = 0; - - if (scp->gone) { - return ENXIO; - } - - s = splimp(); - - switch (command) { - - case SIOCSIFADDR: - case SIOCGIFADDR: - case SIOCSIFMTU: - error = ether_ioctl(ifp, command, data); - break; - - case SIOCSIFFLAGS: - /* - * If the interface is marked up and stopped, then start it. If it is - * marked down and running, then stop it. - */ - if (ifp->if_flags & IFF_UP) { - if (!(ifp->if_flags & IFF_RUNNING)) { - xe_hard_reset(scp); - xe_setmedia(scp); - xe_init(scp); - } - } - else { - if (ifp->if_flags & IFF_RUNNING) - xe_stop(scp); - } - - case SIOCADDMULTI: - case SIOCDELMULTI: - /* - * Multicast list has (maybe) changed; set the hardware filter - * accordingly. This also serves to deal with promiscuous mode if we have - * a BPF listener active. - */ - xe_setmulti(scp); - error = 0; - break; - - case SIOCSIFMEDIA: - case SIOCGIFMEDIA: - /* - * Someone wants to get/set media options. - */ - error = ifmedia_ioctl(ifp, (struct ifreq *)data, &scp->ifmedia, command); - break; - - default: - error = EINVAL; - } - - (void)splx(s); - - return error; -} - - -/* - * Card interrupt handler: should return true if the interrupt was for us, in - * case we are sharing our IRQ line with other devices (this will probably be - * the case for multifunction cards). - * - * This function is probably more complicated than it needs to be, as it - * attempts to deal with the case where multiple packets get sent between - * interrupts. This is especially annoying when working out the collision - * stats. Not sure whether this case ever really happens or not (maybe on a - * slow/heavily loaded machine?) so it's probably best to leave this like it - * is. - * - * Note that the crappy PIO used to get packets on and off the card means that - * you will spend a lot of time in this routine -- I can get my P150 to spend - * 90% of its time servicing interrupts if I really hammer the network. Could - * fix this, but then you'd start dropping/losing packets. The moral of this - * story? If you want good network performance _and_ some cycles left over to - * get your work done, don't buy a Xircom card. Or convince them to tell me - * how to do memory-mapped I/O :) - */ -static int -xe_card_intr(struct pccard_devinfo *devi) { - struct xe_softc *scp; - struct ifnet *ifp; - int unit, result; - u_int16_t rx_bytes, rxs, txs; - u_int8_t psr, isr, esr, rsr; - - unit = devi->isahd.id_unit; - scp = sca[unit]; - ifp = &scp->arpcom.ac_if; - rx_bytes = 0; /* Bytes received on this interrupt */ - result = 0; /* Set true if the interrupt is for us */ - - if (scp->gone) - return 0; - - if (scp->mohawk) { - XE_OUTB(XE_CR, 0); /* Disable interrupts */ - } - - psr = XE_INB(XE_PR); /* Stash the current register page */ - - /* - * Read ISR to see what caused this interrupt. Note that this clears the - * ISR on CE2 type cards. - */ - if ((isr = XE_INB(XE_ISR)) && isr != 0xff) { - - result = 1; /* This device did generate an int */ - esr = XE_INB(XE_ESR); /* Read the other status registers */ - XE_SELECT_PAGE(0x40); - rxs = XE_INB(XE_RST0); - XE_OUTB(XE_RST0, ~rxs & 0xff); - txs = XE_INB(XE_TXST0); - txs |= XE_INB(XE_TXST1) << 8; - XE_OUTB(XE_TXST0, 0); - XE_OUTB(XE_TXST1, 0); - XE_SELECT_PAGE(0); - -#if XE_DEBUG > 2 - printf("xe%d: ISR=%#2.2x ESR=%#2.2x RST=%#2.2x TXST=%#4.4x\n", unit, isr, esr, rxs, txs); -#endif - - /* - * Handle transmit interrupts - */ - if (isr & XE_ISR_TX_PACKET) { - u_int8_t new_tpr, sent; - - if ((new_tpr = XE_INB(XE_TPR)) < scp->tx_tpr) /* Update packet count */ - sent = (0xff - scp->tx_tpr) + new_tpr; /* TPR rolled over */ - else - sent = new_tpr - scp->tx_tpr; - - if (sent > 0) { /* Packets sent since last interrupt */ - scp->tx_tpr = new_tpr; - scp->tx_queued -= sent; - ifp->if_opackets += sent; - ifp->if_collisions += scp->tx_collisions; - - /* - * Collision stats are a PITA. If multiples frames have been sent, we - * distribute any outstanding collision count equally amongst them. - * However, if we're missing interrupts we're quite likely to also - * miss some collisions; thus the total count will be off anyway. - * Likewise, if we miss a frame dropped due to excessive collisions - * any outstanding collisions count will be held against the next - * frame to be successfully sent. Hopefully it averages out in the - * end! - * XXX - This will screw up if tx_collisions/sent > 14. FIX IT! - */ - switch (scp->tx_collisions) { - case 0: - break; - case 1: - scp->mibdata.dot3StatsSingleCollisionFrames++; - scp->mibdata.dot3StatsCollFrequencies[0]++; - break; - default: - if (sent == 1) { - scp->mibdata.dot3StatsMultipleCollisionFrames++; - scp->mibdata.dot3StatsCollFrequencies[scp->tx_collisions-1]++; - } - else { /* Distribute across multiple frames */ - scp->mibdata.dot3StatsMultipleCollisionFrames += sent; - scp->mibdata. - dot3StatsCollFrequencies[scp->tx_collisions/sent] += sent - scp->tx_collisions%sent; - scp->mibdata. - dot3StatsCollFrequencies[scp->tx_collisions/sent + 1] += scp->tx_collisions%sent; - } - } - scp->tx_collisions = 0; - } - ifp->if_timer = 0; - ifp->if_flags &= ~IFF_OACTIVE; - } - if (txs & 0x0002) { /* Excessive collisions (packet dropped) */ - ifp->if_collisions += 16; - ifp->if_oerrors++; - scp->tx_collisions = 0; - scp->mibdata.dot3StatsExcessiveCollisions++; - scp->mibdata.dot3StatsMultipleCollisionFrames++; - scp->mibdata.dot3StatsCollFrequencies[15]++; - XE_OUTB(XE_CR, XE_CR_RESTART_TX); - } - if (txs & 0x0040) /* Transmit aborted -- probably collisions */ - scp->tx_collisions++; - - - /* - * Handle receive interrupts - */ - while ((esr = XE_INB(XE_ESR)) & XE_ESR_FULL_PACKET_RX) { - - if ((rsr = XE_INB(XE_RSR)) & XE_RSR_RX_OK) { - struct ether_header *ehp; - struct mbuf *mbp; - u_int16_t len; - - len = XE_INW(XE_RBC); - - if (len == 0) - continue; - -#if 0 - /* - * Limit the amount of time we spend in this loop, dropping packets if - * necessary. The Linux code does this with considerably more - * finesse, adjusting the threshold dynamically. - */ - if ((rx_bytes += len) > 22000) { - ifp->if_iqdrops++; - scp->mibData.dot3StatsMissedFrames++; - XE_OUTW(XE_DO, 0x8000); - continue; - } -#endif - - if (len & 0x01) - len++; - - MGETHDR(mbp, M_DONTWAIT, MT_DATA); /* Allocate a header mbuf */ - if (mbp != NULL) { - mbp->m_pkthdr.rcvif = ifp; - mbp->m_pkthdr.len = mbp->m_len = len; - - /* - * If the mbuf header isn't big enough for the packet, attach an - * mbuf cluster to hold it. The +2 is to allow for the nasty little - * alignment hack below. - */ - if (len + 2 > MHLEN) { - MCLGET(mbp, M_DONTWAIT); - if ((mbp->m_flags & M_EXT) == 0) { - m_freem(mbp); - mbp = NULL; - } - } - } - - if (mbp != NULL) { - /* - * The Ethernet header is 14 bytes long; thus the actual packet data - * won't be 32-bit aligned when it's dumped into the mbuf. We - * offset everything by 2 bytes to fix this. Apparently the - * alignment is important for NFS, damn its eyes. - */ - mbp->m_data += 2; - ehp = mtod(mbp, struct ether_header *); - - /* - * Now get the packet, including the Ethernet header and trailer (?) - * We use programmed I/O, because we don't know how to do shared - * memory with these cards. So yes, it's real slow, and heavy on - * the interrupts (CPU on my P150 maxed out at ~950KBps incoming). - */ - if (scp->srev == 0) { /* Workaround a bug in old cards */ - u_short rhs; - - XE_SELECT_PAGE(5); - rhs = XE_INW(XE_RHSA); - XE_SELECT_PAGE(0); - - rhs += 3; /* Skip control info */ - - if (rhs >= 0x8000) - rhs = 0; - - if (rhs + len > 0x8000) { - int i; - - /* - * XXX - This i-- seems very wrong, but it's what the Linux guys - * XXX - do. Need someone with an old CE2 to test this for me. - * XXX - 99/3/28: Changed the first i-- to an i++, maybe that'll - * XXX - fix it? It seems as though the previous version would - * XXX - have caused an infinite loop (what, another one?). - */ - for (i = 0; i < len; i++, rhs++) { - ((char *)ehp)[i] = XE_INB(XE_EDP); - if (rhs == 0x8000) { - rhs = 0; - i--; - } - } - } - else - insw(scp->dev->id_iobase+XE_EDP, ehp, len >> 1); - } - else - insw(scp->dev->id_iobase+XE_EDP, ehp, len >> 1); - - /* - * Check if there's a BPF listener on this interface. If so, hand - * off the raw packet to bpf. - */ - if (ifp->if_bpf) { -#if XE_DEBUG > 1 - printf("xe%d: passing input packet to BPF\n", scp->unit); -#endif - bpf_mtap(ifp, mbp); - - /* - * Note that the interface cannot be in promiscuous mode if there - * are no BPF listeners. And if we are in promiscuous mode, we - * have to check if this packet is really ours. - */ - if ((ifp->if_flags & IFF_PROMISC) && - bcmp(ehp->ether_dhost, scp->arpcom.ac_enaddr, sizeof(ehp->ether_dhost)) != 0 && - (rsr & XE_RSR_PHYS_PACKET)) { - m_freem(mbp); - mbp = NULL; - } - } - - if (mbp != NULL) { - mbp->m_pkthdr.len = mbp->m_len = len - ETHER_HDR_LEN; - mbp->m_data += ETHER_HDR_LEN; /* Strip off Ethernet header */ - ether_input(ifp, ehp, mbp); /* Send the packet on its way */ - ifp->if_ipackets++; /* Success! */ - } - XE_OUTW(XE_DO, 0x8000); /* skip_rx_packet command */ - } - } - else if (rsr & XE_RSR_LONG_PACKET) { /* Packet length >1518 bytes */ - scp->mibdata.dot3StatsFrameTooLongs++; - ifp->if_ierrors++; - } - else if (rsr & XE_RSR_CRC_ERROR) { /* Bad checksum on packet */ - scp->mibdata.dot3StatsFCSErrors++; - ifp->if_ierrors++; - } - else if (rsr & XE_RSR_ALIGN_ERROR) { /* Packet alignment error */ - scp->mibdata.dot3StatsAlignmentErrors++; - ifp->if_ierrors++; - } - } - if (rxs & 0x10) { /* Receiver overrun */ - scp->mibdata.dot3StatsInternalMacReceiveErrors++; - ifp->if_ierrors++; - XE_OUTB(XE_CR, XE_CR_CLEAR_OVERRUN); - } - } - - XE_SELECT_PAGE(psr); /* Restore saved page */ - XE_OUTB(XE_CR, XE_CR_ENABLE_INTR); /* Re-enable interrupts */ - - /* Could force an int here, instead of dropping packets? */ - /* XE_OUTB(XE_CR, XE_CR_ENABLE_INTR|XE_CE_FORCE_INTR); */ - - return result; -} - - -/* - * Device timeout/watchdog routine. Called automatically if we queue a packet - * for transmission but don't get an interrupt within a specified timeout - * (usually 5 seconds). When this happens we assume the worst and reset the - * card. - */ -static void -xe_watchdog(struct ifnet *ifp) { - struct xe_softc *scp = ifp->if_softc; - - if (scp->gone) return; - - printf("xe%d: watchdog timeout; resetting card\n", scp->unit); - scp->tx_timeouts++; - ifp->if_oerrors += scp->tx_queued; - xe_stop(scp); - xe_hard_reset(scp); - xe_setmedia(scp); - xe_init(scp); -} - - -/* - * Change media selection. - */ -static int -xe_media_change(struct ifnet *ifp) { - struct xe_softc *scp = ifp->if_softc; - -#ifdef XE_DEBUG - printf("xe%d: media_change\n", ifp->if_unit); -#endif - - if (IFM_TYPE(scp->ifm->ifm_media) != IFM_ETHER) - return(EINVAL); - - /* - * Some card/media combos aren't always possible -- filter those out here. - */ - if ((IFM_SUBTYPE(scp->ifm->ifm_media) == IFM_AUTO || - IFM_SUBTYPE(scp->ifm->ifm_media) == IFM_100_TX) && !scp->phy_ok) - return (EINVAL); - - xe_setmedia(scp); - - return 0; -} - - -/* - * Return current media selection. - */ -static void -xe_media_status(struct ifnet *ifp, struct ifmediareq *mrp) { - -#ifdef XE_DEBUG - printf("xe%d: media_status\n", ifp->if_unit); -#endif - - mrp->ifm_active = ((struct xe_softc *)ifp->if_softc)->media; - - return; -} - - -/* - * Select active media. - */ -static void xe_setmedia(void *xscp) { - struct xe_softc *scp = xscp; - u_int16_t bmcr, bmsr, anar, lpar; - -#ifdef XE_DEBUG - printf("xe%d: setmedia\n", scp->unit); -#endif - - /* Cancel any pending timeout */ - untimeout(xe_setmedia, scp, scp->chand); - xe_disable_intr(scp); - - /* Select media */ - scp->media = IFM_ETHER; - switch (IFM_SUBTYPE(scp->ifm->ifm_media)) { - - case IFM_AUTO: /* Autoselect media */ - scp->media = IFM_ETHER|IFM_AUTO; - - /* - * Autoselection is really awful. It goes something like this: - * - * Wait until the transmitter goes idle (2sec timeout). - * Reset card - * IF a 100Mbit PHY exists - * Start NWAY autonegotiation (3.5sec timeout) - * IF that succeeds - * Select 100baseTX or 10baseT, whichever was detected - * ELSE - * Reset card - * IF a 100Mbit PHY exists - * Try to force a 100baseTX link (3sec timeout) - * IF that succeeds - * Select 100baseTX - * ELSE - * Disable the PHY - * ENDIF - * ENDIF - * ENDIF - * ENDIF - * IF nothing selected so far - * IF a 100Mbit PHY exists - * Select 10baseT - * ELSE - * Select 10baseT or 10base2, whichever is connected - * ENDIF - * ENDIF - */ - switch (scp->autoneg_status) { - - case XE_AUTONEG_NONE: -#if XE_DEBUG > 1 - printf("xe%d: Waiting for idle transmitter\n", scp->unit); -#endif - scp->arpcom.ac_if.if_flags |= IFF_OACTIVE; - scp->autoneg_status = XE_AUTONEG_WAITING; - scp->chand = timeout(xe_setmedia, scp, hz * 2); - return; - - case XE_AUTONEG_WAITING: - xe_soft_reset(scp); - if (scp->phy_ok) { -#if XE_DEBUG > 1 - printf("xe%d: Starting autonegotiation\n", scp->unit); -#endif - bmcr = xe_phy_readreg(scp, PHY_BMCR); - bmcr &= ~(PHY_BMCR_AUTONEGENBL); - xe_phy_writereg(scp, PHY_BMCR, bmcr); - anar = xe_phy_readreg(scp, PHY_ANAR); - anar &= ~(PHY_ANAR_100BT4|PHY_ANAR_100BTXFULL|PHY_ANAR_10BTFULL); - anar |= PHY_ANAR_100BTXHALF|PHY_ANAR_10BTHALF; - xe_phy_writereg(scp, PHY_ANAR, anar); - bmcr |= PHY_BMCR_AUTONEGENBL|PHY_BMCR_AUTONEGRSTR; - xe_phy_writereg(scp, PHY_BMCR, bmcr); - scp->autoneg_status = XE_AUTONEG_STARTED; - scp->chand = timeout(xe_setmedia, scp, hz * 7/2); - return; - } - else { - scp->autoneg_status = XE_AUTONEG_FAIL; - } - break; - - case XE_AUTONEG_STARTED: - bmsr = xe_phy_readreg(scp, PHY_BMSR); - lpar = xe_phy_readreg(scp, PHY_LPAR); - if (bmsr & (PHY_BMSR_AUTONEGCOMP|PHY_BMSR_LINKSTAT)) { -#if XE_DEBUG > 1 - printf("xe%d: Autonegotiation complete!\n", scp->unit); -#endif - /* - * XXX - Shouldn't have to do this, but (on my hub at least) the - * XXX - transmitter won't work after a successful autoneg. So we see - * XXX - what the negotiation result was and force that mode. I'm - * XXX - sure there is an easy fix for this. - */ - if (lpar & PHY_LPAR_100BTXHALF) { - xe_phy_writereg(scp, PHY_BMCR, PHY_BMCR_SPEEDSEL); - XE_MII_DUMP(scp); - XE_SELECT_PAGE(2); - XE_OUTB(XE_MSR, XE_INB(XE_MSR) | 0x08); - scp->media = IFM_ETHER|IFM_100_TX; - scp->autoneg_status = XE_AUTONEG_NONE; - } - else { - /* - * XXX - Bit of a hack going on in here. - * XXX - This is derived from Ken Hughes patch to the Linux driver - * XXX - to make it work with 10Mbit _autonegotiated_ links on CE3B - * XXX - cards. What's a CE3B and how's it differ from a plain CE3? - * XXX - these are the things we need to find out. - */ - xe_phy_writereg(scp, PHY_BMCR, 0x0000); - XE_SELECT_PAGE(2); - /* BEGIN HACK */ - XE_OUTB(XE_MSR, XE_INB(XE_MSR) | 0x08); - XE_SELECT_PAGE(0x42); - XE_OUTB(XE_SWC1, 0x80); - scp->media = IFM_ETHER|IFM_10_T; - scp->autoneg_status = XE_AUTONEG_NONE; - /* END HACK */ - /*XE_OUTB(XE_MSR, XE_INB(XE_MSR) & ~0x08);*/ /* Disable PHY? */ - /*scp->autoneg_status = XE_AUTONEG_FAIL;*/ - } - } - else { -#if XE_DEBUG > 1 - printf("xe%d: Autonegotiation failed; trying 100baseTX\n", scp->unit); -#endif - XE_MII_DUMP(scp); - xe_soft_reset(scp); - if (scp->phy_ok) { - xe_phy_writereg(scp, PHY_BMCR, PHY_BMCR_SPEEDSEL); - scp->autoneg_status = XE_AUTONEG_100TX; - scp->chand = timeout(xe_setmedia, scp, hz * 3); - return; - } - else { - scp->autoneg_status = XE_AUTONEG_FAIL; - } - } - break; - - case XE_AUTONEG_100TX: - (void)xe_phy_readreg(scp, PHY_BMSR); - bmsr = xe_phy_readreg(scp, PHY_BMSR); - if (bmsr & PHY_BMSR_LINKSTAT) { -#if XE_DEBUG > 1 - printf("xe%d: Got 100baseTX link!\n", scp->unit); -#endif - XE_MII_DUMP(scp); - XE_SELECT_PAGE(2); - XE_OUTB(XE_MSR, XE_INB(XE_MSR) | 0x08); - scp->media = IFM_ETHER|IFM_100_TX; - scp->autoneg_status = XE_AUTONEG_NONE; - } - else { -#if XE_DEBUG > 1 - printf("xe%d: Autonegotiation failed; disabling PHY\n", scp->unit); -#endif - XE_MII_DUMP(scp); - xe_phy_writereg(scp, PHY_BMCR, 0x0000); - XE_SELECT_PAGE(2); - XE_OUTB(XE_MSR, XE_INB(XE_MSR) & ~0x08); /* Disable PHY? */ - scp->autoneg_status = XE_AUTONEG_FAIL; - } - break; - } - - /* - * If we got down here _and_ autoneg_status is XE_AUTONEG_FAIL, then - * either autonegotiation failed, or never got started to begin with. In - * either case, select a suitable 10Mbit media and hope it works. We - * don't need to reset the card again, since it will have been done - * already by the big switch above. - */ - if (scp->autoneg_status == XE_AUTONEG_FAIL) { -#if XE_DEBUG > 1 - printf("xe%d: Selecting 10baseX\n", scp->unit); -#endif - if (scp->mohawk) { - XE_SELECT_PAGE(0x42); - XE_OUTB(XE_SWC1, 0x80); - scp->media = IFM_ETHER|IFM_10_T; - scp->autoneg_status = XE_AUTONEG_NONE; - } - else { - XE_SELECT_PAGE(4); - XE_OUTB(XE_GPR0, 4); - DELAY(50000); - XE_SELECT_PAGE(0x42); - XE_OUTB(XE_SWC1, (XE_INB(XE_ESR) & XE_ESR_MEDIA_SELECT) ? 0x80 : 0xc0); - scp->media = IFM_ETHER|((XE_INB(XE_ESR) & XE_ESR_MEDIA_SELECT) ? IFM_10_T : IFM_10_2); - scp->autoneg_status = XE_AUTONEG_NONE; - } - } - break; - - - /* - * If a specific media has been requested, we just reset the card and - * select it (one small exception -- if 100baseTX is requested by there is - * no PHY, we fall back to 10baseT operation). - */ - case IFM_100_TX: /* Force 100baseTX */ - xe_soft_reset(scp); - if (scp->phy_ok) { -#if XE_DEBUG > 1 - printf("xe%d: Selecting 100baseTX\n", scp->unit); -#endif - XE_SELECT_PAGE(0x42); - XE_OUTB(XE_SWC1, 0); - xe_phy_writereg(scp, PHY_BMCR, PHY_BMCR_SPEEDSEL); - XE_SELECT_PAGE(2); - XE_OUTB(XE_MSR, XE_INB(XE_MSR) | 0x08); - scp->media |= IFM_100_TX; - break; - } - /* FALLTHROUGH */ - - case IFM_10_T: /* Force 10baseT */ - xe_soft_reset(scp); -#if XE_DEBUG > 1 - printf("xe%d: Selecting 10baseT\n", scp->unit); -#endif - if (scp->phy_ok) { - xe_phy_writereg(scp, PHY_BMCR, 0x0000); - XE_SELECT_PAGE(2); - XE_OUTB(XE_MSR, XE_INB(XE_MSR) & ~0x08); /* Disable PHY */ - } - XE_SELECT_PAGE(0x42); - XE_OUTB(XE_SWC1, 0x80); - scp->media |= IFM_10_T; - break; - - case IFM_10_2: - xe_soft_reset(scp); -#if XE_DEBUG > 1 - printf("xe%d: Selecting 10base2\n", scp->unit); -#endif - XE_SELECT_PAGE(0x42); - XE_OUTB(XE_SWC1, 0xc0); - scp->media |= IFM_10_2; - break; - } - - - /* - * Finally, the LEDs are set to match whatever media was chosen and the - * transmitter is unblocked. - */ -#if XE_DEBUG > 1 - printf("xe%d: Setting LEDs\n", scp->unit); -#endif - XE_SELECT_PAGE(2); - switch (IFM_SUBTYPE(scp->media)) { - case IFM_100_TX: - case IFM_10_T: - XE_OUTB(XE_LED, 0x3b); - if (scp->dingo) - XE_OUTB(0x0b, 0x04); /* 100Mbit LED */ - break; - - case IFM_10_2: - XE_OUTB(XE_LED, 0x3a); - break; - } - - /* Restart output? */ - scp->ifp->if_flags &= ~IFF_OACTIVE; - xe_init(scp); -} - - -/* - * Hard reset (power cycle) the card. - */ -static void -xe_hard_reset(struct xe_softc *scp) { - int s; - -#ifdef XE_DEBUG - printf("xe%d: hard_reset\n", scp->unit); -#endif - - if (scp->gone) return; - - s = splimp(); - - /* - * Power cycle the card. - */ - XE_SELECT_PAGE(4); - XE_OUTB(XE_GPR1, 0); /* Power off */ - DELAY(40000); - - if (scp->mohawk) - XE_OUTB(XE_GPR1, 1); /* And back on again */ - else - XE_OUTB(XE_GPR1, 5); /* Also set AIC bit, whatever that is */ - DELAY(40000); - XE_SELECT_PAGE(0); - - (void)splx(s); -} - - -/* - * Soft reset the card. Also makes sure that the ML6692 and 10Mbit controller - * are powered up, sets the silicon revision number in softc, disables - * interrupts and checks for the prescence of a 100Mbit PHY. This should - * leave us in a position where we can access the PHY and do media - * selection. The function imposes a 0.5s delay while the hardware powers up. - */ -static void -xe_soft_reset(struct xe_softc *scp) { - int s; - -#ifdef XE_DEBUG - printf("xe%d: soft_reset\n", scp->unit); -#endif - - if (scp->gone) return; - - s = splimp(); - - /* - * Reset the card, (again). - */ - XE_SELECT_PAGE(0); - XE_OUTB(XE_CR, XE_CR_SOFT_RESET); - DELAY(40000); - XE_OUTB(XE_CR, 0); - DELAY(40000); - - if (scp->mohawk) { - /* - * set GP1 and GP2 as outputs (bits 2 & 3) - * set GP1 low to power on the ML6692 (bit 0) - * set GP2 high to power on the 10Mhz chip (bit 1) - */ - XE_SELECT_PAGE(4); - XE_OUTB(XE_GPR0, 0x0e); - } - - /* - * Wait for everything to wake up. - */ - DELAY(500000); - - /* - * Get silicon revision number. - */ - XE_SELECT_PAGE(4); - if (scp->mohawk) - scp->srev = (XE_INB(XE_BOV) & 0x70) >> 4; - else - scp->srev = (XE_INB(XE_BOV) & 0x30) >> 4; -#ifdef XE_DEBUG - printf("xe%d: silicon revision = %d\n", scp->unit, scp->srev); -#endif - - /* - * Shut off interrupts. - */ - xe_disable_intr(scp); - - /* - * Check for PHY. - */ - if (scp->mohawk) { - scp->phy_ok = xe_mii_init(scp); - } - - XE_SELECT_PAGE(0); - - (void)splx(s); -} - - -/* - * Take interface offline. This is done by powering down the device, which I - * assume means just shutting down the transceiver and Ethernet logic. This - * requires a _hard_ reset to recover from, as we need to power up again. - */ -static void -xe_stop(struct xe_softc *scp) { - int s; - -#ifdef XE_DEBUG - printf("xe%d: stop\n", scp->unit); -#endif - - if (scp->gone) return; - - s = splimp(); - - /* - * Shut off interrupts. - */ - xe_disable_intr(scp); - - /* - * Power down. - */ - XE_SELECT_PAGE(4); - XE_OUTB(XE_GPR1, 0); - XE_SELECT_PAGE(0); - - /* - * ~IFF_RUNNING == interface down. - */ - scp->ifp->if_flags &= ~IFF_RUNNING; - scp->ifp->if_flags &= ~IFF_OACTIVE; - scp->ifp->if_timer = 0; - - (void)splx(s); -} - - -/* - * Enable Ethernet interrupts from the card. - */ -static void -xe_enable_intr(struct xe_softc *scp) { -#ifdef XE_DEBUG - printf("xe%d: enable_intr\n", scp->unit); -#endif - - XE_SELECT_PAGE(1); - XE_OUTB(XE_IMR0, 0xff); /* Unmask everything */ - XE_OUTB(XE_IMR1, 0x01); /* Unmask TX underrun detection */ - DELAY(1); - - XE_SELECT_PAGE(0); - XE_OUTB(XE_CR, XE_CR_ENABLE_INTR); /* Enable interrupts */ - if (scp->modem && !scp->dingo) { /* This bit is just magic */ - if (!(XE_INB(0x10) & 0x01)) { - XE_OUTB(0x10, 0x11); /* Unmask master int enable bit */ - } - } -} - - -/* - * Disable all Ethernet interrupts from the card. - */ -static void -xe_disable_intr(struct xe_softc *scp) { -#ifdef XE_DEBUG - printf("xe%d: disable_intr\n", scp->unit); -#endif - - XE_SELECT_PAGE(0); - XE_OUTB(XE_CR, 0); /* Disable interrupts */ - if (scp->modem && !scp->dingo) { /* More magic (does this work?) */ - XE_OUTB(0x10, 0x10); /* Mask the master int enable bit */ - } - - XE_SELECT_PAGE(1); - XE_OUTB(XE_IMR0, 0); /* Forbid all interrupts */ - XE_OUTB(XE_IMR1, 0); - XE_SELECT_PAGE(0); -} - - -/* - * Set up multicast filter and promiscuous mode - */ -static void -xe_setmulti(struct xe_softc *scp) { - struct ifnet *ifp; - struct ifmultiaddr *maddr; - int count; - - ifp = &scp->arpcom.ac_if; - maddr = ifp->if_multiaddrs.lh_first; - - /* Get length of multicast list */ - for (count = 0; maddr != NULL; maddr = maddr->ifma_link.le_next, count++); - - if ((ifp->if_flags & IFF_PROMISC) || (ifp->if_flags & IFF_ALLMULTI) || (count > 9)) { - /* - * Go into promiscuous mode if either of the PROMISC or ALLMULTI flags are - * set, or if we have been asked to deal with more than 9 multicast - * addresses. To do this: set MPE and PME in SWC1 - */ - XE_SELECT_PAGE(0x42); - XE_OUTB(XE_SWC1, 0x06); - } - else if ((ifp->if_flags & IFF_MULTICAST) && (count > 0)) { - /* - * Program the filters for up to 9 addresses - */ - XE_SELECT_PAGE(0x42); - XE_OUTB(XE_SWC1, 0x01); - XE_SELECT_PAGE(0x40); - XE_OUTB(XE_CMD0, XE_CMD0_OFFLINE); - /*xe_reg_dump(scp);*/ - xe_setaddrs(scp); - /*xe_reg_dump(scp);*/ - XE_SELECT_PAGE(0x40); - XE_OUTB(XE_CMD0, XE_CMD0_RX_ENABLE|XE_CMD0_ONLINE); - } - else { - /* - * No multicast operation (default) - */ - XE_SELECT_PAGE(0x42); - XE_OUTB(XE_SWC1, 0); - } - XE_SELECT_PAGE(0); -} - - -/* - * Set up all on-chip addresses (for multicast). AFAICS, there are 10 - * of these things; the first is our MAC address, the other 9 are mcast - * addresses, padded with the MAC address if there aren't enough. - * XXX - This doesn't work right, but I'm not sure why yet. We seem to be - * XXX - doing much the same as the Linux code, which is weird enough that - * XXX - it's probably right (despite my earlier comments to the contrary). - */ -static void -xe_setaddrs(struct xe_softc *scp) { - struct ifmultiaddr *maddr; - u_int8_t *addr; - u_int8_t page, slot, byte, i; - - maddr = scp->arpcom.ac_if.if_multiaddrs.lh_first; - - XE_SELECT_PAGE(page = 0x50); - - for (slot = 0, byte = 8; slot < 10; slot++) { - - if (slot == 0) - addr = (u_int8_t *)(&scp->arpcom.ac_enaddr); - else { - while (maddr != NULL && maddr->ifma_addr->sa_family != AF_LINK) - maddr = maddr->ifma_link.le_next; - if (maddr != NULL) - addr = LLADDR((struct sockaddr_dl *)maddr->ifma_addr); - else - addr = (u_int8_t *)(&scp->arpcom.ac_enaddr); - } - - for (i = 0; i < 6; i++, byte++) { -#if XE_DEBUG > 2 - if (i) - printf(":%x", addr[i]); - else - printf("xe%d: individual addresses %d: %x", scp->unit, slot, addr[0]); -#endif - - if (byte > 15) { - page++; - byte = 8; - XE_SELECT_PAGE(page); - } - - if (scp->mohawk) - XE_OUTB(byte, addr[5 - i]); - else - XE_OUTB(byte, addr[i]); - } -#if XE_DEBUG > 2 - printf("\n"); -#endif - } - - XE_SELECT_PAGE(0); -} - - -/* - * Write an outgoing packet to the card using programmed I/O. - */ -static int -xe_pio_write_packet(struct xe_softc *scp, struct mbuf *mbp) { - struct mbuf *mbp2; - u_int16_t len, pad, free, ok; - u_int8_t *data; - u_int8_t savebyte[2], wantbyte; - - /* Get total packet length */ - for (len = 0, mbp2 = mbp; mbp2 != NULL; len += mbp2->m_len, mbp2 = mbp2->m_next); - - /* Packets < minimum length may need to be padded out */ - pad = 0; - if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) { - pad = (ETHER_MIN_LEN - ETHER_CRC_LEN - len + 1) >> 1; - len = ETHER_MIN_LEN - ETHER_CRC_LEN; - } - - /* Check transmit buffer space */ - XE_SELECT_PAGE(0); - XE_OUTW(XE_TRS, len+2); - free = XE_INW(XE_TSO); - ok = free & 0x8000; - free &= 0x7fff; - if (free <= len + 2) - return 1; - - /* Send packet length to card */ - XE_OUTW(XE_EDP, len); - - /* - * Write packet to card using PIO (code stolen from the ed driver) - */ - wantbyte = 0; - while (mbp != NULL) { - len = mbp->m_len; - if (len > 0) { - data = mtod(mbp, caddr_t); - if (wantbyte) { /* Finish the last word */ - savebyte[1] = *data; - XE_OUTW(XE_EDP, *(u_short *)savebyte); - data++; - len--; - wantbyte = 0; - } - if (len > 1) { /* Output contiguous words */ - outsw(scp->dev->id_iobase+XE_EDP, data, len >> 1); - data += len & ~1; - len &= 1; - } - if (len == 1) { /* Save last byte, if necessary */ - savebyte[0] = *data; - wantbyte = 1; - } - } - mbp = mbp->m_next; - } - if (wantbyte) /* Last byte for odd-length packets */ - XE_OUTW(XE_EDP, *(u_short *)savebyte); - - /* - * For CE3 cards, just tell 'em to send -- apparently the card will pad out - * short packets with random cruft. Otherwise, write nonsense words to fill - * out the packet. I guess it is then sent automatically (?) - */ - if (scp->mohawk) - XE_OUTB(XE_CR, XE_CR_TX_PACKET|XE_CR_ENABLE_INTR); - else - while (pad > 0) { - XE_OUTW(XE_EDP, 0xdead); - pad--; - } - - return 0; -} - - -/* - * The device entry is being removed, probably because someone ejected the - * card. The interface should have been brought down manually before calling - * this function; if not you may well lose packets. In any case, I shut down - * the card and the interface, and hope for the best. The 'gone' flag is set, - * so hopefully no-one else will try to access the missing card. - */ -static void -xe_card_unload(struct pccard_devinfo *devi) { - struct xe_softc *scp; - struct ifnet *ifp; - int unit; - - unit = devi->isahd.id_unit; - scp = sca[unit]; - ifp = &scp->arpcom.ac_if; - - if (scp->gone) { - printf("xe%d: already unloaded\n", unit); - return; - } - - if_down(ifp); - ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); - xe_stop(scp); - scp->gone = 1; -} - - -/* - * Compute the 32-bit Ethernet CRC for the given buffer. - */ -static u_int32_t -xe_compute_crc(u_int8_t *data, int len) { - u_int32_t crc = 0xffffffff; - u_int32_t poly = 0x04c11db6; - u_int8_t current, crc31, bit; - int i, k; - - for (i = 0; i < len; i++) { - current = data[i]; - for (k = 1; k <= 8; k++) { - if (crc & 0x80000000) { - crc31 = 0x01; - } - else { - crc31 = 0; - } - bit = crc31 ^ (current & 0x01); - crc <<= 1; - current >>= 1; - if (bit) { - crc = (crc ^ poly)|1; - } - } - } - return crc; -} - - -/* - * Convert a CRC into an index into the multicast hash table. What we do is - * take the most-significant 6 bits of the CRC, reverse them, and use that as - * the bit number in the hash table. Bits 5:3 of the result give the byte - * within the table (0-7); bits 2:0 give the bit number within that byte (also - * 0-7), ie. the number of shifts needed to get it into the lsb position. - */ -static int -xe_compute_hashbit(u_int32_t crc) { - u_int8_t hashbit = 0; - int i; - - for (i = 0; i < 6; i++) { - hashbit >>= 1; - if (crc & 0x80000000) { - hashbit &= 0x80; - } - crc <<= 1; - } - return (hashbit >> 2); -} - - - -/************************************************************** - * * - * M I I F U N C T I O N S * - * * - **************************************************************/ - -/* - * Alternative MII/PHY handling code adapted from the xl driver. It doesn't - * seem to work any better than the xirc2_ps stuff, but it's cleaner code. - * XXX - this stuff shouldn't be here. It should all be abstracted off to - * XXX - some kind of common MII-handling code, shared by all drivers. But - * XXX - that's a whole other mission. - */ -#define XE_MII_SET(x) XE_OUTB(XE_GPR2, (XE_INB(XE_GPR2) | 0x04) | (x)) -#define XE_MII_CLR(x) XE_OUTB(XE_GPR2, (XE_INB(XE_GPR2) | 0x04) & ~(x)) - - -/* - * Sync the PHYs by setting data bit and strobing the clock 32 times. - */ -static void -xe_mii_sync(struct xe_softc *scp) { - register int i; - - XE_SELECT_PAGE(2); - XE_MII_SET(XE_MII_DIR|XE_MII_WRD); - - for (i = 0; i < 32; i++) { - XE_MII_SET(XE_MII_CLK); - DELAY(1); - XE_MII_CLR(XE_MII_CLK); - DELAY(1); - } -} - - -/* - * Look for a MII-compliant PHY. If we find one, reset it. - */ -static int -xe_mii_init(struct xe_softc *scp) { - u_int16_t status; - - status = xe_phy_readreg(scp, PHY_BMSR); - if ((status & 0xff00) != 0x7800) { -#if XE_DEBUG > 1 - printf("xe%d: no PHY found, %0x\n", scp->unit, status); -#endif - return 0; - } - else { -#if XE_DEBUG > 1 - printf("xe%d: PHY OK!\n", scp->unit); -#endif - - /* Reset the PHY */ - xe_phy_writereg(scp, PHY_BMCR, PHY_BMCR_RESET); - DELAY(500); - while(xe_phy_readreg(scp, PHY_BMCR) & PHY_BMCR_RESET); - XE_MII_DUMP(scp); - return 1; - } -} - - -/* - * Clock a series of bits through the MII. - */ -static void -xe_mii_send(struct xe_softc *scp, u_int32_t bits, int cnt) { - int i; - - XE_SELECT_PAGE(2); - XE_MII_CLR(XE_MII_CLK); - - for (i = (0x1 << (cnt - 1)); i; i >>= 1) { - if (bits & i) { - XE_MII_SET(XE_MII_WRD); - } else { - XE_MII_CLR(XE_MII_WRD); - } - DELAY(1); - XE_MII_CLR(XE_MII_CLK); - DELAY(1); - XE_MII_SET(XE_MII_CLK); - } -} - - -/* - * Read an PHY register through the MII. - */ -static int -xe_mii_readreg(struct xe_softc *scp, struct xe_mii_frame *frame) { - int i, ack, s; - - s = splimp(); - - /* - * Set up frame for RX. - */ - frame->mii_stdelim = XE_MII_STARTDELIM; - frame->mii_opcode = XE_MII_READOP; - frame->mii_turnaround = 0; - frame->mii_data = 0; - - XE_SELECT_PAGE(2); - XE_OUTB(XE_GPR2, 0); - - /* - * Turn on data xmit. - */ - XE_MII_SET(XE_MII_DIR); - - xe_mii_sync(scp); - - /* - * Send command/address info. - */ - xe_mii_send(scp, frame->mii_stdelim, 2); - xe_mii_send(scp, frame->mii_opcode, 2); - xe_mii_send(scp, frame->mii_phyaddr, 5); - xe_mii_send(scp, frame->mii_regaddr, 5); - - /* Idle bit */ - XE_MII_CLR((XE_MII_CLK|XE_MII_WRD)); - DELAY(1); - XE_MII_SET(XE_MII_CLK); - DELAY(1); - - /* Turn off xmit. */ - XE_MII_CLR(XE_MII_DIR); - - /* Check for ack */ - XE_MII_CLR(XE_MII_CLK); - DELAY(1); - XE_MII_SET(XE_MII_CLK); - DELAY(1); - ack = XE_INB(XE_GPR2) & XE_MII_RDD; - - /* - * Now try reading data bits. If the ack failed, we still - * need to clock through 16 cycles to keep the PHY(s) in sync. - */ - if (ack) { - for(i = 0; i < 16; i++) { - XE_MII_CLR(XE_MII_CLK); - DELAY(1); - XE_MII_SET(XE_MII_CLK); - DELAY(1); - } - goto fail; - } - - for (i = 0x8000; i; i >>= 1) { - XE_MII_CLR(XE_MII_CLK); - DELAY(1); - if (!ack) { - if (XE_INB(XE_GPR2) & XE_MII_RDD) - frame->mii_data |= i; - DELAY(1); - } - XE_MII_SET(XE_MII_CLK); - DELAY(1); - } - -fail: - - XE_MII_CLR(XE_MII_CLK); - DELAY(1); - XE_MII_SET(XE_MII_CLK); - DELAY(1); - - splx(s); - - if (ack) - return(1); - return(0); -} - - -/* - * Write to a PHY register through the MII. - */ -static int -xe_mii_writereg(struct xe_softc *scp, struct xe_mii_frame *frame) { - int s; - - s = splimp(); - - /* - * Set up frame for TX. - */ - frame->mii_stdelim = XE_MII_STARTDELIM; - frame->mii_opcode = XE_MII_WRITEOP; - frame->mii_turnaround = XE_MII_TURNAROUND; - - XE_SELECT_PAGE(2); - - /* - * Turn on data output. - */ - XE_MII_SET(XE_MII_DIR); - - xe_mii_sync(scp); - - xe_mii_send(scp, frame->mii_stdelim, 2); - xe_mii_send(scp, frame->mii_opcode, 2); - xe_mii_send(scp, frame->mii_phyaddr, 5); - xe_mii_send(scp, frame->mii_regaddr, 5); - xe_mii_send(scp, frame->mii_turnaround, 2); - xe_mii_send(scp, frame->mii_data, 16); - - /* Idle bit. */ - XE_MII_SET(XE_MII_CLK); - DELAY(1); - XE_MII_CLR(XE_MII_CLK); - DELAY(1); - - /* - * Turn off xmit. - */ - XE_MII_CLR(XE_MII_DIR); - - splx(s); - - return(0); -} - - -/* - * Read a register from the PHY. - */ -static u_int16_t -xe_phy_readreg(struct xe_softc *scp, u_int16_t reg) { - struct xe_mii_frame frame; - - bzero((char *)&frame, sizeof(frame)); - - frame.mii_phyaddr = 0; - frame.mii_regaddr = reg; - xe_mii_readreg(scp, &frame); - - return(frame.mii_data); -} - - -/* - * Write to a PHY register. - */ -static void -xe_phy_writereg(struct xe_softc *scp, u_int16_t reg, u_int16_t data) { - struct xe_mii_frame frame; - - bzero((char *)&frame, sizeof(frame)); - - frame.mii_phyaddr = 0; - frame.mii_regaddr = reg; - frame.mii_data = data; - xe_mii_writereg(scp, &frame); - - return; -} - - -#ifdef XE_DEBUG -/* - * A bit of debugging code. - */ -static void -xe_mii_dump(struct xe_softc *scp) { - int i, s; - - s = splimp(); - - printf("xe%d: MII registers: ", scp->unit); - for (i = 0; i < 2; i++) { - printf(" %d:%04x", i, xe_phy_readreg(scp, i)); - } - for (i = 4; i < 7; i++) { - printf(" %d:%04x", i, xe_phy_readreg(scp, i)); - } - printf("\n"); - - (void)splx(s); -} - -static void -xe_reg_dump(struct xe_softc *scp) { - int page, i, s; - - s = splimp(); - - printf("xe%d: Common registers: ", scp->unit); - for (i = 0; i < 8; i++) { - printf(" %2.2x", XE_INB(i)); - } - printf("\n"); - - for (page = 0; page <= 8; page++) { - printf("xe%d: Register page %2.2x: ", scp->unit, page); - XE_SELECT_PAGE(page); - for (i = 8; i < 16; i++) { - printf(" %2.2x", XE_INB(i)); - } - printf("\n"); - } - - for (page = 0x10; page < 0x5f; page++) { - if ((page >= 0x11 && page <= 0x3f) || - (page == 0x41) || - (page >= 0x43 && page <= 0x4f) || - (page >= 0x59)) - continue; - printf("xe%d: Register page %2.2x: ", scp->unit, page); - XE_SELECT_PAGE(page); - for (i = 8; i < 16; i++) { - printf(" %2.2x", XE_INB(i)); - } - printf("\n"); - } - - (void)splx(s); -} -#endif - - - -#if NAPM > 0 -/************************************************************** - * * - * A P M F U N C T I O N S * - * * - **************************************************************/ - -/* - * This is called when we go into suspend/standby mode - */ -static int -xe_suspend(void *xunit) { - -#ifdef XE_DEBUG - struct xe_softc *scp = sca[(int)xunit]; - - printf("xe%d: APM suspend\n", scp->unit); -#endif - - return 0; -} - -/* - * This is called when we wake up again - */ -static int -xe_resume(void *xunit) { - -#ifdef XE_DEBUG - struct xe_softc *scp = sca[(int)xunit]; - - printf("xe%d: APM resume\n", scp->unit); -#endif - - return 0; -} - -#endif /* NAPM > 0 */ - -#endif /* NCARD > 0 */ - -#endif /* NXE > 0 */ diff --git a/sys/dev/pccard/if_xereg.h b/sys/dev/pccard/if_xereg.h deleted file mode 100644 index 981c5c4bd06c..000000000000 --- a/sys/dev/pccard/if_xereg.h +++ /dev/null @@ -1,697 +0,0 @@ -/*- - * Copyright (c) 1998, 1999 Scott Mitchell - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: if_xereg.h,v 1.5 1999/05/20 21:53:58 scott Exp $ - * $FreeBSD$ - */ - -/* - * Register definitions for Xircom PCMCIA Ethernet controllers, based on - * Rev. B of the "Dingo" 10/100 controller used in Xircom CEM56 and RealPort - * Ethernet/modem cards. The Dingo can be configured to be register - * compatible with the "Mohawk" 10/100 controller used in Xircom CE3 cards - * (also some Intel and Compaq OEM versions of the CE3). The older 10Mbps CE2 - * cards seem to use earlier revisions of the same device. Some registers and - * bits below are marked 'CE2 only'; these are used by Werner Koch's xirc2ps - * driver that was originally for the CE2 but, according to the spec, aren't - * present on the Dingo. They often seem to relate to operation on coax - * cables, which Mohawk can do in theory (it has the SSI interface) so they - * _might_ also work on Mohawk. I've also noted the few registers that are - * specific to Dingo. - * - * As far as I can tell, the Dingo is basically a Mohawk device with a few - * registers and support for a second PCMCIA function (the modem) added. In - * Dingo mode the SSI (non-MII) PHY interface of the Mohawk is not available. - * The CE2 chip is most likely a Mohawk without the MII and definitely with a - * slightly different register set. - * - * In all cases, the controller uses a paged model of register access. The - * first eight registers are always the same, the function of the second eight - * is selected by the value in the Page Register (reg 0x01). - * - * References: - * 1. Dingo External Reference Specification, Revision B. Xircom Inc., - * Thousand Oaks, California. August 1998. Available under licence from - * Xircom, http://www.xircom.com/ - * 2. ML6692 100BASE-TX Physical Layer with MII specification. MicroLinear - * Corp, San Jose, California. May 1997. Available for download from - * http://www.microlinear.com/ - * 3. DP83840 10/100 Mb/s Ethernet Physical Layer specification. National - * Semiconductor Corp., Arlington, Texas. March 1997. Available for - * download from http://www.ns.com/ - * 4. Werner Koch's xirc2ps driver for Linux, for all the CE2 and CE3 frobs - * that aren't documented in the Xircom spec. Available for download from - * http://www.d.shuttle.de/isil/xircom/xirc2ps.html - */ - -#include "xe.h" -#if NXE > 0 - - - -/******************* - * PCMCIA registers - *******************/ - -/* - * These are probably Dingo-specific, but you won't need them unless you have - * a CEM card that needs a bit of hackery to get the Ethernet function to - * operate. All addresses are in card attribute space. - */ -#define DINGO_CIS 0x0000 /* Start of CIS tuples */ -#define DINGO_ETH 0x0800 /* Ethernet configuration registers */ -#define DINGO_COR 0x0820 /* Dingo configuration option registers */ -#define DINGO_2ND 0x0840 /* 2nd function configuration registers */ - - -/* - * Ethernet configuration registers - */ -#define DINGO_ECOR (DINGO_ETH+0) /* Ethernet Configuration Option Register */ -#define DINGO_ECSR (DINGO_ETH+2) /* Ethernet Configuration Status Register */ -#define DINGO_EBAR0 (DINGO_ETH+10) /* Ethernet Base Address Register bits 7:4 (3:0 always 0) */ -#define DINGO_EBAR1 (DINGO_ETH+12) /* Ethernet Base Address Register bits 15:8 */ - -/* DINGO_ECOR bits */ -#define DINGO_ECOR_ETH_ENABLE 0x01 /* 1 = Enable Ethernet part of adapter */ -#define DINGO_ECOR_IOB_ENABLE 0x02 /* 1 = Enable EBAR, else use INDEX bits */ -#define DINGO_ECOR_INT_ENABLE 0x04 /* 1 = Enable Ethernet interrupts */ -#define DINGO_ECOR_IOB_INDEX 0x18 /* 00 = 0x300; 01 = 0x310; 10 = 0x320; 11 = no IO base */ -#define DINGO_ECOR_IOB_SHIFT 0x03 -#define DINGO_ECOR_IRQ_STSCHG 0x20 /* 1 = Route interrupts to -STSCHG pin, else use -INT pin */ -#define DINGO_ECOR_IRQ_LEVEL 0x40 /* 1 = Level-triggered interrupts, else edge-triggered */ -#define DINGO_ECOR_SRESET 0x80 /* 1 = Soft reset Ethernet adpater. Must write to 0 */ - -/* DINGO_ECSR bits */ -#define DINGO_ECSR_INT_ACK 0x01 /* 1 = Host must acknowledge interrupts (Clear ECSR_INT bit) */ -#define DINGO_ECSR_INT 0x02 /* 1 = Interrupt service requested */ -#define DINGO_ECSR_POWER_DOWN 0x04 /* 1 = Power down Ethernet adapter */ - -/* - * EBAR0/EBAR1 set the I/O base address of the Ethernet adapter when - * ECOR_IOB_ENABLE is set. 12 significant bits. - */ - - -/* - * Dingo configuration registers - */ -#define DINGO_DCOR0 (DINGO_COR+0) /* Dingo Configuration Options Register 0 */ -#define DINGO_DCOR1 (DINGO_COR+2) /* Dingo Configuration Options Register 1 */ -#define DINGO_DCOR2 (DINGO_COR+4) /* Dingo Configuration Options Register 2 */ -#define DINGO_DCOR3 (DINGO_COR+6) /* Dingo Configuration Options Register 3 */ -#define DINGO_DCOR4 (DINGO_COR+8) /* Dingo Configuration Options Register 4 */ - -/* DINGO_DCOR0 bits */ -#define DINGO_DCOR0_SF_INT 0x01 /* 1 = Enable 2ndF interrupts (alternate to SFCOR:2) */ -#define DINGO_DCOR0_DECODE 0x04 /* 1 = Decode 2ndF interrupts in Dingo, else in 2ndF */ -#define DINGO_DCOR0_BUS 0x08 /* 1 = 2ndF bus is ISA, else PCMCIA */ -#define DINGO_DCOR0_LED3_POWER 0x10 /* 1 = Drive LED3 line from SFCSR:2 */ -#define DINGO_DCOR0_LED3_RESET 0x20 /* 1 = Drive LED3 line from SFCOR:7 */ -#define DINGO_DCOR0_MR_POWER 0x40 /* 1 = Drive MRESET line from SFCSR:2 */ -#define DINGO_DCOR0_MR_RESET 0x80 /* 1 = Drive MRESET line from SFCOR:7 */ - -/* DINGO_DCOR1 bits */ -#define DINGO_DCOR1_INT_STSCHG 0x01 /* 1 = Route 2ndF interrupts to -STSCHG (alternate to SFCOR:5) */ -#define DINGO_DCOR1_MSTSCHG 0x02 /* 1 = Route 2ndF -MSTSCHG line to -STSCHG */ -#define DINGO_DCOR1_EEDIO 0x04 /* 1 = Use EEDIO pin as data line 6 to 2ndF */ -#define DINGO_DCOR1_INT_LEVEL 0x08 /* 1 = Force level-triggered interrupts from 2ndF */ -#define DINGO_DCOR1_SHADOW_CSR 0x10 /* Reserved, always write 0 */ -#define DINGO_DCOR1_SHADOW_IOB 0x20 /* Reserved, always write 0 */ -#define DINGO_DCOR1_CSR_WAIT 0xC0 /* Reserved, always write 0 */ -#define DINGO_DCOR1_CSR_SHIFT 0x06 - -/* DINGO_DCOR2 bits */ -#define DINGO_DCOR2_SHM_BASE 0x0f /* Bits 15-12 of Ethernet shared memory window */ -#define DINGO_DCOR2_SHM_SHIFT 0x00 -#define DINGO_DCOR2_SHADOW_COR 0x10 /* Reserved, always write 0 */ - -/* - * DCOR3/DCOR4 configure Dingo to assert -IOIS16 on any access to each pair of - * ports in the range SFIOB+0 .. SFIOB+31. Each pair can be set individually, - * eg. DCOR3:0 enables this function on ports SFIOB+0 and SFIOB+1. - */ - - -/* - * Second function configuration registers - */ -#define DINGO_SFCOR (DINGO_2ND+0) /* 2nd Function Configuration Option Register */ -#define DINGO_SFCSR (DINGO_2ND+2) /* 2nd Function Configuration Status Register */ -#define DINGO_SFBAR0 (DINGO_2ND+10) /* 2nd Function Base Address Register bits 7:0 */ -#define DINGO_SFBAR1 (DINGO_2ND+12) /* 2nd Function Base Address Register bits 15:8 */ -#define DINGO_SFILR (DINGO_2ND+18) /* 2nd Function I/O Limit Register */ - -/* DINGO_SFCOR bits */ -#define DINGO_SFCOR_SF_ENABLE 0x01 /* 1 = Enable second fuction */ -#define DINGO_SFCOR_IOB_ENABLE 0x02 /* 1 = Enable SFBAR, else use COM_SELECT bits */ -#define DINGO_SFCOR_INT_ENABLE 0x04 /* 1 = Enable second function interrupts */ -#define DINGO_SFCOR_COM_SELECT 0x18 /* 00 = 0x3f8; 01 = 0x2f8; 10 = 0x3e8; 11 = 0x2e8 */ -#define DINGO_SFCOR_COM_SHIFT 0x03 -#define DINGO_SFCOR_IRQ_STSCHG 0x20 /* 1 = Route interrupts to -STSCHG pin, else use -INT pin */ -#define DINGO_SFCOR_IRQ_LEVEL 0x40 /* 1 = Level-triggered interrupts, else edge-triggered */ -#define DINGO_SFCOR_SRESET 0x80 /* 1 = Soft reset second function. Must write to 0 */ - -/* DINGO_SFCSR bits */ -#define DINGO_SFCSR_INT_ACK 0x01 /* 1 = Host must acknowledge interrupts (Clear SFCSR_INT bit) */ -#define DINGO_SFCSR_INT 0x02 /* 1 = Interrupt service requested */ -#define DINGO_SFCSR_POWER_DOWN 0x04 /* 1 = Power down second function */ - -/* - * SFBAR0/SFBAR1 set the I/O base address of the second function when - * SFCOR_IOB_ENABLE is set. 16 significant bits. - */ - -/* - * SFILR is a bitmap of address lines 7:0 decoded by the second function - * device. Eg. a device with 16 ports should write 0x0f to this register. - */ - - - -/******************************** - * Ethernet controller registers - ********************************/ - -/* - * Common registers (available from any register page) - * - * Note: The EDP is actually 32 bits wide, occupying registers 2-5. In PCMCIA - * operation we can only access 16 bits at once, through registers 4 & 5. - */ -#define XE_CR 0x00 /* Command register (write) */ -#define XE_ESR 0x00 /* Ethernet status register (read) */ -#define XE_PR 0x01 /* Page select register */ -#define XE_EDP 0x04 /* Ethernet data port */ -#define XE_ISR 0x06 /* Ethernet interrupt status register (read) */ -#define XE_GIR 0x07 /* Global interrupt register (Dingo only) */ - -/* XE_CR bits */ -#define XE_CR_TX_PACKET 0x01 /* Transmit packet */ -#define XE_CR_SOFT_RESET 0x02 /* Software reset */ -#define XE_CR_ENABLE_INTR 0x04 /* Enable interrupts */ -#define XE_CR_FORCE_INTR 0x08 /* Force an interrupt */ -#define XE_CR_CLEAR_FIFO 0x10 /* Clear FIFO after transmit overrun */ -#define XE_CR_CLEAR_OVERRUN 0x20 /* Clear receive overrun condition */ -#define XE_CR_RESTART_TX 0x40 /* Restart TX after 16 collisions or TX underrun */ - -/* XE_ESR bits */ -#define XE_ESR_FULL_PACKET_RX 0x01 /* At least one full packet received */ -#define XE_ESR_PART_PACKET_RX 0x02 /* At least 64 bytes of packet received */ -#define XE_ESR_REJECT_PACKET 0x04 /* Partial packet rejected */ -#define XE_ESR_TX_PENDING 0x08 /* At least one packet waiting to transmit */ -#define XE_ESR_BAD_POLARITY 0x10 /* Bad cable polarity? (CE2 only) */ -#define XE_ESR_MEDIA_SELECT 0x20 /* SSI(?) media select: 1 = Twisted pair; 0 = AUI */ - -/* XE_ISR bits */ -#define XE_ISR_TX_OVERFLOW 0x01 /* No space in transmit buffer */ -#define XE_ISR_TX_PACKET 0x02 /* Packet sent successfully */ -#define XE_ISR_MAC_INTR 0x04 /* Some kind of MAC interrupt happened */ -#define XE_ISR_RX_EARLY 0x10 /* Incoming packet in early receive mode */ -#define XE_ISR_RX_PACKET 0x20 /* Complete packet received successfully */ -#define XE_ISR_RX_REJECT 0x40 /* Partial incoming packet rejected by MAC */ -#define XE_ISR_FORCE_INTR 0x80 /* Interrupt forced */ - -/* XE_GIR bits */ -#define XE_GIR_ETH_IRQ 0x01 /* Ethernet IRQ pending */ -#define XE_GIR_ETH_MASK 0x02 /* 1 = Mask Ethernet interrupts to host */ -#define XE_GIR_SF_IRQ 0x04 /* Second function IRQ pending */ -#define XE_GIR_SF_MASK 0x08 /* 1 = Mask second function interrupts to host */ - - -/* - * Page 0 registers - */ -#define XE_TSO 0x08 /* Transmit space open (17 bits) */ -#define XE_TRS 0x0a /* Transmit reservation size (CE2 only, removed in rev. 1) */ -#define XE_DO 0x0c /* Data offset register (13 bits/3 flags, write) */ -#define XE_RSR 0x0c /* Receive status register (read) */ -#define XE_TPR 0x0d /* Packets transmitted register (read) */ -#define XE_RBC 0x0e /* Received byte count (13 bits/3 flags, read) */ - -/* XE_DO bits */ -#define XE_DO_OFFSET 0x1fff /* First byte fetched when CHANGE_OFFSET issued */ -#define XE_DO_OFFSET_SHIFT 0x00 -#define XE_DO_CHANGE_OFFSET 0x2000 /* Flush RX FIFO, start fetching from OFFSET */ -#define XE_DO_SHARED_MEM 0x4000 /* Enable shared memory mode */ -#define XE_DO_SKIP_RX_PACKET 0x8000 /* Skip to next packet in buffer memory */ - -/* XE_RSR bits */ -#define XE_RSR_PHYS_PACKET 0x01 /* 1 = Physical packet, 0 = Multicast packet */ -#define XE_RSR_BCAST_PACKET 0x02 /* Broadcast packet */ -#define XE_RSR_LONG_PACKET 0x04 /* Packet >1518 bytes */ -#define XE_RSR_ADDR_MATCH 0x08 /* Packet matched one of our node addresses */ -#define XE_RSR_ALIGN_ERROR 0x10 /* Bad alignment? (CE2 only) */ -#define XE_RSR_CRC_ERROR 0x20 /* Incorrect CRC */ -#define XE_RSR_RX_OK 0x80 /* No errors on received packet */ - -/* XE_RBC bits */ -#define XE_RBC_BYTE_COUNT 0x1fff /* Bytes received for current packet */ -#define XE_RBC_COUNT_SHIFT 0x00 -#define XE_RBC_FULL_PACKET_RX 0x2000 /* These mirror bits 2:0 of ESR, if ECR:7 is set */ -#define XE_RBC_PART_PACKET_RX 0x4000 -#define XE_RBC_REJECT_PACKET 0x8000 - - -/* - * Page 1 registers - */ -#define XE_IMR0 0x0c /* Interrupt mask register 0 */ -#define XE_IMR1 0x0d /* Interrupt mask register 1 (CE2 only) */ -#define XE_ECR 0x0e /* Ethernet configuration register */ - -/* XE_IMR0 bits */ -#define XE_IMR0_TX_OVERFLOW 0x01 /* Masks for bits in ISR */ -#define XE_IMR0_TX_PACKET 0x02 -#define XE_IMR0_MAC_INTR 0x04 -#define XE_IMR0_RX_EARLY 0x10 -#define XE_IMR0_RX_PACKET 0x20 -#define XE_IMR0_RX_REJECT 0x40 -#define XE_IMR0_FORCE_INTR 0x80 - -/* XE_ECR bits */ -#define XE_ECR_EARLY_TX 0x01 /* Enable early transmit mode */ -#define XE_ECR_EARLY_RX 0x02 /* Enable early receive mode */ -#define XE_ECR_FULL_DUPLEX 0x04 /* Enable full-duplex (disable collision detection) */ -#define XE_ECR_LONG_TPCABLE 0x08 /* CE2 only */ -#define XE_ECR_NO_POL_COL 0x10 /* CE2 only */ -#define XE_ECR_NO_LINK_PULSE 0x20 /* Don't check/send link pulses (not 10BT compliant) */ -#define XE_ECR_NO_AUTO_TX 0x40 /* CE2 only */ -#define XE_ECR_SOFT_COMPAT 0x80 /* Map ESR bits 2:0 to RBC bits 15:13 */ - - -/* - * Page 2 registers - */ -#define XE_RBS 0x08 /* Receive buffer start (16 bits) */ -#define XE_LED 0x0a /* LED control register */ -#define XE_LED3 0x0b /* LED3 control register */ -#define XE_MSR 0x0c /* Misc. setup register (Mohawk specific register?) */ -#define XE_GPR2 0x0d /* General purpose register 2 */ - -/* - * LED function selection: - * 000 - Disabled - * 001 - Collision activity - * 010 - !Collision activity - * 011 - 10Mbit link detected - * 100 - 100Mbit link detected - * 101 - 10/100Mbit link detected - * 110 - Automatic assertion - * 111 - Transmit activity - */ - -/* XE_LED bits */ -#define XE_LED_LED0_MASK 0x07 /* LED0 function selection */ -#define XE_LED_LED0_SHIFT 0x00 -#define XE_LED_LED1_MASK 0x38 /* LED1 function selection */ -#define XE_LED_LED1_SHIFT 0x03 -#define XE_LED_LED0_RX 0x40 /* Add receive activity to LED0 */ -#define XE_LED_LED1_RX 0x80 /* Add receive activity to LED1 */ - -/* XE_LED3 bits */ -#define XE_LED3_MASK 0x07 /* LED3 function selection */ -#define XE_LED3_SHIFT 0x00 -#define XE_LED3_RX 0x40 /* Add receive activity to LED3 */ - -/* XE_MSR bits */ -#define XE_MSR_128K_SRAM 0x01 /* Select 128K SRAM */ -#define XE_MSR_RBS_BIT16 0x02 /* Bit 16 of RBS (only useful with big SRAM) */ -#define XE_MSR_MII_SELECT 0x08 /* Select MII instead of SSI interface */ -#define XE_MSR_HASH_TABLE 0x20 /* Enable hash table filtering */ - -/* XE_GPR2 bits */ -#define XE_GPR2_GP3_OUT 0x01 /* Value written to GP3 line */ -#define XE_GPR2_GP4_OUT 0x02 /* Value written to GP4 line */ -#define XE_GPR2_GP3_SELECT 0x04 /* 1 = GP3 is output, 0 = GP3 is input */ -#define XE_GPR2_GP4_SELECT 0x08 /* 1 = GP4 is output, 0 = GP3 is input */ -#define XE_GPR2_GP3_IN 0x10 /* Value read from GP3 line */ -#define XE_GPR2_GP4_IN 0x20 /* Value read from GP4 line */ - - -/* - * Page 3 registers - */ -#define XE_TPT 0x0a /* Transmit packet threshold (13 bits) */ - - -/* - * Page 4 registers - */ -#define XE_GPR0 0x08 /* General purpose register 0 */ -#define XE_GPR1 0x09 /* General purpose register 1 */ -#define XE_BOV 0x0a /* Bonding version register (read) */ -#define XE_EES 0x0b /* EEPROM control register */ -#define XE_LMA 0x0c /* Local memory address (CE2 only) */ -#define XE_LMD 0x0e /* Local memory data (CE2 only) */ - -/* XE_GPR0 bits */ -#define XE_GPR0_GP1_OUT 0x01 /* Value written to GP1 line */ -#define XE_GPR0_GP2_OUT 0x02 /* Value wirtten to GP2 line */ -#define XE_GPR0_GP1_SELECT 0x04 /* 1 = GP1 is output, 0 = GP1 is input */ -#define XE_GPR0_GP2_SELECT 0x08 /* 1 = GP2 is output, 0 = GP2 is input */ -#define XE_GPR0_GP1_IN 0x10 /* Value read from GP1 line */ -#define XE_GPR0_GP2_IN 0x20 /* Value read from GP2 line */ - -/* XE_GPR1 bits */ -#define XE_GPR1_POWER_DOWN 0x01 /* Power down analog section (down to 20mA load) */ - -/* XE_BOV values */ -#define XE_BOV_DINGO 0x55 /* Dingo in Dingo mode */ -#define XE_BOV_MOHAWK 0x41 /* Original Mohawk */ -#define XE_BOV_MOHAWK_REV1 0x45 /* Rev. 1 Mohawk, or Dingo in Mohawk mode */ -#define XE_BOV_CEM28 0x11 /* CEM28 */ - -/* XE_EES bits */ -#define XE_EES_SCL_OUTPUT 0x01 /* Value written to SCL line, when MANUAL_ROM set */ -#define XE_EES_SDA_OUTPUT 0x02 /* Value written to SDA line, when MANUAL_ROM set */ -#define XE_EES_SDA_INPUT 0x04 /* Value read from SDA line */ -#define XE_EES_SDA_TRISTATE 0x08 /* 1 = SDA is output, 0 = SDA is input */ -#define XE_EES_MANUAL_ROM 0x20 /* Enable manual contro of serial EEPROM */ - - -/* - * Page 5 registers (all read only) - */ -#define XE_CRHA 0x08 /* Current Rx host address (16 bits) */ -#define XE_RHSA 0x0a /* Rx host start address (16 bits) */ -#define XE_RNSA 0x0c /* Rx network start address (16 bits) */ -#define XE_CRNA 0x0e /* Current Rx network address (16 bits) */ - - -/* - * Page 6 registers (all read only) - */ -#define XE_CTHA 0x08 /* Current Tx host address (16 bits) */ -#define XE_THSA 0x0a /* Tx host start address (16 bits) */ -#define XE_TNSA 0x0c /* Tx network statr address (16 bits) */ -#define XE_CTNA 0x0e /* Current Tx network address (16 bits) */ - - -/* - * Page 8 registers (all read only) - */ -#define XE_THBC 0x08 /* Tx host byte count (16 bits) */ -#define XE_THPS 0x0a /* Tx host packet size (16 bits) */ -#define XE_TNBC 0x0c /* Tx network byte count (16 bits) */ -#define XE_TNPS 0x0e /* Tx network packet size (16 bits) */ - - -/* - * Page 0x10 registers (all read only) - */ -#define XE_DINGOID 0x08 /* Dingo ID register (16 bits) (Dingo only) */ -#define XE_RevID 0x0a /* Dingo revision ID (16 bits) (Dingo only) */ -#define XE_VendorID 0x0c /* Dingo vendor ID (16 bits) (Dingo only) */ - -/* Values for the above registers */ -#define XE_DINGOID_DINGO3 0x444b /* In both Dingo and Mohawk modes */ -#define XE_RevID_DINGO3 0x0001 -#define XE_VendorID_DINGO3 0x0041 - - -/* - * Page 0x40 registers - */ -#define XE_CMD0 0x08 /* MAC Command register (write) */ -#define XE_RST0 0x09 /* Receive status register */ -#define XE_TXST0 0x0b /* Transmit status register 0 */ -#define XE_TXST1 0x0c /* Transmit status register 1 */ -#define XE_RX0Msk 0x0d /* Receive status mask register */ -#define XE_TX0Msk 0x0e /* Transmit status 0 mask register */ -#define XE_TX1Msk 0x0f /* Transmit status 1 mask register */ - -/* CMD0 bits */ -#define XE_CMD0_TX 0x01 /* CE2 only */ -#define XE_CMD0_RX_ENABLE 0x04 /* Enable receiver */ -#define XE_CMD0_RX_DISABLE 0x08 /* Disable receiver */ -#define XE_CMD0_ABORT 0x10 /* CE2 only */ -#define XE_CMD0_ONLINE 0x20 /* Take MAC online */ -#define XE_CMD0_ACK_INTR 0x40 /* CE2 only */ -#define XE_CMD0_OFFLINE 0x80 /* Take MAC offline */ - -/* RST0 bits */ -#define XE_RST0_LONG_PACKET 0x02 /* Packet received with >1518 and <8184 bytes */ -#define XE_RST0_CRC_ERROR 0x08 /* Packet received with incorrect CRC */ -#define XE_RST0_RX_OVERRUN 0x10 /* Receiver overrun, byte(s) dropped */ -#define XE_RST0_RX_ENABLE 0x20 /* Receiver enabled */ -#define XE_RST0_RX_ABORT 0x40 /* Receive aborted: CRC, FIFO overrun or addr mismatch */ -#define XE_RST0_RX_OK 0x80 /* Complete packet received OK */ - -/* TXST0 bits */ -#define XE_TXST0_NO_CARRIER 0x01 /* Lost carrier. Only valid in 10Mbit half-duplex */ -#define XE_TXST0_16_COLLISIONS 0x02 /* Packet aborted after 16 collisions */ -#define XE_TXST0_TX_UNDERRUN 0x08 /* MAC ran out of data to send */ -#define XE_TXST0_LATE_COLLISION 0x10 /* Collision later than 512 bits */ -#define XE_TXST0_SQE_FAIL 0x20 /* SQE test failed. */ -#define XE_TXST0_TX_ABORT 0x40 /* Transmit aborted: collisions, underrun or overrun */ -#define XE_TXST0_TX_OK 0x80 /* Complete packet sent OK */ - -/* TXST1 bits */ -#define XE_TXST1_RETRY_COUNT 0x0f /* Collision counter for current packet */ -#define XE_TXST1_LINK_STATUS 0x10 /* Valid link status */ - -/* RX0Msk bits */ -#define XE_RX0M_LONG_PACKET 0x02 /* Masks for bits in RXST0 */ -#define XE_RX0M_ALIGN_ERROR 0x04 /* Alignment error (CE2 only) */ -#define XE_RX0M_CRC_ERROR 0x08 -#define XE_RX0M_RX_OVERRUN 0x10 -#define XE_RX0M_RX_ABORT 0x40 -#define XE_RX0M_RX_OK 0x80 - -/* TX0Msk bits */ -#define XE_TX0M_NO_CARRIER 0x01 /* Masks for bits in TXST0 */ -#define XE_TX0M_16_COLLISIONS 0x02 -#define XE_TX0M_TX_UNDERRUN 0x08 -#define XE_TX0M_LATE_COLLISION 0x10 -#define XE_TX0M_SQE_FAIL 0x20 -#define XE_TX0M_TX_ABORT 0x40 -#define XE_TX0M_TX_OK 0x80 - -/* TX1Msk bits */ -#define XE_TX1M_PKTDEF 0x20 - - -/* - * Page 0x42 registers - */ -#define XE_SWC0 0x08 /* Software configuration 0 */ -#define XE_SWC1 0x09 /* Software configuration 1 */ -#define XE_BOC 0x0a /* Back-off configuration */ -#define XE_TCD 0x0b /* Transmit collision deferral */ - -/* SWC0 bits */ -#define XE_SWC0_LOOPBACK_ENABLE 0x01 /* Enable loopback operation */ -#define XE_SWC0_LOOPBACK_SOURCE 0x02 /* 1 = Transceiver, 0 = MAC */ -#define XE_SWC0_ACCEPT_ERROR 0x04 /* Accept otherwise OK packets with CRC errors */ -#define XE_SWC0_ACCEPT_SHORT 0x08 /* Accept otherwise OK packets that are too short */ -#define XE_SWC0_NO_CRC_INSERT 0x40 /* Don't add CRC to outgoing packets */ - -/* SWC1 bits */ -#define XE_SWC1_IA_ENABLE 0x01 /* Enable individual address filters */ -#define XE_SWC1_ALLMULTI 0x02 /* Accept all multicast packets */ -#define XE_SWC1_PROMISCUOUS 0x04 /* Accept all non-multicast packets */ -#define XE_SWC1_BCAST_DISABLE 0x08 /* Reject broadcast packets */ -#define XE_SWC1_MEDIA_SELECT 0x40 /* AUI media select (Mohawk only) */ -#define XE_SWC1_AUTO_MEDIA 0x80 /* Auto media select (Mohawk only) */ - - -/* - * Page 0x44 registers (CE2 only) - */ -#define XE_TDR0 0x08 /* Time domain reflectometry register 0 */ -#define XE_TDR1 0x09 /* Time domain reflectometry register 1 */ -#define XE_RXC0 0x0a /* Receive byte count low */ -#define XE_RXC1 0x0b /* Receive byte count high */ - - -/* - * Page 0x45 registers (CE2 only) - */ -#define XE_REV 0x0f /* Revision (read) */ - - -/* - * Page 0x50-0x57: Individual address 0-9 - * - * Used to filter incoming packets by matching against individual node - * addresses. If IA matching is enabled (SWC1, bit0) any incoming packet with - * a destination matching one of these 10 addresses will be received. IA0 is - * always enabled and usually matches the card's unique address. - * - * Addresses are stored LSB first, ie. IA00 (reg. 8 on page 0x50) contains the - * LSB of IA0, and so on. The data is stored contiguously, in that addresses - * can be broken across page boundaries. That is: - * - * Reg: 50/8 50/9 50/a 50/b 50/c 50/d 50/e 50/f 51/8 51/9 ... 57/a 57/b - * IA00 IA01 IA02 IA03 IA04 IA05 IA10 IA11 IA12 IA13 ... IA94 IA95 - */ - -/* - * Page 0x58: Multicast hash table filter - * - * In case the 10 individual addresses aren't enough, we also have a multicast - * hash filter, enabled through MSR:5. The most significant six bits of the - * CRC on each incoming packet are reversed and used as an index into the 64 - * bits of the hash table. If the appropriate bit is set the packet it - * received, although higher layers may still need to filter it out. The CRC - * calculation is as follows: - * - * crc = 0xffffffff; - * poly = 0x04c11db6; - * for (i = 0; i < 6; i++) { - * current = mcast_addr[i]; - * for (k = 1; k <= 8; k++) { - * if (crc & 0x80000000); - * crc31 = 0x01; - * else - * crc31 = 0; - * bit = crc31 ^ (current & 0x01); - * crc <<= 1; - * current >>= 1; - * if (bit) - * crc = (crc ^ poly)|1 - * } - * } - */ - - - -/**************** - * MII registers - ****************/ - -/* - * Basic MII-compliant PHY register definitions. According to the Dingo spec, - * PHYs from (at least) MicroLinear, National Semiconductor, ICS, TDK and - * Quality Semiconductor have been used. These apparently all come up with - * PHY ID 0x00 unless the "interceptor module" on the Dingo 3 is in use. With - * the interceptor enabled, the PHY is faked up to look like an ICS unit with - * ID 0x16. The interceptor can be enabled/disabled in software. - * - * The ML6692 (and maybe others) doesn't have a 10Mbps mode -- this is handled - * by an internal 10Mbps transceiver that we know nothing about... some cards - * seem to work with the MII in 10Mbps mode, so I guess some PHYs must support - * it. The question is, how can you figure out which one you have? Just to - * add to the fun there are also 10Mbps _only_ Mohawk/Dingo cards. Aaargh! - */ - -/* - * Masks for the MII-related bits in GPR2 - */ -#define XE_MII_CLK XE_GPR2_GP3_OUT -#define XE_MII_DIR XE_GPR2_GP4_SELECT -#define XE_MII_WRD XE_GPR2_GP4_OUT -#define XE_MII_RDD XE_GPR2_GP4_IN - -/* - * MII PHY ID register values - */ -#define PHY_ID_ML6692 0x0000 /* MicroLinear ML6692? Or unknown */ -#define PHY_ID_ICS1890 0x0015 /* ICS1890 */ -#define PHY_ID_QS6612 0x0181 /* Quality QS6612 */ -#define PHY_ID_DP83840 0x2000 /* National DP83840 */ - -/* - * MII command (etc) bit strings. - */ -#define XE_MII_STARTDELIM 0x01 -#define XE_MII_READOP 0x02 -#define XE_MII_WRITEOP 0x01 -#define XE_MII_TURNAROUND 0x02 - -/* - * PHY registers. - */ -#define PHY_BMCR 0x00 /* Basic Mode Control Register */ -#define PHY_BMSR 0x01 /* Basic Mode Status Register */ -#define PHY_ID1 0x02 /* PHY ID 1 */ -#define PHY_ID2 0x03 /* PHY ID 2 */ -#define PHY_ANAR 0x04 /* Auto-Negotiation Advertisment Register */ -#define PHY_LPAR 0x05 /* Auto-Negotiation Link Partner Ability Register */ -#define PHY_ANER 0x06 /* Auto-Negotiation Expansion Register */ - -/* BMCR bits */ -#define PHY_BMCR_RESET 0x8000 /* Soft reset PHY. Self-clearing */ -#define PHY_BMCR_LOOPBK 0x4000 /* Enable loopback */ -#define PHY_BMCR_SPEEDSEL 0x2000 /* 1=100Mbps, 0=10Mbps */ -#define PHY_BMCR_AUTONEGENBL 0x1000 /* Auto-negotiation enabled */ -#define PHY_BMCR_ISOLATE 0x0400 /* Isolate ML6692 from MII */ -#define PHY_BMCR_AUTONEGRSTR 0x0200 /* Restart auto-negotiation. Self-clearing */ -#define PHY_BMCR_DUPLEX 0x0100 /* Full duplex operation */ -#define PHY_BMCR_COLLTEST 0x0080 /* Enable collision test */ - -/* BMSR bits */ -#define PHY_BMSR_100BT4 0x8000 /* 100Base-T4 capable */ -#define PHY_BMSR_100BTXFULL 0x4000 /* 100Base-TX full duplex capable */ -#define PHY_BMSR_100BTXHALF 0x2000 /* 100Base-TX half duplex capable */ -#define PHY_BMSR_10BTFULL 0x1000 /* 10Base-T full duplex capable */ -#define PHY_BMSR_10BTHALF 0x0800 /* 10Base-T half duplex capable */ -#define PHY_BMSR_AUTONEGCOMP 0x0020 /* Auto-negotiation complete */ -#define PHY_BMSR_CANAUTONEG 0x0008 /* Auto-negotiation supported */ -#define PHY_BMSR_LINKSTAT 0x0004 /* Link is up */ -#define PHY_BMSR_EXTENDED 0x0001 /* Extended register capabilities */ - -/* ANAR bits */ -#define PHY_ANAR_NEXTPAGE 0x8000 /* Additional link code word pages */ -#define PHY_ANAR_TLRFLT 0x2000 /* Remote wire fault detected */ -#define PHY_ANAR_100BT4 0x0200 /* 100Base-T4 capable */ -#define PHY_ANAR_100BTXFULL 0x0100 /* 100Base-TX full duplex capable */ -#define PHY_ANAR_100BTXHALF 0x0080 /* 100Base-TX half duplex capable */ -#define PHY_ANAR_10BTFULL 0x0040 /* 10Base-T full duplex capable */ -#define PHY_ANAR_10BTHALF 0x0020 /* 10Base-T half duplex capable */ -#define PHY_ANAR_PROTO4 0x0010 /* Protocol selection (00001 = 802.3) */ -#define PHY_ANAR_PROTO3 0x0008 -#define PHY_ANAR_PROTO2 0x0004 -#define PHY_ANAR_PROTO1 0x0002 -#define PHY_ANAR_PROTO0 0x0001 -#define PHY_ANAR_8023 PHY_ANAR_PROTO0 -#define PHY_ANAR_DINGO PHY_ANAR_100BT+PHY_ANAR_10BT_FD+PHY_ANAR_10BT+PHY_ANAR_8023 -#define PHY_ANAR_MOHAWK PHY_ANAR_100BT+PHY_ANAR_10BT_FD+PHY_ANAR_10BT+PHY_ANAR_8023 - -/* LPAR bits */ -#define PHY_LPAR_NEXTPAGE 0x8000 /* Additional link code word pages */ -#define PHY_LPAR_LPACK 0x4000 /* Link partner acknowledged receipt */ -#define PHY_LPAR_TLRFLT 0x2000 /* Remote wire fault detected */ -#define PHY_LPAR_100BT4 0x0200 /* 100Base-T4 capable */ -#define PHY_LPAR_100BTXFULL 0x0100 /* 100Base-TX full duplex capable */ -#define PHY_LPAR_100BTXHALF 0x0080 /* 100Base-TX half duplex capable */ -#define PHY_LPAR_10BTFULL 0x0040 /* 10Base-T full duplex capable */ -#define PHY_LPAR_10BTHALF 0x0020 /* 10Base-T half duplex capable */ -#define PHY_LPAR_PROTO4 0x0010 /* Protocol selection (00001 = 802.3) */ -#define PHY_LPAR_PROTO3 0x0008 -#define PHY_LPAR_PROTO2 0x0004 -#define PHY_LPAR_PROTO1 0x0002 -#define PHY_LPAR_PROTO0 0x0001 - -/* ANER bits */ -#define PHY_ANER_MLFAULT 0x0010 /* More than one link is up! */ -#define PHY_ANER_LPNPABLE 0x0008 /* Link partner supports next page */ -#define PHY_ANER_NPABLE 0x0004 /* Local port supports next page */ -#define PHY_ANER_PAGERX 0x0002 /* Page received */ -#define PHY_ANER_LPAUTONEG 0x0001 /* Link partner can auto-negotiate */ - - -#endif /* NXE > 0 */ diff --git a/sys/dev/xe/if_xe.c b/sys/dev/xe/if_xe.c index 715ab79191de..e66ddd78bb5f 100644 --- a/sys/dev/xe/if_xe.c +++ b/sys/dev/xe/if_xe.c @@ -27,6 +27,19 @@ * $FreeBSD$ */ +/* + * XXX TODO XXX + * + * I've pushed this fairly far, but there are some things that need to be + * done here. I'm documenting them here in case I get destracted. -- imp + * + * xe_memwrite -- maybe better handled pccard layer? + * xe_cem56fix -- need to figure out how to map the extra stuff. + * xe_activate -- need to write it, and add some stuff to it. Look at if_sn + * for guidance. resources/interrupts. + * xe_deactivate -- turn off resources/interrupts. + */ + /* * Portions of this software were derived from Werner Koch's xirc2ps driver * for Linux under the terms of the following license (from v1.30 of the @@ -103,16 +116,6 @@ #define XE_DEBUG 1 /* Increase for more voluminous output! */ #endif -#include "xe.h" -#include "card.h" -#include "apm.h" - -#if NXE > 0 - -#undef NCARD -#define NCARD 0 -#if NCARD > 0 - #include #include #include @@ -126,6 +129,13 @@ #include #include +#include +#include + +#include +#include +#include + #include #include #include @@ -134,58 +144,10 @@ #include #include -#include -#include -#include +#include +#include + #include -#if NAPM > 0 -#include -#endif /* NAPM > 0 */ - -#include -#include -#include -#include - - - -/* - * One of these structures per allocated device - */ -struct xe_softc { - struct arpcom arpcom; - struct ifmedia ifmedia; - struct ifmib_iso_8802_3 mibdata; - struct callout_handle chand; - struct isa_device *dev; - struct pccard_devinfo *crd; - struct ifnet *ifp; - struct ifmedia *ifm; - char *card_type; /* Card model name */ - char *vendor; /* Card manufacturer */ - int unit; /* Unit number, from dev->id_unit */ - int srev; /* Silicon revision */ - int tx_queued; /* Packets currently waiting to transmit */ - int tx_tpr; /* Last value of TPR reg on card */ - int tx_collisions; /* Collisions since last successful send */ - int tx_timeouts; /* Count of transmit timeouts */ - int autoneg_status; /* Autonegotiation progress state */ - int media; /* Private media word */ - u_char version; /* Bonding Version register from card */ - u_char modem; /* 1 = Card has a modem */ - u_char ce2; /* 1 = Card has CE2 silicon */ - u_char mohawk; /* 1 = Card has Mohawk (CE3) silicon */ - u_char dingo; /* 1 = Card has Dingo (CEM56) silicon */ - u_char phy_ok; /* 1 = MII-compliant PHY found and initialised */ - u_char gone; /* 1 = Card bailed out */ -#if NAPM > 0 - struct apmhook suspend_hook; - struct apmhook resume_hook; -#endif /* NAPM > 0 */ -}; - -static struct xe_softc *sca[MAXSLOT]; - /* * MII command structure @@ -199,24 +161,6 @@ struct xe_mii_frame { u_int16_t mii_data; }; -/* - * For accessing card registers - */ -#define XE_INB(r) inb(scp->dev->id_iobase+(r)) -#define XE_INW(r) inw(scp->dev->id_iobase+(r)) -#define XE_OUTB(r, b) outb(scp->dev->id_iobase+(r), (b)) -#define XE_OUTW(r, w) outw(scp->dev->id_iobase+(r), (w)) -#define XE_SELECT_PAGE(p) XE_OUTB(XE_PR, (p)) - -/* - * Horrid stuff for accessing CIS tuples - */ -#define CARD_MAJOR 50 -#define CISTPL_BUFSIZE 512 -#define CISTPL_TYPE(tpl) tpl[0] -#define CISTPL_LEN(tpl) tpl[2] -#define CISTPL_DATA(tpl,pos) tpl[4 + ((pos)<<1)] - /* * Media autonegotiation progress constants */ @@ -230,13 +174,14 @@ struct xe_mii_frame { /* * Prototypes start here */ -static int xe_probe (struct isa_device *dev); -static int xe_card_init (struct pccard_devinfo *devi); -static int xe_attach (struct isa_device *dev); +static int xe_probe (device_t dev); +static int xe_attach (device_t dev); +static int xe_detach (device_t dev); +static int xe_activate (device_t dev); +static void xe_deactivate (device_t dev); static void xe_init (void *xscp); static void xe_start (struct ifnet *ifp); static int xe_ioctl (struct ifnet *ifp, u_long command, caddr_t data); -static int xe_card_intr (struct pccard_devinfo *devi); static void xe_watchdog (struct ifnet *ifp); static int xe_media_change (struct ifnet *ifp); static void xe_media_status (struct ifnet *ifp, struct ifmediareq *mrp); @@ -249,7 +194,6 @@ static void xe_disable_intr (struct xe_softc *scp); static void xe_setmulti (struct xe_softc *scp); static void xe_setaddrs (struct xe_softc *scp); static int xe_pio_write_packet (struct xe_softc *scp, struct mbuf *mbp); -static void xe_card_unload (struct pccard_devinfo *devi); static u_int32_t xe_compute_crc (u_int8_t *data, int len); static int xe_compute_hashbit (u_int32_t crc); @@ -277,61 +221,6 @@ static void xe_mii_dump (struct xe_softc *scp); #define XE_MII_DUMP(scp) #endif -#if NAPM > 0 -/* - * APM hook functions - */ -static int xe_suspend (void *xunit); -static int xe_resume (void *xunit); -#endif /* NAPM > 0 */ - - -/* - * PCMCIA driver hooks - */ -#ifdef PCCARD_MODULE -PCCARD_MODULE(xe, xe_card_init, xe_card_unload, xe_card_intr, 0, net_imask); -#else -static struct pccard_device xe_info = { /* For pre 3.1-STABLE code */ - "xe", - xe_card_init, - xe_card_unload, - xe_card_intr, - 0, - &net_imask -}; -DATA_SET(pccarddrv_set, xe_info); -#endif /* PCCARD_MODULE */ - - -/* - * ISA driver hooks. I'd like to do without these but the kernel config stuff - * seems to require them. - */ -struct isa_driver xedriver = { - xe_probe, - xe_attach, - "xe" -}; - - - -/* - * ISA probe routine. - * All of the supported devices are PCMCIA cards. I have no idea if it's even - * possible to successfully probe/attach these at boot time (pccardd normally - * does a lot of setup work) so I don't even bother trying. - */ -static int -xe_probe (struct isa_device *dev) { -#ifdef XE_DEBUG - printf("xe%d: probe\n", dev->id_unit); -#endif - bzero(sca, MAXSLOT * sizeof(sca[0])); - return 0; -} - - /* * Two routines to read from/write to the attribute memory * the write portion is used only for fixing up the RealPort cards, @@ -341,71 +230,21 @@ xe_probe (struct isa_device *dev) { * -aDe Lovett */ static int -xe_memwrite(struct pccard_devinfo *devi, off_t offset, u_char byte) +xe_memwrite(device_t dev, off_t offset, u_char byte) { - struct iovec iov; - struct uio uios; - - iov.iov_base = &byte; - iov.iov_len = sizeof(byte); - - uios.uio_iov = &iov; - uios.uio_iovcnt = 1; - uios.uio_offset = offset; - uios.uio_resid = sizeof(byte); - uios.uio_segflg = UIO_SYSSPACE; - uios.uio_rw = UIO_WRITE; - uios.uio_procp = 0; - -#if 0 /* THIS IS BOGUS */ - return cdevsw[CARD_MAJOR]->d_write(makedev(CARD_MAJOR, devi->slt->slotnum), &uios, 0); -#else + /* XXX */ return (-1); -#endif } - -static int -xe_memread(struct pccard_devinfo *devi, off_t offset, u_char *buf, int size) -{ - struct iovec iov; - struct uio uios; - - iov.iov_base = buf; - iov.iov_len = size; - - uios.uio_iov = &iov; - uios.uio_iovcnt = 1; - uios.uio_offset = offset; - uios.uio_resid = size; - uios.uio_segflg = UIO_SYSSPACE; - uios.uio_rw = UIO_READ; - uios.uio_procp = 0; - -#if 0 /* THIS IS BOGUS */ - return cdevsw[CARD_MAJOR]->d_read(makedev(CARD_MAJOR, devi->slt->slotnum), &uios, 0); -#else - return (-1); -#endif -} - - /* * Hacking for RealPort cards */ static int xe_cem56fix(struct xe_softc *scp) { - struct pccard_devinfo *devi; - struct slot *slt; - struct slot_ctrl *ctrl; +#if XXX /* Need to revisit */ int ioport, fail; - /* initialise a few variables */ - devi = scp->crd; - slt = devi->slt; - ctrl = slt->ctrl; - /* allocate a new I/O slot for the ethernet */ /* XXX: ctrl->mapio() always appears to return 0 (success), so * this may cause problems if another device is listening @@ -420,7 +259,7 @@ xe_cem56fix(struct xe_softc *scp) #ifdef XE_IOBASE - printf( "xe%d: user requested ioport 0x%x\n", scp->unit, XE_IOBASE ); + device_printf(scp->dev, "user requested ioport 0x%x\n", XE_IOBASE ); ioport = XE_IOBASE; slt->io[1].start = ioport; fail = ctrl->mapio(slt, 1); @@ -437,34 +276,39 @@ xe_cem56fix(struct xe_softc *scp) /* did we find one? */ if (fail) { - printf( "xe%d: xe_cem56fix: no free address space\n", scp->unit ); + device_printf(scp->dev, "xe_cem56fix: no free address space\n"); return -1; } /* munge the id_iobase entry for use by the rest of the driver */ #if XE_DEBUG > 1 - printf( "xe%d: using 0x%x for RealPort ethernet\n", scp->unit, ioport ); + device_printf(scp->dev, "using 0x%x for RealPort ethernet\n", ioport); #endif +#if 0 scp->dev->id_iobase = ioport; scp->dev->id_alive = 0x10; +#endif /* magic to set up the ethernet */ - xe_memwrite( devi, DINGO_ECOR, DINGO_ECOR_IRQ_LEVEL|DINGO_ECOR_INT_ENABLE| - DINGO_ECOR_IOB_ENABLE|DINGO_ECOR_ETH_ENABLE ); - xe_memwrite( devi, DINGO_EBAR0, ioport & 0xff ); - xe_memwrite( devi, DINGO_EBAR1, (ioport >> 8) & 0xff ); + xe_memwrite( scp->dev, DINGO_ECOR, DINGO_ECOR_IRQ_LEVEL| + DINGO_ECOR_INT_ENABLE|DINGO_ECOR_IOB_ENABLE| + DINGO_ECOR_ETH_ENABLE ); + xe_memwrite( scp->dev, DINGO_EBAR0, ioport & 0xff ); + xe_memwrite( scp->dev, DINGO_EBAR1, (ioport >> 8) & 0xff ); - xe_memwrite( devi, DINGO_DCOR0, DINGO_DCOR0_SF_INT ); - xe_memwrite( devi, DINGO_DCOR1, DINGO_DCOR1_INT_LEVEL|DINGO_DCOR1_EEDIO ); - xe_memwrite( devi, DINGO_DCOR2, 0x00 ); - xe_memwrite( devi, DINGO_DCOR3, 0x00 ); - xe_memwrite( devi, DINGO_DCOR4, 0x00 ); + xe_memwrite( scp->dev, DINGO_DCOR0, DINGO_DCOR0_SF_INT ); + xe_memwrite( scp->dev, DINGO_DCOR1, DINGO_DCOR1_INT_LEVEL|DINGO_DCOR1_EEDIO ); + xe_memwrite( scp->dev, DINGO_DCOR2, 0x00 ); + xe_memwrite( scp->dev, DINGO_DCOR3, 0x00 ); + xe_memwrite( scp->dev, DINGO_DCOR4, 0x00 ); /* success! */ return 0; +#else + return -1; +#endif /* XXX */ } - /* * PCMCIA probe routine. @@ -473,50 +317,32 @@ xe_cem56fix(struct xe_softc *scp) * structure has been initialised already. */ static int -xe_card_init(struct pccard_devinfo *devi) +xe_probe(device_t dev) { - struct xe_softc *scp; - struct isa_device *dev; - u_char buf[CISTPL_BUFSIZE]; + struct xe_softc *scp = (struct xe_softc *) device_get_softc(dev); + u_char *buf; u_char ver_str[CISTPL_BUFSIZE>>1]; off_t offs; - int unit, success, rc, i; + int success, rc, i; + int rid; + struct resource *r; - unit = devi->isahd.id_unit; - scp = sca[unit]; - dev = &devi->isahd; success = 0; #ifdef XE_DEBUG - printf("xe: Probing for unit %d\n", unit); + device_printf(dev, "xe: Probing\n"); #endif - /* Check that unit number is OK */ - if (unit > MAXSLOT) { - printf("xe%d: bad unit\n", unit); - return (ENODEV); - } - - /* Don't attach an active device */ - if (scp && !scp->gone) { - printf("xe%d: already attached\n", unit); - return (EBUSY); - } - - /* Allocate per-instance storage */ - if (!scp) { - if ((scp = malloc(sizeof(*scp), M_DEVBUF, M_NOWAIT)) == NULL) { - printf("xe%d: failed to allocage driver storage\n", unit); - return (ENOMEM); - } - bzero(scp, sizeof(*scp)); - } - - /* Re-attach an existing device */ - if (scp->gone) { - scp->gone = 0; - return 0; + /* Map in the CIS */ + /* XXX This CANNOT work as it needs RF_PCCARD_ATTR support */ + r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 4 << 10, RF_ACTIVE); + if (!r) { +#ifdef XE_DEBUG + device_printf(dev, "Can't map in cis\n"); +#endif + return ENOMEM; } + buf = (u_char *) rman_get_start(r); /* Grep through CIS looking for relevant tuples */ offs = 0; @@ -524,136 +350,129 @@ xe_card_init(struct pccard_devinfo *devi) u_int16_t vendor; u_int8_t rev, media, prod; - /* - * Read tuples one at a time into buf. Sucks, but it only happens once. - * XXX - This assumes that attribute has been mapped by pccardd, which - * XXX - seems to be the default situation. If not, we're well and truly - * XXX - FUBAR. This is a general PCCARD problem, not our fault :) - */ - if ((rc = xe_memread( devi, offs, buf, CISTPL_BUFSIZE )) == 0) { + switch (CISTPL_TYPE(buf)) { - switch (CISTPL_TYPE(buf)) { + case 0x15: /* Grab version string (needed to ID some weird CE2's) */ +#if XE_DEBUG > 1 + device_printf(dev, "Got version string (0x15)\n"); +#endif + for (i = 0; i < CISTPL_LEN(buf); ver_str[i] = CISTPL_DATA(buf, i++)); + ver_str[i] = '\0'; + ver_str[(CISTPL_BUFSIZE>>1) - 1] = CISTPL_LEN(buf); + success++; + break; - case 0x15: /* Grab version string (needed to ID some weird CE2's) */ + case 0x20: /* Figure out what type of card we have */ #if XE_DEBUG > 1 - printf("xe%d: Got version string (0x15)\n", unit); + device_printf(dev, "Got card ID (0x20)\n"); #endif - for (i = 0; i < CISTPL_LEN(buf); ver_str[i] = CISTPL_DATA(buf, i++)); - ver_str[i] = '\0'; - ver_str[(CISTPL_BUFSIZE>>1) - 1] = CISTPL_LEN(buf); - success++; - break; + vendor = CISTPL_DATA(buf, 0) + (CISTPL_DATA(buf, 1) << 8); + rev = CISTPL_DATA(buf, 2); + media = CISTPL_DATA(buf, 3); + prod = CISTPL_DATA(buf, 4); - case 0x20: /* Figure out what type of card we have */ -#if XE_DEBUG > 1 - printf("xe%d: Got card ID (0x20)\n", unit); -#endif - vendor = CISTPL_DATA(buf, 0) + (CISTPL_DATA(buf, 1) << 8); - rev = CISTPL_DATA(buf, 2); - media = CISTPL_DATA(buf, 3); - prod = CISTPL_DATA(buf, 4); - - switch (vendor) { /* Get vendor ID */ - case 0x0105: - scp->vendor = "Xircom"; break; - case 0x0138: - case 0x0183: - scp->vendor = "Compaq"; break; - case 0x0089: - scp->vendor = "Intel"; break; - default: - scp->vendor = "Unknown"; - } - - if (!((prod & 0x40) && (media & 0x01))) { -#if XE_DEBUG > 1 - printf("xe%d: Not a PCMCIA Ethernet card!\n", unit); -#endif - rc = ENODEV; /* Not a PCMCIA Ethernet device */ - } - else { - if (media & 0x10) { /* Ethernet/modem cards */ -#if XE_DEBUG > 1 - printf("xe%d: Card is Ethernet/modem combo\n", unit); -#endif - scp->modem = 1; - switch (prod & 0x0f) { - case 1: - scp->card_type = "CEM"; break; - case 2: - scp->ce2 = 1; - scp->card_type = "CEM2"; break; - case 3: - scp->ce2 = 1; - scp->card_type = "CEM3"; break; - case 4: - scp->ce2 = 1; - scp->card_type = "CEM33"; break; - case 5: - scp->mohawk = 1; - scp->card_type = "CEM56M"; break; - case 6: - case 7: /* Some kind of RealPort card */ - scp->mohawk = 1; - scp->dingo = 1; - scp->card_type = "CEM56"; break; - default: - rc = ENODEV; - } - } - else { /* Ethernet-only cards */ -#if XE_DEBUG > 1 - printf("xe%d: Card is Ethernet only\n", unit); -#endif - switch (prod & 0x0f) { - case 1: - scp->card_type = "CE"; break; - case 2: - scp->ce2 = 1; - scp->card_type = "CE2"; break; - case 3: - scp->mohawk = 1; - scp->card_type = "CE3"; break; - default: - rc = ENODEV; - } - } - } - success++; - break; - - case 0x22: /* Get MAC address */ - if ((CISTPL_LEN(buf) == 8) && - (CISTPL_DATA(buf, 0) == 0x04) && - (CISTPL_DATA(buf, 1) == ETHER_ADDR_LEN)) { -#if XE_DEBUG > 1 - printf("xe%d: Got MAC address (0x22)\n", unit); -#endif - for (i = 0; i < ETHER_ADDR_LEN; scp->arpcom.ac_enaddr[i] = CISTPL_DATA(buf, i+2), i++); - } - success++; - break; - default: + switch (vendor) { /* Get vendor ID */ + case 0x0105: + scp->vendor = "Xircom"; break; + case 0x0138: + case 0x0183: + scp->vendor = "Compaq"; break; + case 0x0089: + scp->vendor = "Intel"; break; + default: + scp->vendor = "Unknown"; } + + if (!((prod & 0x40) && (media & 0x01))) { +#if XE_DEBUG > 1 + device_printf(dev, "Not a PCMCIA Ethernet card!\n"); +#endif + rc = ENODEV; /* Not a PCMCIA Ethernet device */ + } else { + if (media & 0x10) { /* Ethernet/modem cards */ +#if XE_DEBUG > 1 + device_printf(dev, "Card is Ethernet/modem combo\n"); +#endif + scp->modem = 1; + switch (prod & 0x0f) { + case 1: + scp->card_type = "CEM"; break; + case 2: + scp->ce2 = 1; + scp->card_type = "CEM2"; break; + case 3: + scp->ce2 = 1; + scp->card_type = "CEM3"; break; + case 4: + scp->ce2 = 1; + scp->card_type = "CEM33"; break; + case 5: + scp->mohawk = 1; + scp->card_type = "CEM56M"; break; + case 6: + case 7: /* Some kind of RealPort card */ + scp->mohawk = 1; + scp->dingo = 1; + scp->card_type = "CEM56"; break; + default: + rc = ENODEV; + } + } else { /* Ethernet-only cards */ +#if XE_DEBUG > 1 + device_printf(dev, "Card is Ethernet only\n"); +#endif + switch (prod & 0x0f) { + case 1: + scp->card_type = "CE"; break; + case 2: + scp->ce2 = 1; + scp->card_type = "CE2"; break; + case 3: + scp->mohawk = 1; + scp->card_type = "CE3"; break; + default: + rc = ENODEV; + } + } + } + success++; + break; + + case 0x22: /* Get MAC address */ + if ((CISTPL_LEN(buf) == 8) && + (CISTPL_DATA(buf, 0) == 0x04) && + (CISTPL_DATA(buf, 1) == ETHER_ADDR_LEN)) { +#if XE_DEBUG > 1 + device_printf(dev, "Got MAC address (0x22)\n"); +#endif + for (i = 0; i < ETHER_ADDR_LEN; i++) + scp->arpcom.ac_enaddr[i] = CISTPL_DATA(buf, i+2); + } + success++; + break; + default: + break; } + if (CISTPL_TYPE(buf) == 0xff) + break; /* Skip to next tuple */ - offs += ((CISTPL_LEN(buf) + 2) << 1); + buf += ((CISTPL_LEN(buf) + 2) << 1); - } while ((CISTPL_TYPE(buf) != 0xff) && (CISTPL_LEN(buf) != 0xff) && (rc == 0)); + } while (1); + /* unmap the cis */ + bus_release_resource(dev, SYS_RES_MEMORY, rid, r); /* Die now if something went wrong above */ - if ((rc != 0) || (success < 3)) { - free(scp, M_DEVBUF); - return rc; - } + if (success < 3) + return ENXIO; /* Check for certain strange CE2's that look like CE's */ if (strcmp(scp->card_type, "CE") == 0) { u_char *str = ver_str; #if XE_DEBUG > 1 - printf("xe%d: Checking for weird CE2 string\n", unit); + device_printf(dev, "Checking for weird CE2 string\n"); #endif str += strlen(str) + 1; /* Skip forward to 3rd version string */ str += strlen(str) + 1; @@ -667,25 +486,53 @@ xe_card_init(struct pccard_devinfo *devi) /* Reject unsupported cards */ if (strcmp(scp->card_type, "CE") == 0 || strcmp(scp->card_type, "CEM") == 0) { - printf("xe%d: Sorry, your %s card is not supported :(\n", unit, scp->card_type); - free(scp, M_DEVBUF); + device_printf(dev, "Sorry, your %s card is not supported :(\n", + scp->card_type); return ENODEV; } + /* Success */ + return 0; +} + +/* + * The device entry is being removed, probably because someone ejected the + * card. The interface should have been brought down manually before calling + * this function; if not you may well lose packets. In any case, I shut down + * the card and the interface, and hope for the best. + */ +static int +xe_detach(device_t dev) { + struct xe_softc *sc = device_get_softc(dev); + + sc->arpcom.ac_if.if_flags &= ~IFF_RUNNING; + if_detach(&sc->arpcom.ac_if); + xe_deactivate(dev); + return 0; +} + +/* + * Attach a device. + */ +static int +xe_attach (device_t dev) { + struct xe_softc *scp = device_get_softc(dev); + +#ifdef XE_DEBUG + device_printf(dev, "attach\n"); +#endif + + xe_activate(dev); + /* Fill in some private data */ - sca[unit] = scp; - scp->dev = &devi->isahd; - scp->crd = devi; scp->ifp = &scp->arpcom.ac_if; scp->ifm = &scp->ifmedia; - scp->unit = unit; scp->autoneg_status = 0; /* Hack RealPorts into submission */ if (scp->dingo && xe_cem56fix(scp) < 0) { - printf( "xe%d: Unable to fix your RealPort\n", unit ); - sca[unit] = 0; - free(scp, M_DEVBUF); + device_printf(dev, "Unable to fix your RealPort\n"); + xe_deactivate(dev); return ENODEV; } @@ -693,51 +540,12 @@ xe_card_init(struct pccard_devinfo *devi) XE_SELECT_PAGE(4); scp->version = XE_INB(XE_BOV); - /* Attempt to attach the device */ - if (!xe_attach(scp->dev)) { - sca[unit] = 0; - free(scp, M_DEVBUF); - return ENXIO; - } - -#if NAPM > 0 - /* Establish APM hooks once device attached */ - scp->suspend_hook.ah_name = "xe_suspend"; - scp->suspend_hook.ah_fun = xe_suspend; - scp->suspend_hook.ah_arg = (void *)unit; - scp->suspend_hook.ah_order = APM_MIN_ORDER; - apm_hook_establish(APM_HOOK_SUSPEND, &scp->suspend_hook); - scp->resume_hook.ah_name = "xe_resume"; - scp->resume_hook.ah_fun = xe_resume; - scp->resume_hook.ah_arg = (void *)unit; - scp->resume_hook.ah_order = APM_MIN_ORDER; - apm_hook_establish(APM_HOOK_RESUME, &scp->resume_hook); -#endif /* NAPM > 0 */ - - /* Success */ - return 0; -} - - -/* - * Attach a device (called when xe_card_init succeeds). Assume that the probe - * routine has set up the softc structure correctly and that we can trust the - * unit number. - */ -static int -xe_attach (struct isa_device *dev) { - struct xe_softc *scp = sca[dev->id_unit]; - int i; - -#ifdef XE_DEBUG - printf("xe%d: attach\n", scp->unit); -#endif - + scp->dev = dev; /* Initialise the ifnet structure */ if (!scp->ifp->if_name) { scp->ifp->if_softc = scp; scp->ifp->if_name = "xe"; - scp->ifp->if_unit = scp->unit; + scp->ifp->if_unit = device_get_unit(dev); scp->ifp->if_timer = 0; scp->ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); scp->ifp->if_linkmib = &scp->mibdata; @@ -773,9 +581,7 @@ xe_attach (struct isa_device *dev) { ifmedia_set(scp->ifm, IFM_ETHER|IFM_AUTO); /* Print some useful information */ - printf("\n"); - printf("xe%d: %s %s, bonding version %#x%s%s\n", - scp->unit, + device_printf(dev, "%s %s, bonding version %#x%s%s\n", scp->vendor, scp->card_type, scp->version, @@ -783,33 +589,26 @@ xe_attach (struct isa_device *dev) { scp->modem ? ", with modem" : ""); if (scp->mohawk) { XE_SELECT_PAGE(0x10); - printf("xe%d: DingoID = %#x, RevisionID = %#x, VendorID = %#x\n", - scp->unit, + device_printf(dev, "DingoID = %#x, RevisionID = %#x, VendorID = %#x\n", XE_INW(XE_DINGOID), XE_INW(XE_RevID), XE_INW(XE_VendorID)); } if (scp->ce2) { XE_SELECT_PAGE(0x45); - printf("xe%d: CE2 version = %#x\n", - scp->unit, - XE_INB(XE_REV)); + device_printf(dev, "CE2 version = %#x\n", XE_INB(XE_REV)); } /* Print MAC address */ - printf("xe%d: Ethernet address %02x", scp->unit, scp->arpcom.ac_enaddr[0]); - for (i = 1; i < ETHER_ADDR_LEN; i++) { - printf(":%02x", scp->arpcom.ac_enaddr[i]); - } - printf("\n"); + device_printf(dev, "Ethernet address %6D\n", scp->arpcom.ac_enaddr, ":"); /* Attach the interface */ if_attach(scp->ifp); ether_ifattach(scp->ifp); - /* If BPF is in the kernel, call the attach for it */ + /* BPF is in the kernel, call the attach for it */ #if XE_DEBUG > 1 - printf("xe%d: BPF listener attached\n", scp->unit); + device_printf(dev, "BPF listener attached\n"); #endif bpfattach(scp->ifp, DLT_EN10MB, sizeof(struct ether_header)); @@ -829,11 +628,9 @@ xe_init(void *xscp) { int s; #ifdef XE_DEBUG - printf("xe%d: init\n", scp->unit); + device_printf(scp->dev, "init\n"); #endif - if (scp->gone) return; - if (TAILQ_EMPTY(&scp->ifp->if_addrhead)) return; /* Reset transmitter flags */ @@ -915,8 +712,6 @@ xe_start(struct ifnet *ifp) { struct xe_softc *scp = ifp->if_softc; struct mbuf *mbp; - if (scp->gone) return; - /* * Loop while there are packets to be sent, and space to send them. */ @@ -944,7 +739,7 @@ xe_start(struct ifnet *ifp) { /* Tap off here if there is a bpf listener */ if (ifp->if_bpf) { #if XE_DEBUG > 1 - printf("xe%d: sending output packet to BPF\n", scp->unit); + device_printf(scp->dev, "sending output packet to BPF\n"); #endif bpf_mtap(ifp, mbp); } @@ -968,10 +763,6 @@ xe_ioctl (register struct ifnet *ifp, u_long command, caddr_t data) { scp = ifp->if_softc; error = 0; - if (scp->gone) { - return ENXIO; - } - s = splimp(); switch (command) { @@ -1029,9 +820,7 @@ xe_ioctl (register struct ifnet *ifp, u_long command, caddr_t data) { /* - * Card interrupt handler: should return true if the interrupt was for us, in - * case we are sharing our IRQ line with other devices (this will probably be - * the case for multifunction cards). + * Card interrupt handler. * * This function is probably more complicated than it needs to be, as it * attempts to deal with the case where multiple packets get sent between @@ -1048,23 +837,19 @@ xe_ioctl (register struct ifnet *ifp, u_long command, caddr_t data) { * get your work done, don't buy a Xircom card. Or convince them to tell me * how to do memory-mapped I/O :) */ -static int -xe_card_intr(struct pccard_devinfo *devi) { - struct xe_softc *scp; +static void +xe_intr(void *xscp) +{ + struct xe_softc *scp = (struct xe_softc *) xscp; struct ifnet *ifp; - int unit, result; + int result; u_int16_t rx_bytes, rxs, txs; u_int8_t psr, isr, esr, rsr; - unit = devi->isahd.id_unit; - scp = sca[unit]; ifp = &scp->arpcom.ac_if; rx_bytes = 0; /* Bytes received on this interrupt */ result = 0; /* Set true if the interrupt is for us */ - if (scp->gone) - return 0; - if (scp->mohawk) { XE_OUTB(XE_CR, 0); /* Disable interrupts */ } @@ -1256,10 +1041,12 @@ xe_card_intr(struct pccard_devinfo *devi) { } } else - insw(scp->dev->id_iobase+XE_EDP, ehp, len >> 1); + bus_space_read_multi_2(scp->bst, scp->bsh, XE_EDP, + (u_int16_t *) ehp, len >> 1); } else - insw(scp->dev->id_iobase+XE_EDP, ehp, len >> 1); + bus_space_read_multi_2(scp->bst, scp->bsh, XE_EDP, + (u_int16_t *) ehp, len >> 1); /* * Check if there's a BPF listener on this interface. If so, hand @@ -1267,7 +1054,7 @@ xe_card_intr(struct pccard_devinfo *devi) { */ if (ifp->if_bpf) { #if XE_DEBUG > 1 - printf("xe%d: passing input packet to BPF\n", scp->unit); + device_printf(scp->dev, "passing input packet to BPF\n"); #endif bpf_mtap(ifp, mbp); @@ -1319,7 +1106,7 @@ xe_card_intr(struct pccard_devinfo *devi) { /* Could force an int here, instead of dropping packets? */ /* XE_OUTB(XE_CR, XE_CR_ENABLE_INTR|XE_CE_FORCE_INTR); */ - return result; + return; } @@ -1333,9 +1120,7 @@ static void xe_watchdog(struct ifnet *ifp) { struct xe_softc *scp = ifp->if_softc; - if (scp->gone) return; - - printf("xe%d: watchdog timeout; resetting card\n", scp->unit); + device_printf(scp->dev, "watchdog timeout; resetting card\n"); scp->tx_timeouts++; ifp->if_oerrors += scp->tx_queued; xe_stop(scp); @@ -1396,7 +1181,7 @@ static void xe_setmedia(void *xscp) { u_int16_t bmcr, bmsr, anar, lpar; #ifdef XE_DEBUG - printf("xe%d: setmedia\n", scp->unit); + device_printf(scp->dev, "setmedia\n"); #endif /* Cancel any pending timeout */ @@ -1443,7 +1228,7 @@ static void xe_setmedia(void *xscp) { case XE_AUTONEG_NONE: #if XE_DEBUG > 1 - printf("xe%d: Waiting for idle transmitter\n", scp->unit); + device_printf(scp->dev, "Waiting for idle transmitter\n"); #endif scp->arpcom.ac_if.if_flags |= IFF_OACTIVE; scp->autoneg_status = XE_AUTONEG_WAITING; @@ -1454,7 +1239,7 @@ static void xe_setmedia(void *xscp) { xe_soft_reset(scp); if (scp->phy_ok) { #if XE_DEBUG > 1 - printf("xe%d: Starting autonegotiation\n", scp->unit); + device_printf(scp->dev, "Starting autonegotiation\n"); #endif bmcr = xe_phy_readreg(scp, PHY_BMCR); bmcr &= ~(PHY_BMCR_AUTONEGENBL); @@ -1479,7 +1264,7 @@ static void xe_setmedia(void *xscp) { lpar = xe_phy_readreg(scp, PHY_LPAR); if (bmsr & (PHY_BMSR_AUTONEGCOMP|PHY_BMSR_LINKSTAT)) { #if XE_DEBUG > 1 - printf("xe%d: Autonegotiation complete!\n", scp->unit); + device_printf(scp->dev, "Autonegotiation complete!\n"); #endif /* * XXX - Shouldn't have to do this, but (on my hub at least) the @@ -1518,7 +1303,7 @@ static void xe_setmedia(void *xscp) { } else { #if XE_DEBUG > 1 - printf("xe%d: Autonegotiation failed; trying 100baseTX\n", scp->unit); + device_printf(scp->dev, "Autonegotiation failed; trying 100baseTX\n"); #endif XE_MII_DUMP(scp); xe_soft_reset(scp); @@ -1539,7 +1324,7 @@ static void xe_setmedia(void *xscp) { bmsr = xe_phy_readreg(scp, PHY_BMSR); if (bmsr & PHY_BMSR_LINKSTAT) { #if XE_DEBUG > 1 - printf("xe%d: Got 100baseTX link!\n", scp->unit); + device_printf(scp->dev, "Got 100baseTX link!\n"); #endif XE_MII_DUMP(scp); XE_SELECT_PAGE(2); @@ -1549,7 +1334,7 @@ static void xe_setmedia(void *xscp) { } else { #if XE_DEBUG > 1 - printf("xe%d: Autonegotiation failed; disabling PHY\n", scp->unit); + device_printf(scp->dev, "Autonegotiation failed; disabling PHY\n"); #endif XE_MII_DUMP(scp); xe_phy_writereg(scp, PHY_BMCR, 0x0000); @@ -1569,7 +1354,7 @@ static void xe_setmedia(void *xscp) { */ if (scp->autoneg_status == XE_AUTONEG_FAIL) { #if XE_DEBUG > 1 - printf("xe%d: Selecting 10baseX\n", scp->unit); + device_printf(scp->dev, "Selecting 10baseX\n"); #endif if (scp->mohawk) { XE_SELECT_PAGE(0x42); @@ -1599,7 +1384,7 @@ static void xe_setmedia(void *xscp) { xe_soft_reset(scp); if (scp->phy_ok) { #if XE_DEBUG > 1 - printf("xe%d: Selecting 100baseTX\n", scp->unit); + device_printf(scp->dev, "Selecting 100baseTX\n"); #endif XE_SELECT_PAGE(0x42); XE_OUTB(XE_SWC1, 0); @@ -1614,7 +1399,7 @@ static void xe_setmedia(void *xscp) { case IFM_10_T: /* Force 10baseT */ xe_soft_reset(scp); #if XE_DEBUG > 1 - printf("xe%d: Selecting 10baseT\n", scp->unit); + device_printf(csp->dev, "Selecting 10baseT\n"); #endif if (scp->phy_ok) { xe_phy_writereg(scp, PHY_BMCR, 0x0000); @@ -1629,7 +1414,7 @@ static void xe_setmedia(void *xscp) { case IFM_10_2: xe_soft_reset(scp); #if XE_DEBUG > 1 - printf("xe%d: Selecting 10base2\n", scp->unit); + device_printf(scp->dev, "Selecting 10base2\n"); #endif XE_SELECT_PAGE(0x42); XE_OUTB(XE_SWC1, 0xc0); @@ -1643,7 +1428,7 @@ static void xe_setmedia(void *xscp) { * transmitter is unblocked. */ #if XE_DEBUG > 1 - printf("xe%d: Setting LEDs\n", scp->unit); + device_printf(scp->dev, "Setting LEDs\n"); #endif XE_SELECT_PAGE(2); switch (IFM_SUBTYPE(scp->media)) { @@ -1673,11 +1458,9 @@ xe_hard_reset(struct xe_softc *scp) { int s; #ifdef XE_DEBUG - printf("xe%d: hard_reset\n", scp->unit); + device_printf(scp->dev, "hard_reset\n"); #endif - if (scp->gone) return; - s = splimp(); /* @@ -1710,11 +1493,9 @@ xe_soft_reset(struct xe_softc *scp) { int s; #ifdef XE_DEBUG - printf("xe%d: soft_reset\n", scp->unit); + device_printf(scp->dev, "soft_reset\n"); #endif - if (scp->gone) return; - s = splimp(); /* @@ -1750,7 +1531,7 @@ xe_soft_reset(struct xe_softc *scp) { else scp->srev = (XE_INB(XE_BOV) & 0x30) >> 4; #ifdef XE_DEBUG - printf("xe%d: silicon revision = %d\n", scp->unit, scp->srev); + device_printf(scp->dev, "silicon revision = %d\n", scp->srev); #endif /* @@ -1781,11 +1562,9 @@ xe_stop(struct xe_softc *scp) { int s; #ifdef XE_DEBUG - printf("xe%d: stop\n", scp->unit); + device_printf(scp->dev, "stop\n"); #endif - if (scp->gone) return; - s = splimp(); /* @@ -1817,7 +1596,7 @@ xe_stop(struct xe_softc *scp) { static void xe_enable_intr(struct xe_softc *scp) { #ifdef XE_DEBUG - printf("xe%d: enable_intr\n", scp->unit); + device_printf(scp->dev, "enable_intr\n"); #endif XE_SELECT_PAGE(1); @@ -1841,7 +1620,7 @@ xe_enable_intr(struct xe_softc *scp) { static void xe_disable_intr(struct xe_softc *scp) { #ifdef XE_DEBUG - printf("xe%d: disable_intr\n", scp->unit); + device_printf(scp->dev, "disable_intr\n"); #endif XE_SELECT_PAGE(0); @@ -1942,7 +1721,7 @@ xe_setaddrs(struct xe_softc *scp) { if (i) printf(":%x", addr[i]); else - printf("xe%d: individual addresses %d: %x", scp->unit, slot, addr[0]); + device_printf(scp->dev, "individual addresses %d: %x", slot, addr[0]); #endif if (byte > 15) { @@ -2013,7 +1792,8 @@ xe_pio_write_packet(struct xe_softc *scp, struct mbuf *mbp) { wantbyte = 0; } if (len > 1) { /* Output contiguous words */ - outsw(scp->dev->id_iobase+XE_EDP, data, len >> 1); + bus_space_write_multi_2(scp->bst, scp->bsh, XE_EDP, (u_int16_t *) data, + len >> 1); data += len & ~1; len &= 1; } @@ -2043,36 +1823,6 @@ xe_pio_write_packet(struct xe_softc *scp, struct mbuf *mbp) { return 0; } - -/* - * The device entry is being removed, probably because someone ejected the - * card. The interface should have been brought down manually before calling - * this function; if not you may well lose packets. In any case, I shut down - * the card and the interface, and hope for the best. The 'gone' flag is set, - * so hopefully no-one else will try to access the missing card. - */ -static void -xe_card_unload(struct pccard_devinfo *devi) { - struct xe_softc *scp; - struct ifnet *ifp; - int unit; - - unit = devi->isahd.id_unit; - scp = sca[unit]; - ifp = &scp->arpcom.ac_if; - - if (scp->gone) { - printf("xe%d: already unloaded\n", unit); - return; - } - - if_down(ifp); - ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); - xe_stop(scp); - scp->gone = 1; -} - - /* * Compute the 32-bit Ethernet CRC for the given buffer. */ @@ -2174,13 +1924,13 @@ xe_mii_init(struct xe_softc *scp) { status = xe_phy_readreg(scp, PHY_BMSR); if ((status & 0xff00) != 0x7800) { #if XE_DEBUG > 1 - printf("xe%d: no PHY found, %0x\n", scp->unit, status); + device_printf(scp->dev, "no PHY found, %0x\n", status); #endif return 0; } else { #if XE_DEBUG > 1 - printf("xe%d: PHY OK!\n", scp->unit); + device_printf(scp->dev, "PHY OK!\n"); #endif /* Reset the PHY */ @@ -2403,7 +2153,7 @@ xe_mii_dump(struct xe_softc *scp) { s = splimp(); - printf("xe%d: MII registers: ", scp->unit); + device_printf(scp->dev, "MII registers: "); for (i = 0; i < 2; i++) { printf(" %d:%04x", i, xe_phy_readreg(scp, i)); } @@ -2421,14 +2171,14 @@ xe_reg_dump(struct xe_softc *scp) { s = splimp(); - printf("xe%d: Common registers: ", scp->unit); + device_printf(scp->dev, "Common registers: "); for (i = 0; i < 8; i++) { printf(" %2.2x", XE_INB(i)); } printf("\n"); for (page = 0; page <= 8; page++) { - printf("xe%d: Register page %2.2x: ", scp->unit, page); + device_printf(scp->dev, "Register page %2.2x: ", page); XE_SELECT_PAGE(page); for (i = 8; i < 16; i++) { printf(" %2.2x", XE_INB(i)); @@ -2442,7 +2192,7 @@ xe_reg_dump(struct xe_softc *scp) { (page >= 0x43 && page <= 0x4f) || (page >= 0x59)) continue; - printf("xe%d: Register page %2.2x: ", scp->unit, page); + device_printf(scp->dev, "Register page %2.2x: ", page); XE_SELECT_PAGE(page); for (i = 8; i < 16; i++) { printf(" %2.2x", XE_INB(i)); @@ -2454,47 +2204,77 @@ xe_reg_dump(struct xe_softc *scp) { } #endif +int +xe_activate(device_t dev) +{ + struct xe_softc *sc = device_get_softc(dev); + int err; + sc->port_rid = 0; + sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid, + 0, ~0, 16, RF_ACTIVE); + if (!sc->port_res) { +#if XE_DEBUG > 0 + device_printf(dev, "Cannot allocate ioport\n"); +#endif + return ENOMEM; + } -#if NAPM > 0 -/************************************************************** - * * - * A P M F U N C T I O N S * - * * - **************************************************************/ - -/* - * This is called when we go into suspend/standby mode - */ -static int -xe_suspend(void *xunit) { - -#ifdef XE_DEBUG - struct xe_softc *scp = sca[(int)xunit]; - - printf("xe%d: APM suspend\n", scp->unit); + sc->irq_rid = 0; + sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid, + 0, ~0, 1, RF_ACTIVE); + if (!sc->irq_res) { +#if XE_DEBUG > 0 + device_printf(dev, "Cannot allocate irq\n"); #endif - - return 0; + xe_deactivate(dev); + return ENOMEM; + } + if ((err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET, xe_intr, sc, + &sc->intrhand)) != 0) { + xe_deactivate(dev); + return err; + } + + sc->bst = rman_get_bustag(sc->port_res); + sc->bsh = rman_get_bushandle(sc->port_res); + return (0); } -/* - * This is called when we wake up again - */ -static int -xe_resume(void *xunit) { - -#ifdef XE_DEBUG - struct xe_softc *scp = sca[(int)xunit]; - - printf("xe%d: APM resume\n", scp->unit); -#endif - - return 0; +void +xe_deactivate(device_t dev) +{ + struct xe_softc *sc = device_get_softc(dev); + + if (sc->intrhand) + bus_teardown_intr(dev, sc->irq_res, sc->intrhand); + sc->intrhand = 0; + if (sc->port_res) + bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid, + sc->port_res); + sc->port_res = 0; + if (sc->irq_res) + bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, + sc->irq_res); + sc->irq_res = 0; + return; } -#endif /* NAPM > 0 */ +static device_method_t xe_pccard_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, xe_probe), + DEVMETHOD(device_attach, xe_attach), + DEVMETHOD(device_detach, xe_detach), -#endif /* NCARD > 0 */ + { 0, 0 } +}; -#endif /* NXE > 0 */ +static driver_t xe_pccard_driver = { + "xe", + xe_pccard_methods, + sizeof(struct xe_softc), +}; + +devclass_t xe_devclass; + +DRIVER_MODULE(xe, pccard, xe_pccard_driver, xe_devclass, 0, 0); diff --git a/sys/dev/xe/if_xereg.h b/sys/dev/xe/if_xereg.h index 981c5c4bd06c..cdb6a3a9616c 100644 --- a/sys/dev/xe/if_xereg.h +++ b/sys/dev/xe/if_xereg.h @@ -26,6 +26,8 @@ * $Id: if_xereg.h,v 1.5 1999/05/20 21:53:58 scott Exp $ * $FreeBSD$ */ +#ifndef DEV_XE_IF_XEREG_H +#define DEV_XE_IF_XEREG_H /* * Register definitions for Xircom PCMCIA Ethernet controllers, based on @@ -66,11 +68,6 @@ * http://www.d.shuttle.de/isil/xircom/xirc2ps.html */ -#include "xe.h" -#if NXE > 0 - - - /******************* * PCMCIA registers *******************/ @@ -693,5 +690,4 @@ #define PHY_ANER_PAGERX 0x0002 /* Page received */ #define PHY_ANER_LPAUTONEG 0x0001 /* Link partner can auto-negotiate */ - -#endif /* NXE > 0 */ +#endif /* DEV_XE_IF_XEREG_H */ diff --git a/sys/dev/xe/if_xevar.h b/sys/dev/xe/if_xevar.h new file mode 100644 index 000000000000..eb2bdf901be2 --- /dev/null +++ b/sys/dev/xe/if_xevar.h @@ -0,0 +1,85 @@ +/*- + * Copyright (c) 1998, 1999 Scott Mitchell + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: if_xe.c,v 1.20 1999/06/13 19:17:40 scott Exp $ + * $FreeBSD$ + */ +#ifndef DEV_XE_IF_XEDEV_H +#define DEV_XE_IF_XEDEV_H + +/* + * One of these structures per allocated device + */ +struct xe_softc { + struct arpcom arpcom; + struct ifmedia ifmedia; + struct ifmib_iso_8802_3 mibdata; + struct callout_handle chand; + struct ifnet *ifp; + struct ifmedia *ifm; + char *card_type; /* Card model name */ + char *vendor; /* Card manufacturer */ + device_t dev; /* Device */ + bus_space_tag_t bst; /* Bus space tag for card */ + bus_space_handle_t bsh; /* Bus space handle for card */ + void *intrhand; + struct resource *irq_res; + int irq_rid; + struct resource *port_res; + int port_rid; + int srev; /* Silicon revision */ + int tx_queued; /* Packets currently waiting to transmit */ + int tx_tpr; /* Last value of TPR reg on card */ + int tx_collisions; /* Collisions since last successful send */ + int tx_timeouts; /* Count of transmit timeouts */ + int autoneg_status; /* Autonegotiation progress state */ + int media; /* Private media word */ + u_char version; /* Bonding Version register from card */ + u_char modem; /* 1 = Card has a modem */ + u_char ce2; /* 1 = Card has CE2 silicon */ + u_char mohawk; /* 1 = Card has Mohawk (CE3) silicon */ + u_char dingo; /* 1 = Card has Dingo (CEM56) silicon */ + u_char phy_ok; /* 1 = MII-compliant PHY found and initialised */ + u_char gone; /* 1 = Card bailed out */ +}; + +/* + * For accessing card registers + */ +#define XE_INB(r) bus_space_read_1(scp->bst, scp->bsh, (r)) +#define XE_INW(r) bus_space_read_2(scp->bst, scp->bsh, (r)) +#define XE_OUTB(r, b) bus_space_write_1(scp->bst, scp->bsh, (r), (b)) +#define XE_OUTW(r, w) bus_space_write_2(scp->bst, scp->bsh, (r), (w)) +#define XE_SELECT_PAGE(p) XE_OUTB(XE_PR, (p)) + +/* + * Horrid stuff for accessing CIS tuples + */ +#define CISTPL_BUFSIZE 512 +#define CISTPL_TYPE(tpl) tpl[0] +#define CISTPL_LEN(tpl) tpl[2] +#define CISTPL_DATA(tpl,pos) tpl[4 + ((pos)<<1)] + +#endif /* DEV_XE_IF_XEVAR_H */