2005-01-06 01:43:34 +00:00
|
|
|
/*-
|
1995-01-08 10:47:23 +00:00
|
|
|
* Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
1994-01-10 18:56:26 +00:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
1995-01-08 10:47:23 +00:00
|
|
|
* 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.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by Herb Peyerl.
|
|
|
|
* 4. The name of Herb Peyerl may not be used to endorse or promote products
|
|
|
|
* derived from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
|
1995-01-24 20:53:45 +00:00
|
|
|
*/
|
|
|
|
|
2003-08-24 17:55:58 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
1995-01-24 20:53:45 +00:00
|
|
|
/*
|
|
|
|
* Modified from the FreeBSD 1.1.5.1 version by:
|
1995-05-30 08:16:23 +00:00
|
|
|
* Andres Vega Garcia
|
1995-01-24 20:53:45 +00:00
|
|
|
* INRIA - Sophia Antipolis, France
|
|
|
|
* avega@sophia.inria.fr
|
1994-01-10 18:56:26 +00:00
|
|
|
*/
|
1994-05-02 22:27:33 +00:00
|
|
|
|
1995-03-31 06:41:38 +00:00
|
|
|
/*
|
|
|
|
* Promiscuous mode added and interrupt logic slightly changed
|
|
|
|
* to reduce the number of adapter failures. Transceiver select
|
|
|
|
* logic changed to use value from EEPROM. Autoconfiguration
|
|
|
|
* features added.
|
|
|
|
* Done by:
|
|
|
|
* Serge Babkin
|
|
|
|
* Chelindbank (Chelyabinsk, Russia)
|
|
|
|
* babkin@hq.icb.chel.su
|
|
|
|
*/
|
|
|
|
|
1996-06-14 22:11:38 +00:00
|
|
|
/*
|
|
|
|
* Pccard support for 3C589 by:
|
|
|
|
* HAMADA Naoki
|
|
|
|
* nao@tom-yam.or.jp
|
|
|
|
*/
|
|
|
|
|
1999-10-27 06:25:16 +00:00
|
|
|
/*
|
|
|
|
* MAINTAINER: Matthew N. Dodd <winter@jurai.net>
|
|
|
|
* <mdodd@FreeBSD.org>
|
|
|
|
*/
|
1994-01-26 09:06:29 +00:00
|
|
|
|
1994-05-02 22:27:33 +00:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/mbuf.h>
|
|
|
|
#include <sys/socket.h>
|
1997-03-24 11:33:46 +00:00
|
|
|
#include <sys/sockio.h>
|
1999-10-25 02:52:16 +00:00
|
|
|
#include <sys/bus.h>
|
1994-01-26 09:06:29 +00:00
|
|
|
|
1999-10-27 06:25:16 +00:00
|
|
|
#include <machine/bus.h>
|
|
|
|
#include <machine/resource.h>
|
2003-07-17 19:37:56 +00:00
|
|
|
#include <sys/rman.h>
|
1999-10-27 06:25:16 +00:00
|
|
|
|
1994-05-02 22:27:33 +00:00
|
|
|
#include <net/if.h>
|
2005-11-11 16:04:59 +00:00
|
|
|
#include <net/if_dl.h>
|
2003-07-17 19:37:56 +00:00
|
|
|
#include <net/if_media.h>
|
2005-06-10 16:49:24 +00:00
|
|
|
#include <net/if_types.h>
|
1999-10-27 06:25:16 +00:00
|
|
|
#include <net/ethernet.h>
|
|
|
|
#include <net/bpf.h>
|
|
|
|
|
1999-09-26 06:42:36 +00:00
|
|
|
#include <dev/ep/if_epreg.h>
|
|
|
|
#include <dev/ep/if_epvar.h>
|
1999-01-31 22:41:51 +00:00
|
|
|
|
1996-02-26 01:05:36 +00:00
|
|
|
/* Exported variables */
|
1999-10-25 02:52:16 +00:00
|
|
|
devclass_t ep_devclass;
|
1999-07-25 01:20:37 +00:00
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
static int ep_media2if_media[] =
|
|
|
|
{IFM_10_T, IFM_10_5, IFM_NONE, IFM_10_2, IFM_NONE};
|
1996-06-14 22:11:38 +00:00
|
|
|
|
1999-10-27 06:25:16 +00:00
|
|
|
/* if functions */
|
2003-10-25 04:09:49 +00:00
|
|
|
static void epinit(void *);
|
|
|
|
static int epioctl(struct ifnet *, u_long, caddr_t);
|
|
|
|
static void epstart(struct ifnet *);
|
|
|
|
static void epwatchdog(struct ifnet *);
|
|
|
|
|
2003-10-25 21:28:40 +00:00
|
|
|
static void epstart_locked(struct ifnet *);
|
|
|
|
static void epinit_locked(struct ep_softc *);
|
1996-06-14 22:11:38 +00:00
|
|
|
|
1999-10-27 06:25:16 +00:00
|
|
|
/* if_media functions */
|
2003-07-17 19:37:56 +00:00
|
|
|
static int ep_ifmedia_upd(struct ifnet *);
|
|
|
|
static void ep_ifmedia_sts(struct ifnet *, struct ifmediareq *);
|
1999-10-27 06:25:16 +00:00
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
static void epstop(struct ep_softc *);
|
|
|
|
static void epread(struct ep_softc *);
|
|
|
|
static int eeprom_rdy(struct ep_softc *);
|
1999-10-27 06:25:16 +00:00
|
|
|
|
|
|
|
#define EP_FTST(sc, f) (sc->stat & (f))
|
|
|
|
#define EP_FSET(sc, f) (sc->stat |= (f))
|
|
|
|
#define EP_FRST(sc, f) (sc->stat &= ~(f))
|
1996-06-14 22:11:38 +00:00
|
|
|
|
1994-11-13 10:12:37 +00:00
|
|
|
static int
|
2003-07-17 19:37:56 +00:00
|
|
|
eeprom_rdy(struct ep_softc *sc)
|
1994-11-13 10:12:37 +00:00
|
|
|
{
|
2003-07-17 19:37:56 +00:00
|
|
|
int i;
|
|
|
|
|
2003-10-18 15:22:43 +00:00
|
|
|
for (i = 0; is_eeprom_busy(sc) && i < MAX_EEPROMBUSY; i++)
|
2003-07-17 19:37:56 +00:00
|
|
|
DELAY(100);
|
|
|
|
|
|
|
|
if (i >= MAX_EEPROMBUSY) {
|
Minor cleanup of ep driver and pccard attachment:
o Grab the MAC address out of the CIS if the card has the special
3Com 0x88 tuple. Most 3Com cards don't have this tuple, but we
prefer it to the eeprom since it only appears to be present when
the eeprom doesn't have the info. So far, I've only observed this
on my 3C362 and 3C362B cards, but the NetBSD driver implies that
the 3C362C also has this tuple, and that some 3C574 cards do too (none
of mine do). ep_pccard_mac was written after looking at the NetBSD
code.
o Store the enet addr in the softc for this device, so we can use the
overridden MAC to set the station address.
o Create a routine to set the station address and use it where we need it.
o setup the cmd shitfs and such before we call ep_alloc(), and remove
setting up the cmd shift value there. It initializes to 0, and those
attachments that need to frob it do so before calling ep_alloc.
o Remove some obsolete comments
o No longer a need to export ep_get_macaddr, so make it static
o ep_alloc already grabs the EEPROM id, so we don't need to grab it again
in ep_pccard_attach.
o eliminate unit, it isn't needed, fix some printfs to be device_printf
instead.
# All my pccards except the 3C1 work now. Didn't test ISA or cbus cards
# that I have: 3C509B-TP or 3C569B-J-TPO
Tested on: 3C589B, 3C589C, 3C589D, 3C589D-TP, 3C562, 3C562B/3C563B,
3C562D/3C563D, 3CCFE574BT, 3CXEM556, 3CCSH572BT, 3C574-TX,
3CCE589EC, 3CXE589EC, 3CCFEM556, 3C1
Approved by: re (scottl)
2005-07-01 04:23:32 +00:00
|
|
|
device_printf(sc->dev, "eeprom failed to come ready.\n");
|
2003-11-02 20:10:09 +00:00
|
|
|
return (ENXIO);
|
2003-07-17 19:37:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
1994-11-13 10:12:37 +00:00
|
|
|
}
|
1994-09-03 18:10:44 +00:00
|
|
|
|
1994-01-10 18:56:26 +00:00
|
|
|
/*
|
1994-11-13 10:12:37 +00:00
|
|
|
* get_e: gets a 16 bits word from the EEPROM. we must have set the window
|
|
|
|
* before
|
1994-01-10 18:56:26 +00:00
|
|
|
*/
|
2003-03-29 21:44:46 +00:00
|
|
|
int
|
2005-06-26 04:19:45 +00:00
|
|
|
ep_get_e(struct ep_softc *sc, uint16_t offset, uint16_t *result)
|
1994-11-13 10:12:37 +00:00
|
|
|
{
|
2003-03-29 21:44:46 +00:00
|
|
|
|
|
|
|
if (eeprom_rdy(sc))
|
|
|
|
return (ENXIO);
|
2003-07-17 19:37:56 +00:00
|
|
|
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_W0_EEPROM_COMMAND,
|
2003-07-17 19:37:56 +00:00
|
|
|
(EEPROM_CMD_RD << sc->epb.cmd_off) | offset);
|
|
|
|
|
2003-03-29 21:44:46 +00:00
|
|
|
if (eeprom_rdy(sc))
|
|
|
|
return (ENXIO);
|
2003-07-17 19:37:56 +00:00
|
|
|
|
2003-10-25 04:09:49 +00:00
|
|
|
(*result) = CSR_READ_2(sc, EP_W0_EEPROM_DATA);
|
2003-03-29 21:44:46 +00:00
|
|
|
|
2000-01-15 05:21:43 +00:00
|
|
|
return (0);
|
1996-02-26 01:05:36 +00:00
|
|
|
}
|
|
|
|
|
Minor cleanup of ep driver and pccard attachment:
o Grab the MAC address out of the CIS if the card has the special
3Com 0x88 tuple. Most 3Com cards don't have this tuple, but we
prefer it to the eeprom since it only appears to be present when
the eeprom doesn't have the info. So far, I've only observed this
on my 3C362 and 3C362B cards, but the NetBSD driver implies that
the 3C362C also has this tuple, and that some 3C574 cards do too (none
of mine do). ep_pccard_mac was written after looking at the NetBSD
code.
o Store the enet addr in the softc for this device, so we can use the
overridden MAC to set the station address.
o Create a routine to set the station address and use it where we need it.
o setup the cmd shitfs and such before we call ep_alloc(), and remove
setting up the cmd shift value there. It initializes to 0, and those
attachments that need to frob it do so before calling ep_alloc.
o Remove some obsolete comments
o No longer a need to export ep_get_macaddr, so make it static
o ep_alloc already grabs the EEPROM id, so we don't need to grab it again
in ep_pccard_attach.
o eliminate unit, it isn't needed, fix some printfs to be device_printf
instead.
# All my pccards except the 3C1 work now. Didn't test ISA or cbus cards
# that I have: 3C509B-TP or 3C569B-J-TPO
Tested on: 3C589B, 3C589C, 3C589D, 3C589D-TP, 3C562, 3C562B/3C563B,
3C562D/3C563D, 3CCFE574BT, 3CXEM556, 3CCSH572BT, 3C574-TX,
3CCE589EC, 3CXE589EC, 3CCFEM556, 3C1
Approved by: re (scottl)
2005-07-01 04:23:32 +00:00
|
|
|
static int
|
2003-07-17 19:37:56 +00:00
|
|
|
ep_get_macaddr(struct ep_softc *sc, u_char *addr)
|
1996-02-26 01:05:36 +00:00
|
|
|
{
|
2003-07-17 19:37:56 +00:00
|
|
|
int i;
|
2005-01-20 19:39:33 +00:00
|
|
|
uint16_t result;
|
2003-07-17 19:37:56 +00:00
|
|
|
int error;
|
2005-01-20 19:39:33 +00:00
|
|
|
uint16_t *macaddr;
|
2003-03-29 21:44:46 +00:00
|
|
|
|
2005-01-20 19:39:33 +00:00
|
|
|
macaddr = (uint16_t *) addr;
|
1996-02-26 01:05:36 +00:00
|
|
|
|
2003-10-26 22:28:20 +00:00
|
|
|
GO_WINDOW(sc, 0);
|
2003-07-17 19:37:56 +00:00
|
|
|
for (i = EEPROM_NODE_ADDR_0; i <= EEPROM_NODE_ADDR_2; i++) {
|
2005-06-26 04:19:45 +00:00
|
|
|
error = ep_get_e(sc, i, &result);
|
2003-03-29 21:44:46 +00:00
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
macaddr[i] = htons(result);
|
2003-07-17 19:37:56 +00:00
|
|
|
}
|
2003-03-29 21:44:46 +00:00
|
|
|
return (0);
|
1999-10-27 06:25:16 +00:00
|
|
|
}
|
1996-02-26 01:05:36 +00:00
|
|
|
|
1999-10-27 06:25:16 +00:00
|
|
|
int
|
|
|
|
ep_alloc(device_t dev)
|
|
|
|
{
|
2003-07-17 19:37:56 +00:00
|
|
|
struct ep_softc *sc = device_get_softc(dev);
|
|
|
|
int rid;
|
|
|
|
int error = 0;
|
2005-01-20 19:39:33 +00:00
|
|
|
uint16_t result;
|
2003-07-17 19:37:56 +00:00
|
|
|
|
|
|
|
rid = 0;
|
2004-03-17 17:50:55 +00:00
|
|
|
sc->iobase = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
|
|
|
|
RF_ACTIVE);
|
2003-07-17 19:37:56 +00:00
|
|
|
if (!sc->iobase) {
|
|
|
|
device_printf(dev, "No I/O space?!\n");
|
1999-10-27 06:25:16 +00:00
|
|
|
error = ENXIO;
|
2003-07-17 19:37:56 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
rid = 0;
|
2004-03-17 17:50:55 +00:00
|
|
|
sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
|
2003-07-17 19:37:56 +00:00
|
|
|
if (!sc->irq) {
|
|
|
|
device_printf(dev, "No irq?!\n");
|
1999-10-27 06:25:16 +00:00
|
|
|
error = ENXIO;
|
2003-07-17 19:37:56 +00:00
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
sc->dev = dev;
|
|
|
|
sc->stat = 0; /* 16 bit access */
|
1999-10-27 06:25:16 +00:00
|
|
|
|
2003-10-18 15:22:43 +00:00
|
|
|
sc->bst = rman_get_bustag(sc->iobase);
|
|
|
|
sc->bsh = rman_get_bushandle(sc->iobase);
|
1999-10-27 06:25:16 +00:00
|
|
|
|
|
|
|
sc->ep_connectors = 0;
|
|
|
|
sc->ep_connector = 0;
|
|
|
|
|
2003-10-26 22:28:20 +00:00
|
|
|
GO_WINDOW(sc, 0);
|
2003-03-29 21:44:46 +00:00
|
|
|
|
2005-06-26 04:19:45 +00:00
|
|
|
error = ep_get_e(sc, EEPROM_PROD_ID, &result);
|
2003-03-29 21:44:46 +00:00
|
|
|
if (error)
|
|
|
|
goto bad;
|
|
|
|
sc->epb.prod_id = result;
|
|
|
|
|
2005-06-26 04:19:45 +00:00
|
|
|
error = ep_get_e(sc, EEPROM_RESOURCE_CFG, &result);
|
2003-03-29 21:44:46 +00:00
|
|
|
if (error)
|
|
|
|
goto bad;
|
|
|
|
sc->epb.res_cfg = result;
|
1999-10-27 06:25:16 +00:00
|
|
|
|
|
|
|
bad:
|
2003-11-02 20:10:09 +00:00
|
|
|
if (error != 0)
|
|
|
|
ep_free(dev);
|
1999-10-27 06:25:16 +00:00
|
|
|
return (error);
|
1996-02-26 01:05:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2003-07-17 19:37:56 +00:00
|
|
|
ep_get_media(struct ep_softc *sc)
|
1996-02-26 01:05:36 +00:00
|
|
|
{
|
2005-01-20 19:39:33 +00:00
|
|
|
uint16_t config;
|
2003-07-17 19:37:56 +00:00
|
|
|
|
2003-10-26 22:28:20 +00:00
|
|
|
GO_WINDOW(sc, 0);
|
2003-10-25 04:09:49 +00:00
|
|
|
config = CSR_READ_2(sc, EP_W0_CONFIG_CTRL);
|
2003-07-17 19:37:56 +00:00
|
|
|
if (config & IS_AUI)
|
|
|
|
sc->ep_connectors |= AUI;
|
|
|
|
if (config & IS_BNC)
|
|
|
|
sc->ep_connectors |= BNC;
|
|
|
|
if (config & IS_UTP)
|
|
|
|
sc->ep_connectors |= UTP;
|
|
|
|
|
|
|
|
if (!(sc->ep_connectors & 7))
|
1999-10-27 06:25:16 +00:00
|
|
|
if (bootverbose)
|
2003-07-17 19:37:56 +00:00
|
|
|
device_printf(sc->dev, "no connectors!\n");
|
1999-10-27 06:25:16 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This works for most of the cards so we'll do it here.
|
|
|
|
* The cards that require something different can override
|
|
|
|
* this later on.
|
|
|
|
*/
|
2003-10-25 04:09:49 +00:00
|
|
|
sc->ep_connector = CSR_READ_2(sc, EP_W0_ADDRESS_CFG) >> ACF_CONNECTOR_BITS;
|
1994-11-13 10:12:37 +00:00
|
|
|
}
|
|
|
|
|
1999-10-27 06:25:16 +00:00
|
|
|
void
|
|
|
|
ep_free(device_t dev)
|
|
|
|
{
|
2003-07-17 19:37:56 +00:00
|
|
|
struct ep_softc *sc = device_get_softc(dev);
|
1999-10-27 06:25:16 +00:00
|
|
|
|
2003-03-29 22:27:41 +00:00
|
|
|
if (sc->ep_intrhand)
|
|
|
|
bus_teardown_intr(dev, sc->irq, sc->ep_intrhand);
|
1999-10-27 06:25:16 +00:00
|
|
|
if (sc->iobase)
|
|
|
|
bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->iobase);
|
|
|
|
if (sc->irq)
|
|
|
|
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq);
|
2005-07-31 03:33:22 +00:00
|
|
|
sc->ep_intrhand = 0;
|
|
|
|
sc->iobase = 0;
|
|
|
|
sc->irq = 0;
|
1999-10-27 06:25:16 +00:00
|
|
|
}
|
2003-07-17 19:37:56 +00:00
|
|
|
|
Minor cleanup of ep driver and pccard attachment:
o Grab the MAC address out of the CIS if the card has the special
3Com 0x88 tuple. Most 3Com cards don't have this tuple, but we
prefer it to the eeprom since it only appears to be present when
the eeprom doesn't have the info. So far, I've only observed this
on my 3C362 and 3C362B cards, but the NetBSD driver implies that
the 3C362C also has this tuple, and that some 3C574 cards do too (none
of mine do). ep_pccard_mac was written after looking at the NetBSD
code.
o Store the enet addr in the softc for this device, so we can use the
overridden MAC to set the station address.
o Create a routine to set the station address and use it where we need it.
o setup the cmd shitfs and such before we call ep_alloc(), and remove
setting up the cmd shift value there. It initializes to 0, and those
attachments that need to frob it do so before calling ep_alloc.
o Remove some obsolete comments
o No longer a need to export ep_get_macaddr, so make it static
o ep_alloc already grabs the EEPROM id, so we don't need to grab it again
in ep_pccard_attach.
o eliminate unit, it isn't needed, fix some printfs to be device_printf
instead.
# All my pccards except the 3C1 work now. Didn't test ISA or cbus cards
# that I have: 3C509B-TP or 3C569B-J-TPO
Tested on: 3C589B, 3C589C, 3C589D, 3C589D-TP, 3C562, 3C562B/3C563B,
3C562D/3C563D, 3CCFE574BT, 3CXEM556, 3CCSH572BT, 3C574-TX,
3CCE589EC, 3CXE589EC, 3CCFEM556, 3C1
Approved by: re (scottl)
2005-07-01 04:23:32 +00:00
|
|
|
static void
|
|
|
|
ep_setup_station(struct ep_softc *sc, u_char *enaddr)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Setup the station address
|
|
|
|
*/
|
|
|
|
GO_WINDOW(sc, 2);
|
|
|
|
for (i = 0; i < ETHER_ADDR_LEN; i++)
|
|
|
|
CSR_WRITE_1(sc, EP_W2_ADDR_0 + i, enaddr[i]);
|
|
|
|
}
|
|
|
|
|
1996-02-26 01:05:36 +00:00
|
|
|
int
|
2003-07-17 19:37:56 +00:00
|
|
|
ep_attach(struct ep_softc *sc)
|
1996-02-26 01:05:36 +00:00
|
|
|
{
|
2003-07-17 19:37:56 +00:00
|
|
|
struct ifnet *ifp = NULL;
|
|
|
|
struct ifmedia *ifm = NULL;
|
|
|
|
int error;
|
1996-06-14 22:11:38 +00:00
|
|
|
|
1999-10-27 06:25:16 +00:00
|
|
|
sc->gone = 0;
|
2003-10-25 21:28:40 +00:00
|
|
|
EP_LOCK_INIT(sc);
|
Minor cleanup of ep driver and pccard attachment:
o Grab the MAC address out of the CIS if the card has the special
3Com 0x88 tuple. Most 3Com cards don't have this tuple, but we
prefer it to the eeprom since it only appears to be present when
the eeprom doesn't have the info. So far, I've only observed this
on my 3C362 and 3C362B cards, but the NetBSD driver implies that
the 3C362C also has this tuple, and that some 3C574 cards do too (none
of mine do). ep_pccard_mac was written after looking at the NetBSD
code.
o Store the enet addr in the softc for this device, so we can use the
overridden MAC to set the station address.
o Create a routine to set the station address and use it where we need it.
o setup the cmd shitfs and such before we call ep_alloc(), and remove
setting up the cmd shift value there. It initializes to 0, and those
attachments that need to frob it do so before calling ep_alloc.
o Remove some obsolete comments
o No longer a need to export ep_get_macaddr, so make it static
o ep_alloc already grabs the EEPROM id, so we don't need to grab it again
in ep_pccard_attach.
o eliminate unit, it isn't needed, fix some printfs to be device_printf
instead.
# All my pccards except the 3C1 work now. Didn't test ISA or cbus cards
# that I have: 3C509B-TP or 3C569B-J-TPO
Tested on: 3C589B, 3C589C, 3C589D, 3C589D-TP, 3C562, 3C562B/3C563B,
3C562D/3C563D, 3CCFE574BT, 3CXEM556, 3CCSH572BT, 3C574-TX,
3CCE589EC, 3CXE589EC, 3CCFEM556, 3C1
Approved by: re (scottl)
2005-07-01 04:23:32 +00:00
|
|
|
if (! (sc->stat & F_ENADDR_SKIP)) {
|
|
|
|
error = ep_get_macaddr(sc, sc->eaddr);
|
|
|
|
if (error) {
|
|
|
|
device_printf(sc->dev, "Unable to get MAC address!\n");
|
2005-07-19 22:26:44 +00:00
|
|
|
EP_LOCK_DESTROY(sc);
|
Minor cleanup of ep driver and pccard attachment:
o Grab the MAC address out of the CIS if the card has the special
3Com 0x88 tuple. Most 3Com cards don't have this tuple, but we
prefer it to the eeprom since it only appears to be present when
the eeprom doesn't have the info. So far, I've only observed this
on my 3C362 and 3C362B cards, but the NetBSD driver implies that
the 3C362C also has this tuple, and that some 3C574 cards do too (none
of mine do). ep_pccard_mac was written after looking at the NetBSD
code.
o Store the enet addr in the softc for this device, so we can use the
overridden MAC to set the station address.
o Create a routine to set the station address and use it where we need it.
o setup the cmd shitfs and such before we call ep_alloc(), and remove
setting up the cmd shift value there. It initializes to 0, and those
attachments that need to frob it do so before calling ep_alloc.
o Remove some obsolete comments
o No longer a need to export ep_get_macaddr, so make it static
o ep_alloc already grabs the EEPROM id, so we don't need to grab it again
in ep_pccard_attach.
o eliminate unit, it isn't needed, fix some printfs to be device_printf
instead.
# All my pccards except the 3C1 work now. Didn't test ISA or cbus cards
# that I have: 3C509B-TP or 3C569B-J-TPO
Tested on: 3C589B, 3C589C, 3C589D, 3C589D-TP, 3C562, 3C562B/3C563B,
3C562D/3C563D, 3CCFE574BT, 3CXEM556, 3CCSH572BT, 3C574-TX,
3CCE589EC, 3CXE589EC, 3CCFEM556, 3C1
Approved by: re (scottl)
2005-07-01 04:23:32 +00:00
|
|
|
return (ENXIO);
|
|
|
|
}
|
2003-03-29 21:44:46 +00:00
|
|
|
}
|
Minor cleanup of ep driver and pccard attachment:
o Grab the MAC address out of the CIS if the card has the special
3Com 0x88 tuple. Most 3Com cards don't have this tuple, but we
prefer it to the eeprom since it only appears to be present when
the eeprom doesn't have the info. So far, I've only observed this
on my 3C362 and 3C362B cards, but the NetBSD driver implies that
the 3C362C also has this tuple, and that some 3C574 cards do too (none
of mine do). ep_pccard_mac was written after looking at the NetBSD
code.
o Store the enet addr in the softc for this device, so we can use the
overridden MAC to set the station address.
o Create a routine to set the station address and use it where we need it.
o setup the cmd shitfs and such before we call ep_alloc(), and remove
setting up the cmd shift value there. It initializes to 0, and those
attachments that need to frob it do so before calling ep_alloc.
o Remove some obsolete comments
o No longer a need to export ep_get_macaddr, so make it static
o ep_alloc already grabs the EEPROM id, so we don't need to grab it again
in ep_pccard_attach.
o eliminate unit, it isn't needed, fix some printfs to be device_printf
instead.
# All my pccards except the 3C1 work now. Didn't test ISA or cbus cards
# that I have: 3C509B-TP or 3C569B-J-TPO
Tested on: 3C589B, 3C589C, 3C589D, 3C589D-TP, 3C562, 3C562B/3C563B,
3C562D/3C563D, 3CCFE574BT, 3CXEM556, 3CCSH572BT, 3C574-TX,
3CCE589EC, 3CXE589EC, 3CCFEM556, 3C1
Approved by: re (scottl)
2005-07-01 04:23:32 +00:00
|
|
|
ep_setup_station(sc, sc->eaddr);
|
2005-06-10 16:49:24 +00:00
|
|
|
ifp = sc->ifp = if_alloc(IFT_ETHER);
|
|
|
|
if (ifp == NULL) {
|
2005-07-01 05:31:23 +00:00
|
|
|
device_printf(sc->dev, "if_alloc() failed\n");
|
2005-07-19 22:26:44 +00:00
|
|
|
EP_LOCK_DESTROY(sc);
|
2005-06-10 16:49:24 +00:00
|
|
|
return (ENOSPC);
|
|
|
|
}
|
1999-10-27 06:25:16 +00:00
|
|
|
|
|
|
|
ifp->if_softc = sc;
|
2003-10-31 18:32:15 +00:00
|
|
|
if_initname(ifp, device_get_name(sc->dev), device_get_unit(sc->dev));
|
1999-10-27 06:25:16 +00:00
|
|
|
ifp->if_mtu = ETHERMTU;
|
|
|
|
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
|
2003-10-25 04:09:49 +00:00
|
|
|
ifp->if_start = epstart;
|
|
|
|
ifp->if_ioctl = epioctl;
|
|
|
|
ifp->if_watchdog = epwatchdog;
|
|
|
|
ifp->if_init = epinit;
|
2006-12-01 20:29:55 +00:00
|
|
|
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
|
|
|
|
ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
|
|
|
|
IFQ_SET_READY(&ifp->if_snd);
|
1999-10-27 06:25:16 +00:00
|
|
|
|
|
|
|
if (!sc->epb.mii_trans) {
|
|
|
|
ifmedia_init(&sc->ifmedia, 0, ep_ifmedia_upd, ep_ifmedia_sts);
|
|
|
|
|
|
|
|
if (sc->ep_connectors & AUI)
|
2003-08-30 08:10:58 +00:00
|
|
|
ifmedia_add(&sc->ifmedia,
|
|
|
|
IFM_ETHER | IFM_10_5, 0, NULL);
|
1999-10-27 06:25:16 +00:00
|
|
|
if (sc->ep_connectors & UTP)
|
2003-08-30 08:10:58 +00:00
|
|
|
ifmedia_add(&sc->ifmedia,
|
|
|
|
IFM_ETHER | IFM_10_T, 0, NULL);
|
1999-10-27 06:25:16 +00:00
|
|
|
if (sc->ep_connectors & BNC)
|
2003-08-30 08:10:58 +00:00
|
|
|
ifmedia_add(&sc->ifmedia,
|
|
|
|
IFM_ETHER | IFM_10_2, 0, NULL);
|
1999-10-27 06:25:16 +00:00
|
|
|
if (!sc->ep_connectors)
|
2003-08-30 08:10:58 +00:00
|
|
|
ifmedia_add(&sc->ifmedia,
|
|
|
|
IFM_ETHER | IFM_NONE, 0, NULL);
|
2003-07-17 19:37:56 +00:00
|
|
|
|
2003-08-30 08:10:58 +00:00
|
|
|
ifmedia_set(&sc->ifmedia,
|
|
|
|
IFM_ETHER | ep_media2if_media[sc->ep_connector]);
|
2003-07-17 19:37:56 +00:00
|
|
|
|
1999-10-27 06:25:16 +00:00
|
|
|
ifm = &sc->ifmedia;
|
|
|
|
ifm->ifm_media = ifm->ifm_cur->ifm_media;
|
|
|
|
ep_ifmedia_upd(ifp);
|
|
|
|
}
|
Minor cleanup of ep driver and pccard attachment:
o Grab the MAC address out of the CIS if the card has the special
3Com 0x88 tuple. Most 3Com cards don't have this tuple, but we
prefer it to the eeprom since it only appears to be present when
the eeprom doesn't have the info. So far, I've only observed this
on my 3C362 and 3C362B cards, but the NetBSD driver implies that
the 3C362C also has this tuple, and that some 3C574 cards do too (none
of mine do). ep_pccard_mac was written after looking at the NetBSD
code.
o Store the enet addr in the softc for this device, so we can use the
overridden MAC to set the station address.
o Create a routine to set the station address and use it where we need it.
o setup the cmd shitfs and such before we call ep_alloc(), and remove
setting up the cmd shift value there. It initializes to 0, and those
attachments that need to frob it do so before calling ep_alloc.
o Remove some obsolete comments
o No longer a need to export ep_get_macaddr, so make it static
o ep_alloc already grabs the EEPROM id, so we don't need to grab it again
in ep_pccard_attach.
o eliminate unit, it isn't needed, fix some printfs to be device_printf
instead.
# All my pccards except the 3C1 work now. Didn't test ISA or cbus cards
# that I have: 3C509B-TP or 3C569B-J-TPO
Tested on: 3C589B, 3C589C, 3C589D, 3C589D-TP, 3C562, 3C562B/3C563B,
3C562D/3C563D, 3CCFE574BT, 3CXEM556, 3CCSH572BT, 3C574-TX,
3CCE589EC, 3CXE589EC, 3CCFEM556, 3C1
Approved by: re (scottl)
2005-07-01 04:23:32 +00:00
|
|
|
ether_ifattach(ifp, sc->eaddr);
|
1996-01-29 03:16:14 +00:00
|
|
|
|
1994-11-13 10:12:37 +00:00
|
|
|
#ifdef EP_LOCAL_STATS
|
1999-10-27 06:25:16 +00:00
|
|
|
sc->rx_no_first = sc->rx_no_mbuf = sc->rx_bpf_disc =
|
2003-07-17 19:37:56 +00:00
|
|
|
sc->rx_overrunf = sc->rx_overrunl = sc->tx_underrun = 0;
|
1994-11-13 10:12:37 +00:00
|
|
|
#endif
|
1999-10-27 06:25:16 +00:00
|
|
|
EP_FSET(sc, F_RX_FIRST);
|
|
|
|
sc->top = sc->mcur = 0;
|
1994-01-26 09:06:29 +00:00
|
|
|
|
2000-03-13 11:48:03 +00:00
|
|
|
epstop(sc);
|
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
return (0);
|
1994-01-10 18:56:26 +00:00
|
|
|
}
|
|
|
|
|
2003-03-29 22:27:41 +00:00
|
|
|
int
|
|
|
|
ep_detach(device_t dev)
|
|
|
|
{
|
|
|
|
struct ep_softc *sc;
|
|
|
|
struct ifnet *ifp;
|
|
|
|
|
|
|
|
sc = device_get_softc(dev);
|
2005-06-10 16:49:24 +00:00
|
|
|
ifp = sc->ifp;
|
2005-09-20 19:50:27 +00:00
|
|
|
EP_ASSERT_UNLOCKED(sc);
|
|
|
|
EP_LOCK(sc);
|
2003-08-19 14:06:42 +00:00
|
|
|
if (bus_child_present(dev))
|
|
|
|
epstop(sc);
|
2005-09-20 19:50:27 +00:00
|
|
|
sc->gone = 1;
|
2005-08-09 10:20:02 +00:00
|
|
|
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
|
2005-09-20 19:50:27 +00:00
|
|
|
EP_UNLOCK(sc);
|
2003-03-29 22:27:41 +00:00
|
|
|
ether_ifdetach(ifp);
|
|
|
|
ep_free(dev);
|
2005-09-20 19:50:27 +00:00
|
|
|
|
2005-09-19 03:10:21 +00:00
|
|
|
if_free(ifp);
|
2005-07-19 22:26:44 +00:00
|
|
|
EP_LOCK_DESTROY(sc);
|
2003-03-29 22:27:41 +00:00
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2003-10-25 04:09:49 +00:00
|
|
|
static void
|
|
|
|
epinit(void *xsc)
|
|
|
|
{
|
|
|
|
struct ep_softc *sc = xsc;
|
|
|
|
EP_LOCK(sc);
|
2003-10-25 21:28:40 +00:00
|
|
|
epinit_locked(sc);
|
2003-10-25 04:09:49 +00:00
|
|
|
EP_UNLOCK(sc);
|
|
|
|
}
|
|
|
|
|
1994-01-26 09:06:29 +00:00
|
|
|
/*
|
|
|
|
* The order in here seems important. Otherwise we may not receive
|
|
|
|
* interrupts. ?!
|
|
|
|
*/
|
1995-12-10 13:40:44 +00:00
|
|
|
static void
|
2003-10-25 21:28:40 +00:00
|
|
|
epinit_locked(struct ep_softc *sc)
|
1994-01-10 18:56:26 +00:00
|
|
|
{
|
2005-06-10 16:49:24 +00:00
|
|
|
struct ifnet *ifp = sc->ifp;
|
2003-10-25 04:09:49 +00:00
|
|
|
int i;
|
1996-06-14 22:11:38 +00:00
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
if (sc->gone)
|
|
|
|
return;
|
1994-01-10 19:13:50 +00:00
|
|
|
|
2003-10-25 21:28:40 +00:00
|
|
|
EP_ASSERT_LOCKED(sc);
|
|
|
|
EP_BUSY_WAIT(sc);
|
1994-01-10 18:56:26 +00:00
|
|
|
|
2003-10-26 22:28:20 +00:00
|
|
|
GO_WINDOW(sc, 0);
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, STOP_TRANSCEIVER);
|
2003-10-26 22:28:20 +00:00
|
|
|
GO_WINDOW(sc, 4);
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_W4_MEDIA_TYPE, DISABLE_UTP);
|
2003-10-26 22:28:20 +00:00
|
|
|
GO_WINDOW(sc, 0);
|
1994-01-10 18:56:26 +00:00
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
/* Disable the card */
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_W0_CONFIG_CTRL, 0);
|
1994-01-26 09:13:56 +00:00
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
/* Enable the card */
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ);
|
1994-01-10 18:56:26 +00:00
|
|
|
|
2003-10-26 22:28:20 +00:00
|
|
|
GO_WINDOW(sc, 2);
|
2003-07-17 19:37:56 +00:00
|
|
|
/* Reload the ether_addr. */
|
2005-11-11 16:04:59 +00:00
|
|
|
ep_setup_station(sc, IF_LLADDR(sc->ifp));
|
1994-01-10 18:56:26 +00:00
|
|
|
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, RX_RESET);
|
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, TX_RESET);
|
2003-10-25 21:28:40 +00:00
|
|
|
EP_BUSY_WAIT(sc);
|
1994-01-10 18:56:26 +00:00
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
/* Window 1 is operating window */
|
2003-10-26 22:28:20 +00:00
|
|
|
GO_WINDOW(sc, 1);
|
2003-07-17 19:37:56 +00:00
|
|
|
for (i = 0; i < 31; i++)
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_READ_1(sc, EP_W1_TX_STATUS);
|
1994-01-10 18:56:26 +00:00
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
/* get rid of stray intr's */
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, ACK_INTR | 0xff);
|
1994-01-10 18:56:26 +00:00
|
|
|
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, SET_RD_0_MASK | S_5_INTS);
|
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, SET_INTR_MASK | S_5_INTS);
|
1994-11-13 10:12:37 +00:00
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
if (ifp->if_flags & IFF_PROMISC)
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
|
|
|
|
FIL_MULTICAST | FIL_BRDCST | FIL_PROMISC);
|
2003-07-17 19:37:56 +00:00
|
|
|
else
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL |
|
|
|
|
FIL_MULTICAST | FIL_BRDCST);
|
1997-10-14 06:56:09 +00:00
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
if (!sc->epb.mii_trans)
|
|
|
|
ep_ifmedia_upd(ifp);
|
1995-03-31 06:41:38 +00:00
|
|
|
|
2009-04-11 04:30:38 +00:00
|
|
|
if (sc->stat & F_HAS_TX_PLL)
|
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, TX_PLL_ENABLE);
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, RX_ENABLE);
|
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, TX_ENABLE);
|
1994-11-13 10:12:37 +00:00
|
|
|
|
2005-08-09 10:20:02 +00:00
|
|
|
ifp->if_drv_flags |= IFF_DRV_RUNNING;
|
|
|
|
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; /* just in case */
|
1994-11-13 10:12:37 +00:00
|
|
|
|
|
|
|
#ifdef EP_LOCAL_STATS
|
2003-07-17 19:37:56 +00:00
|
|
|
sc->rx_no_first = sc->rx_no_mbuf =
|
|
|
|
sc->rx_overrunf = sc->rx_overrunl = sc->tx_underrun = 0;
|
1994-11-13 10:12:37 +00:00
|
|
|
#endif
|
2003-07-17 19:37:56 +00:00
|
|
|
EP_FSET(sc, F_RX_FIRST);
|
|
|
|
if (sc->top) {
|
|
|
|
m_freem(sc->top);
|
|
|
|
sc->top = sc->mcur = 0;
|
|
|
|
}
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);
|
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, SET_TX_START_THRESH | 16);
|
1995-04-10 21:25:06 +00:00
|
|
|
|
2003-10-26 22:28:20 +00:00
|
|
|
GO_WINDOW(sc, 1);
|
2003-10-25 21:28:40 +00:00
|
|
|
epstart_locked(ifp);
|
1994-01-10 18:56:26 +00:00
|
|
|
}
|
|
|
|
|
1995-12-10 13:40:44 +00:00
|
|
|
static void
|
2003-10-25 04:09:49 +00:00
|
|
|
epstart(struct ifnet *ifp)
|
|
|
|
{
|
|
|
|
struct ep_softc *sc;
|
|
|
|
sc = ifp->if_softc;
|
|
|
|
EP_LOCK(sc);
|
2003-10-25 21:28:40 +00:00
|
|
|
epstart_locked(ifp);
|
2003-10-25 04:09:49 +00:00
|
|
|
EP_UNLOCK(sc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2003-10-25 21:28:40 +00:00
|
|
|
epstart_locked(struct ifnet *ifp)
|
1994-01-10 18:56:26 +00:00
|
|
|
{
|
2003-07-17 19:37:56 +00:00
|
|
|
struct ep_softc *sc;
|
|
|
|
u_int len;
|
|
|
|
struct mbuf *m, *m0;
|
2009-04-11 04:30:38 +00:00
|
|
|
int pad, started;
|
1994-11-13 10:12:37 +00:00
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
sc = ifp->if_softc;
|
|
|
|
if (sc->gone)
|
|
|
|
return;
|
2003-10-25 21:28:40 +00:00
|
|
|
EP_ASSERT_LOCKED(sc);
|
|
|
|
EP_BUSY_WAIT(sc);
|
2005-08-09 10:20:02 +00:00
|
|
|
if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
|
2003-07-17 19:37:56 +00:00
|
|
|
return;
|
2009-04-11 04:30:38 +00:00
|
|
|
started = 0;
|
1994-01-10 18:56:26 +00:00
|
|
|
startagain:
|
2003-07-17 19:37:56 +00:00
|
|
|
/* Sneak a peek at the next packet */
|
2006-12-01 20:29:55 +00:00
|
|
|
IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
|
2003-07-17 19:37:56 +00:00
|
|
|
if (m0 == NULL)
|
|
|
|
return;
|
2009-04-11 04:30:38 +00:00
|
|
|
if (!started && (sc->stat & F_HAS_TX_PLL))
|
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, TX_PLL_ENABLE);
|
|
|
|
started++;
|
2003-07-17 19:37:56 +00:00
|
|
|
for (len = 0, m = m0; m != NULL; m = m->m_next)
|
|
|
|
len += m->m_len;
|
|
|
|
|
|
|
|
pad = (4 - len) & 3;
|
|
|
|
|
|
|
|
/*
|
2003-08-30 08:10:58 +00:00
|
|
|
* The 3c509 automatically pads short packets to minimum
|
|
|
|
* ethernet length, but we drop packets that are too large.
|
|
|
|
* Perhaps we should truncate them instead?
|
|
|
|
*/
|
2003-07-17 19:37:56 +00:00
|
|
|
if (len + pad > ETHER_MAX_LEN) {
|
|
|
|
/* packet is obviously too large: toss it */
|
|
|
|
ifp->if_oerrors++;
|
|
|
|
m_freem(m0);
|
|
|
|
goto readcheck;
|
2000-01-12 06:42:49 +00:00
|
|
|
}
|
2003-10-25 04:09:49 +00:00
|
|
|
if (CSR_READ_2(sc, EP_W1_FREE_TX) < len + pad + 4) {
|
2003-07-17 19:37:56 +00:00
|
|
|
/* no room in FIFO */
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4));
|
2003-07-17 19:37:56 +00:00
|
|
|
/* make sure */
|
2003-10-25 04:09:49 +00:00
|
|
|
if (CSR_READ_2(sc, EP_W1_FREE_TX) < len + pad + 4) {
|
2005-08-09 10:20:02 +00:00
|
|
|
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
|
2006-12-01 20:29:55 +00:00
|
|
|
IFQ_DRV_PREPEND(&ifp->if_snd, m0);
|
2003-10-25 04:09:49 +00:00
|
|
|
goto done;
|
2003-07-17 19:37:56 +00:00
|
|
|
}
|
|
|
|
} else
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND,
|
2003-08-30 08:10:58 +00:00
|
|
|
SET_TX_AVAIL_THRESH | EP_THRESH_DISABLE);
|
2003-07-17 19:37:56 +00:00
|
|
|
|
2003-10-25 04:09:49 +00:00
|
|
|
/* XXX 4.x and earlier would splhigh here */
|
2003-07-17 19:37:56 +00:00
|
|
|
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_W1_TX_PIO_WR_1, len);
|
2003-08-30 08:10:58 +00:00
|
|
|
/* Second dword meaningless */
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_W1_TX_PIO_WR_1, 0x0);
|
2003-07-17 19:37:56 +00:00
|
|
|
|
|
|
|
if (EP_FTST(sc, F_ACCESS_32_BITS)) {
|
|
|
|
for (m = m0; m != NULL; m = m->m_next) {
|
|
|
|
if (m->m_len > 3)
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_MULTI_4(sc, EP_W1_TX_PIO_WR_1,
|
2003-10-18 15:22:43 +00:00
|
|
|
mtod(m, uint32_t *), m->m_len / 4);
|
2003-07-17 19:37:56 +00:00
|
|
|
if (m->m_len & 3)
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_MULTI_1(sc, EP_W1_TX_PIO_WR_1,
|
2003-10-18 15:22:43 +00:00
|
|
|
mtod(m, uint8_t *)+(m->m_len & (~3)),
|
2003-08-30 08:10:58 +00:00
|
|
|
m->m_len & 3);
|
2003-07-17 19:37:56 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (m = m0; m != NULL; m = m->m_next) {
|
|
|
|
if (m->m_len > 1)
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_MULTI_2(sc, EP_W1_TX_PIO_WR_1,
|
2003-10-18 15:22:43 +00:00
|
|
|
mtod(m, uint16_t *), m->m_len / 2);
|
2003-07-17 19:37:56 +00:00
|
|
|
if (m->m_len & 1)
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_1(sc, EP_W1_TX_PIO_WR_1,
|
2003-10-18 15:22:43 +00:00
|
|
|
*(mtod(m, uint8_t *)+m->m_len - 1));
|
2003-07-17 19:37:56 +00:00
|
|
|
}
|
1994-01-10 18:56:26 +00:00
|
|
|
}
|
1994-09-03 18:10:44 +00:00
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
while (pad--)
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_1(sc, EP_W1_TX_PIO_WR_1, 0); /* Padding */
|
1994-01-26 09:06:29 +00:00
|
|
|
|
2003-10-25 04:09:49 +00:00
|
|
|
/* XXX and drop splhigh here */
|
2000-01-12 06:42:49 +00:00
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
BPF_MTAP(ifp, m0);
|
1994-11-13 10:12:37 +00:00
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
ifp->if_timer = 2;
|
|
|
|
ifp->if_opackets++;
|
|
|
|
m_freem(m0);
|
1994-11-13 10:12:37 +00:00
|
|
|
|
|
|
|
/*
|
2003-08-30 08:10:58 +00:00
|
|
|
* Is another packet coming in? We don't want to overflow
|
|
|
|
* the tiny RX fifo.
|
|
|
|
*/
|
2003-07-17 19:37:56 +00:00
|
|
|
readcheck:
|
2003-10-25 04:09:49 +00:00
|
|
|
if (CSR_READ_2(sc, EP_W1_RX_STATUS) & RX_BYTES_MASK) {
|
2003-07-17 19:37:56 +00:00
|
|
|
/*
|
2003-08-30 08:10:58 +00:00
|
|
|
* we check if we have packets left, in that case
|
|
|
|
* we prepare to come back later
|
2003-07-17 19:37:56 +00:00
|
|
|
*/
|
2006-12-01 20:29:55 +00:00
|
|
|
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, SET_TX_AVAIL_THRESH | 8);
|
|
|
|
goto done;
|
2003-07-17 19:37:56 +00:00
|
|
|
}
|
|
|
|
goto startagain;
|
2003-10-25 04:09:49 +00:00
|
|
|
done:;
|
|
|
|
return;
|
1994-01-10 18:56:26 +00:00
|
|
|
}
|
|
|
|
|
1996-02-26 01:05:36 +00:00
|
|
|
void
|
2003-07-17 19:37:56 +00:00
|
|
|
ep_intr(void *arg)
|
1996-02-26 01:05:36 +00:00
|
|
|
{
|
2003-07-17 19:37:56 +00:00
|
|
|
struct ep_softc *sc;
|
|
|
|
int status;
|
|
|
|
struct ifnet *ifp;
|
1996-02-26 01:05:36 +00:00
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
sc = (struct ep_softc *) arg;
|
2003-10-25 04:09:49 +00:00
|
|
|
EP_LOCK(sc);
|
|
|
|
/* XXX 4.x splbio'd here to reduce interruptability */
|
1999-10-25 02:52:16 +00:00
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
/*
|
2003-08-30 08:10:58 +00:00
|
|
|
* quick fix: Try to detect an interrupt when the card goes away.
|
|
|
|
*/
|
2003-10-25 04:09:49 +00:00
|
|
|
if (sc->gone || CSR_READ_2(sc, EP_STATUS) == 0xffff) {
|
|
|
|
EP_UNLOCK(sc);
|
2003-07-17 19:37:56 +00:00
|
|
|
return;
|
|
|
|
}
|
2005-06-10 16:49:24 +00:00
|
|
|
ifp = sc->ifp;
|
1996-02-13 15:55:33 +00:00
|
|
|
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, SET_INTR_MASK); /* disable all Ints */
|
1995-04-05 13:12:13 +00:00
|
|
|
|
1995-03-23 06:53:39 +00:00
|
|
|
rescan:
|
1994-11-13 10:12:37 +00:00
|
|
|
|
2003-10-25 04:09:49 +00:00
|
|
|
while ((status = CSR_READ_2(sc, EP_STATUS)) & S_5_INTS) {
|
1995-03-31 06:41:38 +00:00
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
/* first acknowledge all interrupt sources */
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, ACK_INTR | (status & S_MASK));
|
1995-03-31 06:41:38 +00:00
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
if (status & (S_RX_COMPLETE | S_RX_EARLY))
|
|
|
|
epread(sc);
|
|
|
|
if (status & S_TX_AVAIL) {
|
|
|
|
/* we need ACK */
|
|
|
|
ifp->if_timer = 0;
|
2005-08-09 10:20:02 +00:00
|
|
|
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
|
2003-10-26 22:28:20 +00:00
|
|
|
GO_WINDOW(sc, 1);
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_READ_2(sc, EP_W1_FREE_TX);
|
2003-10-25 21:28:40 +00:00
|
|
|
epstart_locked(ifp);
|
2003-07-17 19:37:56 +00:00
|
|
|
}
|
|
|
|
if (status & S_CARD_FAILURE) {
|
|
|
|
ifp->if_timer = 0;
|
1994-11-13 10:12:37 +00:00
|
|
|
#ifdef EP_LOCAL_STATS
|
Minor cleanup of ep driver and pccard attachment:
o Grab the MAC address out of the CIS if the card has the special
3Com 0x88 tuple. Most 3Com cards don't have this tuple, but we
prefer it to the eeprom since it only appears to be present when
the eeprom doesn't have the info. So far, I've only observed this
on my 3C362 and 3C362B cards, but the NetBSD driver implies that
the 3C362C also has this tuple, and that some 3C574 cards do too (none
of mine do). ep_pccard_mac was written after looking at the NetBSD
code.
o Store the enet addr in the softc for this device, so we can use the
overridden MAC to set the station address.
o Create a routine to set the station address and use it where we need it.
o setup the cmd shitfs and such before we call ep_alloc(), and remove
setting up the cmd shift value there. It initializes to 0, and those
attachments that need to frob it do so before calling ep_alloc.
o Remove some obsolete comments
o No longer a need to export ep_get_macaddr, so make it static
o ep_alloc already grabs the EEPROM id, so we don't need to grab it again
in ep_pccard_attach.
o eliminate unit, it isn't needed, fix some printfs to be device_printf
instead.
# All my pccards except the 3C1 work now. Didn't test ISA or cbus cards
# that I have: 3C509B-TP or 3C569B-J-TPO
Tested on: 3C589B, 3C589C, 3C589D, 3C589D-TP, 3C562, 3C562B/3C563B,
3C562D/3C563D, 3CCFE574BT, 3CXEM556, 3CCSH572BT, 3C574-TX,
3CCE589EC, 3CXE589EC, 3CCFEM556, 3C1
Approved by: re (scottl)
2005-07-01 04:23:32 +00:00
|
|
|
device_printf(sc->dev, "\n\tStatus: %x\n", status);
|
2003-10-26 22:28:20 +00:00
|
|
|
GO_WINDOW(sc, 4);
|
2003-08-30 08:10:58 +00:00
|
|
|
printf("\tFIFO Diagnostic: %x\n",
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_READ_2(sc, EP_W4_FIFO_DIAG));
|
2003-07-17 19:37:56 +00:00
|
|
|
printf("\tStat: %x\n", sc->stat);
|
|
|
|
printf("\tIpackets=%d, Opackets=%d\n",
|
|
|
|
ifp->if_ipackets, ifp->if_opackets);
|
|
|
|
printf("\tNOF=%d, NOMB=%d, RXOF=%d, RXOL=%d, TXU=%d\n",
|
|
|
|
sc->rx_no_first, sc->rx_no_mbuf, sc->rx_overrunf,
|
|
|
|
sc->rx_overrunl, sc->tx_underrun);
|
1994-11-13 10:12:37 +00:00
|
|
|
#else
|
1996-01-29 03:16:14 +00:00
|
|
|
|
|
|
|
#ifdef DIAGNOSTIC
|
Minor cleanup of ep driver and pccard attachment:
o Grab the MAC address out of the CIS if the card has the special
3Com 0x88 tuple. Most 3Com cards don't have this tuple, but we
prefer it to the eeprom since it only appears to be present when
the eeprom doesn't have the info. So far, I've only observed this
on my 3C362 and 3C362B cards, but the NetBSD driver implies that
the 3C362C also has this tuple, and that some 3C574 cards do too (none
of mine do). ep_pccard_mac was written after looking at the NetBSD
code.
o Store the enet addr in the softc for this device, so we can use the
overridden MAC to set the station address.
o Create a routine to set the station address and use it where we need it.
o setup the cmd shitfs and such before we call ep_alloc(), and remove
setting up the cmd shift value there. It initializes to 0, and those
attachments that need to frob it do so before calling ep_alloc.
o Remove some obsolete comments
o No longer a need to export ep_get_macaddr, so make it static
o ep_alloc already grabs the EEPROM id, so we don't need to grab it again
in ep_pccard_attach.
o eliminate unit, it isn't needed, fix some printfs to be device_printf
instead.
# All my pccards except the 3C1 work now. Didn't test ISA or cbus cards
# that I have: 3C509B-TP or 3C569B-J-TPO
Tested on: 3C589B, 3C589C, 3C589D, 3C589D-TP, 3C562, 3C562B/3C563B,
3C562D/3C563D, 3CCFE574BT, 3CXEM556, 3CCSH572BT, 3C574-TX,
3CCE589EC, 3CXE589EC, 3CCFEM556, 3C1
Approved by: re (scottl)
2005-07-01 04:23:32 +00:00
|
|
|
device_printf(sc->dev,
|
|
|
|
"Status: %x (input buffer overflow)\n", status);
|
1996-01-29 03:16:14 +00:00
|
|
|
#else
|
2003-07-17 19:37:56 +00:00
|
|
|
++ifp->if_ierrors;
|
1996-01-29 03:16:14 +00:00
|
|
|
#endif
|
|
|
|
|
1994-11-13 10:12:37 +00:00
|
|
|
#endif
|
2003-10-25 21:28:40 +00:00
|
|
|
epinit_locked(sc);
|
2003-10-25 04:09:49 +00:00
|
|
|
EP_UNLOCK(sc);
|
2003-07-17 19:37:56 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (status & S_TX_COMPLETE) {
|
|
|
|
ifp->if_timer = 0;
|
|
|
|
/*
|
2003-08-30 08:10:58 +00:00
|
|
|
* We need ACK. We do it at the end.
|
|
|
|
*
|
|
|
|
* We need to read TX_STATUS until we get a
|
|
|
|
* 0 status in order to turn off the interrupt flag.
|
2003-07-17 19:37:56 +00:00
|
|
|
*/
|
2003-10-25 04:09:49 +00:00
|
|
|
while ((status = CSR_READ_1(sc, EP_W1_TX_STATUS)) &
|
2003-08-30 08:10:58 +00:00
|
|
|
TXS_COMPLETE) {
|
2005-04-13 06:42:43 +00:00
|
|
|
if (status & TXS_SUCCES_INTR_REQ)
|
|
|
|
; /* nothing */
|
2003-08-30 08:10:58 +00:00
|
|
|
else if (status &
|
|
|
|
(TXS_UNDERRUN | TXS_JABBER |
|
|
|
|
TXS_MAX_COLLISION)) {
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, TX_RESET);
|
2003-07-17 19:37:56 +00:00
|
|
|
if (status & TXS_UNDERRUN) {
|
1994-11-13 10:12:37 +00:00
|
|
|
#ifdef EP_LOCAL_STATS
|
2003-07-17 19:37:56 +00:00
|
|
|
sc->tx_underrun++;
|
1994-11-13 10:12:37 +00:00
|
|
|
#endif
|
2009-09-08 16:37:18 +00:00
|
|
|
}
|
|
|
|
if (status & TXS_MAX_COLLISION) {
|
|
|
|
/*
|
|
|
|
* TXS_MAX_COLLISION we
|
|
|
|
* shouldn't get here
|
|
|
|
*/
|
|
|
|
++ifp->if_collisions;
|
2003-07-17 19:37:56 +00:00
|
|
|
}
|
|
|
|
++ifp->if_oerrors;
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, TX_ENABLE);
|
2003-07-17 19:37:56 +00:00
|
|
|
/*
|
2003-08-30 08:10:58 +00:00
|
|
|
* To have a tx_avail_int but giving
|
|
|
|
* the chance to the Reception
|
2003-07-17 19:37:56 +00:00
|
|
|
*/
|
2006-12-01 20:29:55 +00:00
|
|
|
if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND,
|
2003-08-30 08:10:58 +00:00
|
|
|
SET_TX_AVAIL_THRESH | 8);
|
2003-07-17 19:37:56 +00:00
|
|
|
}
|
2003-08-30 08:10:58 +00:00
|
|
|
/* pops up the next status */
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_1(sc, EP_W1_TX_STATUS, 0x0);
|
2003-07-17 19:37:56 +00:00
|
|
|
} /* while */
|
2005-08-09 10:20:02 +00:00
|
|
|
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
|
2003-10-26 22:28:20 +00:00
|
|
|
GO_WINDOW(sc, 1);
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_READ_2(sc, EP_W1_FREE_TX);
|
2003-10-25 21:28:40 +00:00
|
|
|
epstart_locked(ifp);
|
2003-08-30 08:10:58 +00:00
|
|
|
} /* end TX_COMPLETE */
|
2003-07-17 19:37:56 +00:00
|
|
|
}
|
1995-03-23 06:53:39 +00:00
|
|
|
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, C_INTR_LATCH); /* ACK int Latch */
|
1995-03-23 06:53:39 +00:00
|
|
|
|
2003-10-25 04:09:49 +00:00
|
|
|
if ((status = CSR_READ_2(sc, EP_STATUS)) & S_5_INTS)
|
2003-07-17 19:37:56 +00:00
|
|
|
goto rescan;
|
1995-04-05 13:12:13 +00:00
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
/* re-enable Ints */
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, SET_INTR_MASK | S_5_INTS);
|
|
|
|
EP_UNLOCK(sc);
|
1994-01-10 18:56:26 +00:00
|
|
|
}
|
|
|
|
|
1995-12-10 13:40:44 +00:00
|
|
|
static void
|
2003-07-17 19:37:56 +00:00
|
|
|
epread(struct ep_softc *sc)
|
1994-01-10 18:56:26 +00:00
|
|
|
{
|
2003-07-17 19:37:56 +00:00
|
|
|
struct mbuf *top, *mcur, *m;
|
|
|
|
struct ifnet *ifp;
|
|
|
|
int lenthisone;
|
|
|
|
short rx_fifo2, status;
|
|
|
|
short rx_fifo;
|
1994-11-13 10:12:37 +00:00
|
|
|
|
2003-10-25 04:09:49 +00:00
|
|
|
/* XXX Must be called with sc locked */
|
|
|
|
|
2005-06-10 16:49:24 +00:00
|
|
|
ifp = sc->ifp;
|
2003-10-25 04:09:49 +00:00
|
|
|
status = CSR_READ_2(sc, EP_W1_RX_STATUS);
|
1994-11-13 10:12:37 +00:00
|
|
|
|
|
|
|
read_again:
|
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
if (status & ERR_RX) {
|
|
|
|
++ifp->if_ierrors;
|
|
|
|
if (status & ERR_RX_OVERRUN) {
|
|
|
|
/*
|
2003-08-30 08:10:58 +00:00
|
|
|
* We can think the rx latency is actually
|
|
|
|
* greather than we expect
|
2003-07-17 19:37:56 +00:00
|
|
|
*/
|
1994-11-13 10:12:37 +00:00
|
|
|
#ifdef EP_LOCAL_STATS
|
2003-07-17 19:37:56 +00:00
|
|
|
if (EP_FTST(sc, F_RX_FIRST))
|
|
|
|
sc->rx_overrunf++;
|
|
|
|
else
|
|
|
|
sc->rx_overrunl++;
|
1994-11-13 10:12:37 +00:00
|
|
|
#endif
|
2003-07-17 19:37:56 +00:00
|
|
|
}
|
|
|
|
goto out;
|
1994-01-26 09:06:29 +00:00
|
|
|
}
|
2003-07-17 19:37:56 +00:00
|
|
|
rx_fifo = rx_fifo2 = status & RX_BYTES_MASK;
|
|
|
|
|
|
|
|
if (EP_FTST(sc, F_RX_FIRST)) {
|
|
|
|
MGETHDR(m, M_DONTWAIT, MT_DATA);
|
|
|
|
if (!m)
|
|
|
|
goto out;
|
|
|
|
if (rx_fifo >= MINCLSIZE)
|
|
|
|
MCLGET(m, M_DONTWAIT);
|
|
|
|
sc->top = sc->mcur = top = m;
|
1994-01-26 09:06:29 +00:00
|
|
|
#define EROUND ((sizeof(struct ether_header) + 3) & ~3)
|
|
|
|
#define EOFF (EROUND - sizeof(struct ether_header))
|
2003-07-17 19:37:56 +00:00
|
|
|
top->m_data += EOFF;
|
|
|
|
|
|
|
|
/* Read what should be the header. */
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_READ_MULTI_2(sc, EP_W1_RX_PIO_RD_1,
|
2003-10-18 15:22:43 +00:00
|
|
|
mtod(top, uint16_t *), sizeof(struct ether_header) / 2);
|
2003-07-17 19:37:56 +00:00
|
|
|
top->m_len = sizeof(struct ether_header);
|
|
|
|
rx_fifo -= sizeof(struct ether_header);
|
|
|
|
sc->cur_len = rx_fifo2;
|
1994-11-13 10:12:37 +00:00
|
|
|
} else {
|
2003-07-17 19:37:56 +00:00
|
|
|
/* come here if we didn't have a complete packet last time */
|
|
|
|
top = sc->top;
|
|
|
|
m = sc->mcur;
|
|
|
|
sc->cur_len += rx_fifo2;
|
1994-11-13 10:12:37 +00:00
|
|
|
}
|
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
/* Reads what is left in the RX FIFO */
|
|
|
|
while (rx_fifo > 0) {
|
|
|
|
lenthisone = min(rx_fifo, M_TRAILINGSPACE(m));
|
|
|
|
if (lenthisone == 0) { /* no room in this one */
|
|
|
|
mcur = m;
|
|
|
|
MGET(m, M_DONTWAIT, MT_DATA);
|
|
|
|
if (!m)
|
|
|
|
goto out;
|
|
|
|
if (rx_fifo >= MINCLSIZE)
|
|
|
|
MCLGET(m, M_DONTWAIT);
|
|
|
|
m->m_len = 0;
|
|
|
|
mcur->m_next = m;
|
|
|
|
lenthisone = min(rx_fifo, M_TRAILINGSPACE(m));
|
|
|
|
}
|
2003-08-30 08:10:58 +00:00
|
|
|
if (EP_FTST(sc, F_ACCESS_32_BITS)) {
|
|
|
|
/* default for EISA configured cards */
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_READ_MULTI_4(sc, EP_W1_RX_PIO_RD_1,
|
2003-10-23 03:42:47 +00:00
|
|
|
(uint32_t *)(mtod(m, caddr_t)+m->m_len),
|
2003-07-17 19:37:56 +00:00
|
|
|
lenthisone / 4);
|
|
|
|
m->m_len += (lenthisone & ~3);
|
|
|
|
if (lenthisone & 3)
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_READ_MULTI_1(sc, EP_W1_RX_PIO_RD_1,
|
2003-08-30 08:10:58 +00:00
|
|
|
mtod(m, caddr_t)+m->m_len, lenthisone & 3);
|
2003-07-17 19:37:56 +00:00
|
|
|
m->m_len += (lenthisone & 3);
|
|
|
|
} else {
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_READ_MULTI_2(sc, EP_W1_RX_PIO_RD_1,
|
2003-10-23 05:33:53 +00:00
|
|
|
(uint16_t *)(mtod(m, caddr_t)+m->m_len),
|
2003-10-23 03:42:47 +00:00
|
|
|
lenthisone / 2);
|
2003-07-17 19:37:56 +00:00
|
|
|
m->m_len += lenthisone;
|
|
|
|
if (lenthisone & 1)
|
2003-08-30 08:10:58 +00:00
|
|
|
*(mtod(m, caddr_t)+m->m_len - 1) =
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_READ_1(sc, EP_W1_RX_PIO_RD_1);
|
2003-07-17 19:37:56 +00:00
|
|
|
}
|
|
|
|
rx_fifo -= lenthisone;
|
|
|
|
}
|
|
|
|
|
2003-08-30 08:10:58 +00:00
|
|
|
if (status & ERR_RX_INCOMPLETE) {
|
|
|
|
/* we haven't received the complete packet */
|
2003-07-17 19:37:56 +00:00
|
|
|
sc->mcur = m;
|
1994-11-13 10:12:37 +00:00
|
|
|
#ifdef EP_LOCAL_STATS
|
2003-08-30 08:10:58 +00:00
|
|
|
/* to know how often we come here */
|
|
|
|
sc->rx_no_first++;
|
1994-11-13 10:12:37 +00:00
|
|
|
#endif
|
2003-07-17 19:37:56 +00:00
|
|
|
EP_FRST(sc, F_RX_FIRST);
|
2003-10-25 04:09:49 +00:00
|
|
|
status = CSR_READ_2(sc, EP_W1_RX_STATUS);
|
2003-08-30 08:10:58 +00:00
|
|
|
if (!status & ERR_RX_INCOMPLETE) {
|
2003-07-17 19:37:56 +00:00
|
|
|
/*
|
2003-08-30 08:10:58 +00:00
|
|
|
* We see if by now, the packet has completly
|
2003-07-17 19:37:56 +00:00
|
|
|
* arrived
|
|
|
|
*/
|
|
|
|
goto read_again;
|
|
|
|
}
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND,
|
2003-08-30 08:10:58 +00:00
|
|
|
SET_RX_EARLY_THRESH | RX_NEXT_EARLY_THRESH);
|
2003-07-17 19:37:56 +00:00
|
|
|
return;
|
1994-11-13 10:12:37 +00:00
|
|
|
}
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, RX_DISCARD_TOP_PACK);
|
2003-07-17 19:37:56 +00:00
|
|
|
++ifp->if_ipackets;
|
|
|
|
EP_FSET(sc, F_RX_FIRST);
|
2005-06-10 16:49:24 +00:00
|
|
|
top->m_pkthdr.rcvif = sc->ifp;
|
2003-07-17 19:37:56 +00:00
|
|
|
top->m_pkthdr.len = sc->cur_len;
|
|
|
|
|
2003-10-25 04:09:49 +00:00
|
|
|
/*
|
|
|
|
* Drop locks before calling if_input() since it may re-enter
|
|
|
|
* ep_start() in the netisr case. This would result in a
|
|
|
|
* lock reversal. Better performance might be obtained by
|
|
|
|
* chaining all packets received, dropping the lock, and then
|
|
|
|
* calling if_input() on each one.
|
|
|
|
*/
|
|
|
|
EP_UNLOCK(sc);
|
2003-07-17 19:37:56 +00:00
|
|
|
(*ifp->if_input) (ifp, top);
|
2003-10-25 04:09:49 +00:00
|
|
|
EP_LOCK(sc);
|
2003-07-17 19:37:56 +00:00
|
|
|
sc->top = 0;
|
2003-10-25 21:28:40 +00:00
|
|
|
EP_BUSY_WAIT(sc);
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);
|
1994-11-13 10:12:37 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
out:
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, RX_DISCARD_TOP_PACK);
|
2003-07-17 19:37:56 +00:00
|
|
|
if (sc->top) {
|
|
|
|
m_freem(sc->top);
|
|
|
|
sc->top = 0;
|
1994-11-13 10:12:37 +00:00
|
|
|
#ifdef EP_LOCAL_STATS
|
2003-07-17 19:37:56 +00:00
|
|
|
sc->rx_no_mbuf++;
|
1994-11-13 10:12:37 +00:00
|
|
|
#endif
|
2003-07-17 19:37:56 +00:00
|
|
|
}
|
|
|
|
EP_FSET(sc, F_RX_FIRST);
|
2003-10-25 21:28:40 +00:00
|
|
|
EP_BUSY_WAIT(sc);
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, SET_RX_EARLY_THRESH | RX_INIT_EARLY_THRESH);
|
1994-01-10 18:56:26 +00:00
|
|
|
}
|
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
static int
|
|
|
|
ep_ifmedia_upd(struct ifnet *ifp)
|
1994-01-10 18:56:26 +00:00
|
|
|
{
|
2003-07-17 19:37:56 +00:00
|
|
|
struct ep_softc *sc = ifp->if_softc;
|
|
|
|
int i = 0, j;
|
1999-10-27 06:25:16 +00:00
|
|
|
|
2003-10-26 22:28:20 +00:00
|
|
|
GO_WINDOW(sc, 0);
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, STOP_TRANSCEIVER);
|
2003-10-26 22:28:20 +00:00
|
|
|
GO_WINDOW(sc, 4);
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_W4_MEDIA_TYPE, DISABLE_UTP);
|
2003-10-26 22:28:20 +00:00
|
|
|
GO_WINDOW(sc, 0);
|
1999-10-27 06:25:16 +00:00
|
|
|
|
|
|
|
switch (IFM_SUBTYPE(sc->ifmedia.ifm_media)) {
|
2003-07-17 19:37:56 +00:00
|
|
|
case IFM_10_T:
|
|
|
|
if (sc->ep_connectors & UTP) {
|
|
|
|
i = ACF_CONNECTOR_UTP;
|
2003-10-26 22:28:20 +00:00
|
|
|
GO_WINDOW(sc, 4);
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_W4_MEDIA_TYPE, ENABLE_UTP);
|
2003-07-17 19:37:56 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IFM_10_2:
|
|
|
|
if (sc->ep_connectors & BNC) {
|
|
|
|
i = ACF_CONNECTOR_BNC;
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, START_TRANSCEIVER);
|
2003-07-17 19:37:56 +00:00
|
|
|
DELAY(DELAY_MULTIPLE * 1000);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IFM_10_5:
|
|
|
|
if (sc->ep_connectors & AUI)
|
|
|
|
i = ACF_CONNECTOR_AUI;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
i = sc->ep_connector;
|
|
|
|
device_printf(sc->dev,
|
|
|
|
"strange connector type in EEPROM: assuming AUI\n");
|
1999-10-27 06:25:16 +00:00
|
|
|
}
|
1994-11-13 10:12:37 +00:00
|
|
|
|
2003-10-26 22:28:20 +00:00
|
|
|
GO_WINDOW(sc, 0);
|
2003-10-25 04:09:49 +00:00
|
|
|
j = CSR_READ_2(sc, EP_W0_ADDRESS_CFG) & 0x3fff;
|
|
|
|
CSR_WRITE_2(sc, EP_W0_ADDRESS_CFG, j | (i << ACF_CONNECTOR_BITS));
|
1995-07-05 07:21:34 +00:00
|
|
|
|
1999-10-27 06:25:16 +00:00
|
|
|
return (0);
|
|
|
|
}
|
1999-08-18 06:12:00 +00:00
|
|
|
|
1999-10-27 06:25:16 +00:00
|
|
|
static void
|
2003-07-17 19:37:56 +00:00
|
|
|
ep_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
|
1999-10-27 06:25:16 +00:00
|
|
|
{
|
2003-07-17 19:37:56 +00:00
|
|
|
struct ep_softc *sc = ifp->if_softc;
|
2009-04-11 02:47:03 +00:00
|
|
|
uint16_t ms;
|
1996-01-29 03:16:14 +00:00
|
|
|
|
2009-04-11 02:47:03 +00:00
|
|
|
switch (IFM_SUBTYPE(sc->ifmedia.ifm_media)) {
|
|
|
|
case IFM_10_T:
|
|
|
|
GO_WINDOW(sc, 4);
|
|
|
|
ms = CSR_READ_2(sc, EP_W4_MEDIA_TYPE);
|
|
|
|
GO_WINDOW(sc, 0);
|
|
|
|
ifmr->ifm_status = IFM_AVALID;
|
|
|
|
if (ms & MT_LB) {
|
|
|
|
ifmr->ifm_status |= IFM_ACTIVE;
|
|
|
|
ifmr->ifm_active = IFM_ETHER | IFM_10_T;
|
|
|
|
} else {
|
|
|
|
ifmr->ifm_active = IFM_ETHER | IFM_NONE;
|
|
|
|
}
|
2009-05-15 21:06:28 +00:00
|
|
|
break;
|
2009-04-11 02:47:03 +00:00
|
|
|
default:
|
|
|
|
ifmr->ifm_active = sc->ifmedia.ifm_media;
|
|
|
|
break;
|
|
|
|
}
|
1999-10-27 06:25:16 +00:00
|
|
|
}
|
1995-03-31 06:41:38 +00:00
|
|
|
|
1999-10-27 06:25:16 +00:00
|
|
|
static int
|
2003-10-25 04:09:49 +00:00
|
|
|
epioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
1999-10-27 06:25:16 +00:00
|
|
|
{
|
2003-07-17 19:37:56 +00:00
|
|
|
struct ep_softc *sc = ifp->if_softc;
|
|
|
|
struct ifreq *ifr = (struct ifreq *) data;
|
2003-10-25 04:09:49 +00:00
|
|
|
int error = 0;
|
1999-10-27 06:25:16 +00:00
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case SIOCSIFFLAGS:
|
2003-10-25 04:09:49 +00:00
|
|
|
EP_LOCK(sc);
|
1999-10-27 06:25:16 +00:00
|
|
|
if (((ifp->if_flags & IFF_UP) == 0) &&
|
2005-08-09 10:20:02 +00:00
|
|
|
(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
|
|
|
|
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
|
1999-10-27 06:25:16 +00:00
|
|
|
epstop(sc);
|
2003-07-17 19:37:56 +00:00
|
|
|
} else
|
1999-10-27 06:25:16 +00:00
|
|
|
/* reinitialize card on any parameter change */
|
2003-10-25 21:28:40 +00:00
|
|
|
epinit_locked(sc);
|
2003-10-25 04:09:49 +00:00
|
|
|
EP_UNLOCK(sc);
|
1999-10-27 06:25:16 +00:00
|
|
|
break;
|
1996-01-29 03:16:14 +00:00
|
|
|
case SIOCADDMULTI:
|
|
|
|
case SIOCDELMULTI:
|
1999-10-27 06:25:16 +00:00
|
|
|
/*
|
|
|
|
* The Etherlink III has no programmable multicast
|
|
|
|
* filter. We always initialize the card to be
|
|
|
|
* promiscuous to multicast, since we're always a
|
|
|
|
* member of the ALL-SYSTEMS group, so there's no
|
|
|
|
* need to process SIOC*MULTI requests.
|
|
|
|
*/
|
|
|
|
error = 0;
|
|
|
|
break;
|
|
|
|
case SIOCSIFMEDIA:
|
|
|
|
case SIOCGIFMEDIA:
|
2003-07-17 19:37:56 +00:00
|
|
|
if (!sc->epb.mii_trans)
|
2000-01-15 05:21:43 +00:00
|
|
|
error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, cmd);
|
2003-07-17 19:37:56 +00:00
|
|
|
else
|
2000-01-15 05:21:43 +00:00
|
|
|
error = EINVAL;
|
1999-10-27 06:25:16 +00:00
|
|
|
break;
|
|
|
|
default:
|
2002-11-14 23:54:55 +00:00
|
|
|
error = ether_ioctl(ifp, cmd, data);
|
1999-10-27 06:25:16 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (error);
|
1994-01-10 18:56:26 +00:00
|
|
|
}
|
|
|
|
|
1995-12-10 13:40:44 +00:00
|
|
|
static void
|
2003-10-25 04:09:49 +00:00
|
|
|
epwatchdog(struct ifnet *ifp)
|
1994-01-10 18:56:26 +00:00
|
|
|
{
|
2003-07-17 19:37:56 +00:00
|
|
|
struct ep_softc *sc = ifp->if_softc;
|
1994-01-26 09:13:56 +00:00
|
|
|
|
2003-07-17 19:37:56 +00:00
|
|
|
if (sc->gone)
|
|
|
|
return;
|
2005-08-09 10:20:02 +00:00
|
|
|
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
|
2003-10-25 04:09:49 +00:00
|
|
|
epstart(ifp);
|
2003-07-17 19:37:56 +00:00
|
|
|
ep_intr(ifp->if_softc);
|
1994-01-10 18:56:26 +00:00
|
|
|
}
|
|
|
|
|
1995-12-10 13:40:44 +00:00
|
|
|
static void
|
2003-07-17 19:37:56 +00:00
|
|
|
epstop(struct ep_softc *sc)
|
1994-01-10 18:56:26 +00:00
|
|
|
{
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, RX_DISABLE);
|
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, RX_DISCARD_TOP_PACK);
|
2003-10-25 21:28:40 +00:00
|
|
|
EP_BUSY_WAIT(sc);
|
1996-06-14 22:11:38 +00:00
|
|
|
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, TX_DISABLE);
|
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, STOP_TRANSCEIVER);
|
2003-07-17 19:37:56 +00:00
|
|
|
DELAY(800);
|
2000-03-13 11:55:09 +00:00
|
|
|
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, RX_RESET);
|
2003-10-25 21:28:40 +00:00
|
|
|
EP_BUSY_WAIT(sc);
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, TX_RESET);
|
2003-10-25 21:28:40 +00:00
|
|
|
EP_BUSY_WAIT(sc);
|
2000-03-13 11:55:09 +00:00
|
|
|
|
2003-10-25 04:09:49 +00:00
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, C_INTR_LATCH);
|
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, SET_RD_0_MASK);
|
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, SET_INTR_MASK);
|
|
|
|
CSR_WRITE_2(sc, EP_COMMAND, SET_RX_FILTER);
|
1994-01-10 18:56:26 +00:00
|
|
|
}
|