On 11/27/15 12:43, David Gwynne wrote:
On Wed, Nov 25, 2015 at 08:32:19PM +0000, Fred wrote:

Well with that diff I hit another panic - which seems to be
triggered by the nic:

i also think this is related to the nic. i have started cleaning
dc(4), but would like some tests before going further.

could you guys try this and let me know how it goes? i dont expect
it to fix the problems, but i also dont expect them to get worse.

cheers,
dlg

Index: dc.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/dc.c,v
retrieving revision 1.148
diff -u -p -r1.148 dc.c
--- dc.c        25 Nov 2015 03:09:58 -0000      1.148
+++ dc.c        27 Nov 2015 12:37:04 -0000
@@ -125,8 +125,7 @@
  int dc_intr(void *);
  struct dc_type *dc_devtype(void *);
  int dc_newbuf(struct dc_softc *, int, struct mbuf *);
-int dc_encap(struct dc_softc *, struct mbuf *, u_int32_t *);
-int dc_coal(struct dc_softc *, struct mbuf **);
+int dc_encap(struct dc_softc *, bus_dmamap_t, struct mbuf *, u_int32_t *);

  void dc_pnic_rx_bug_war(struct dc_softc *, int);
  int dc_rx_resync(struct dc_softc *);
@@ -1658,17 +1657,19 @@ hasmac:
            BUS_DMA_NOWAIT, &sc->sc_rx_sparemap) != 0) {
                printf(": can't create rx spare map\n");
                return;
-       }
+       }       

        for (i = 0; i < DC_TX_LIST_CNT; i++) {
                if (bus_dmamap_create(sc->sc_dmat, MCLBYTES,
-                   DC_TX_LIST_CNT - 5, MCLBYTES, 0, BUS_DMA_NOWAIT,
+                   (sc->dc_flags & DC_TX_COALESCE) ? 1 : DC_TX_LIST_CNT - 5,
+                   MCLBYTES, 0, BUS_DMA_NOWAIT,
                    &sc->dc_cdata.dc_tx_chain[i].sd_map) != 0) {
                        printf(": can't create tx map\n");
                        return;
                }
        }
