Rototill vx(4), add locking, and mark MPSAFE:

- Rename vxfoo() functions to vx_foo() to improve readability and
  consistency with other drivers.
- Prefix most the softc members with 'vx_' (the other members already had
  the prefix).
- Switch to using callout_init_mtx() and callout_*() rather than
  timeout() and untimeout().
- Add some missing calls to if_free() in some failure cases in vx_attach().
- Use if_printf() and remove the unit number from the softc.
- Remove uses of the 'register' keyword and spls.
- Add locked variants of vx_init() and vx_start().
- Add a mutex to the softc and lock it in various appropriate places.
- Setup the interrupt handler last during attach.

Tested by:	imp
MFC after:	1 week
This commit is contained in:
John Baldwin 2005-10-06 18:27:59 +00:00
parent 2628fdabad
commit fa08ebbbb1
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=151014
4 changed files with 287 additions and 233 deletions

View file

@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sockio.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
@ -121,42 +122,46 @@ static struct connector_entry {
}
};
/* int vxattach(struct vx_softc *); */
static void vxtxstat(struct vx_softc *);
static int vxstatus(struct vx_softc *);
static void vxinit(void *);
static int vxioctl(struct ifnet *, u_long, caddr_t);
static void vxstart(struct ifnet *);
static void vxwatchdog(struct ifnet *);
static void vxreset(struct vx_softc *);
static void vxread(struct vx_softc *);
static struct mbuf *vxget(struct vx_softc *, u_int);
static void vxmbuffill(void *);
static void vxmbufempty(struct vx_softc *);
static void vxsetfilter(struct vx_softc *);
static void vxgetlink(struct vx_softc *);
static void vxsetlink(struct vx_softc *);
static void vx_txstat(struct vx_softc *);
static int vx_status(struct vx_softc *);
static void vx_init(void *);
static void vx_init_locked(struct vx_softc *);
static int vx_ioctl(struct ifnet *, u_long, caddr_t);
static void vx_start(struct ifnet *);
static void vx_start_locked(struct ifnet *);
static void vx_watchdog(struct ifnet *);
static void vx_reset(struct vx_softc *);
static void vx_read(struct vx_softc *);
static struct mbuf *vx_get(struct vx_softc *, u_int);
static void vx_mbuf_fill(void *);
static void vx_mbuf_empty(struct vx_softc *);
static void vx_setfilter(struct vx_softc *);
static void vx_getlink(struct vx_softc *);
static void vx_setlink(struct vx_softc *);
int
vxattach(device_t dev)
vx_attach(device_t dev)
{
struct vx_softc *sc = device_get_softc(dev);
struct ifnet *ifp;
int i;
u_char eaddr[6];
ifp = sc->ifp = if_alloc(IFT_ETHER);
ifp = sc->vx_ifp = if_alloc(IFT_ETHER);
if (ifp == NULL) {
device_printf(dev, "can not if_alloc()\n");
return 0;
}
if_initname(ifp, device_get_name(dev), device_get_unit(dev));
callout_handle_init(&sc->ch);
mtx_init(&sc->vx_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
MTX_DEF);
callout_init_mtx(&sc->vx_callout, &sc->vx_mtx, 0);
GO_WINDOW(0);
CSR_WRITE_2(sc, VX_COMMAND, GLOBAL_RESET);
VX_BUSY_WAIT;
vxgetlink(sc);
vx_getlink(sc);
/*
* Read the station address from the eeprom
@ -165,33 +170,37 @@ vxattach(device_t dev)
for (i = 0; i < 3; i++) {
int x;
if (vxbusyeeprom(sc))
if (vx_busy_eeprom(sc)) {
mtx_destroy(&sc->vx_mtx);
if_free(ifp);
return 0;
}
CSR_WRITE_2(sc, VX_W0_EEPROM_COMMAND, EEPROM_CMD_RD
| (EEPROM_OEM_ADDR0 + i));
if (vxbusyeeprom(sc))
if (vx_busy_eeprom(sc)) {
mtx_destroy(&sc->vx_mtx);
if_free(ifp);
return 0;
}
x = CSR_READ_2(sc, VX_W0_EEPROM_DATA);
eaddr[(i << 1)] = x >> 8;
eaddr[(i << 1) + 1] = x;
}
if_initname(ifp, device_get_name(dev), device_get_unit(dev));
ifp->if_mtu = ETHERMTU;
ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST |
IFF_NEEDSGIANT;
ifp->if_start = vxstart;
ifp->if_ioctl = vxioctl;
ifp->if_init = vxinit;
ifp->if_watchdog = vxwatchdog;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_start = vx_start;
ifp->if_ioctl = vx_ioctl;
ifp->if_init = vx_init;
ifp->if_watchdog = vx_watchdog;
ifp->if_softc = sc;
ether_ifattach(ifp, eaddr);
sc->tx_start_thresh = 20; /* probably a good starting point. */
sc->vx_tx_start_thresh = 20; /* probably a good starting point. */
vxstop(sc);
vx_stop(sc);
return 1;
}
@ -201,18 +210,29 @@ vxattach(device_t dev)
* interrupts. ?!
*/
static void
vxinit(void *xsc)
vx_init(void *xsc)
{
struct vx_softc *sc = (struct vx_softc *)xsc;
struct ifnet *ifp = sc->ifp;
VX_LOCK(sc);
vx_init_locked(sc);
VX_UNLOCK(sc);
}
static void
vx_init_locked(struct vx_softc *sc)
{
struct ifnet *ifp = sc->vx_ifp;
int i;
VX_LOCK_ASSERT(sc);
VX_BUSY_WAIT;
GO_WINDOW(2);
for (i = 0; i < 6; i++) /* Reload the ether_addr. */
CSR_WRITE_1(sc, VX_W2_ADDR_0 + i, IFP2ENADDR(sc->ifp)[i]);
CSR_WRITE_1(sc, VX_W2_ADDR_0 + i, IFP2ENADDR(sc->vx_ifp)[i]);
CSR_WRITE_2(sc, VX_COMMAND, RX_RESET);
VX_BUSY_WAIT;
@ -236,27 +256,28 @@ vxinit(void *xsc)
*/
CSR_WRITE_2(sc, VX_COMMAND, ACK_INTR | 0xff);
vxsetfilter(sc);
vxsetlink(sc);
vx_setfilter(sc);
vx_setlink(sc);
CSR_WRITE_2(sc, VX_COMMAND, RX_ENABLE);
CSR_WRITE_2(sc, VX_COMMAND, TX_ENABLE);
vxmbuffill((caddr_t) sc);
vx_mbuf_fill(sc);
/* Interface is now `running', with no output active. */
ifp->if_drv_flags |= IFF_DRV_RUNNING;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
/* Attempt to start output, if any. */
vxstart(ifp);
vx_start_locked(ifp);
}
static void
vxsetfilter(struct vx_softc *sc)
vx_setfilter(struct vx_softc *sc)
{
register struct ifnet *ifp = sc->ifp;
struct ifnet *ifp = sc->vx_ifp;
VX_LOCK_ASSERT(sc);
GO_WINDOW(1); /* Window 1 is operating window */
CSR_WRITE_2(sc, VX_COMMAND, SET_RX_FILTER |
FIL_INDIVIDUAL | FIL_BRDCST | FIL_MULTICAST |
@ -264,7 +285,7 @@ vxsetfilter(struct vx_softc *sc)
}
static void
vxgetlink(struct vx_softc *sc)
vx_getlink(struct vx_softc *sc)
{
int n, k;
@ -296,14 +317,15 @@ vxgetlink(struct vx_softc *sc)
}
static void
vxsetlink(struct vx_softc *sc)
vx_setlink(struct vx_softc *sc)
{
register struct ifnet *ifp = sc->ifp;
struct ifnet *ifp = sc->vx_ifp;
int i, j, k;
char *reason, *warning;
static int prev_flags;
static signed char prev_conn = -1;
VX_LOCK_ASSERT(sc);
if (prev_conn == -1)
prev_conn = sc->vx_connector;
@ -356,11 +378,9 @@ vxsetlink(struct vx_softc *sc)
/* Avoid unnecessary message. */
k = (prev_flags ^ ifp->if_flags) & (IFF_LINK0 | IFF_LINK1 | IFF_LINK2);
if ((k != 0) || (prev_conn != i)) {
if (warning != 0) {
printf("vx%d: warning: %s\n", sc->unit, warning);
}
printf("vx%d: selected %s. (%s)\n",
sc->unit, conn_tab[i].name, reason);
if (warning != NULL)
if_printf(ifp, "warning: %s\n", warning);
if_printf(ifp, "selected %s. (%s)\n", conn_tab[i].name, reason);
}
/* Set the selected connector. */
GO_WINDOW(3);
@ -398,14 +418,26 @@ vxsetlink(struct vx_softc *sc)
}
static void
vxstart(struct ifnet *ifp)
vx_start(struct ifnet *ifp)
{
register struct vx_softc *sc = ifp->if_softc;
register struct mbuf *m;
int sh, len, pad;
struct vx_softc *sc = ifp->if_softc;
VX_LOCK(sc);
vx_start_locked(ifp);
VX_UNLOCK(sc);
}
static void
vx_start_locked(struct ifnet *ifp)
{
struct vx_softc *sc = ifp->if_softc;
struct mbuf *m;
int len, pad;
VX_LOCK_ASSERT(sc);
/* Don't transmit if interface is busy or not running */
if ((sc->ifp->if_drv_flags &
if ((sc->vx_ifp->if_drv_flags &
(IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING)
return;
@ -451,25 +483,26 @@ vxstart(struct ifnet *ifp)
VX_BUSY_WAIT;
CSR_WRITE_2(sc, VX_COMMAND, SET_TX_START_THRESH |
((len / 4 + sc->tx_start_thresh) >> 2));
((len / 4 + sc->vx_tx_start_thresh) >> 2));
BPF_MTAP(sc->ifp, m);
BPF_MTAP(sc->vx_ifp, m);
/*
* Do the output at splhigh() so that an interrupt from another device
* won't cause a FIFO underrun.
*
* XXX: Can't enforce that anymore.
*/
sh = splhigh();
CSR_WRITE_4(sc, VX_W1_TX_PIO_WR_1, len | TX_INDICATE);
while (m) {
if (m->m_len > 3)
bus_space_write_multi_4(sc->bst, sc->bsh,
bus_space_write_multi_4(sc->vx_bst, sc->vx_bsh,
VX_W1_TX_PIO_WR_1, (u_int32_t *)mtod(m, caddr_t),
m->m_len / 4);
if (m->m_len & 3)
bus_space_write_multi_1(sc->bst, sc->bsh,
bus_space_write_multi_1(sc->vx_bst, sc->vx_bsh,
VX_W1_TX_PIO_WR_1,
mtod(m, caddr_t) + (m->m_len & ~3), m->m_len & 3);
m = m_free(m);
@ -477,8 +510,6 @@ vxstart(struct ifnet *ifp)
while (pad--)
CSR_WRITE_1(sc, VX_W1_TX_PIO_WR_1, 0); /* Padding */
splx(sh);
++ifp->if_opackets;
ifp->if_timer = 1;
@ -492,7 +523,7 @@ vxstart(struct ifnet *ifp)
* Is this supposed to happen? Is my motherboard
* completely busted?
*/
vxread(sc);
vx_read(sc);
} else
/*
* Got an interrupt, return so that it gets
@ -501,10 +532,10 @@ vxstart(struct ifnet *ifp)
return;
} else {
/* Check if we are stuck and reset [see XXX comment] */
if (vxstatus(sc)) {
if (vx_status(sc)) {
if (ifp->if_flags & IFF_DEBUG)
if_printf(ifp, "adapter reset\n");
vxreset(sc);
vx_reset(sc);
}
}
@ -519,10 +550,13 @@ vxstart(struct ifnet *ifp)
* on the cable (once in a blue moon).
*/
static int
vxstatus(struct vx_softc *sc)
vx_status(struct vx_softc *sc)
{
struct ifnet *ifp;
int fifost;
VX_LOCK_ASSERT(sc);
/*
* Check the FIFO status and act accordingly
*/
@ -530,74 +564,81 @@ vxstatus(struct vx_softc *sc)
fifost = CSR_READ_2(sc, VX_W4_FIFO_DIAG);
GO_WINDOW(1);
ifp = sc->vx_ifp;
if (fifost & FIFOS_RX_UNDERRUN) {
if (sc->ifp->if_flags & IFF_DEBUG)
printf("vx%d: RX underrun\n", sc->unit);
vxreset(sc);
if (ifp->if_flags & IFF_DEBUG)
if_printf(ifp, "RX underrun\n");
vx_reset(sc);
return 0;
}
if (fifost & FIFOS_RX_STATUS_OVERRUN) {
if (sc->ifp->if_flags & IFF_DEBUG)
printf("vx%d: RX Status overrun\n", sc->unit);
if (ifp->if_flags & IFF_DEBUG)
if_printf(ifp, "RX Status overrun\n");
return 1;
}
if (fifost & FIFOS_RX_OVERRUN) {
if (sc->ifp->if_flags & IFF_DEBUG)
printf("vx%d: RX overrun\n", sc->unit);
if (ifp->if_flags & IFF_DEBUG)
if_printf(ifp, "RX overrun\n");
return 1;
}
if (fifost & FIFOS_TX_OVERRUN) {
if (sc->ifp->if_flags & IFF_DEBUG)
printf("vx%d: TX overrun\n", sc->unit);
vxreset(sc);
if (ifp->if_flags & IFF_DEBUG)
if_printf(ifp, "TX overrun\n");
vx_reset(sc);
return 0;
}
return 0;
}
static void
vxtxstat(struct vx_softc *sc)
vx_txstat(struct vx_softc *sc)
{
struct ifnet *ifp;
int i;
VX_LOCK_ASSERT(sc);
/*
* We need to read+write TX_STATUS until we get a 0 status
* in order to turn off the interrupt flag.
*/
ifp = sc->vx_ifp;
while ((i = CSR_READ_1(sc, VX_W1_TX_STATUS)) & TXS_COMPLETE) {
CSR_WRITE_1(sc, VX_W1_TX_STATUS, 0x0);
if (i & TXS_JABBER) {
++sc->ifp->if_oerrors;
if (sc->ifp->if_flags & IFF_DEBUG)
printf("vx%d: jabber (%x)\n", sc->unit, i);
vxreset(sc);
++ifp->if_oerrors;
if (ifp->if_flags & IFF_DEBUG)
if_printf(ifp, "jabber (%x)\n", i);
vx_reset(sc);
} else if (i & TXS_UNDERRUN) {
++sc->ifp->if_oerrors;
if (sc->ifp->if_flags & IFF_DEBUG)
printf("vx%d: fifo underrun (%x) @%d\n",
sc->unit, i, sc->tx_start_thresh);
if (sc->tx_succ_ok < 100)
sc->tx_start_thresh =
min(ETHER_MAX_LEN,sc->tx_start_thresh + 20);
sc->tx_succ_ok = 0;
vxreset(sc);
++ifp->if_oerrors;
if (ifp->if_flags & IFF_DEBUG)
if_printf(ifp, "fifo underrun (%x) @%d\n", i,
sc->vx_tx_start_thresh);
if (sc->vx_tx_succ_ok < 100)
sc->vx_tx_start_thresh =
min(ETHER_MAX_LEN,
sc->vx_tx_start_thresh + 20);
sc->vx_tx_succ_ok = 0;
vx_reset(sc);
} else if (i & TXS_MAX_COLLISION) {
++sc->ifp->if_collisions;
++ifp->if_collisions;
CSR_WRITE_2(sc, VX_COMMAND, TX_ENABLE);
sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
} else
sc->tx_succ_ok = (sc->tx_succ_ok + 1) & 127;
sc->vx_tx_succ_ok = (sc->vx_tx_succ_ok + 1) & 127;
}
}
void
vxintr(void *voidsc)
vx_intr(void *voidsc)
{
register short status;
short status;
struct vx_softc *sc = voidsc;
struct ifnet *ifp = sc->ifp;
struct ifnet *ifp = sc->vx_ifp;
VX_LOCK(sc);
for (;;) {
CSR_WRITE_2(sc, VX_COMMAND, C_INTR_LATCH);
@ -616,40 +657,40 @@ vxintr(void *voidsc)
CSR_WRITE_2(sc, VX_COMMAND, ACK_INTR | status);
if (status & S_RX_COMPLETE)
vxread(sc);
vx_read(sc);
if (status & S_TX_AVAIL) {
ifp->if_timer = 0;
sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
vxstart(sc->ifp);
sc->vx_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
vx_start_locked(sc->vx_ifp);
}
if (status & S_CARD_FAILURE) {
printf("vx%d: adapter failure (%x)\n",
sc->unit, status);
if_printf(ifp, "adapter failure (%x)\n", status);
ifp->if_timer = 0;
vxreset(sc);
return;
vx_reset(sc);
break;
}
if (status & S_TX_COMPLETE) {
ifp->if_timer = 0;
vxtxstat(sc);
vxstart(ifp);
vx_txstat(sc);
vx_start_locked(ifp);
}
}
VX_UNLOCK(sc);
/* no more interrupts */
return;
}
static void
vxread(struct vx_softc *sc)
vx_read(struct vx_softc *sc)
{
struct ifnet *ifp = sc->ifp;
struct ifnet *ifp = sc->vx_ifp;
struct mbuf *m;
struct ether_header *eh;
u_int len;
VX_LOCK_ASSERT(sc);
len = CSR_READ_2(sc, VX_W1_RX_STATUS);
again:
if (ifp->if_flags & IFF_DEBUG) {
@ -672,7 +713,7 @@ vxread(struct vx_softc *sc)
s = "dribble bits";
if (s)
printf("vx%d: %s\n", sc->unit, s);
if_printf(ifp, "%s\n", s);
}
if (len & ERR_INCOMPLETE)
return;
@ -684,7 +725,7 @@ vxread(struct vx_softc *sc)
len &= RX_BYTES_MASK; /* Lower 11 bits = RX bytes. */
/* Pull packet off interface. */
m = vxget(sc, len);
m = vx_get(sc, len);
if (m == 0) {
ifp->if_ierrors++;
goto abort;
@ -694,7 +735,8 @@ vxread(struct vx_softc *sc)
{
struct mbuf *m0;
m0 = m_devget(mtod(m, char *), m->m_pkthdr.len, ETHER_ALIGN, ifp, NULL);
m0 = m_devget(mtod(m, char *), m->m_pkthdr.len, ETHER_ALIGN,
ifp, NULL);
if (m0 == NULL) {
ifp->if_ierrors++;
goto abort;
@ -714,11 +756,14 @@ vxread(struct vx_softc *sc)
if (!(ifp->if_flags & IFF_PROMISC)
&& (eh->ether_dhost[0] & 1) == 0 /* !mcast and !bcast */
&& bcmp(eh->ether_dhost, IFP2ENADDR(sc->ifp), ETHER_ADDR_LEN)!=0) {
&& bcmp(eh->ether_dhost, IFP2ENADDR(sc->vx_ifp),
ETHER_ADDR_LEN) != 0) {
m_freem(m);
return;
}
(*ifp->if_input) (ifp, m);
VX_UNLOCK(sc);
(*ifp->if_input)(ifp, m);
VX_LOCK(sc);
/*
* In periods of high traffic we can actually receive enough
@ -726,7 +771,7 @@ vxread(struct vx_softc *sc)
* even though we just read a packet. In this case we
* are not going to receive any more interrupts. We check for
* this condition and read again until the fifo is not full.
* We could simplify this test by not using vxstatus(), but
* We could simplify this test by not using vx_status(), but
* rechecking the RX_STATUS register directly. This test could
* result in unnecessary looping in cases where there is a new
* packet but the fifo is not full, but it will not fix the
@ -734,15 +779,15 @@ vxread(struct vx_softc *sc)
*
* Even with this improvement, we still get packet overrun errors
* which are hurting performance. Maybe when I get some more time
* I'll modify vxread() so that it can handle RX_EARLY interrupts.
* I'll modify vx_read() so that it can handle RX_EARLY interrupts.
*/
if (vxstatus(sc)) {
if (vx_status(sc)) {
len = CSR_READ_2(sc, VX_W1_RX_STATUS);
/* Check if we are stuck and reset [see XXX comment] */
if (len & ERR_INCOMPLETE) {
if (ifp->if_flags & IFF_DEBUG)
printf("vx%d: adapter reset\n", sc->unit);
vxreset(sc);
if_printf(ifp, "adapter reset\n");
vx_reset(sc);
return;
}
goto again;
@ -754,27 +799,29 @@ vxread(struct vx_softc *sc)
}
static struct mbuf *
vxget(struct vx_softc *sc, u_int totlen)
vx_get(struct vx_softc *sc, u_int totlen)
{
struct ifnet *ifp = sc->ifp;
struct ifnet *ifp = sc->vx_ifp;
struct mbuf *top, **mp, *m;
int len;
int sh;
m = sc->mb[sc->next_mb];
sc->mb[sc->next_mb] = 0;
if (m == 0) {
VX_LOCK_ASSERT(sc);
m = sc->vx_mb[sc->vx_next_mb];
sc->vx_mb[sc->vx_next_mb] = NULL;
if (m == NULL) {
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == 0)
return 0;
if (m == NULL)
return NULL;
} else {
/* If the queue is no longer full, refill. */
if (sc->last_mb == sc->next_mb && sc->buffill_pending == 0) {
sc->ch = timeout(vxmbuffill, sc, 1);
sc->buffill_pending = 1;
if (sc->vx_last_mb == sc->vx_next_mb &&
sc->vx_buffill_pending == 0) {
callout_reset(&sc->vx_callout, hz / 100, vx_mbuf_fill,
sc);
sc->vx_buffill_pending = 1;
}
/* Convert one of our saved mbuf's. */
sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
sc->vx_next_mb = (sc->vx_next_mb + 1) % MAX_MBS;
m->m_data = m->m_pktdat;
m->m_flags = M_PKTHDR;
bzero(&m->m_pkthdr, sizeof(m->m_pkthdr));
@ -782,15 +829,16 @@ vxget(struct vx_softc *sc, u_int totlen)
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = totlen;
len = MHLEN;
top = 0;
top = NULL;
mp = &top;
/*
* We read the packet at splhigh() so that an interrupt from another
* device doesn't cause the card's buffer to overflow while we're
* reading it. We may still lose packets at other times.
*
* XXX: Can't enforce this anymore.
*/
sh = splhigh();
/*
* Since we don't set allowLargePackets bit in MacControl register,
@ -800,17 +848,16 @@ vxget(struct vx_softc *sc, u_int totlen)
*/
while (totlen > 0) {
if (top) {
m = sc->mb[sc->next_mb];
sc->mb[sc->next_mb] = 0;
if (m == 0) {
m = sc->vx_mb[sc->vx_next_mb];
sc->vx_mb[sc->vx_next_mb] = NULL;
if (m == NULL) {
MGET(m, M_DONTWAIT, MT_DATA);
if (m == 0) {
splx(sh);
if (m == NULL) {
m_freem(top);
return 0;
return NULL;
}
} else {
sc->next_mb = (sc->next_mb + 1) % MAX_MBS;
sc->vx_next_mb = (sc->vx_next_mb + 1) % MAX_MBS;
}
len = MLEN;
}
@ -821,10 +868,10 @@ vxget(struct vx_softc *sc, u_int totlen)
}
len = min(totlen, len);
if (len > 3)
bus_space_read_multi_4(sc->bst, sc->bsh,
bus_space_read_multi_4(sc->vx_bst, sc->vx_bsh,
VX_W1_RX_PIO_RD_1, mtod(m, u_int32_t *), len / 4);
if (len & 3) {
bus_space_read_multi_1(sc->bst, sc->bsh,
bus_space_read_multi_1(sc->vx_bst, sc->vx_bsh,
VX_W1_RX_PIO_RD_1, mtod(m, u_int8_t *) + (len & ~3),
len & 3);
}
@ -836,30 +883,27 @@ vxget(struct vx_softc *sc, u_int totlen)
CSR_WRITE_2(sc, VX_COMMAND, RX_DISCARD_TOP_PACK);
splx(sh);
return top;
}
static int
vxioctl(register struct ifnet *ifp, u_long cmd, caddr_t data)
vx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
struct vx_softc *sc = ifp->if_softc;
struct ifreq *ifr = (struct ifreq *) data;
int s, error = 0;
s = splimp();
int error = 0;
switch (cmd) {
case SIOCSIFFLAGS:
VX_LOCK(sc);
if ((ifp->if_flags & IFF_UP) == 0 &&
(ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
/*
* If interface is marked up and it is stopped, then
* start it.
*/
vxstop(sc);
vx_stop(sc);
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
} else if ((ifp->if_flags & IFF_UP) != 0 &&
(ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
@ -867,27 +911,30 @@ vxioctl(register struct ifnet *ifp, u_long cmd, caddr_t data)
* If interface is marked up and it is stopped, then
* start it.
*/
vxinit(sc);
vx_init_locked(sc);
} else {
/*
* deal with flags changes:
* IFF_MULTICAST, IFF_PROMISC,
* IFF_LINK0, IFF_LINK1,
*/
vxsetfilter(sc);
vxsetlink(sc);
vx_setfilter(sc);
vx_setlink(sc);
}
VX_UNLOCK(sc);
break;
case SIOCSIFMTU:
/*
* Set the interface MTU.
*/
VX_LOCK(sc);
if (ifr->ifr_mtu > ETHERMTU) {
error = EINVAL;
} else {
ifp->if_mtu = ifr->ifr_mtu;
}
VX_UNLOCK(sc);
break;
case SIOCADDMULTI:
@ -896,7 +943,9 @@ vxioctl(register struct ifnet *ifp, u_long cmd, caddr_t data)
* Multicast list has changed; set the hardware filter
* accordingly.
*/
vxreset(sc);
VX_LOCK(sc);
vx_reset(sc);
VX_UNLOCK(sc);
error = 0;
break;
@ -906,40 +955,38 @@ vxioctl(register struct ifnet *ifp, u_long cmd, caddr_t data)
break;
}
splx(s);
return (error);
}
static void
vxreset(struct vx_softc *sc)
vx_reset(struct vx_softc *sc)
{
int s;
s = splimp();
vxstop(sc);
vxinit(sc);
splx(s);
VX_LOCK_ASSERT(sc);
vx_stop(sc);
vx_init_locked(sc);
}
static void
vxwatchdog(struct ifnet *ifp)
vx_watchdog(struct ifnet *ifp)
{
struct vx_softc *sc = ifp->if_softc;
VX_LOCK(sc);
if (ifp->if_flags & IFF_DEBUG)
if_printf(ifp, "device timeout\n");
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
vxstart(ifp);
vxintr(sc);
vx_start_locked(ifp);
vx_intr(sc);
VX_UNLOCK(sc);
}
void
vxstop(struct vx_softc *sc)
vx_stop(struct vx_softc *sc)
{
struct ifnet *ifp = sc->ifp;
struct ifnet *ifp = sc->vx_ifp;
VX_LOCK_ASSERT(sc);
ifp->if_timer = 0;
CSR_WRITE_2(sc, VX_COMMAND, RX_DISABLE);
@ -957,11 +1004,11 @@ vxstop(struct vx_softc *sc)
CSR_WRITE_2(sc, VX_COMMAND, SET_INTR_MASK);
CSR_WRITE_2(sc, VX_COMMAND, SET_RX_FILTER);
vxmbufempty(sc);
vx_mbuf_empty(sc);
}
int
vxbusyeeprom(struct vx_softc *sc)
vx_busy_eeprom(struct vx_softc *sc)
{
int j, i = 100;
@ -973,52 +1020,50 @@ vxbusyeeprom(struct vx_softc *sc)
break;
}
if (!i) {
printf("vx%d: eeprom failed to come ready\n", sc->unit);
if_printf(sc->vx_ifp, "eeprom failed to come ready\n");
return (1);
}
return (0);
}
static void
vxmbuffill(void *sp)
vx_mbuf_fill(void *sp)
{
struct vx_softc *sc = (struct vx_softc *)sp;
int s, i;
int i;
s = splimp();
i = sc->last_mb;
VX_LOCK_ASSERT(sc);
i = sc->vx_last_mb;
do {
if (sc->mb[i] == NULL)
MGET(sc->mb[i], M_DONTWAIT, MT_DATA);
if (sc->mb[i] == NULL)
if (sc->vx_mb[i] == NULL)
MGET(sc->vx_mb[i], M_DONTWAIT, MT_DATA);
if (sc->vx_mb[i] == NULL)
break;
i = (i + 1) % MAX_MBS;
} while (i != sc->next_mb);
sc->last_mb = i;
} while (i != sc->vx_next_mb);
sc->vx_last_mb = i;
/* If the queue was not filled, try again. */
if (sc->last_mb != sc->next_mb) {
sc->ch = timeout(vxmbuffill, sc, 1);
sc->buffill_pending = 1;
if (sc->vx_last_mb != sc->vx_next_mb) {
callout_reset(&sc->vx_callout, hz / 100, vx_mbuf_fill, sc);
sc->vx_buffill_pending = 1;
} else {
sc->buffill_pending = 0;
sc->vx_buffill_pending = 0;
}
splx(s);
}
static void
vxmbufempty(struct vx_softc *sc)
vx_mbuf_empty(struct vx_softc *sc)
{
int s, i;
int i;
s = splimp();
VX_LOCK_ASSERT(sc);
for (i = 0; i < MAX_MBS; i++) {
if (sc->mb[i]) {
m_freem(sc->mb[i]);
sc->mb[i] = NULL;
if (sc->vx_mb[i]) {
m_freem(sc->vx_mb[i]);
sc->vx_mb[i] = NULL;
}
}
sc->last_mb = sc->next_mb = 0;
if (sc->buffill_pending != 0)
untimeout(vxmbuffill, sc, sc->ch);
splx(s);
sc->vx_last_mb = sc->vx_next_mb = 0;
if (sc->vx_buffill_pending != 0)
callout_stop(&sc->vx_callout);
}

View file

@ -114,7 +114,6 @@ vx_eisa_attach(device_t dev)
struct resource *eisa_io = 0;
struct resource *irq = 0;
int rid;
void *ih;
/*
* The addresses are sorted in increasing order
@ -136,8 +135,8 @@ vx_eisa_attach(device_t dev)
sc = device_get_softc(dev);
sc->vx_res = io;
sc->bst = rman_get_bustag(io);
sc->bsh = rman_get_bushandle(io);
sc->vx_bst = rman_get_bustag(io);
sc->vx_bsh = rman_get_bushandle(io);
rid = 0;
irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
@ -149,15 +148,17 @@ vx_eisa_attach(device_t dev)
/* Now the registers are availible through the lower ioport */
vxattach(dev);
if (bus_setup_intr(dev, irq, INTR_TYPE_NET, vxintr, sc, &ih))
if (vx_attach(dev) == 0)
goto bad;
sc->vx_intrhand = ih;
if (bus_setup_intr(dev, irq, INTR_TYPE_NET | INTR_MPSAFE, vx_intr, sc,
&sc->vx_intrhand))
goto bad_mtx;
return 0;
return (0);
bad_mtx:
mtx_destroy(&sc->vx_mtx);
bad:
if (io)
bus_release_resource(dev, SYS_RES_IOPORT, 0, io);
@ -165,7 +166,7 @@ vx_eisa_attach(device_t dev)
bus_release_resource(dev, SYS_RES_IOPORT, 0, eisa_io);
if (irq)
bus_release_resource(dev, SYS_RES_IRQ, 0, irq);
return -1;
return (ENXIO);
}
static device_method_t vx_eisa_methods[] = {

View file

@ -81,7 +81,9 @@ vx_pci_shutdown(device_t dev)
struct vx_softc *sc;
sc = device_get_softc(dev);
vxstop(sc);
VX_LOCK(sc);
vx_stop(sc);
VX_UNLOCK(sc);
}
static int
@ -131,8 +133,8 @@ vx_pci_attach(device_t dev)
if (sc->vx_res == NULL)
goto bad;
sc->bst = rman_get_bustag(sc->vx_res);
sc->bsh = rman_get_bushandle(sc->vx_res);
sc->vx_bst = rman_get_bustag(sc->vx_res);
sc->vx_bsh = rman_get_bushandle(sc->vx_res);
rid = 0;
sc->vx_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
@ -141,27 +143,30 @@ vx_pci_attach(device_t dev)
if (sc->vx_irq == NULL)
goto bad;
if (bus_setup_intr(dev, sc->vx_irq, INTR_TYPE_NET,
vxintr, sc, &sc->vx_intrhand))
if (vx_attach(dev) == 0)
goto bad;
if (vxattach(dev) == 0)
goto bad;
if (bus_setup_intr(dev, sc->vx_irq, INTR_TYPE_NET | INTR_MPSAFE,
vx_intr, sc, &sc->vx_intrhand))
goto bad_mtx;
/* defect check for 3C590 */
if ((pci_read_config(dev, PCIR_DEVVENDOR, 4) >> 16) == 0x5900) {
GO_WINDOW(0);
if (vxbusyeeprom(sc))
goto bad;
if (vx_busy_eeprom(sc))
goto bad_mtx;
CSR_WRITE_2(sc, VX_W0_EEPROM_COMMAND,
EEPROM_CMD_RD | EEPROM_SOFTINFO2);
if (vxbusyeeprom(sc))
goto bad;
if (vx_busy_eeprom(sc))
goto bad_mtx;
if (!(CSR_READ_2(sc, VX_W0_EEPROM_DATA) & NO_RX_OVN_ANOMALY))
printf("Warning! Defective early revision adapter!\n");
device_printf(dev,
"Warning! Defective early revision adapter!\n");
}
return (0);
bad_mtx:
mtx_destroy(&sc->vx_mtx);
bad:
if (sc->vx_intrhand != NULL)
bus_teardown_intr(dev, sc->vx_irq, sc->vx_intrhand);

View file

@ -35,42 +35,45 @@
* Ethernet software status per interface.
*/
struct vx_softc {
struct ifnet *ifp;
int unit; /* unit number */
bus_space_tag_t bst;
bus_space_handle_t bsh;
struct ifnet *vx_ifp;
bus_space_tag_t vx_bst;
bus_space_handle_t vx_bsh;
void *vx_intrhand;
struct resource *vx_irq;
struct resource *vx_res;
#define MAX_MBS 8 /* # of mbufs we keep around */
struct mbuf *mb[MAX_MBS]; /* spare mbuf storage. */
int next_mb; /* Which mbuf to use next. */
int last_mb; /* Last mbuf. */
struct mbuf *vx_mb[MAX_MBS]; /* spare mbuf storage. */
int vx_next_mb; /* Which mbuf to use next. */
int vx_last_mb; /* Last mbuf. */
char vx_connectors; /* Connectors on this card. */
char vx_connector; /* Connector to use. */
short tx_start_thresh; /* Current TX_start_thresh. */
int tx_succ_ok; /* # packets sent in sequence */
short vx_tx_start_thresh; /* Current TX_start_thresh. */
int vx_tx_succ_ok; /* # packets sent in sequence */
/* w/o underrun */
struct callout_handle ch; /* Callout handle for timeouts */
int buffill_pending;
struct callout vx_callout; /* Callout for timeouts */
struct mtx vx_mtx;
int vx_buffill_pending;
};
#define CSR_WRITE_4(sc, reg, val) \
bus_space_write_4(sc->bst, sc->bsh, reg, val)
bus_space_write_4(sc->vx_bst, sc->vx_bsh, reg, val)
#define CSR_WRITE_2(sc, reg, val) \
bus_space_write_2(sc->bst, sc->bsh, reg, val)
bus_space_write_2(sc->vx_bst, sc->vx_bsh, reg, val)
#define CSR_WRITE_1(sc, reg, val) \
bus_space_write_1(sc->bst, sc->bsh, reg, val)
bus_space_write_1(sc->vx_bst, sc->vx_bsh, reg, val)
#define CSR_READ_4(sc, reg) \
bus_space_read_4(sc->bst, sc->bsh, reg)
bus_space_read_4(sc->vx_bst, sc->vx_bsh, reg)
#define CSR_READ_2(sc, reg) \
bus_space_read_2(sc->bst, sc->bsh, reg)
bus_space_read_2(sc->vx_bst, sc->vx_bsh, reg)
#define CSR_READ_1(sc, reg) \
bus_space_read_1(sc->bst, sc->bsh, reg)
bus_space_read_1(sc->vx_bst, sc->vx_bsh, reg)
extern void vxfree(struct vx_softc *);
extern int vxattach(device_t);
extern void vxstop(struct vx_softc *);
extern void vxintr(void *);
extern int vxbusyeeprom(struct vx_softc *);
#define VX_LOCK(sc) mtx_lock(&(sc)->vx_mtx)
#define VX_UNLOCK(sc) mtx_unlock(&(sc)->vx_mtx)
#define VX_LOCK_ASSERT(sc) mtx_assert(&(sc)->vx_mtx, MA_OWNED)
int vx_attach(device_t);
void vx_stop(struct vx_softc *);
void vx_intr(void *);
int vx_busy_eeprom(struct vx_softc *);