[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

sf(4) problems - slow upload



Heya,
This is one for the network driver guys.
I've recently gotten an Adaptec 62044 4port NIC, based on the starfire
chipset. Today I've finally gotten around to installing it, just to find
out that when it's configured in 100mbit full-duplex uploads stall after
about 25k gets through, then the connection just dies. Downloads at
100mbit/full-duplex work like a charm. Also 10mbit operation works like
it should for up- and downloads. To verify that the switch wasn't the
problem I tested with a crossover cable and another box, still no go.

This is a sample of the ´netstat -in´ output after trying to upload
something, sf1 was the active NIC.

Name  Mtu   Network     Address           Ipkts Ierrs  Opkts Oerrs Colls
sf0   1500  <DEFANGED_Link>      00:00:d1:ec:c0:45     4     0      7     0     0
sf0   1500  fe80::%sf0/ fe80::200:d1ff:fe     4     0      7     0     0
sf0   1500  81.82.124/2 81.82.124.133         4     0      7     0     0
sf1   1500  <DEFANGED_Link>      00:00:d1:ec:c0:46    72     0     81    24     0
sf1   1500  192.168.0/2 192.168.0.1          72     0     81    24     0
sf1   1500  fe80::%sf1/ fe80::200:d1ff:fe    72     0     81    24     0
sf2   1500  <DEFANGED_Link>      00:00:d1:ec:c0:47     2     0      4     0     0
sf2   1500  192.168.255 192.168.255.2         2     0      4     0     0
sf2   1500  fe80::%sf2/ fe80::200:d1ff:fe     2     0      4     0     0

As you can see there are a lot of Oerrs.

Now looking through the source I see this driver was initially imported
from FreeBSD, and looking through the FreeBSD cvs logs it seems they've
also had this problem. On the following 2 pages there have references
to the TX problems:
http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/pci/if_sf.c
http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/pci/if_sfreg.h

Now, after looking through their changes it seems they can be ported to
OpenBSD without to much hassle. So I took the patches and applied them
to the OpenBSD code. I can't really figure out what some of the stuff
does, it's the second time that I've taken a look at a driver. But with
the small patch I cooked up at least the uploads starts working in
100mbit mode at full speed. Both patches are included below in this
email, as well as a dmesg. The system is i386, dec30 snapshot. So, to
conclude, it would be nice if someone who is into network drivers could
perhaps port the FreeBSD changes -correctly- to OpenBSD, unlike my own
crooked attempt.


++ patch sys/dec/pci/if_sfreg.h ++

Index: if_sfreg.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_sfreg.h,v
retrieving revision 1.5
diff -u -r1.5 if_sfreg.h
--- if_sfreg.h  8 Apr 2002 06:06:10 -0000       1.5
+++ if_sfreg.h  3 Jan 2003 20:57:45 -0000
@@ -346,7 +346,8 @@
        (SF_IMR_RXDQ2_NOBUFS|SF_IMR_RXDQ1_DMADONE|SF_IMR_RXDQ2_DMADONE| \
         SF_IMR_TX_TXDONE|SF_IMR_RXDQ1_NOBUFS|SF_IMR_RXDQ2_DMADONE|     \
         SF_IMR_NORMALINTR|SF_IMR_ABNORMALINTR|SF_IMR_TXCQ_NOBUFS|      \
-        SF_IMR_RXCQ1_NOBUFS|SF_IMR_RXCQ2_NOBUFS|SF_IMR_STATSOFLOW)
+        SF_IMR_RXCQ1_NOBUFS|SF_IMR_RXCQ2_NOBUFS|SF_IMR_STATSOFLOW|     \
+        SF_IMR_TX_LOFIFO)

 /* TX descriptor queue control registers */
 #define SF_TXDQCTL_DESCTYPE    0x00000007


++ patch sys/dec/pci/if_sfreg.h (ugly and most likely incorrect) ++

Index: if_sf.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_sf.c,v
retrieving revision 1.18
diff -u -r1.18 if_sf.c
--- if_sf.c     19 Nov 2002 18:40:17 -0000      1.18
+++ if_sf.c     3 Jan 2003 20:58:22 -0000
@@ -161,6 +161,7 @@

 u_int32_t csr_read_4(struct sf_softc *, int);
 void csr_write_4(struct sf_softc *, int, u_int32_t);
+void sf_txthresh_adjust(struct sf_softc *);

 #define SF_SETBIT(sc, reg, x)  \
        csr_write_4(sc, reg, csr_read_4(sc, reg) | x)
