Driver for the standard Archimedes Econet interface, based around the
Motorola 6854 ADLC.
This commit is contained in:
parent
bd81d66bb5
commit
e416135347
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: genassym.cf,v 1.3 2001/01/20 17:14:20 bjh21 Exp $
|
||||
# $NetBSD: genassym.cf,v 1.4 2001/09/10 23:41:48 bjh21 Exp $
|
||||
#
|
||||
# Copyright (c) 1999 Ben Harris
|
||||
# All rights reserved.
|
||||
|
@ -29,6 +29,7 @@
|
|||
|
||||
include <sys/param.h>
|
||||
|
||||
include <sys/mbuf.h>
|
||||
include <sys/proc.h>
|
||||
include <sys/user.h>
|
||||
include <machine/pcb.h>
|
||||
|
@ -46,3 +47,7 @@ define IF_R15 offsetof(struct irqframe, if_r15)
|
|||
define IF_SIZE sizeof(struct irqframe)
|
||||
|
||||
define SIGF_SC offsetof(struct sigframe, sf_sc)
|
||||
|
||||
define M_NEXT offsetof(struct mbuf, m_next)
|
||||
define M_DATA offsetof(struct mbuf, m_data)
|
||||
define M_LEN offsetof(struct mbuf, m_len)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# $NetBSD: files.arm26,v 1.37 2001/08/20 23:08:10 bjh21 Exp $
|
||||
# $NetBSD: files.arm26,v 1.38 2001/09/10 23:41:49 bjh21 Exp $
|
||||
|
||||
# Copyright (c) 1997, 1998, 2000 Ben Harris
|
||||
# All rights reserved.
|
||||
|
@ -111,8 +111,10 @@ attach wf at wfdc
|
|||
#major {...}
|
||||
|
||||
# Econet module (Motorola 6854) (usually at bank 2 fiq 2)
|
||||
device ec: ifnet, arp
|
||||
attach ec at ioc
|
||||
device eca: fiq, eco, ifnet
|
||||
attach eca at ioc
|
||||
file arch/arm26/ioc/if_eca.c eca
|
||||
file arch/arm26/ioc/if_eca_fiq.S eca
|
||||
|
||||
# On-board Rockwell 6551 serial (usually at bank 3 irq 10/1)
|
||||
device rs: tty
|
||||
|
|
|
@ -0,0 +1,482 @@
|
|||
/* $NetBSD: if_eca.c,v 1.1 2001/09/10 23:41:49 bjh21 Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2001 Ben Harris
|
||||
* 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.
|
||||
* 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 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.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
__KERNEL_RCSID(0, "$NetBSD: if_eca.c,v 1.1 2001/09/10 23:41:49 bjh21 Exp $");
|
||||
|
||||
#include <sys/device.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_eco.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/fiq.h>
|
||||
#include <machine/intr.h>
|
||||
#include <machine/machdep.h>
|
||||
|
||||
#include <arch/arm26/iobus/iocvar.h>
|
||||
|
||||
#include <dev/ic/mc6854reg.h>
|
||||
#include <arch/arm26/ioc/if_ecavar.h>
|
||||
|
||||
static int eca_match(struct device *, struct cfdata *, void *);
|
||||
static void eca_attach(struct device *, struct device *, void *);
|
||||
|
||||
static int eca_init(struct ifnet *);
|
||||
static void eca_stop(struct ifnet *ifp, int disable);
|
||||
|
||||
static int eca_claimwire(struct ifnet *);
|
||||
static void eca_txframe(struct ifnet *, struct mbuf *);
|
||||
|
||||
static void eca_tx_downgrade(void);
|
||||
static void eca_txdone(void *);
|
||||
|
||||
static int eca_init_rxbuf(struct eca_softc *sc, int flags);
|
||||
static void eca_init_rx(struct eca_softc *sc);
|
||||
|
||||
static void eca_rx_downgrade(void);
|
||||
static void eca_gotframe(void *);
|
||||
|
||||
struct eca_softc *eca_fiqowner;
|
||||
|
||||
struct cfattach eca_ca = {
|
||||
sizeof(struct eca_softc), eca_match, eca_attach
|
||||
};
|
||||
|
||||
static int
|
||||
eca_match(struct device *parent, struct cfdata *cf, void *aux)
|
||||
{
|
||||
struct ioc_attach_args *ioc = aux;
|
||||
|
||||
/* Econet never uses LOOP mode. */
|
||||
if ((bus_space_read_1(ioc->ioc_sync_t, ioc->ioc_sync_h, MC6854_SR1) &
|
||||
MC6854_SR1_LOOP) != 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
eca_attach(struct device *parent, struct device *self, void *aux)
|
||||
{
|
||||
struct eca_softc *sc = (void *)self;
|
||||
struct ioc_attach_args *ioc = aux;
|
||||
struct ifnet *ifp = &sc->sc_ec.ec_if;
|
||||
u_int8_t myaddr[ECO_ADDR_LEN];
|
||||
|
||||
sc->sc_iot = ioc->ioc_sync_t;
|
||||
sc->sc_ioh = ioc->ioc_sync_h;
|
||||
|
||||
myaddr[0] = cmos_read(0x40);
|
||||
myaddr[1] = 0;
|
||||
|
||||
printf(": station %s", eco_sprintf(myaddr));
|
||||
/* It's traditional to print the clock state at boot. */
|
||||
if ((bus_space_read_1(sc->sc_iot, sc->sc_ioh, MC6854_SR2) &
|
||||
MC6854_SR2_NDCD))
|
||||
printf(", no clock");
|
||||
|
||||
/* Initialise ifnet structure. */
|
||||
|
||||
strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
|
||||
ifp->if_softc = sc;
|
||||
ifp->if_init = eca_init;
|
||||
ifp->if_stop = eca_stop;
|
||||
ifp->if_flags = IFF_SIMPLEX | IFF_NOTRAILERS;
|
||||
IFQ_SET_READY(&ifp->if_snd);
|
||||
sc->sc_ec.ec_claimwire = eca_claimwire;
|
||||
sc->sc_ec.ec_txframe = eca_txframe;
|
||||
|
||||
sc->sc_rx_soft = softintr_establish(IPL_SOFTNET, eca_gotframe, sc);
|
||||
sc->sc_tx_soft = softintr_establish(IPL_SOFTNET, eca_txdone, sc);
|
||||
if (sc->sc_rx_soft == NULL || sc->sc_tx_soft == NULL) {
|
||||
printf("\n%s: failed to establish software interrupt\n",
|
||||
sc->sc_dev.dv_xname);
|
||||
return;
|
||||
}
|
||||
|
||||
if_attach(ifp);
|
||||
eco_ifattach(ifp, myaddr);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int
|
||||
eca_init(struct ifnet *ifp)
|
||||
{
|
||||
struct eca_softc *sc = ifp->if_softc;
|
||||
bus_space_tag_t iot = sc->sc_iot;
|
||||
bus_space_handle_t ioh = sc->sc_ioh;
|
||||
int sr1, sr2;
|
||||
int err;
|
||||
|
||||
/* Claim the FIQ early, in case we don't get it. */
|
||||
if (fiq_claim(eca_fiqhandler_rx,
|
||||
eca_efiqhandler_rx - eca_fiqhandler_rx))
|
||||
return EBUSY;
|
||||
|
||||
if (sc->sc_rcvmbuf == NULL) {
|
||||
err = eca_init_rxbuf(sc, M_WAIT);
|
||||
if (err != 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
sc->sc_transmitting = 0;
|
||||
|
||||
/* Interrupts disabled, no DMA, hold Tx and Rx in reset. */
|
||||
sc->sc_cr1 = MC6854_CR1_RX_RS | MC6854_CR1_TX_RS;
|
||||
/* 1-byte transfers, mark idle. */
|
||||
sc->sc_cr2 = 0;
|
||||
/* Nothing exciting. */
|
||||
sc->sc_cr3 = 0;
|
||||
/* single flag, 8 data bits, NRZ */
|
||||
sc->sc_cr4 = MC6854_CR4_TX_WL_8BITS | MC6854_CR4_RX_WL_8BITS;
|
||||
|
||||
bus_space_write_1(iot, ioh, MC6854_CR1, sc->sc_cr1);
|
||||
bus_space_write_1(iot, ioh, MC6854_CR2, sc->sc_cr2);
|
||||
bus_space_write_1(iot, ioh, MC6854_CR1, sc->sc_cr1 | MC6854_CR1_AC);
|
||||
bus_space_write_1(iot, ioh, MC6854_CR3, sc->sc_cr3);
|
||||
bus_space_write_1(iot, ioh, MC6854_CR4, sc->sc_cr4);
|
||||
bus_space_write_1(iot, ioh, MC6854_CR1, sc->sc_cr1);
|
||||
|
||||
/* Everything's set up. Take chip out of reset. */
|
||||
sc->sc_cr1 &= ~(MC6854_CR1_RX_RS | MC6854_CR1_TX_RS);
|
||||
bus_space_write_1(iot, ioh, MC6854_CR1, sc->sc_cr1);
|
||||
|
||||
/* Read and clear status registers. */
|
||||
sr1 = bus_space_read_1(iot, ioh, MC6854_SR1);
|
||||
sr2 = bus_space_read_1(iot, ioh, MC6854_SR2);
|
||||
bus_space_write_1(iot, ioh, MC6854_CR2, sc->sc_cr2 |
|
||||
MC6854_CR2_CLR_RX_ST | MC6854_CR2_CLR_TX_ST);
|
||||
|
||||
/* Set up FIQ registers and enable FIQs */
|
||||
eca_init_rx(sc);
|
||||
|
||||
ifp->if_flags |= IFF_RUNNING;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the network's idle, and if it is, start flag-filling.
|
||||
*/
|
||||
static int
|
||||
eca_claimwire(struct ifnet *ifp)
|
||||
{
|
||||
struct eca_softc *sc = ifp->if_softc;
|
||||
bus_space_tag_t iot = sc->sc_iot;
|
||||
bus_space_handle_t ioh = sc->sc_ioh;
|
||||
|
||||
if (bus_space_read_1(iot, ioh, MC6854_SR2) & MC6854_SR2_RX_IDLE) {
|
||||
/* Start flag fill. */
|
||||
sc->sc_cr2 |= MC6854_CR2_RTS | MC6854_CR2_F_M_IDLE;
|
||||
bus_space_write_1(iot, ioh, MC6854_CR2, sc->sc_cr2);
|
||||
return 0;
|
||||
}
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
static void
|
||||
eca_txframe(struct ifnet *ifp, struct mbuf *m)
|
||||
{
|
||||
struct eca_softc *sc = ifp->if_softc;
|
||||
bus_space_tag_t iot = sc->sc_iot;
|
||||
bus_space_handle_t ioh = sc->sc_ioh;
|
||||
struct fiq_regs fr;
|
||||
|
||||
ioc_fiq_setmask(0);
|
||||
/* Start flag-filling while we work out what to do next. */
|
||||
sc->sc_cr2 |= MC6854_CR2_RTS | MC6854_CR2_F_M_IDLE;
|
||||
bus_space_write_1(iot, ioh, MC6854_CR2, sc->sc_cr2);
|
||||
fiq_installhandler(eca_fiqhandler_tx,
|
||||
eca_efiqhandler_tx - eca_fiqhandler_tx);
|
||||
sc->sc_transmitting = 1;
|
||||
sc->sc_txmbuf = m;
|
||||
fr.r8_fiq = (register_t)sc->sc_ioh.a1;
|
||||
fr.r9_fiq = (register_t)sc->sc_txmbuf->m_data;
|
||||
fr.r10_fiq = (register_t)sc->sc_txmbuf->m_len;
|
||||
fr.r11_fiq = (register_t)&sc->sc_txstate;
|
||||
fiq_setregs(&fr);
|
||||
sc->sc_txstate.etx_curmbuf = sc->sc_txmbuf;
|
||||
fiq_downgrade_handler = eca_tx_downgrade;
|
||||
/* Read and clear Tx status. */
|
||||
bus_space_read_1(iot, ioh, MC6854_SR1);
|
||||
bus_space_write_1(iot, ioh, MC6854_CR2,
|
||||
sc->sc_cr2 | MC6854_CR2_CLR_TX_ST);
|
||||
sc->sc_cr1 = MC6854_CR1_TIE;
|
||||
bus_space_write_1(iot, ioh, MC6854_CR1, sc->sc_cr1 |
|
||||
MC6854_CR1_DISCONTINUE);
|
||||
ioc_fiq_setmask(IOC_FIQ_BIT(FIQ_EFIQ));
|
||||
}
|
||||
|
||||
static void
|
||||
eca_tx_downgrade(void)
|
||||
{
|
||||
struct eca_softc *sc = eca_fiqowner;
|
||||
bus_space_tag_t iot = sc->sc_iot;
|
||||
bus_space_handle_t ioh = sc->sc_ioh;
|
||||
int sr1;
|
||||
char buf[128];
|
||||
#if 0
|
||||
struct fiq_regs fr;
|
||||
#endif
|
||||
|
||||
KASSERT(sc->sc_transmitting);
|
||||
sc->sc_cr2 = 0;
|
||||
if (__predict_true(sc->sc_txstate.etx_curmbuf == NULL)) {
|
||||
/* Entire frame got transmitted. */
|
||||
} else {
|
||||
sr1 = bus_space_read_1(iot, ioh, MC6854_SR1);
|
||||
if (sr1 & MC6854_SR1_TXU)
|
||||
log(LOG_ERR, "%s: Tx underrun\n", sc->sc_dev.dv_xname);
|
||||
else if (sr1 & MC6854_SR1_NCTS)
|
||||
log(LOG_WARNING, "%s: collision\n",
|
||||
sc->sc_dev.dv_xname);
|
||||
else {
|
||||
log(LOG_ERR, "%s: incomplete transmission\n",
|
||||
sc->sc_dev.dv_xname);
|
||||
bitmask_snprintf(sr1, MC6854_SR1_BITS, buf, 128);
|
||||
log(LOG_ERR, "%s: SR1 = %s\n",
|
||||
sc->sc_dev.dv_xname, buf);
|
||||
}
|
||||
bus_space_write_1(iot, ioh, MC6854_CR2,
|
||||
sc->sc_cr2 | MC6854_CR2_CLR_TX_ST);
|
||||
}
|
||||
sc->sc_txmbuf = NULL;
|
||||
eca_init_rx(sc);
|
||||
softintr_schedule(sc->sc_tx_soft);
|
||||
}
|
||||
|
||||
/*
|
||||
* Low-priority soft interrupt taken after a frame's been transmitted.
|
||||
*/
|
||||
static void
|
||||
eca_txdone(void *arg)
|
||||
{
|
||||
struct eca_softc *sc = arg;
|
||||
|
||||
m_freem(sc->sc_txmbuf);
|
||||
sc->sc_txmbuf = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the Rx buffer for the interface.
|
||||
* flags is M_WAIT or M_DONTWAIT. Returns an errno or 0 for success.
|
||||
*/
|
||||
static int
|
||||
eca_init_rxbuf(struct eca_softc *sc, int flags)
|
||||
{
|
||||
struct mbuf *m, *n;
|
||||
size_t totlen;
|
||||
|
||||
/*
|
||||
* The Rx buffer takes the form of a chain of mbufs, set up as
|
||||
* if they contain data already. The FIQ handler is
|
||||
* responsible for filling the marked space, and indicating
|
||||
* how much it's put in there.
|
||||
*/
|
||||
|
||||
totlen = 0;
|
||||
n = NULL;
|
||||
while (totlen < sc->sc_ec.ec_if.if_mtu + ECO_HDR_LEN) {
|
||||
MGETHDR(m, flags, MT_DATA);
|
||||
if (m == NULL)
|
||||
return ENOBUFS;
|
||||
MCLGET(m, flags);
|
||||
if ((m->m_flags & M_EXT) == 0) {
|
||||
m_freem(m);
|
||||
return ENOBUFS;
|
||||
}
|
||||
/* XXX may want to tweak for payload alignment here. */
|
||||
m->m_len = m->m_ext.ext_size;
|
||||
m->m_next = n;
|
||||
totlen += m->m_len;
|
||||
n = m;
|
||||
}
|
||||
|
||||
sc->sc_rcvmbuf = m;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the chip and FIQ handler for reception. Assumes the Rx buffer is
|
||||
* set up already by eca_init_rxbuf().
|
||||
*/
|
||||
void
|
||||
eca_init_rx(struct eca_softc *sc)
|
||||
{
|
||||
struct ifnet *ifp = &sc->sc_ec.ec_if;
|
||||
bus_space_tag_t iot = sc->sc_iot;
|
||||
bus_space_handle_t ioh = sc->sc_ioh;
|
||||
struct fiq_regs fr;
|
||||
|
||||
fiq_installhandler(eca_fiqhandler_rx,
|
||||
eca_efiqhandler_rx - eca_fiqhandler_rx);
|
||||
sc->sc_transmitting = 0;
|
||||
sc->sc_cr1 = MC6854_CR1_RIE;
|
||||
bus_space_write_1(iot, ioh, MC6854_CR1, sc->sc_cr1);
|
||||
memset(&fr, 0, sizeof(fr));
|
||||
fr.r8_fiq = (register_t)sc->sc_ioh.a1;
|
||||
fr.r9_fiq = (register_t)sc->sc_rcvmbuf->m_data;
|
||||
fr.r10_fiq = (register_t)ECO_ADDR_LEN;
|
||||
fr.r11_fiq = (register_t)&sc->sc_rxstate;
|
||||
sc->sc_rxstate.erx_curmbuf = sc->sc_rcvmbuf;
|
||||
sc->sc_rxstate.erx_flags = 0;
|
||||
sc->sc_rxstate.erx_myaddr = LLADDR(ifp->if_sadl)[0];
|
||||
fiq_setregs(&fr);
|
||||
fiq_downgrade_handler = eca_rx_downgrade;
|
||||
eca_fiqowner = sc;
|
||||
ioc_fiq_setmask(IOC_FIQ_BIT(FIQ_EFIQ));
|
||||
}
|
||||
|
||||
static void
|
||||
eca_stop(struct ifnet *ifp, int disable)
|
||||
{
|
||||
struct eca_softc *sc = ifp->if_softc;
|
||||
bus_space_tag_t iot = sc->sc_iot;
|
||||
bus_space_handle_t ioh = sc->sc_ioh;
|
||||
|
||||
ifp->if_flags &= ~IFF_RUNNING;
|
||||
|
||||
/* Interrupts disabled, no DMA, hold Tx and Rx in reset. */
|
||||
sc->sc_cr1 = MC6854_CR1_RX_RS | MC6854_CR1_TX_RS;
|
||||
bus_space_write_1(iot, ioh, MC6854_CR1, sc->sc_cr1);
|
||||
|
||||
ioc_fiq_setmask(0);
|
||||
fiq_downgrade_handler = NULL;
|
||||
eca_fiqowner = NULL;
|
||||
fiq_release();
|
||||
if (sc->sc_rcvmbuf != NULL) {
|
||||
m_freem(sc->sc_rcvmbuf);
|
||||
sc->sc_rcvmbuf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a FIQ downgrade handler, and as such is entered at IPL_HIGH with
|
||||
* FIQs disabled (but still owned by us).
|
||||
*/
|
||||
static void
|
||||
eca_rx_downgrade(void)
|
||||
{
|
||||
|
||||
softintr_schedule(eca_fiqowner->sc_rx_soft);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a soft interrupt handler, and hence can get away with anything.
|
||||
*/
|
||||
static void
|
||||
eca_gotframe(void *arg)
|
||||
{
|
||||
struct eca_softc *sc = arg;
|
||||
struct ifnet *ifp = &sc->sc_ec.ec_if;
|
||||
bus_space_tag_t iot = sc->sc_iot;
|
||||
bus_space_handle_t ioh = sc->sc_ioh;
|
||||
struct fiq_regs fr;
|
||||
int sr2;
|
||||
struct mbuf *m, *mtail, *n, *reply;
|
||||
|
||||
reply = NULL;
|
||||
KASSERT(!sc->sc_transmitting);
|
||||
KASSERT(sc == eca_fiqowner);
|
||||
sr2 = bus_space_read_1(iot, ioh, MC6854_SR2);
|
||||
/* OVRN and FV can be set together. */
|
||||
if (__predict_false(sr2 & MC6854_SR2_OVRN)) {
|
||||
log(LOG_ERR, "%s: Rx overrun\n", sc->sc_dev.dv_xname);
|
||||
ifp->if_ierrors++;
|
||||
/* Discard the rest of the frame. */
|
||||
bus_space_write_1(iot, ioh, MC6854_CR1,
|
||||
sc->sc_cr1 | MC6854_CR1_DISCONTINUE);
|
||||
} else if (__predict_true(sr2 & MC6854_SR2_FV)) {
|
||||
/* Frame Valid. */
|
||||
fiq_getregs(&fr);
|
||||
m = sc->sc_rcvmbuf;
|
||||
mtail = sc->sc_rxstate.erx_curmbuf;
|
||||
/*
|
||||
* Before we process this buffer, make sure we can get
|
||||
* a new one.
|
||||
*/
|
||||
if (eca_init_rxbuf(sc, M_DONTWAIT) == 0) {
|
||||
ifp->if_ipackets++; /* XXX packet vs frame? */
|
||||
/* Trim the tail of the mbuf chain. */
|
||||
mtail->m_len = (caddr_t)(fr.r9_fiq) - mtail->m_data;
|
||||
m_freem(mtail->m_next);
|
||||
mtail->m_next = NULL;
|
||||
/* Set up the header of the chain. */
|
||||
m->m_pkthdr.rcvif = ifp;
|
||||
m->m_pkthdr.len = 0;
|
||||
for (n = m; n != NULL; n = n->m_next)
|
||||
m->m_pkthdr.len += n->m_len;
|
||||
reply = eco_inputframe(ifp, m);
|
||||
} else
|
||||
ifp->if_iqdrops++;
|
||||
} else if (sr2 & MC6854_SR2_RXABT) {
|
||||
log(LOG_NOTICE, "%s: Rx abort\n", sc->sc_dev.dv_xname);
|
||||
ifp->if_ierrors++;
|
||||
} else if (sr2 & MC6854_SR2_ERR) {
|
||||
log(LOG_NOTICE, "%s: CRC error\n", sc->sc_dev.dv_xname);
|
||||
ifp->if_ierrors++;
|
||||
}
|
||||
|
||||
if (__predict_false(sr2 & MC6854_SR2_NDCD)) {
|
||||
log(LOG_ERR, "%s: No clock\n", sc->sc_dev.dv_xname);
|
||||
ifp->if_ierrors++;
|
||||
}
|
||||
|
||||
if (sr2 & MC6854_SR2_RX_IDLE)
|
||||
eco_inputidle(ifp);
|
||||
|
||||
if (sc->sc_rxstate.erx_curmbuf == NULL) {
|
||||
log(LOG_NOTICE, "%s: Oversized frame\n", sc->sc_dev.dv_xname);
|
||||
ifp->if_ierrors++;
|
||||
/* Discard the rest of the frame. */
|
||||
bus_space_write_1(iot, ioh, MC6854_CR1,
|
||||
sc->sc_cr1 | MC6854_CR1_DISCONTINUE);
|
||||
}
|
||||
|
||||
bus_space_write_1(iot, ioh, MC6854_CR2,
|
||||
sc->sc_cr2 | MC6854_CR2_CLR_RX_ST);
|
||||
|
||||
if (reply)
|
||||
eca_txframe(ifp, reply);
|
||||
else {
|
||||
/* Make sure we're not flag-filling. */
|
||||
bus_space_write_1(iot, ioh, MC6854_CR2,
|
||||
sc->sc_cr2);
|
||||
/* Set the ADLC up to receive the next frame. */
|
||||
eca_init_rx(sc);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
/* $NetBSD: if_eca_fiq.S,v 1.1 2001/09/10 23:41:49 bjh21 Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2001 Ben Harris
|
||||
* 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.
|
||||
* 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 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.
|
||||
*/
|
||||
|
||||
#include <machine/asm.h>
|
||||
|
||||
RCSID("$NetBSD: if_eca_fiq.S,v 1.1 2001/09/10 23:41:49 bjh21 Exp $")
|
||||
|
||||
#include <dev/ic/mc6854reg.h>
|
||||
#include <arch/arm26/ioc/if_ecavar.h>
|
||||
|
||||
#include "assym.h"
|
||||
|
||||
/*
|
||||
* Econet Rx FIQ handler registers:
|
||||
* R8: Address of 6854
|
||||
* R9: Data buffer address
|
||||
* R10: Space left in buffer
|
||||
* R11: struct eca_rxstate pointer
|
||||
* R12: Scratch
|
||||
* R13: Scratch
|
||||
*/
|
||||
|
||||
ENTRY(eca_fiqhandler_rx)
|
||||
/* If there's something in the Rx FIFO, read it now. */
|
||||
ldrb r12, [r8, #(MC6854_SR2 << 2)]
|
||||
tst r12, #MC6854_SR2_RDA
|
||||
beq Leca_rx_nodata
|
||||
Leca_rx_loop:
|
||||
ldrb r12, [r8, #(MC6854_RXFIFO << 2)]
|
||||
strb r12, [r9], #1
|
||||
subs r10, r10, #1
|
||||
beq Leca_rx_counter /* Rx buffer full */
|
||||
ldrb r12, [r8, #(MC6854_SR2 << 2)]
|
||||
tst r12, #MC6854_SR2_RDA /* More data? */
|
||||
bne Leca_rx_loop
|
||||
Leca_rx_nodata:
|
||||
teq r12, #0 /* No more status? */
|
||||
subeqs pc, r14, #4 /* Return. */
|
||||
tst r12, #MC6854_SR2_FV /* End of frame? */
|
||||
ldrne r12, [r11, #ERX_FLAGS]
|
||||
tstne r12, #ERXF_FLAGFILL /* Want flag fill? */
|
||||
movne r12, #(MC6854_CR2_RTS | MC6854_CR2_F_M_IDLE)
|
||||
strneb r12, [r8, #(MC6854_CR2 << 2)]
|
||||
Leca_rx_downgrade:
|
||||
ldr pc, Leca_rx_fiq_downgrade
|
||||
|
||||
Leca_rx_fiq_downgrade:
|
||||
.word fiq_downgrade
|
||||
|
||||
Leca_rx_counter:
|
||||
/* If we've already got the header, this indicates end-of-buffer. */
|
||||
ldr r12, [r11, #ERX_FLAGS]
|
||||
tst r12, #ERXF_GOTHDR
|
||||
bne Leca_rx_full
|
||||
ldrb r12, [r9, #-2]
|
||||
ldrb r13, [r11, #ERX_MYADDR]
|
||||
teq r12, r13 /* Our host */
|
||||
ldreqb r12, [r9, #-1]
|
||||
teqeq r12, #0 /* Local network? */
|
||||
ldr r12, [r11, #ERX_FLAGS]
|
||||
orrne r12, r12, #ERXF_GOTHDR
|
||||
orreq r12, r12, #(ERXF_GOTHDR | ERXF_FLAGFILL)
|
||||
str r12, [r11, #ERX_FLAGS]
|
||||
ldr r12, [r11, #ERX_CURMBUF]
|
||||
ldr r10, [r12, #M_LEN]
|
||||
ldr r12, [r12, #M_DATA]
|
||||
sub r12, r9, r12 /* Amount got already */
|
||||
sub r10, r10, r12
|
||||
subs pc, r14, #4
|
||||
|
||||
Leca_rx_full:
|
||||
/* Rx buffer full. See if there's another mbuf in the chain. */
|
||||
ldr r12, [r11, #ERX_CURMBUF]
|
||||
ldr r12, [r12, #M_NEXT]
|
||||
str r12, [r11, #ERX_CURMBUF]
|
||||
teq r12, #0
|
||||
beq Leca_rx_downgrade
|
||||
ldr r9, [r12, #M_DATA]
|
||||
ldr r10, [r12, #M_LEN]
|
||||
subs pc, r14, #4
|
||||
|
||||
.global eca_efiqhandler_rx
|
||||
_C_LABEL(eca_efiqhandler_rx):
|
||||
|
||||
/*
|
||||
* Econet Tx FIQ handler registers:
|
||||
* R8: Address of 6854
|
||||
* R9: Data buffer address
|
||||
* R10: Data left in buffer
|
||||
* R11: struct eca_txstate pointer
|
||||
* R12: Scratch
|
||||
* R13: Scratch
|
||||
*/
|
||||
ENTRY(eca_fiqhandler_tx)
|
||||
ldrb r12, [r8, #(MC6854_SR1 << 2)]
|
||||
tst r12, #MC6854_SR1_TDRA
|
||||
beq Leca_tx_nospace
|
||||
Leca_tx_loop:
|
||||
ldrb r12, [r9], #1
|
||||
strb r12, [r8, #(MC6854_TXFIFOFC << 2)]
|
||||
subs r10, r10, #1
|
||||
beq Leca_tx_nodata
|
||||
ldrb r12, [r8, #(MC6854_SR1 << 2)]
|
||||
tst r12, #MC6854_SR1_TDRA
|
||||
bne Leca_tx_loop
|
||||
Leca_tx_nospace:
|
||||
tst r12, #MC6854_SR1_IRQ /* No more status? */
|
||||
subeqs pc, r14, #4 /* Return. */
|
||||
ldr pc, Leca_tx_fiq_downgrade
|
||||
|
||||
Leca_tx_nodata:
|
||||
/* We get here when the current data block is empty. */
|
||||
ldr r12, [r11, #ETX_CURMBUF]
|
||||
ldr r12, [r12, #M_NEXT]
|
||||
str r12, [r11, #ETX_CURMBUF]
|
||||
teq r12, #0 /* Another mbuf? */
|
||||
moveq r12, #(MC6854_CR2_TX_LAST) /* If not, finish frame... */
|
||||
streqb r12, [r8, #(MC6854_CR2 << 2)]
|
||||
ldreq pc, Leca_tx_fiq_downgrade /* ... and report back. */
|
||||
ldr r9, [r12, #M_DATA] /* Line up next mbuf. */
|
||||
ldr r10, [r12, #M_LEN]
|
||||
subs pc, r14, #4
|
||||
|
||||
Leca_tx_fiq_downgrade:
|
||||
.word fiq_downgrade
|
||||
|
||||
.global eca_efiqhandler_tx
|
||||
_C_LABEL(eca_efiqhandler_tx):
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/* $NetBSD: if_ecavar.h,v 1.1 2001/09/10 23:41:49 bjh21 Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2001 Ben Harris
|
||||
* 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.
|
||||
* 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 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.
|
||||
*/
|
||||
|
||||
#ifndef _ECAVAR_H_
|
||||
#define _ECAVAR_H_
|
||||
|
||||
#ifndef _LOCORE
|
||||
#include <net/if.h>
|
||||
#include <net/if_eco.h>
|
||||
|
||||
struct eca_rxstate {
|
||||
struct mbuf *erx_curmbuf;
|
||||
u_int32_t erx_flags;
|
||||
u_int8_t erx_myaddr;
|
||||
};
|
||||
|
||||
struct eca_txstate {
|
||||
struct mbuf *etx_curmbuf;
|
||||
};
|
||||
|
||||
struct eca_softc {
|
||||
struct device sc_dev;
|
||||
struct ecocom sc_ec;
|
||||
u_int8_t sc_cr1;
|
||||
u_int8_t sc_cr2;
|
||||
u_int8_t sc_cr3;
|
||||
u_int8_t sc_cr4;
|
||||
bus_space_tag_t sc_iot;
|
||||
bus_space_handle_t sc_ioh;
|
||||
struct mbuf *sc_rcvmbuf;
|
||||
void *sc_rx_soft;
|
||||
struct eca_rxstate sc_rxstate;
|
||||
struct mbuf *sc_txmbuf;
|
||||
void *sc_tx_soft;
|
||||
struct eca_txstate sc_txstate;
|
||||
int sc_transmitting;
|
||||
};
|
||||
|
||||
extern char eca_fiqhandler_rx[], eca_efiqhandler_rx[];
|
||||
extern char eca_fiqhandler_tx[], eca_efiqhandler_tx[];
|
||||
|
||||
#endif
|
||||
/* Sync with rxstate above */
|
||||
#define ERX_CURMBUF 0
|
||||
#define ERX_FLAGS 4
|
||||
#define ERXF_GOTHDR 0x01
|
||||
#define ERXF_FLAGFILL 0x02
|
||||
#define ERX_MYADDR 8
|
||||
/* Sync with txstate above */
|
||||
#define ETX_CURMBUF 0
|
||||
|
||||
#endif
|
|
@ -0,0 +1,103 @@
|
|||
/* $NetBSD: mc6854reg.h,v 1.1 2001/09/10 23:41:49 bjh21 Exp $ */
|
||||
|
||||
/*
|
||||
* Ben Harris, 2001
|
||||
*
|
||||
* This file is in the public domain.
|
||||
*/
|
||||
|
||||
/* mc6854reg.h - Motorola 6854 Advanced Data Link Controller registers */
|
||||
|
||||
/*
|
||||
* The 6854 has two address lines, and uses one of the bits of CR1 as
|
||||
* an additional register select.
|
||||
*/
|
||||
#define MC6854_CR1 0 /* Control Register #1 (W) */
|
||||
#define MC6854_CR2 1 /* Control Register #2 (W) (AC = 0) */
|
||||
#define MC6854_CR3 1 /* Control Register #3 (W) (AC = 1) */
|
||||
#define MC6854_TXFIFOFC 2 /* Transmit FIFO (Frame Continue) (W) */
|
||||
#define MC6854_TXFIFOFT 3 /* Transmit FIFO (Frame Terminate) (W) (AC = 0) */
|
||||
#define MC6854_CR4 3 /* Control Register #4 (W) (AC = 1) */
|
||||
|
||||
#define MC6854_SR1 0 /* Status Register #1 (R) */
|
||||
#define MC6854_SR2 1 /* Status Register #2 (R) */
|
||||
#define MC6854_RXFIFO 2 /* Receiver FIFO (R) */
|
||||
|
||||
/* Control Regsiter #1 bits */
|
||||
#define MC6854_CR1_AC 0x01 /* Address Control */
|
||||
#define MC6854_CR1_RIE 0x02 /* Receiver Interrupt Enable */
|
||||
#define MC6854_CR1_TIE 0x04 /* Transmitter Interrupt Enable */
|
||||
#define MC6854_CR1_RDSR_MODE 0x08 /* Receiver Data Service Request Mode */
|
||||
#define MC6854_CR1_TDSR_MODE 0x10 /* Transmitter Data Service Request Mode*/
|
||||
#define MC6854_CR1_DISCONTINUE 0x20 /* Rx Frame Discontinue */
|
||||
#define MC6854_CR1_RX_RS 0x40 /* Receiver Reset */
|
||||
#define MC6854_CR1_TX_RS 0x80 /* Transmitter Reset */
|
||||
#define MC6854_CR1_BITS \
|
||||
"\20\1AC\2RIE\3TIE\4RDSR_MODE\5TDSR_MODE\6DISCONTINUE\7RX_RS\10TX_RS"
|
||||
|
||||
/* Control Register #2 bits */
|
||||
#define MC6854_CR2_PSE 0x01 /* Prioritized Status Enable */
|
||||
#define MC6854_CR2_2_1_BYTE 0x02 /* 2-Byte/1-Byte Transfer */
|
||||
#define MC6854_CR2_F_M_IDLE 0x04 /* Flag/Mark Idle Select */
|
||||
#define MC6854_CR2_FC_TDRA_SEL 0x08 /* Frame Complete/TDRA Select */
|
||||
#define MC6854_CR2_TX_LAST 0x10 /* Transmit Last Data */
|
||||
#define MC6854_CR2_CLR_RX_ST 0x20 /* Clear Receiver Status */
|
||||
#define MC6854_CR2_CLR_TX_ST 0x40 /* Clear Transmitter Status */
|
||||
#define MC6854_CR2_RTS 0x80 /* Request-to-Send Control */
|
||||
#define MC6854_CR2_BITS \
|
||||
"\20\1PSE\22_1_BYTE\3F_M_IDLE\4RC_TDRA_SEL" \
|
||||
"\5TX_LAST\6CLR_RX_ST\7CLR_TX_ST\10RTS"
|
||||
|
||||
/* Control Register #3 bits */
|
||||
#define MC6854_CR3_LCF 0x01 /* Logical Control Field Select */
|
||||
#define MC6854_CR3_CEX 0x02 /* Extended Control Field Select */
|
||||
#define MC6854_CR3_AEX 0x04 /* Auto/Address Extend Mode */
|
||||
#define MC6854_CR3_00_01_IDLE 0x08 /* 00/01 Idle */
|
||||
#define MC6854_CR3_FDSE 0x10 /* Flag Detect Status Enable */
|
||||
#define MC6854_CR3_LOOP 0x20 /* LOOP/NON-LOOP Mode */
|
||||
#define MC6854_CR3_GAP_TST 0x40 /* Go Active On Poll/Test */
|
||||
#define MC6854_CR3_LOC_DTR 0x80 /* Loop On-Line Control/DTR Control */
|
||||
#define MC6854_CR3_BITS \
|
||||
"\20\1LCF\2CEX\3AEX\400_01_IDLE\5FDSE\6LOOP\7GAP_TST\10LOC_DTR"
|
||||
|
||||
/* Control Register #4 bits */
|
||||
#define MC6854_CR4_FF_F 0x01 /* Double/Single Flag Interframe Control*/
|
||||
#define MC6854_CR4_TX_WL_MASK 0x06 /* Transmitter Word Length Select: */
|
||||
#define MC6854_CR4_TX_WL_5BITS 0x00 /* 5 bits */
|
||||
#define MC6854_CR4_TX_WL_6BITS 0x02 /* 6 bits */
|
||||
#define MC6854_CR4_TX_WL_7BITS 0x04 /* 7 bits */
|
||||
#define MC6854_CR4_TX_WL_8BITS 0x06 /* 8 bits */
|
||||
#define MC6854_CR4_RX_WL_MASK 0x18 /* Receiver Word Length Select: */
|
||||
#define MC6854_CR4_RX_WL_5BITS 0x00 /* 5 bits */
|
||||
#define MC6854_CR4_RX_WL_6BITS 0x08 /* 6 bits */
|
||||
#define MC6854_CR4_RX_WL_7BITS 0x10 /* 7 bits */
|
||||
#define MC6854_CR4_RX_WL_8BITS 0x18 /* 8 bits */
|
||||
#define MC6854_CR4_ABT 0x20 /* Transmit Abort */
|
||||
#define MC6854_CR4_ABTEX 0x40 /* Abort Extend */
|
||||
#define MC6854_CR4_NRZI_NRZ 0x80 /* NRZI (Zero Complement)/NRZ Select */
|
||||
|
||||
/* Status Register #1 bits */
|
||||
#define MC6854_SR1_RDA 0x01 /* Receiver Data Available */
|
||||
#define MC6854_SR1_S2RQ 0x02 /* Status Register #2 Read Request */
|
||||
#define MC6854_SR1_LOOP 0x04 /* Loop Status */
|
||||
#define MC6854_SR1_FD 0x08 /* Flag Detected */
|
||||
#define MC6854_SR1_NCTS 0x10 /* not Clear-to-Send */
|
||||
#define MC6854_SR1_TXU 0x20 /* Transmitter Underrun */
|
||||
#define MC6854_SR1_TDRA 0x40 /* Transmitter Data Register Available */
|
||||
#define MC6854_SR1_FC 0x40 /* Frame Complete */
|
||||
#define MC6854_SR1_IRQ 0x80 /* Interrupt Request */
|
||||
|
||||
#define MC6854_SR1_BITS "\20\1RDA\2S2RQ\3LOOP\4FD\5NCTS\6TXU\7TDRA_FC\10IRQ"
|
||||
|
||||
/* Status Register #2 bits */
|
||||
#define MC6854_SR2_AP 0x01 /* Address Present */
|
||||
#define MC6854_SR2_FV 0x02 /* Frame Valid */
|
||||
#define MC6854_SR2_RX_IDLE 0x04 /* Inactive Idle Received */
|
||||
#define MC6854_SR2_RXABT 0x08 /* Abort Received */
|
||||
#define MC6854_SR2_ERR 0x10 /* FCS/Invalid Frame Error */
|
||||
#define MC6854_SR2_NDCD 0x20 /* not Data Carrier Detect */
|
||||
#define MC6854_SR2_OVRN 0x40 /* Receiver Overrun */
|
||||
#define MC6854_SR2_RDA 0x80 /* Receiver Data Available */
|
||||
|
||||
#define MC6854_SR2_BITS "\20\1AP\2FV\3RX_IDLE\4RXABT\5ERR\6NDCD\7OVRN\10RDA"
|
||||
|
Loading…
Reference in New Issue