summaryrefslogtreecommitdiff
path: root/sys/dev/pci/if_stge.c
diff options
context:
space:
mode:
authorBrad Smith <brad@cvs.openbsd.org>2005-05-23 22:44:21 +0000
committerBrad Smith <brad@cvs.openbsd.org>2005-05-23 22:44:21 +0000
commit50aaf2ae990b7e1ae83950552f80c26675cb8b2d (patch)
tree7b76455be77bdd663278e1aeca859bd629294b33 /sys/dev/pci/if_stge.c
parentd271a729d5c3db995ecffe07f81a5bd8771aec60 (diff)
- Fix some big-endian issues.
- Centralize the interrupt bits for the 3 registers where they are being used. - Replace magic numbers for power management control with PCI_PMCSR* macros. - The flow control registers are 16 bits wide, not 32. - Create the Tx DMA maps with a size large enough for a jumbo Ethernet frame. - Oops, make Rx interrupt deferral actually work. From NetBSD
Diffstat (limited to 'sys/dev/pci/if_stge.c')
-rw-r--r--sys/dev/pci/if_stge.c139
1 files changed, 85 insertions, 54 deletions
diff --git a/sys/dev/pci/if_stge.c b/sys/dev/pci/if_stge.c
index 6fbba2743d5..e335c44b9e7 100644
--- a/sys/dev/pci/if_stge.c
+++ b/sys/dev/pci/if_stge.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: if_stge.c,v 1.11 2005/04/25 17:55:51 brad Exp $ */
-/* $NetBSD: if_stge.c,v 1.4 2001/07/25 15:44:48 thorpej Exp $ */
+/* $OpenBSD: if_stge.c,v 1.12 2005/05/23 22:44:19 brad Exp $ */
+/* $NetBSD: if_stge.c,v 1.27 2005/05/16 21:35:32 bouyer Exp $ */
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -47,16 +47,18 @@
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/sockio.h>
+#include <sys/timeout.h>
#include <sys/mbuf.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
#include <sys/device.h>
+#include <sys/queue.h>
#include <net/if.h>
#include <net/if_dl.h>
-#include <net/if_media.h>
#ifdef INET
#include <netinet/in.h>
@@ -66,6 +68,8 @@
#include <netinet/if_ether.h>
#endif
+#include <net/if_media.h>
+
#if NVLAN > 0
#include <net/if_types.h>
#include <net/if_vlan_var.h>
@@ -75,14 +79,17 @@
#include <net/bpf.h>
#endif
-#include <dev/pci/pcireg.h>
-#include <dev/pci/pcivar.h>
-#include <dev/pci/pcidevs.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
#include <dev/mii/mii_bitbang.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
#include <dev/pci/if_stgereg.h>
/*
@@ -399,8 +406,9 @@ stge_attach(struct device *parent, struct device *self, void *aux)
/* Get it out of power save mode if needed. */
if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PWRMGMT, &pmreg, 0)) {
- pmode = pci_conf_read(pc, pa->pa_tag, pmreg + PCI_PMCSR) & 0x3;
- if (pmode == 3) {
+ pmode = pci_conf_read(pc, pa->pa_tag, pmreg + PCI_PMCSR) &
+ PCI_PMCSR_STATE_MASK;
+ if (pmode == PCI_PMCSR_STATE_D3) {
/*
* The card has lost all configuration data in
* this state, so punt.
@@ -410,7 +418,8 @@ stge_attach(struct device *parent, struct device *self, void *aux)
}
if (pmode != 0) {
printf(": waking up from power state D%d\n", pmode);
- pci_conf_write(pc, pa->pa_tag, pmreg + PCI_PMCSR, 0);
+ pci_conf_write(pc, pa->pa_tag, pmreg + PCI_PMCSR,
+ PCI_PMCSR_STATE_D0);
}
}
@@ -476,8 +485,8 @@ stge_attach(struct device *parent, struct device *self, void *aux)
* such chips to 1.
*/
for (i = 0; i < STGE_NTXDESC; i++) {
- if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
- STGE_NTXFRAGS, MCLBYTES, 0, 0,
+ if ((error = bus_dmamap_create(sc->sc_dmat,
+ ETHER_MAX_LEN_JUMBO, STGE_NTXFRAGS, MCLBYTES, 0, 0,
&sc->sc_txsoft[i].ds_dmamap)) != 0) {
printf("%s: unable to create tx DMA map %d, "
"error = %d\n", sc->sc_dev.dv_xname, i, error);
@@ -515,7 +524,7 @@ stge_attach(struct device *parent, struct device *self, void *aux)
/*
* Reading the station address from the EEPROM doesn't seem
- * to work, at least on my sample boards. Instread, since
+ * to work, at least on my sample boards. Instead, since
* the reset sequence does AutoInit, read it from the station
* address registers.
*/
@@ -564,10 +573,7 @@ stge_attach(struct device *parent, struct device *self, void *aux)
ifp->if_ioctl = stge_ioctl;
ifp->if_start = stge_start;
ifp->if_watchdog = stge_watchdog;
-#ifdef fake
- ifp->if_init = stge_init;
- ifp->if_stop = stge_stop;
-#endif
+ IFQ_SET_MAXLEN(&ifp->if_snd, STGE_NTXDESC - 1);
IFQ_SET_READY(&ifp->if_snd);
/*
@@ -851,16 +857,16 @@ stge_start(struct ifnet *ifp)
*/
if (m0->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT) {
STGE_EVCNT_INCR(&sc->sc_ev_txipsum);
- csum_flags |= htole64(TFD_IPChecksumEnable);
+ csum_flags |= TFD_IPChecksumEnable;
}
if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT) {
STGE_EVCNT_INCR(&sc->sc_ev_txtcpsum);
- csum_flags |= htole64(TFD_TCPChecksumEnable);
+ csum_flags |= TFD_TCPChecksumEnable;
}
else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT) {
STGE_EVCNT_INCR(&sc->sc_ev_txudpsum);
- csum_flags |= htole64(TFD_UDPChecksumEnable);
+ csum_flags |= TFD_UDPChecksumEnable;
}
#endif
@@ -960,6 +966,9 @@ stge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
s = splnet();
if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
+ /* Try to get more packets going. */
+ stge_start(ifp);
+
splx(s);
return (error);
}
@@ -1046,6 +1055,9 @@ stge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
error = EINVAL;
}
+ /* Try to get more packets going. */
+ stge_start(ifp);
+
splx(s);
return (error);
}
@@ -1072,12 +1084,20 @@ stge_intr(void *arg)
isr = bus_space_read_2(sc->sc_st, sc->sc_sh, STGE_IntStatusAck);
if ((isr & sc->sc_IntEnable) == 0)
break;
-
+
+ /* Host interface errors. */
+ if (isr & IS_HostError) {
+ printf("%s: Host interface error\n",
+ sc->sc_dev.dv_xname);
+ wantinit = 1;
+ continue;
+ }
+
/* Receive interrupts. */
- if (isr & (IE_RxDMAComplete|IE_RFDListEnd)) {
+ if (isr & (IS_RxDMAComplete|IS_RFDListEnd)) {
STGE_EVCNT_INCR(&sc->sc_ev_rxintr);
stge_rxintr(sc);
- if (isr & IE_RFDListEnd) {
+ if (isr & IS_RFDListEnd) {
printf("%s: receive ring overflow\n",
sc->sc_dev.dv_xname);
/*
@@ -1089,20 +1109,20 @@ stge_intr(void *arg)
}
/* Transmit interrupts. */
- if (isr & (IE_TxDMAComplete|IE_TxComplete)) {
+ if (isr & (IS_TxDMAComplete|IS_TxComplete)) {
#ifdef STGE_EVENT_COUNTERS
- if (isr & IE_TxDMAComplete)
+ if (isr & IS_TxDMAComplete)
STGE_EVCNT_INCR(&sc->sc_ev_txdmaintr);
#endif
stge_txintr(sc);
}
/* Statistics overflow. */
- if (isr & IE_UpdateStats)
+ if (isr & IS_UpdateStats)
stge_stats_update(sc);
/* Transmission errors. */
- if (isr & IE_TxComplete) {
+ if (isr & IS_TxComplete) {
STGE_EVCNT_INCR(&sc->sc_ev_txindintr);
for (;;) {
txstat = bus_space_read_4(sc->sc_st, sc->sc_sh,
@@ -1125,12 +1145,6 @@ stge_intr(void *arg)
wantinit = 1;
}
- /* Host interface errors. */
- if (isr & IE_HostError) {
- printf("%s: Host interface error\n",
- sc->sc_dev.dv_xname);
- wantinit = 1;
- }
}
if (wantinit)
@@ -1482,8 +1496,8 @@ stge_init(struct ifnet *ifp)
*/
memset(sc->sc_txdescs, 0, sizeof(sc->sc_txdescs));
for (i = 0; i < STGE_NTXDESC; i++) {
- sc->sc_txdescs[i].tfd_next =
- (uint64_t) STGE_CDTXADDR(sc, STGE_NEXTTX(i));
+ sc->sc_txdescs[i].tfd_next = htole64(
+ STGE_CDTXADDR(sc, STGE_NEXTTX(i)));
sc->sc_txdescs[i].tfd_control = htole64(TFD_TFDDone);
}
sc->sc_txpending = 0;
@@ -1564,16 +1578,18 @@ stge_init(struct ifnet *ifp)
/*
* Initialize the Rx DMA interrupt control register. We
* request an interrupt after every incoming packet, but
- * defer it for 32us (64 * 512 ns).
+ * defer it for 32us (64 * 512 ns). When the number of
+ * interrupts pending reaches 8, we stop deferring the
+ * interrupt, and signal it immediately.
*/
bus_space_write_4(st, sh, STGE_RxDMAIntCtrl,
- RDIC_RxFrameCount(1) | RDIC_RxDMAWaitTime(512));
+ RDIC_RxFrameCount(8) | RDIC_RxDMAWaitTime(512));
/*
* Initialize the interrupt mask.
*/
- sc->sc_IntEnable = IE_HostError | IE_TxComplete | IE_UpdateStats |
- IE_TxDMAComplete | IE_RxDMAComplete | IE_RFDListEnd;
+ sc->sc_IntEnable = IS_HostError | IS_TxComplete | IS_UpdateStats |
+ IS_TxDMAComplete | IS_RxDMAComplete | IS_RFDListEnd;
bus_space_write_2(st, sh, STGE_IntStatus, 0xffff);
bus_space_write_2(st, sh, STGE_IntEnable, sc->sc_IntEnable);
@@ -1589,8 +1605,8 @@ stge_init(struct ifnet *ifp)
* FIFO, and send an un-PAUSE frame when the FIFO is totally
* empty again.
*/
- bus_space_write_4(st, sh, STGE_FlowOnTresh, 29696 / 16);
- bus_space_write_4(st, sh, STGE_FlowOffThresh, 0);
+ bus_space_write_2(st, sh, STGE_FlowOnTresh, 29696 / 16);
+ bus_space_write_2(st, sh, STGE_FlowOffThresh, 0);
/*
* Set the maximum frame size.
@@ -1786,7 +1802,7 @@ stge_add_rxbuf(struct stge_softc *sc, int idx)
int error;
MGETHDR(m, M_DONTWAIT, MT_DATA);
- if (m == NULL)
+ if (m == NULL)
return (ENOBUFS);
MCLGET(m, M_DONTWAIT);
@@ -1827,11 +1843,12 @@ stge_add_rxbuf(struct stge_softc *sc, int idx)
void
stge_set_filter(struct stge_softc *sc)
{
+ struct arpcom *ac = &sc->sc_arpcom;
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
struct ether_multi *enm;
struct ether_multistep step;
- int h = 0;
- u_int32_t mchash[2] = { 0, 0 };
+ uint32_t crc;
+ uint32_t mchash[2];
sc->sc_ReceiveMode = RM_ReceiveUnicast;
if (ifp->if_flags & IFF_BROADCAST)
@@ -1850,20 +1867,34 @@ stge_set_filter(struct stge_softc *sc)
* select the bit within the register.
*/
- ETHER_FIRST_MULTI(step, &sc->sc_arpcom, enm);
+ memset(mchash, 0, sizeof(mchash));
+
+ ETHER_FIRST_MULTI(step, ac, enm);
if (enm == NULL)
goto done;
while (enm != NULL) {
- if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN))
+ 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.)
+ */
goto allmulti;
- h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) &
- 0x0000003F;
- if (h < 32)
- mchash[0] |= (1 << h);
- else
- mchash[1] |= (1 << (h - 32));
- ETHER_NEXT_MULTI(step, enm);
+ }
+
+ crc = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN);
+
+ /* Just want the 6 least significant bits. */
+ crc &= 0x3f;
+
+ /* Set the corresponding bit in the hash table. */
+ mchash[crc >> 5] |= 1 << (crc & 0x1f);
+
+ ETHER_NEXT_MULTI(step, enm);
}
sc->sc_ReceiveMode |= RM_ReceiveMulticastHash;
@@ -1886,7 +1917,7 @@ stge_set_filter(struct stge_softc *sc)
mchash[1]);
}
- bus_space_write_1(sc->sc_st, sc->sc_sh, STGE_ReceiveMode,
+ bus_space_write_2(sc->sc_st, sc->sc_sh, STGE_ReceiveMode,
sc->sc_ReceiveMode);
}