@@ -955,18 +956,22 @@
        while (cmpconsidx != cmpprodidx) {
                cur_cmp = &sc->sf_ldata->sf_tx_clist[cmpconsidx];
                cur_tx = &sc->sf_ldata->sf_tx_dlist[cur_cmp->sf_index >> 7];
-               SF_INC(cmpconsidx, SF_TX_CLIST_CNT);

                if (cur_cmp->sf_txstat & SF_TXSTAT_TX_OK)
                        ifp->if_opackets++;
-               else
+               else {
+                       if (cur_cmp->sf_txstat & SF_TXSTAT_TX_UNDERRUN)
+                               sf_txthresh_adjust(sc);
                        ifp->if_oerrors++;
+               }

                sc->sf_tx_cnt--;
                if (cur_tx->sf_mbuf != NULL) {
                        m_freem(cur_tx->sf_mbuf);
                        cur_tx->sf_mbuf = NULL;
-               }
+               } else
+                       break;
+               SF_INC(cmpconsidx, SF_TX_CLIST_CNT);
        }

        ifp->if_timer = 0;
@@ -979,6 +984,30 @@
        return;
 }

+void sf_txthresh_adjust(sc)
+       struct sf_softc     *sc;
+{
+       u_int32_t       txfctl;
+       u_int8_t        txthresh;
+
+       txfctl = csr_read_4(sc, SF_TX_FRAMCTL);
+       txthresh = txfctl & SF_TXFRMCTL_TXTHRESH;
+       if (txthresh < 0xFF) {
+               txthresh++;
+               txfctl &= ~SF_TXFRMCTL_TXTHRESH;
+               txfctl |= txthresh;
+#ifdef DIAGNOSTIC
+       printf("sf%d: tx underrun, increasing "
+         "tx threshold to %d bytes\n",
+         sc->sf_unit, txthresh * 4);
+#endif
+
+       csr_write_4(sc, SF_TX_FRAMCTL, txfctl);
+       }
+
+       return;
+}
+
 int sf_intr(arg)
        void                    *arg;
 {
@@ -1009,9 +1038,15 @@
                if (status & SF_ISR_RXDQ1_DMADONE)
                        sf_rxeof(sc);

-               if (status & SF_ISR_TX_TXDONE)
+               if (status & SF_ISR_TX_TXDONE ||
+                   status & SF_ISR_TX_DMADONE ||
+                   status & SF_ISR_TX_QUEUEDONE ||
+                   status & SF_ISR_TX_LOFIFO)
                        sf_txeof(sc);

+               if (status & SF_ISR_TX_LOFIFO)
+                       sf_txthresh_adjust(sc);
+
                if (status & SF_ISR_ABNORMALINTR) {
                        if (status & SF_ISR_STATSOFLOW) {
                                timeout_del(&sc->sc_stats_tmo);
@@ -1216,7 +1251,7 @@

        sc = ifp->if_softc;

-       if (!sc->sf_link)
+       if (!sc->sf_link && ifp->if_snd.ifq_len < 10)
                return;

        if (ifp->if_flags & IFF_OACTIVE)
@@ -1225,6 +1260,13 @@
        txprod = csr_read_4(sc, SF_TXDQ_PRODIDX);
        i = SF_IDX_HI(txprod) >> 4;

+       if (sc->sf_ldata->sf_tx_dlist[i].sf_mbuf != NULL) {
+               printf("sf%d: TX ring full, resetting\n", sc->sf_unit);
+               sf_init(sc);
+               txprod = csr_read_4(sc, SF_TXDQ_PRODIDX);
+               i = SF_IDX_HI(txprod) >> 4;
+       }
+
        while(sc->sf_ldata->sf_tx_dlist[i].sf_mbuf == NULL) {
                IFQ_DEQUEUE(&ifp->if_snd, m_head);
                if (m_head == NULL)
@@ -1247,7 +1289,10 @@

                SF_INC(i, SF_TX_DLIST_CNT);
                sc->sf_tx_cnt++;
-               if (sc->sf_tx_cnt == (SF_TX_DLIST_CNT - 2))
+               /*
+                * Don't get the TX DMA queue get too full.
+                */
+               if (sc->sf_tx_cnt > 64)
                        break;
        }


++ dmesg ++

OpenBSD 3.2-current (GENERIC) #68: Mon Dec 30 13:45:19 MST 2002
    deraadt_(_at_)_i386_(_dot_)_openbsd_(_dot_)_org:/usr/src/sys/arch/i386/compile/GENERIC
cpu0: F00F bug workaround installed
cpu0: Intel Pentium/MMX ("GenuineIntel" 586-class) 199 MHz
cpu0: FPU,V86,DE,PSE,TSC,MSR,MCE,CX8,MMX
real mem  = 100249600 (97900K)
avail mem = 87265280 (85220K)
using 1249 buffers containing 5115904 bytes (4996K) of memory
mainbus0 (root)
bios0 at mainbus0: AT/286+(00) BIOS, date 01/15/97, BIOS32 rev. 0 @ 0xfd9e0
pcibios0 at bios0: rev. 2.1 @ 0xf0000/0x10000
pcibios0: PCI BIOS has 7 Interrupt Routing table entries
pcibios0: PCI Interrupt Router at 000:07:0 ("Intel 82371SB PCI-ISA" rev 0x00)
pcibios0: PCI bus #1 is the last bus
bios0: ROM list: 0xc0000/0x8000 0xea000/0x2000
pci0 at mainbus0 bus 0: configuration mode 1 (no bios)
pchb0 at pci0 dev 0 function 0 "Intel 82439HX" rev 0x03
pcib0 at pci0 dev 7 function 0 "Intel 82371SB PCI-ISA" rev 0x01
pciide0 at pci0 dev 7 function 1 "Intel 82371SB IDE" rev 0x00: DMA, channel 0 wired to compatibility, channel 1 wired to compatibility
wd0 at pciide0 channel 0 drive 0: <WDC AC35100L>
wd0: 16-sector PIO, LBA, 4924MB, 10672 cyl, 15 head, 63 sec, 10085040 sectors
wd1 at pciide0 channel 0 drive 1: <WDC AC26400B>
wd1: 16-sector PIO, LBA, 6149MB, 13328 cyl, 15 head, 63 sec, 12594960 sectors
wd0(pciide0:0:0): using PIO mode 4, DMA mode 2
wd1(pciide0:0:1): using PIO mode 4, DMA mode 2
pciide0: channel 1 ignored (disabled)
vga1 at pci0 dev 8 function 0 "S3 ViRGE DX/GX" rev 0x01
wsdisplay0 at vga1: console (80x25, vt100 emulation)
wsdisplay0: screen 1-5 added (80x25, vt100 emulation)
ppb0 at pci0 dev 13 function 0 "DEC 21154 PCI-PCI" rev 0x02
pci1 at ppb0 bus 1
sf0 at pci1 dev 4 function 0 "Adaptec AIC-6915" rev 0x03: irq 5 address 00:00:d1:ec:c0:45
sqphy0 at sf0 phy 1: Seeq 80220 10/100 media interface, rev. 1
sf1 at pci1 dev 5 function 0 "Adaptec AIC-6915" rev 0x03: irq 9 address 00:00:d1:ec:c0:46
sqphy1 at sf1 phy 1: Seeq 80220 10/100 media interface, rev. 1
sf2 at pci1 dev 6 function 0 "Adaptec AIC-6915" rev 0x03: irq 11 address 00:00:d1:ec:c0:47
sqphy2 at sf2 phy 1: Seeq 80220 10/100 media interface, rev. 1
sf3 at pci1 dev 7 function 0 "Adaptec AIC-6915" rev 0x03: irq 10 address 00:00:d1:ec:c0:48
sqphy3 at sf3 phy 1: Seeq 80220 10/100 media interface, rev. 1
xl0 at pci0 dev 15 function 0 "3Com 3c905B 100Base-TX" rev 0x30: irq 11 address 00:10:5a:f7:17:af
exphy0 at xl0 phy 24: 3Com internal media interface
isa0 at pcib0
isadma0 at isa0
pckbc0 at isa0 port 0x60/5
pckbd0 at pckbc0 (kbd slot)
pckbc0: using irq 1 for kbd slot
wskbd0 at pckbd0: console keyboard, using wsdisplay0
pcppi0 at isa0 port 0x61
midi0 at pcppi0: <PC speaker>
sysbeep0 at pcppi0
npx0 at isa0 port 0xf0/16: using exception 16
pccom0 at isa0 port 0x3f8/8 irq 4: ns16550a, 16 byte fifo
pccom1 at isa0 port 0x2f8/8 irq 3: ns16550a, 16 byte fifo
fdc0 at isa0 port 0x3f0/6 irq 6 drq 2
fd0 at fdc0 drive 0: 1.44MB 80 cyl, 2 head, 18 sec
biomask 4040 netmask 4e60 ttymask 4e62
pctr: 586-class performance counters and user-level cycle counter enabled
dkcsum: wd0 matched BIOS disk 80
dkcsum: wd1 matched BIOS disk 81
root on wd0a
rootdev=0x0 rrootdev=0x300 rawdev=0x302


// nick