/*-
* Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/*
* Device driver for the Standard Microsystems Corp. 83C170
* Ethernet PCI Integrated Controller (EPIC/100).
*/
/*
* Allocate the control data structures, and create and load the
* DMA map for it.
*/
if ((error = bus_dmamem_alloc(sc->sc_dmat,
sizeof(struct epic_control_data) + ETHER_PAD_LEN, PAGE_SIZE, 0,
&seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
aprint_error_dev(sc->sc_dev,
"unable to allocate control data, error = %d\n", error);
goto fail_0;
}
/*
* Make sure the interface is shutdown during reboot.
*/
if (pmf_device_register1(sc->sc_dev, NULL, NULL, epic_shutdown))
pmf_class_network_register(sc->sc_dev, ifp);
else
aprint_error_dev(sc->sc_dev,
"couldn't establish power handler\n");
return;
/*
* Free any resources we've allocated during the failed attach
* attempt. Do this in reverse order and fall through.
*/
fail_6:
bus_dmamap_destroy(sc->sc_dmat, sc->sc_nulldmamap);
fail_5:
for (i = 0; i < EPIC_NRXDESC; i++) {
if (EPIC_DSRX(sc, i)->ds_dmamap != NULL)
bus_dmamap_destroy(sc->sc_dmat,
EPIC_DSRX(sc, i)->ds_dmamap);
}
fail_4:
for (i = 0; i < EPIC_NTXDESC; i++) {
if (EPIC_DSTX(sc, i)->ds_dmamap != NULL)
bus_dmamap_destroy(sc->sc_dmat,
EPIC_DSTX(sc, i)->ds_dmamap);
}
bus_dmamap_unload(sc->sc_dmat, sc->sc_cddmamap);
fail_3:
bus_dmamap_destroy(sc->sc_dmat, sc->sc_cddmamap);
fail_2:
bus_dmamem_unmap(sc->sc_dmat, (void *)sc->sc_control_data,
sizeof(struct epic_control_data));
fail_1:
bus_dmamem_free(sc->sc_dmat, &seg, rseg);
fail_0:
return;
}
/*
* Shutdown hook. Make sure the interface is stopped at reboot.
*/
static bool
epic_shutdown(device_t self, int howto)
{
struct epic_softc *sc = device_private(self);
/*
* Remember the previous txpending and the first transmit
* descriptor we use.
*/
opending = sc->sc_txpending;
firsttx = EPIC_NEXTTX(sc->sc_txlast);
/*
* Loop through the send queue, setting up transmit descriptors
* until we drain the queue, or use up all available transmit
* descriptors.
*/
while (sc->sc_txpending < EPIC_NTXDESC) {
/*
* Grab a packet off the queue.
*/
IFQ_POLL(&ifp->if_snd, m0);
if (m0 == NULL)
break;
m = NULL;
/*
* Get the last and next available transmit descriptor.
*/
nexttx = EPIC_NEXTTX(sc->sc_txlast);
txd = EPIC_CDTX(sc, nexttx);
fr = EPIC_CDFL(sc, nexttx);
ds = EPIC_DSTX(sc, nexttx);
dmamap = ds->ds_dmamap;
/*
* Load the DMA map. If this fails, the packet either
* didn't fit in the allotted number of frags, or we were
* short on resources. In this case, we'll copy and try
* again.
*/
if ((error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap, m0,
BUS_DMA_WRITE | BUS_DMA_NOWAIT)) != 0 ||
(m0->m_pkthdr.len < ETHER_PAD_LEN &&
dmamap-> dm_nsegs == EPIC_NFRAGS)) {
if (error == 0)
bus_dmamap_unload(sc->sc_dmat, dmamap);
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
printf("%s: unable to allocate Tx mbuf\n",
device_xname(sc->sc_dev));
break;
}
MCLAIM(m, &sc->sc_ethercom.ec_tx_mowner);
if (m0->m_pkthdr.len > MHLEN) {
MCLGET(m, M_DONTWAIT);
if ((m->m_flags & M_EXT) == 0) {
printf("%s: unable to allocate Tx "
"cluster\n",
device_xname(sc->sc_dev));
m_freem(m);
break;
}
}
m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, void *));
m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len;
error = bus_dmamap_load_mbuf(sc->sc_dmat, dmamap,
m, BUS_DMA_WRITE | BUS_DMA_NOWAIT);
if (error) {
printf("%s: unable to load Tx buffer, "
"error = %d\n", device_xname(sc->sc_dev),
error);
break;
}
}
IFQ_DEQUEUE(&ifp->if_snd, m0);
if (m != NULL) {
m_freem(m0);
m0 = m;
}
/* Initialize the fraglist. */
for (seg = 0; seg < dmamap->dm_nsegs; seg++) {
fr->ef_frags[seg].ef_addr =
dmamap->dm_segs[seg].ds_addr;
fr->ef_frags[seg].ef_length =
dmamap->dm_segs[seg].ds_len;
}
len = m0->m_pkthdr.len;
if (len < ETHER_PAD_LEN) {
fr->ef_frags[seg].ef_addr = sc->sc_nulldma;
fr->ef_frags[seg].ef_length = ETHER_PAD_LEN - len;
len = ETHER_PAD_LEN;
seg++;
}
fr->ef_nfrags = seg;
/*
* Store a pointer to the packet so we can free it later.
*/
ds->ds_mbuf = m0;
/*
* Fill in the transmit descriptor.
*/
txd->et_control = ET_TXCTL_LASTDESC | ET_TXCTL_FRAGLIST;
/*
* If this is the first descriptor we're enqueueing,
* don't give it to the EPIC yet. That could cause
* a race condition. We'll do it below.
*/
if (nexttx == firsttx)
txd->et_txstatus = TXSTAT_TXLENGTH(len);
else
txd->et_txstatus =
TXSTAT_TXLENGTH(len) | ET_TXSTAT_OWNER;
/* Advance the tx pointer. */
sc->sc_txpending++;
sc->sc_txlast = nexttx;
/*
* Pass the packet to any BPF listeners.
*/
bpf_mtap(ifp, m0, BPF_D_OUT);
}
if (sc->sc_txpending != opending) {
/*
* We enqueued packets. If the transmitter was idle,
* reset the txdirty pointer.
*/
if (opending == 0)
sc->sc_txdirty = firsttx;
/*
* Cause a transmit interrupt to happen on the
* last packet we enqueued.
*/
EPIC_CDTX(sc, sc->sc_txlast)->et_control |= ET_TXCTL_IAF;
EPIC_CDTXSYNC(sc, sc->sc_txlast,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
/*
* The entire packet chain is set up. Give the
* first descriptor to the EPIC now.
*/
EPIC_CDTX(sc, firsttx)->et_txstatus |= ET_TXSTAT_OWNER;
EPIC_CDTXSYNC(sc, firsttx,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
/* Start the transmitter. */
bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_COMMAND,
COMMAND_TXQUEUED);
/* Set a watchdog timer in case the chip flakes out. */
ifp->if_timer = 5;
}
}
/*
* Handle control requests from the operator.
* [ifnet interface function]
*/
static int
epic_ioctl(struct ifnet *ifp, u_long cmd, void *data)
{
struct epic_softc *sc = ifp->if_softc;
int s, error;
s = splnet();
error = ether_ioctl(ifp, cmd, data);
if (error == ENETRESET) {
/*
* Multicast list has changed; set the hardware filter
* accordingly. Update our idea of the current media;
* epic_set_mchash() needs to know what it is.
*/
if (ifp->if_flags & IFF_RUNNING) {
mii_pollstat(&sc->sc_mii);
epic_set_mchash(sc);
}
error = 0;
}
top:
/*
* Get the interrupt status from the EPIC.
*/
intstat = bus_space_read_4(sc->sc_st, sc->sc_sh, EPIC_INTSTAT);
if ((intstat & INTSTAT_INT_ACTV) == 0)
return claimed;
/*
* Check for receive interrupts.
*/
if (intstat & (INTSTAT_RCC | INTSTAT_RXE | INTSTAT_RQE)) {
for (i = sc->sc_rxptr;; i = EPIC_NEXTRX(i)) {
rxd = EPIC_CDRX(sc, i);
ds = EPIC_DSRX(sc, i);
EPIC_CDRXSYNC(sc, i,
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
rxstatus = rxd->er_rxstatus;
if (rxstatus & ER_RXSTAT_OWNER) {
/*
* We have processed all of the
* receive buffers.
*/
break;
}
/*
* Make sure the packet arrived intact. If an error
* occurred, update stats and reset the descriptor.
* The buffer will be reused the next time the
* descriptor comes up in the ring.
*/
if ((rxstatus & ER_RXSTAT_PKTINTACT) == 0) {
if (rxstatus & ER_RXSTAT_CRCERROR)
printf("%s: CRC error\n",
device_xname(sc->sc_dev));
if (rxstatus & ER_RXSTAT_ALIGNERROR)
printf("%s: alignment error\n",
device_xname(sc->sc_dev));
if_statinc(ifp, if_ierrors);
EPIC_INIT_RXDESC(sc, i);
continue;
}
/*
* The EPIC includes the CRC with every packet;
* trim it.
*/
len = RXSTAT_RXLENGTH(rxstatus) - ETHER_CRC_LEN;
if (len < sizeof(struct ether_header)) {
/*
* Runt packet; drop it now.
*/
if_statinc(ifp, if_ierrors);
EPIC_INIT_RXDESC(sc, i);
bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
ds->ds_dmamap->dm_mapsize,
BUS_DMASYNC_PREREAD);
continue;
}
/*
* If the packet is small enough to fit in a
* single header mbuf, allocate one and copy
* the data into it. This greatly reduces
* memory consumption when we receive lots
* of small packets.
*
* Otherwise, we add a new buffer to the receive
* chain. If this fails, we drop the packet and
* recycle the old buffer.
*/
if (epic_copy_small != 0 && len <= MHLEN) {
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL)
goto dropit;
MCLAIM(m, &sc->sc_ethercom.ec_rx_mowner);
memcpy(mtod(m, void *),
mtod(ds->ds_mbuf, void *), len);
EPIC_INIT_RXDESC(sc, i);
bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
ds->ds_dmamap->dm_mapsize,
BUS_DMASYNC_PREREAD);
} else {
m = ds->ds_mbuf;
if (epic_add_rxbuf(sc, i) != 0) {
dropit:
if_statinc(ifp, if_ierrors);
EPIC_INIT_RXDESC(sc, i);
bus_dmamap_sync(sc->sc_dmat,
ds->ds_dmamap, 0,
ds->ds_dmamap->dm_mapsize,
BUS_DMASYNC_PREREAD);
continue;
}
}
/*
* Cancel the watchdog timer if there are no pending
* transmissions.
*/
if (sc->sc_txpending == 0)
ifp->if_timer = 0;
/*
* Kick the transmitter after a DMA underrun.
*/
if (intstat & INTSTAT_TXU) {
printf("%s: transmit underrun\n",
device_xname(sc->sc_dev));
bus_space_write_4(sc->sc_st, sc->sc_sh,
EPIC_COMMAND, COMMAND_TXUGO);
if (sc->sc_txpending)
bus_space_write_4(sc->sc_st, sc->sc_sh,
EPIC_COMMAND, COMMAND_TXQUEUED);
}
/*
* Try to get more packets going.
*/
if_schedule_deferred_start(ifp);
}
/*
* Check for fatal interrupts.
*/
if (intstat & INTSTAT_FATAL_INT) {
if (intstat & INTSTAT_PTA)
printf("%s: PCI target abort error\n",
device_xname(sc->sc_dev));
else if (intstat & INTSTAT_PMA)
printf("%s: PCI master abort error\n",
device_xname(sc->sc_dev));
else if (intstat & INTSTAT_APE)
printf("%s: PCI address parity error\n",
device_xname(sc->sc_dev));
else if (intstat & INTSTAT_DPE)
printf("%s: PCI data parity error\n",
device_xname(sc->sc_dev));
else
printf("%s: unknown fatal error\n",
device_xname(sc->sc_dev));
(void)epic_init(ifp);
}
/*
* Check for more interrupts.
*/
goto top;
}
/*
* One second timer, used to tick the MII.
*/
static void
epic_tick(void *arg)
{
struct epic_softc *sc = arg;
int s;
s = splnet();
mii_tick(&sc->sc_mii);
splx(s);
callout_schedule(&sc->sc_mii_callout, hz);
}
/*
* Fixup the clock source on the EPIC.
*/
static void
epic_fixup_clock_source(struct epic_softc *sc)
{
int i;
/*
* According to SMC Application Note 7-15, the EPIC's clock
* source is incorrect following a reset. This manifests itself
* as failure to recognize when host software has written to
* a register on the EPIC. The appnote recommends issuing at
* least 16 consecutive writes to the CLOCK TEST bit to correctly
* configure the clock source.
*/
for (i = 0; i < 16; i++)
bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_TEST,
TEST_CLOCKTEST);
}
/*
* Perform a soft reset on the EPIC.
*/
static void
epic_reset(struct epic_softc *sc)
{
/*
* Initialize the interface. Must be called at splnet().
*/
static int
epic_init(struct ifnet *ifp)
{
struct epic_softc *sc = ifp->if_softc;
bus_space_tag_t st = sc->sc_st;
bus_space_handle_t sh = sc->sc_sh;
const uint8_t *enaddr = CLLADDR(ifp->if_sadl);
struct epic_txdesc *txd;
struct epic_descsoft *ds;
uint32_t genctl, reg0;
int i, error = 0;
/*
* Cancel any pending I/O.
*/
epic_stop(ifp, 0);
/*
* Reset the EPIC to a known state.
*/
epic_reset(sc);
/* Set the current media. */
if ((error = epic_mediachange(ifp)) != 0)
goto out;
/* Set up the multicast hash table. */
epic_set_mchash(sc);
/*
* Initialize the transmit descriptor ring. txlast is initialized
* to the end of the list so that it will wrap around to the first
* descriptor when the first packet is transmitted.
*/
for (i = 0; i < EPIC_NTXDESC; i++) {
txd = EPIC_CDTX(sc, i);
memset(txd, 0, sizeof(struct epic_txdesc));
txd->et_bufaddr = EPIC_CDFLADDR(sc, i);
txd->et_nextdesc = EPIC_CDTXADDR(sc, EPIC_NEXTTX(i));
EPIC_CDTXSYNC(sc, i,
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
}
sc->sc_txpending = 0;
sc->sc_txdirty = 0;
sc->sc_txlast = EPIC_NTXDESC - 1;
/*
* Initialize the receive descriptor ring.
*/
for (i = 0; i < EPIC_NRXDESC; i++) {
ds = EPIC_DSRX(sc, i);
if (ds->ds_mbuf == NULL) {
if ((error = epic_add_rxbuf(sc, i)) != 0) {
printf("%s: unable to allocate or map rx "
"buffer %d error = %d\n",
device_xname(sc->sc_dev), i, error);
/*
* XXX Should attempt to run with fewer receive
* XXX buffers instead of just failing.
*/
epic_rxdrain(sc);
goto out;
}
} else
EPIC_INIT_RXDESC(sc, i);
}
sc->sc_rxptr = 0;
/*
* Initialize the interrupt mask and enable interrupts.
*/
bus_space_write_4(st, sh, EPIC_INTMASK, INTMASK);
bus_space_write_4(st, sh, EPIC_GENCTL, genctl | GENCTL_INTENA);
/*
* Give the transmit and receive rings to the EPIC.
*/
bus_space_write_4(st, sh, EPIC_PTCDAR,
EPIC_CDTXADDR(sc, EPIC_NEXTTX(sc->sc_txlast)));
bus_space_write_4(st, sh, EPIC_PRCDAR,
EPIC_CDRXADDR(sc, sc->sc_rxptr));
/*
* Set the EPIC in motion.
*/
bus_space_write_4(st, sh, EPIC_COMMAND,
COMMAND_RXQUEUED | COMMAND_START_RX);
/*
* Stop the DMA engine and take the receiver off-line.
*/
bus_space_write_4(st, sh, EPIC_COMMAND, COMMAND_STOP_RDMA |
COMMAND_STOP_TDMA | COMMAND_STOP_RX);
/*
* Release any queued transmit buffers.
*/
for (i = 0; i < EPIC_NTXDESC; i++) {
ds = EPIC_DSTX(sc, i);
if (ds->ds_mbuf != NULL) {
bus_dmamap_unload(sc->sc_dmat, ds->ds_dmamap);
m_freem(ds->ds_mbuf);
ds->ds_mbuf = NULL;
}
}
/*
* Mark the interface down and cancel the watchdog timer.
*/
ifp->if_flags &= ~IFF_RUNNING;
ifp->if_timer = 0;
if (disable)
epic_rxdrain(sc);
}
/*
* Read the EPIC Serial EEPROM.
*/
static void
epic_read_eeprom(struct epic_softc *sc, int word, int wordcnt, uint16_t *data)
{
bus_space_tag_t st = sc->sc_st;
bus_space_handle_t sh = sc->sc_sh;
uint16_t reg;
int i, x;
/*
* Disable the EEPROM.
*/
bus_space_write_4(st, sh, EPIC_EECTL, 0);
#undef EEPROM_WAIT_READY
}
/*
* Add a receive buffer to the indicated descriptor.
*/
static int
epic_add_rxbuf(struct epic_softc *sc, int idx)
{
struct epic_descsoft *ds = EPIC_DSRX(sc, idx);
struct mbuf *m;
int error;
/*
* Set the EPIC multicast hash table.
*
* NOTE: We rely on a recently-updated mii_media_active here!
*/
static void
epic_set_mchash(struct epic_softc *sc)
{
struct ethercom *ec = &sc->sc_ethercom;
struct ifnet *ifp = &sc->sc_ethercom.ec_if;
struct ether_multi *enm;
struct ether_multistep step;
uint32_t hash, mchash[4];
/*
* Set up the multicast address filter by passing all multicast
* addresses through a CRC generator, and then using the low-order
* 6 bits as an index into the 64 bit multicast hash table (only
* the lower 16 bits of each 32 bit multicast hash register are
* valid). The high order bits select the register, while the
* rest of the bits select the bit within the register.
*/
if (ifp->if_flags & IFF_PROMISC)
goto allmulti;
if (IFM_SUBTYPE(sc->sc_mii.mii_media_active) == IFM_10_T) {
/* XXX hardware bug in 10Mbps mode. */
goto allmulti;
}
ETHER_LOCK(ec);
ETHER_FIRST_MULTI(step, ec, enm);
while (enm != NULL) {
if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
/*
* We must listen to a range of multicast addresses.
* For now, just accept all multicasts, rather than
* trying to set only those filter bits needed to match
* the range. (At this time, the only use of address
* ranges is for IP multicast routing, for which the
* range is big enough to require all bits set.)
*/
ETHER_UNLOCK(ec);
goto allmulti;
}
/*
* Wait for the MII to become ready.
*/
static int
epic_mii_wait(struct epic_softc *sc, uint32_t rw)
{
int i;
for (i = 0; i < 50; i++) {
if ((bus_space_read_4(sc->sc_st, sc->sc_sh, EPIC_MMCTL) & rw)
== 0)
break;
delay(2);
}
if (i == 50) {
printf("%s: MII timed out\n", device_xname(sc->sc_dev));
return ETIMEDOUT;
}
return 0;
}
/*
* Read from the MII.
*/
static int
epic_mii_read(device_t self, int phy, int reg, uint16_t *val)
{
struct epic_softc *sc = device_private(self);
int rv;
if ((rv = epic_mii_wait(sc, MMCTL_WRITE)) != 0)
return rv;
/*
* Write to the MII.
*/
static int
epic_mii_write(device_t self, int phy, int reg, uint16_t val)
{
struct epic_softc *sc = device_private(self);
int rv;
if ((rv = epic_mii_wait(sc, MMCTL_WRITE)) != 0)
return rv;
/* On some cards we need manually set fullduplex led */
if (sc->sc_hwflags & EPIC_DUPLEXLED_ON_694) {
miicfg = bus_space_read_4(sc->sc_st, sc->sc_sh, EPIC_MIICFG);
if (IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX)
miicfg |= MIICFG_ENABLE;
else
miicfg &= ~MIICFG_ENABLE;
bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MIICFG, miicfg);
}
/*
* There is a multicast filter bug in 10Mbps mode. Kick the
* multicast filter in case the speed changed.
*/
epic_set_mchash(sc);
}
/*
* Callback from ifmedia to request new media setting.
*
* XXX Looks to me like some of this complexity should move into
* XXX one or two custom PHY drivers. --dyoung
*/
static int
epic_mediachange(struct ifnet *ifp)
{
struct epic_softc *sc = ifp->if_softc;
struct mii_data *mii = &sc->sc_mii;
struct ifmedia *ifm = &mii->mii_media;
int media = ifm->ifm_cur->ifm_media;
uint32_t miicfg;
struct mii_softc *miisc;
int rc;
uint16_t cfg;
if ((ifp->if_flags & IFF_UP) == 0)
return 0;
if (IFM_INST(media) != sc->sc_serinst) {
/* If we're not selecting serial interface, select MII mode */
#ifdef EPICMEDIADEBUG
printf("%s: parallel mode\n", ifp->if_xname);
#endif
miicfg = bus_space_read_4(sc->sc_st, sc->sc_sh, EPIC_MIICFG);
miicfg &= ~MIICFG_SERMODEENA;
bus_space_write_4(sc->sc_st, sc->sc_sh, EPIC_MIICFG, miicfg);
}