svn commit: r208995 - stable/7/sys/dev/bge
Anders Nordby
anders at FreeBSD.org
Tue Jun 29 08:06:22 UTC 2010
Hi!
Is it possible to get this fix into FreeBSD 7.3-RELEASE?
Without this fix I have serious issues with my bge NICs:
- packet loss around 10%.
- transferrate (scp) is 10% of expected, 2 MB/sec instead of 20 when
testing.
- get "Corrupted MAC on input" while synchronizing large directories
using rsync over SSH.
It seems we also discussed this matter on -fs, where I had issues on a
ZFS+NFS file server. After updating to a newer 8.1 install (which has
the fix) the problem went away.
If this can not make it into 7.3, I and other people using 7.x have to
manually patch this or follow RELENG_7 which not everyone wants to. The
bge driver is such a common server driver, I think this should be rolled
back into affected releases.
Regards,
Anders.
On Thu, Jun 10, 2010 at 06:04:25PM +0000, Pyun YongHyeon wrote:
> Author: yongari
> Date: Thu Jun 10 18:04:25 2010
> New Revision: 208995
> URL: http://svn.freebsd.org/changeset/base/208995
>
> Log:
> MFC r208862:
> Fix a bug introduced in r199011. When bge(4) reuses loaded RX
> buffers it should also reinitialize RX descriptors otherwise some
> stale data could be passed to controller. This could end up with
> mbuf double free or unexpected NULL pointer dereference in upper
> stack. To fix the issue, save loaded buffer's length and
> reinitialize RX descriptors with the saved value whenever bge(4)
> reuses the loaded RX buffers.
> While I'm here, increase the number of RX buffers to 512 from 256.
> This simplifies RX buffer handling as well as giving more RX
> buffers. Controller supports just fixed number of RX buffers
> (i.e. 512) and bge(4) used to rely on hope that our CPU is fast
> enough to keep up with the controller. With this change, bge(4)
> will use 1MB for RX buffers but I don't think it would cause
> problems in these days.
>
> Reported by: marcel
> Tested by: marcel
>
> Modified:
> stable/7/sys/dev/bge/if_bge.c
> stable/7/sys/dev/bge/if_bgereg.h
> Directory Properties:
> stable/7/sys/ (props changed)
> stable/7/sys/cddl/contrib/opensolaris/ (props changed)
> stable/7/sys/contrib/dev/acpica/ (props changed)
> stable/7/sys/contrib/pf/ (props changed)
>
> Modified: stable/7/sys/dev/bge/if_bge.c
> ==============================================================================
> --- stable/7/sys/dev/bge/if_bge.c Thu Jun 10 17:59:47 2010 (r208994)
> +++ stable/7/sys/dev/bge/if_bge.c Thu Jun 10 18:04:25 2010 (r208995)
> @@ -400,6 +400,8 @@ static void bge_setpromisc(struct bge_so
> static void bge_setmulti(struct bge_softc *);
> static void bge_setvlan(struct bge_softc *);
>
> +static __inline void bge_rxreuse_std(struct bge_softc *, int);
> +static __inline void bge_rxreuse_jumbo(struct bge_softc *, int);
> static int bge_newbuf_std(struct bge_softc *, int);
> static int bge_newbuf_jumbo(struct bge_softc *, int);
> static int bge_init_rx_ring_std(struct bge_softc *);
> @@ -949,6 +951,7 @@ bge_newbuf_std(struct bge_softc *sc, int
> sc->bge_cdata.bge_rx_std_dmamap[i] = sc->bge_cdata.bge_rx_std_sparemap;
> sc->bge_cdata.bge_rx_std_sparemap = map;
> sc->bge_cdata.bge_rx_std_chain[i] = m;
> + sc->bge_cdata.bge_rx_std_seglen[i] = segs[0].ds_len;
> r = &sc->bge_ldata.bge_rx_std_ring[sc->bge_std];
> r->bge_addr.bge_addr_lo = BGE_ADDR_LO(segs[0].ds_addr);
> r->bge_addr.bge_addr_hi = BGE_ADDR_HI(segs[0].ds_addr);
> @@ -1006,6 +1009,11 @@ bge_newbuf_jumbo(struct bge_softc *sc, i
> sc->bge_cdata.bge_rx_jumbo_sparemap;
> sc->bge_cdata.bge_rx_jumbo_sparemap = map;
> sc->bge_cdata.bge_rx_jumbo_chain[i] = m;
> + sc->bge_cdata.bge_rx_jumbo_seglen[i][0] = 0;
> + sc->bge_cdata.bge_rx_jumbo_seglen[i][1] = 0;
> + sc->bge_cdata.bge_rx_jumbo_seglen[i][2] = 0;
> + sc->bge_cdata.bge_rx_jumbo_seglen[i][3] = 0;
> +
> /*
> * Fill in the extended RX buffer descriptor.
> */
> @@ -1018,18 +1026,22 @@ bge_newbuf_jumbo(struct bge_softc *sc, i
> r->bge_addr3.bge_addr_lo = BGE_ADDR_LO(segs[3].ds_addr);
> r->bge_addr3.bge_addr_hi = BGE_ADDR_HI(segs[3].ds_addr);
> r->bge_len3 = segs[3].ds_len;
> + sc->bge_cdata.bge_rx_jumbo_seglen[i][3] = segs[3].ds_len;
> case 3:
> r->bge_addr2.bge_addr_lo = BGE_ADDR_LO(segs[2].ds_addr);
> r->bge_addr2.bge_addr_hi = BGE_ADDR_HI(segs[2].ds_addr);
> r->bge_len2 = segs[2].ds_len;
> + sc->bge_cdata.bge_rx_jumbo_seglen[i][2] = segs[2].ds_len;
> case 2:
> r->bge_addr1.bge_addr_lo = BGE_ADDR_LO(segs[1].ds_addr);
> r->bge_addr1.bge_addr_hi = BGE_ADDR_HI(segs[1].ds_addr);
> r->bge_len1 = segs[1].ds_len;
> + sc->bge_cdata.bge_rx_jumbo_seglen[i][1] = segs[1].ds_len;
> case 1:
> r->bge_addr0.bge_addr_lo = BGE_ADDR_LO(segs[0].ds_addr);
> r->bge_addr0.bge_addr_hi = BGE_ADDR_HI(segs[0].ds_addr);
> r->bge_len0 = segs[0].ds_len;
> + sc->bge_cdata.bge_rx_jumbo_seglen[i][0] = segs[0].ds_len;
> break;
> default:
> panic("%s: %d segments\n", __func__, nsegs);
> @@ -1041,12 +1053,6 @@ bge_newbuf_jumbo(struct bge_softc *sc, i
> return (0);
> }
>
> -/*
> - * The standard receive ring has 512 entries in it. At 2K per mbuf cluster,
> - * that's 1MB or memory, which is a lot. For now, we fill only the first
> - * 256 ring entries and hope that our CPU is fast enough to keep up with
> - * the NIC.
> - */
> static int
> bge_init_rx_ring_std(struct bge_softc *sc)
> {
> @@ -1054,7 +1060,7 @@ bge_init_rx_ring_std(struct bge_softc *s
>
> bzero(sc->bge_ldata.bge_rx_std_ring, BGE_STD_RX_RING_SZ);
> sc->bge_std = 0;
> - for (i = 0; i < BGE_SSLOTS; i++) {
> + for (i = 0; i < BGE_STD_RX_RING_CNT; i++) {
> if ((error = bge_newbuf_std(sc, i)) != 0)
> return (error);
> BGE_INC(sc->bge_std, BGE_STD_RX_RING_CNT);
> @@ -1063,8 +1069,8 @@ bge_init_rx_ring_std(struct bge_softc *s
> bus_dmamap_sync(sc->bge_cdata.bge_rx_std_ring_tag,
> sc->bge_cdata.bge_rx_std_ring_map, BUS_DMASYNC_PREWRITE);
>
> - sc->bge_std = i - 1;
> - bge_writembx(sc, BGE_MBX_RX_STD_PROD_LO, sc->bge_std);
> + sc->bge_std = 0;
> + bge_writembx(sc, BGE_MBX_RX_STD_PROD_LO, BGE_STD_RX_RING_CNT - 1);
>
> return (0);
> }
> @@ -1106,14 +1112,14 @@ bge_init_rx_ring_jumbo(struct bge_softc
> bus_dmamap_sync(sc->bge_cdata.bge_rx_jumbo_ring_tag,
> sc->bge_cdata.bge_rx_jumbo_ring_map, BUS_DMASYNC_PREWRITE);
>
> - sc->bge_jumbo = i - 1;
> + sc->bge_jumbo = 0;
>
> rcb = &sc->bge_ldata.bge_info.bge_jumbo_rx_rcb;
> rcb->bge_maxlen_flags = BGE_RCB_MAXLEN_FLAGS(0,
> BGE_RCB_FLAG_USE_EXT_RX_BD);
> CSR_WRITE_4(sc, BGE_RX_JUMBO_RCB_MAXLEN_FLAGS, rcb->bge_maxlen_flags);
>
> - bge_writembx(sc, BGE_MBX_RX_JUMBO_PROD_LO, sc->bge_jumbo);
> + bge_writembx(sc, BGE_MBX_RX_JUMBO_PROD_LO, BGE_JUMBO_RX_RING_CNT - 1);
>
> return (0);
> }
> @@ -3299,6 +3305,33 @@ bge_reset(struct bge_softc *sc)
> return(0);
> }
>
> +static __inline void
> +bge_rxreuse_std(struct bge_softc *sc, int i)
> +{
> + struct bge_rx_bd *r;
> +
> + r = &sc->bge_ldata.bge_rx_std_ring[sc->bge_std];
> + r->bge_flags = BGE_RXBDFLAG_END;
> + r->bge_len = sc->bge_cdata.bge_rx_std_seglen[i];
> + r->bge_idx = i;
> + BGE_INC(sc->bge_std, BGE_STD_RX_RING_CNT);
> +}
> +
> +static __inline void
> +bge_rxreuse_jumbo(struct bge_softc *sc, int i)
> +{
> + struct bge_extrx_bd *r;
> +
> + r = &sc->bge_ldata.bge_rx_jumbo_ring[sc->bge_jumbo];
> + r->bge_flags = BGE_RXBDFLAG_JUMBO_RING | BGE_RXBDFLAG_END;
> + r->bge_len0 = sc->bge_cdata.bge_rx_jumbo_seglen[i][0];
> + r->bge_len1 = sc->bge_cdata.bge_rx_jumbo_seglen[i][1];
> + r->bge_len2 = sc->bge_cdata.bge_rx_jumbo_seglen[i][2];
> + r->bge_len3 = sc->bge_cdata.bge_rx_jumbo_seglen[i][3];
> + r->bge_idx = i;
> + BGE_INC(sc->bge_jumbo, BGE_JUMBO_RX_RING_CNT);
> +}
> +
> /*
> * Frame reception handling. This is called if there's a frame
> * on the receive return list.
> @@ -3362,24 +3395,24 @@ bge_rxeof(struct bge_softc *sc, uint16_t
> jumbocnt++;
> m = sc->bge_cdata.bge_rx_jumbo_chain[rxidx];
> if (cur_rx->bge_flags & BGE_RXBDFLAG_ERROR) {
> - BGE_INC(sc->bge_jumbo, BGE_JUMBO_RX_RING_CNT);
> + bge_rxreuse_jumbo(sc, rxidx);
> continue;
> }
> if (bge_newbuf_jumbo(sc, rxidx) != 0) {
> - BGE_INC(sc->bge_jumbo, BGE_JUMBO_RX_RING_CNT);
> + bge_rxreuse_jumbo(sc, rxidx);
> ifp->if_iqdrops++;
> continue;
> }
> BGE_INC(sc->bge_jumbo, BGE_JUMBO_RX_RING_CNT);
> } else {
> stdcnt++;
> + m = sc->bge_cdata.bge_rx_std_chain[rxidx];
> if (cur_rx->bge_flags & BGE_RXBDFLAG_ERROR) {
> - BGE_INC(sc->bge_std, BGE_STD_RX_RING_CNT);
> + bge_rxreuse_std(sc, rxidx);
> continue;
> }
> - m = sc->bge_cdata.bge_rx_std_chain[rxidx];
> if (bge_newbuf_std(sc, rxidx) != 0) {
> - BGE_INC(sc->bge_std, BGE_STD_RX_RING_CNT);
> + bge_rxreuse_std(sc, rxidx);
> ifp->if_iqdrops++;
> continue;
> }
>
> Modified: stable/7/sys/dev/bge/if_bgereg.h
> ==============================================================================
> --- stable/7/sys/dev/bge/if_bgereg.h Thu Jun 10 17:59:47 2010 (r208994)
> +++ stable/7/sys/dev/bge/if_bgereg.h Thu Jun 10 18:04:25 2010 (r208995)
> @@ -2561,6 +2561,8 @@ struct bge_chain_data {
> struct mbuf *bge_tx_chain[BGE_TX_RING_CNT];
> struct mbuf *bge_rx_std_chain[BGE_STD_RX_RING_CNT];
> struct mbuf *bge_rx_jumbo_chain[BGE_JUMBO_RX_RING_CNT];
> + int bge_rx_std_seglen[BGE_STD_RX_RING_CNT];
> + int bge_rx_jumbo_seglen[BGE_JUMBO_RX_RING_CNT][4];
> };
>
> struct bge_dmamap_arg {
> _______________________________________________
> svn-src-stable-7 at freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/svn-src-stable-7
> To unsubscribe, send any mail to "svn-src-stable-7-unsubscribe at freebsd.org"
--
Anders.
More information about the svn-src-stable
mailing list