-       if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, DC_TX_LIST_CNT - 5,
+       if (bus_dmamap_create(sc->sc_dmat, MCLBYTES,
+           (sc->dc_flags & DC_TX_COALESCE) ? 1 : DC_TX_LIST_CNT - 5,
            MCLBYTES, 0, BUS_DMA_NOWAIT, &sc->sc_tx_sparemap) != 0) {
                printf(": can't create tx spare map\n");
                return;
@@ -2488,39 +2489,14 @@ dc_intr(void *arg)
   * pointers to the fragment pointers.
   */
  int
-dc_encap(struct dc_softc *sc, struct mbuf *m_head, u_int32_t *txidx)
+dc_encap(struct dc_softc *sc, bus_dmamap_t map, struct mbuf *m, u_int32_t *idx)
  {
        struct dc_desc *f = NULL;
        int frag, cur, cnt = 0, i;
-       bus_dmamap_t map;
-
-       /*
-        * Start packing the mbufs in this chain into
-        * the fragment pointers. Stop when we run out
-        * of fragments or hit the end of the mbuf chain.
-        */
-       map = sc->sc_tx_sparemap;
-
-       if (bus_dmamap_load_mbuf(sc->sc_dmat, map,
-           m_head, BUS_DMA_NOWAIT) != 0)
-               return (ENOBUFS);

-       cur = frag = *txidx;
+       cur = frag = *idx;

        for (i = 0; i < map->dm_nsegs; i++) {
-               if (sc->dc_flags & DC_TX_ADMTEK_WAR) {
-                       if (*txidx != sc->dc_cdata.dc_tx_prod &&
-                           frag == (DC_TX_LIST_CNT - 1)) {
-                               bus_dmamap_unload(sc->sc_dmat, map);
-                               return (ENOBUFS);
-                       }
-               }
-               if ((DC_TX_LIST_CNT -
-                   (sc->dc_cdata.dc_tx_cnt + cnt)) < 5) {
-                       bus_dmamap_unload(sc->sc_dmat, map);
-                       return (ENOBUFS);
-               }
-
                f = &sc->dc_ldata->dc_tx_list[frag];
                f->dc_ctl = htole32(DC_TXCTL_TLINK | map->dm_segs[i].ds_len);
                if (cnt == 0) {
@@ -2535,12 +2511,12 @@ dc_encap(struct dc_softc *sc, struct mbu
        }

        sc->dc_cdata.dc_tx_cnt += cnt;
-       sc->dc_cdata.dc_tx_chain[cur].sd_mbuf = m_head;
+       sc->dc_cdata.dc_tx_chain[cur].sd_mbuf = m;
        sc->sc_tx_sparemap = sc->dc_cdata.dc_tx_chain[cur].sd_map;
        sc->dc_cdata.dc_tx_chain[cur].sd_map = map;
        sc->dc_ldata->dc_tx_list[cur].dc_ctl |= htole32(DC_TXCTL_LASTFRAG);
        if (sc->dc_flags & DC_TX_INTR_FIRSTFRAG)
-               sc->dc_ldata->dc_tx_list[*txidx].dc_ctl |=
+               sc->dc_ldata->dc_tx_list[*idx].dc_ctl |=
                    htole32(DC_TXCTL_FINT);
        if (sc->dc_flags & DC_TX_INTR_ALWAYS)
                sc->dc_ldata->dc_tx_list[cur].dc_ctl |=
@@ -2551,43 +2527,9 @@ dc_encap(struct dc_softc *sc, struct mbu
        bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
            BUS_DMASYNC_PREWRITE);

-       sc->dc_ldata->dc_tx_list[*txidx].dc_status = htole32(DC_TXSTAT_OWN);
-
-       bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap,
-           offsetof(struct dc_list_data, dc_tx_list[*txidx]),
-           sizeof(struct dc_desc) * cnt,
-           BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
-
-       *txidx = frag;
+       sc->dc_ldata->dc_tx_list[*idx].dc_status = htole32(DC_TXSTAT_OWN);

-       return (0);
-}
-
-/*
- * Coalesce an mbuf chain into a single mbuf cluster buffer.
- * Needed for some really badly behaved chips that just can't
- * do scatter/gather correctly.
- */
-int
-dc_coal(struct dc_softc *sc, struct mbuf **m_head)
-{
-       struct mbuf             *m_new, *m;
-
-       m = *m_head;
-       MGETHDR(m_new, M_DONTWAIT, MT_DATA);
-       if (m_new == NULL)
-               return (ENOBUFS);
-       if (m->m_pkthdr.len > MHLEN) {
-               MCLGET(m_new, M_DONTWAIT);
-               if (!(m_new->m_flags & M_EXT)) {
-                       m_freem(m_new);
-                       return (ENOBUFS);
-               }
-       }
-       m_copydata(m, 0, m->m_pkthdr.len, mtod(m_new, caddr_t));
-       m_new->m_pkthdr.len = m_new->m_len = m->m_pkthdr.len;
-       m_freem(m);
-       *m_head = m_new;
+       *idx = frag;

        return (0);
  }
@@ -2599,15 +2541,29 @@ dc_coal(struct dc_softc *sc, struct mbuf
   * physical addresses.
   */

+static inline int
+dc_fits(struct dc_softc *sc, int idx, bus_dmamap_t map)
+{
+       if (sc->dc_flags & DC_TX_ADMTEK_WAR) {
+               if (sc->dc_cdata.dc_tx_prod != idx &&
+                   idx + map->dm_nsegs >= DC_TX_LIST_CNT)
+                       return (0);
+       }
+
+       if (sc->dc_cdata.dc_tx_cnt + map->dm_nsegs + 5 > DC_TX_LIST_CNT)
+               return (0);
+
+       return (1);
+}
+
  void
  dc_start(struct ifnet *ifp)
  {
-       struct dc_softc *sc;
-       struct mbuf *m_head = NULL;
+       struct dc_softc *sc = ifp->if_softc;
+       bus_dmamap_t map;
+       struct mbuf *m;
        int idx;

-       sc = ifp->if_softc;
-
        if (!sc->dc_link && IFQ_LEN(&ifp->if_snd) < 10)
                return;

@@ -2616,37 +2572,50 @@ dc_start(struct ifnet *ifp)

        idx = sc->dc_cdata.dc_tx_prod;

-       while(sc->dc_cdata.dc_tx_chain[idx].sd_mbuf == NULL) {
-               m_head = ifq_deq_begin(&ifp->if_snd);
-               if (m_head == NULL)
-                       break;
-
-               if (sc->dc_flags & DC_TX_COALESCE &&
-                   (m_head->m_next != NULL ||
-                       sc->dc_flags & DC_TX_ALIGN)) {
-                       /* note: dc_coal breaks the poll-and-dequeue rule.
-                        * if dc_coal fails, we lose the packet.
-                        */
-                       ifq_deq_commit(&ifp->if_snd, m_head);
-                       if (dc_coal(sc, &m_head)) {
-                               ifq_set_oactive(&ifp->if_snd);
+       bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap,
+           offsetof(struct dc_list_data, dc_tx_list),
+           sizeof(struct dc_desc) * DC_TX_LIST_CNT,
+           BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+       for (;;) {
+               m = ifq_deq_begin(&ifp->if_snd);
+               if (m == NULL)
+                       break;
+
+               map = sc->sc_tx_sparemap;
+               switch (bus_dmamap_load_mbuf(sc->sc_dmat, map, m,
+                   BUS_DMA_NOWAIT)) {
+               case 0:
+                       break;
+               case EFBIG:
+                       if (m_defrag(m, M_DONTWAIT) == 0 &&
+                           bus_dmamap_load_mbuf(sc->sc_dmat, map, m,
+                            BUS_DMA_NOWAIT) == 0)
                                break;
-                       }
-               }

-               if (dc_encap(sc, m_head, &idx)) {
-                       if ((sc->dc_flags & DC_TX_COALESCE) == 0)
-                               ifq_deq_rollback(&ifp->if_snd, m_head);
+                       /* FALLTHROUGH */
+               default:
+                       ifq_deq_commit(&ifp->if_snd, m);
+                       m_freem(m);
+                       ifp->if_oerrors++;
+                       continue;
+               }

+               if (!dc_fits(sc, idx, map)) {
+                       bus_dmamap_unload(sc->sc_dmat, map);
+                       ifq_deq_rollback(&ifp->if_snd, m);
                        ifq_set_oactive(&ifp->if_snd);
                        break;
                }

                /* now we are committed to transmit the packet */
-               if (sc->dc_flags & DC_TX_COALESCE) {
-                       /* if mbuf is coalesced, it is already dequeued */
-               } else
-                       ifq_deq_commit(&ifp->if_snd, m_head);
+               ifq_deq_commit(&ifp->if_snd, m);
+
+               if (dc_encap(sc, map, m, &idx) != 0) {
+                       m_freem(m);
+                       ifp->if_oerrors++;
+                       continue;
+               }

                /*
                 * If there's a BPF listener, bounce a copy of this frame
@@ -2654,13 +2623,20 @@ dc_start(struct ifnet *ifp)
                 */
  #if NBPFILTER > 0
                if (ifp->if_bpf)
-                       bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
+                       bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
  #endif
+
                if (sc->dc_flags & DC_TX_ONE) {
                        ifq_set_oactive(&ifp->if_snd);
                        break;
                }
        }
+
+       bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap,
+           offsetof(struct dc_list_data, dc_tx_list),
+           sizeof(struct dc_desc) * DC_TX_LIST_CNT,
+           BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
        if (idx == sc->dc_cdata.dc_tx_prod)
                return;



Hi David,

I've been running this diff today - and so far the kernel has been more stable then it has been recently.

Output from ifconfig dc, and dmesg below.

Thanks

Fred

dc0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        lladdr 00:03:ba:13:a8:c7
        priority: 0
        media: Ethernet autoselect (none)
        status: no carrier
        inet 192.168.50.50 netmask 0xffffff00 broadcast 192.168.50.255
dc1: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        lladdr 00:03:ba:13:a8:c8
        priority: 0
        groups: egress
        media: Ethernet autoselect (100baseTX full-duplex)
        status: active
        inet 192.168.50.51 netmask 0xffffff00 broadcast 192.168.50.255

dmesg:OpenBSD 5.8-current (bsddc) #0: Sat Nov 28 14:12:26 GMT 2015
    f...@ultra.crowsons.com:/usr/src/sys/arch/sparc64/compile/bsddc
real mem = 268435456 (256MB)
avail mem = 248209408 (236MB)
mpath0 at root
scsibus0 at mpath0: 256 targets
mainbus0 at root: Sun Fire V100 (UltraSPARC-IIe 500MHz)
cpu0 at mainbus0: SUNW,UltraSPARC-IIe (rev 1.4) @ 500 MHz
cpu0: physical 16K instruction (32 b/l), 16K data (32 b/l), 256K external (64 b/l)
psycho0 at mainbus0: SUNW,sabre, impl 0, version 0, ign 7c0
psycho0: bus range 0-0, PCI bus 0
psycho0: dvma map 60000000-7fffffff
pci0 at psycho0
ebus0 at pci0 dev 7 function 0 "Acer Labs M1533 ISA" rev 0x00
"dma" at ebus0 addr 0-ffff ivec 0x2a not configured
rtc0 at ebus0 addr 70-71: m5819
power0 at ebus0 addr 2000-2007 ivec 0x23
lom0 at ebus0 addr 8010-8011 ivec 0x2a: LOMlite2 rev 3.11
com0 at ebus0 addr 3f8-3ff ivec 0x2b: ns16550a, 16 byte fifo
com0: console
com1 at ebus0 addr 2e8-2ef ivec 0x2b: ns16550a, 16 byte fifo
"flashprom" at ebus0 addr 0-7ffff not configured
alipm0 at pci0 dev 3 function 0 "Acer Labs M7101 Power" rev 0x00: 74KHz clock
iic0 at alipm0
"max1617" at alipm0 addr 0x18 skipped due to alipm0 bugs
spdmem0 at iic0 addr 0x56: 128MB SDRAM registered ECC PC133CL2
spdmem1 at iic0 addr 0x57: 128MB SDRAM registered ECC PC133CL2
dc0 at pci0 dev 12 function 0 "Davicom DM9102" rev 0x31: ivec 0x7c6, address 00:03:ba:13:a8:c7
amphy0 at dc0 phy 1: DM9102 10/100 PHY, rev. 0
dc1 at pci0 dev 5 function 0 "Davicom DM9102" rev 0x31: ivec 0x7dc, address 00:03:ba:13:a8:c8
amphy1 at dc1 phy 1: DM9102 10/100 PHY, rev. 0
ohci0 at pci0 dev 10 function 0 "Acer Labs M5237 USB" rev 0x03: ivec 0x7e4, version 1.0, legacy support pciide0 at pci0 dev 13 function 0 "Acer Labs M5229 UDMA IDE" rev 0xc3: DMA, channel 0 configured to native-PCI, channel 1 configured to native-PCI
pciide0: using ivec 0x7cc for native-PCI interrupt
pciide0: channel 0 disabled (no drives)
wd0 at pciide0 channel 1 drive 0: <WDC WD800BB-00DAA3>
wd0: 16-sector PIO, LBA48, 76319MB, 156301488 sectors
atapiscsi0 at pciide0 channel 1 drive 1
scsibus1 at atapiscsi0: 2 targets
cd0 at scsibus1 targ 0 lun 0: <TEAC, CD-224E, 1.7A> ATAPI 5/cdrom removable
wd0(pciide0:1:0): using PIO mode 4, Ultra-DMA mode 2
cd0(pciide0:1:1): using PIO mode 4, Ultra-DMA mode 2
usb0 at ohci0: USB revision 1.0
uhub0 at usb0 "Acer Labs OHCI root hub" rev 1.00/1.00 addr 1
vscsi0 at root
scsibus2 at vscsi0: 256 targets
softraid0 at root
scsibus3 at softraid0: 256 targets
bootpath: /pci@1f,0/ide@d,0/disk@2,0
root on wd0a (a0af7098621c5786.a) swap on wd0b dump on wd0b

Reply via email to