From nobody@FreeBSD.org  Thu Oct 16 09:13:31 2008
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 237DF1065686
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 16 Oct 2008 09:13:31 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id 120458FC20
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 16 Oct 2008 09:13:31 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.3/8.14.3) with ESMTP id m9G9DU9u096541
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 16 Oct 2008 09:13:30 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.3/8.14.3/Submit) id m9G9DUGm096540;
	Thu, 16 Oct 2008 09:13:30 GMT
	(envelope-from nobody)
Message-Id: <200810160913.m9G9DUGm096540@www.freebsd.org>
Date: Thu, 16 Oct 2008 09:13:30 GMT
From: Marcin Kucharczyk <marcinkk@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: NIC with Realtek 8139 (rl driver) doesn't work with RAM higher than 4GB
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         128143
>Category:       kern
>Synopsis:       [rl] NIC Realtek 8139 doesn't work with RAM higher than 4GB
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    yongari
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Oct 16 09:20:00 UTC 2008
>Closed-Date:    Mon Jan 12 03:56:40 UTC 2009
>Last-Modified:  Mon Jan 12 03:56:40 UTC 2009
>Originator:     Marcin Kucharczyk
>Release:        6.3-RELEASE-p5
>Organization:
>Environment:
FreeBSD main.mini.net.pl 6.3-RELEASE-p5 FreeBSD 6.3-RELEASE-p5 #11: Sat Oct  4 11:25:20 CEST 2008     marcinkk@main.mini.net.pl:/usr/obj/usr/src/sys/MAIN  amd64
>Description:
The system: Gigabyte GA-M55plus-S3G (NVIDIA Geforce 6100 + nForce 430 chipset) + Athlon 64 X2 + 6GB RAM.

The system has two NICs:
1. Integrated NVIDIA card (nve driver)
2. Realtek 8139 card (by Edimax or by Asmax) at PCI port (rl driver)

Few days ago I've upgraded system memory to 6GB and I've noticed that network communication on rl0 was lost. I've tried:

- ifconfig: works ok, autoselect recognize 100baseTX connection;
- arp: also works, MAC addresses of connected devices are proprly discovered;
- ping: 
  - ping to IP address of rl0 works
  - ping to any external IP fails, any external communication doesn't work :(

Next I've changed system memory size to 4GB. The communication was partialy restored - ping works with about 25% lost packet. After removing another 1GB, so with 3GB, everything works just fine.

At the same time nve0 card works properly.
>How-To-Repeat:
Check other Realtek 8139 in similar configuration?
>Fix:
The fix ... I've bought Intel 1000 GT, the em driver and everything works ok with 6GB of RAM.

>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->feedback 
State-Changed-By: gavin 
State-Changed-When: Thu Oct 16 14:25:16 UTC 2008 
State-Changed-Why:  
User has been asked for feeback 


Responsible-Changed-From-To: freebsd-amd64->freebsd-bin 
Responsible-Changed-By: gavin 
Responsible-Changed-When: Thu Oct 16 14:25:16 UTC 2008 
Responsible-Changed-Why:  
Probably not amd64 specific 

http://www.freebsd.org/cgi/query-pr.cgi?pr=128143 
Responsible-Changed-From-To: freebsd-bin->gavin 
Responsible-Changed-By: gavin 
Responsible-Changed-When: Thu Oct 16 14:31:29 UTC 2008 
Responsible-Changed-Why:  
Track 

http://www.freebsd.org/cgi/query-pr.cgi?pr=128143 

From: Gavin Atkinson <gavin@FreeBSD.org>
To: Marcin Kucharczyk <marcinkk@gmail.com>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/128143: [rl] NIC Realtek 8139 doesn't work with RAM higher
 than 4GB
Date: Thu, 16 Oct 2008 15:31:49 +0100 (BST)

   This message is in MIME format.  The first part should be readable text,
   while the remaining parts are likely unreadable without MIME-aware tools.
 
 --0-1352983621-1224167509=:22650
 Content-Type: TEXT/PLAIN; charset=US-ASCII; format=flowed
 
 
 Could you test the attached patch please?
 
 Thanks,
 
 Gavin
 --0-1352983621-1224167509=:22650
 Content-Type: TEXT/PLAIN; charset=US-ASCII; name=if_rl-32bit.diff
 Content-Transfer-Encoding: BASE64
 Content-ID: <20081016153149.M22650@ury.york.ac.uk>
 Content-Description: 
 Content-Disposition: attachment; filename=if_rl-32bit.diff
 
 SW5kZXg6IHNyYy9zeXMvcGNpL2lmX3JsLmMNCj09PT09PT09PT09PT09PT09
 PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09
 PT09PT0NClJDUyBmaWxlOiAvaG9tZS9uY3ZzL3NyYy9zeXMvcGNpL2lmX3Js
 LmMsdg0KcmV0cmlldmluZyByZXZpc2lvbiAxLjE3NQ0KZGlmZiAtdSAtcjEu
 MTc1IGlmX3JsLmMNCi0tLSBzcmMvc3lzL3BjaS9pZl9ybC5jCTE2IEp1biAy
 MDA4IDE4OjMyOjIwIC0wMDAwCTEuMTc1DQorKysgc3JjL3N5cy9wY2kvaWZf
 cmwuYwkxNiBPY3QgMjAwOCAxNDoyNDowOCAtMDAwMA0KQEAgLTg4Niw3ICs4
 ODYsNyBAQA0KIAkgKi8NCiAJZXJyb3IgPSBidXNfZG1hX3RhZ19jcmVhdGUo
 c2MtPnJsX3BhcmVudF90YWcsCS8qIHBhcmVudCAqLw0KIAkJCTEsIDAsCQkJ
 LyogYWxpZ25tZW50LCBib3VuZGFyeSAqLw0KLQkJCUJVU19TUEFDRV9NQVhB
 RERSLAkvKiBsb3dhZGRyICovDQorCQkJQlVTX1NQQUNFX01BWEFERFJfMzJC
 SVQsLyogbG93YWRkciAqLw0KIAkJCUJVU19TUEFDRV9NQVhBRERSLAkvKiBo
 aWdoYWRkciAqLw0KIAkJCU5VTEwsIE5VTEwsCQkvKiBmaWx0ZXIsIGZpbHRl
 cmFyZyAqLw0KIAkJCVJMX1JYQlVGTEVOICsgMTUxOCwgMSwJLyogbWF4c2l6
 ZSxuc2VnbWVudHMgKi8NCg==
 
 --0-1352983621-1224167509=:22650--
State-Changed-From-To: feedback->open 
State-Changed-By: gavin 
State-Changed-When: Fri Oct 17 14:29:23 UTC 2008 
State-Changed-Why:  
Submitter has tested patch but it makes no difference. 


Responsible-Changed-From-To: gavin->freebsd-net 
Responsible-Changed-By: gavin 
Responsible-Changed-When: Fri Oct 17 14:29:23 UTC 2008 
Responsible-Changed-Why:  
Over to maintainers 

http://www.freebsd.org/cgi/query-pr.cgi?pr=128143 
Responsible-Changed-From-To: freebsd-net->yongari 
Responsible-Changed-By: yongari 
Responsible-Changed-When: Mon Oct 20 06:46:47 UTC 2008 
Responsible-Changed-Why:  
It looks like rl(4) requires bus_dma(9) cleanup. 
Grab. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=128143 
State-Changed-From-To: open->feedback 
State-Changed-By: yongari 
State-Changed-When: Mon Oct 20 10:54:43 UTC 2008 
State-Changed-Why:  
Would you try bus_dma(9) patch at the following URL? 
http://people.freebsd.org/~yongari/rl.busdma.patch 

http://www.freebsd.org/cgi/query-pr.cgi?pr=128143 
State-Changed-From-To: feedback->patched 
State-Changed-By: yongari 
State-Changed-When: Sat Oct 25 04:02:14 UTC 2008 
State-Changed-Why:  
Submitter tested the patch and patch was committed to HEAD(r184240). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=128143 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/128143: commit references a PR
Date: Mon, 12 Jan 2009 03:48:41 +0000 (UTC)

 Author: yongari
 Date: Mon Jan 12 03:48:25 2009
 New Revision: 187080
 URL: http://svn.freebsd.org/changeset/base/187080
 
 Log:
   MFC r184240:
     Various bus_dma(9) fixes.
      - The hardware does not support DAC so limit DMA address space to
        4GB.
      - Removed BUS_DMA_ALLOC_NOW flag.
      - Created separated Tx buffer and Rx buffer DMA tags. Previously
        it used to single DMA tag and it was not possible to specify
        different DMA restrictions.
      - Apply 4 bytes alignment limitation of Tx buffer.
      - Apply 8 bytes alignment limitation of Rx buffer.
      - Tx side bus_dmamap_load_mbuf_sg(9) support.
      - Preallocate Tx DMA maps as creating DMA maps take very long time
        on architectures that require real DMA maps.
      - Adjust guard buffer size to 1522 + 8 as it should include VLAN
        and additional reserved bytes in Rx buffer.
      - Plug memory leak in device detach. Previously wrong buffer
        address was used to free allocated memory.
      - Added rl_list_rx_init() to clear Rx buffer and cleared the
        buffer.
      - Don't destroy DMA maps in rl_txeof() as the DMA map should be
        reused. There is no reason to destroy/recreate the DMA maps in
        this driver.
      - Removed rl_dma_map_rxbuf()/rl_dma_map_txbuf() callbacks.
      - The hardware does not support descriptor based DMA on Tx side
        and the Tx buffer address should be aligned on 4 bytes boundary
        as well as manual padding for short frames. Because of this
        hardware limitation rl(4) always used to invoke m_defrag(9) to
        get a 4 bytes aligned single buffer. However m_defrag(9) takes
        a lot of CPU cycles on slow machines and not all packets need
        the help of m_defrag(9). Armed with the information, don't
        invoke m_defrag(9) if the following conditions are true.
           1. Buffer is not fragmented.
           2. Buffer is aligned on 4 bytes boundary.
           3. Manual padding is not necessary.
           4. Or padding is necessary but upper stack passed a writable
              buffer and the space needed for padding is satisfied.
        This change combined with preallocated DMA maps greatly
        increased Tx performance of driver on sparc64.
      - Moved bus_dmamap_sync(9) in rl_start_locked() to rl_encap() and
        corrected memory synchronization operation specifier of
        bus_dmamap_sync(9).
      - Removed bus_dmamap_unload(9) in rl_stop(). There is no need to
        reload/unload Rx buffer as rl(4) always have to copy from the
        buffer. It just needs proper bus_dmamap_sync(9) calls before
        copying the received frame.
   
     With this change rl(4) should work on systems with more than 4GB
     memory.
   
     PR:	kern/128143
 
 Modified:
   stable/7/sys/   (props changed)
   stable/7/sys/contrib/pf/   (props changed)
   stable/7/sys/dev/ath/ath_hal/   (props changed)
   stable/7/sys/dev/cxgb/   (props changed)
   stable/7/sys/pci/if_rl.c
   stable/7/sys/pci/if_rlreg.h
 
 Modified: stable/7/sys/pci/if_rl.c
 ==============================================================================
 --- stable/7/sys/pci/if_rl.c	Mon Jan 12 03:33:48 2009	(r187079)
 +++ stable/7/sys/pci/if_rl.c	Mon Jan 12 03:48:25 2009	(r187080)
 @@ -182,12 +182,14 @@ static struct rl_type rl_devs[] = {
  
  static int rl_attach(device_t);
  static int rl_detach(device_t);
 -static void rl_dma_map_rxbuf(void *, bus_dma_segment_t *, int, int);
 -static void rl_dma_map_txbuf(void *, bus_dma_segment_t *, int, int);
 +static void rl_dmamap_cb(void *, bus_dma_segment_t *, int, int);
 +static int rl_dma_alloc(struct rl_softc *);
 +static void rl_dma_free(struct rl_softc *);
  static void rl_eeprom_putbyte(struct rl_softc *, int);
  static void rl_eeprom_getword(struct rl_softc *, int, uint16_t *);
 -static int rl_encap(struct rl_softc *, struct mbuf * );
 +static int rl_encap(struct rl_softc *, struct mbuf **);
  static int rl_list_tx_init(struct rl_softc *);
 +static int rl_list_rx_init(struct rl_softc *);
  static int rl_ifmedia_upd(struct ifnet *);
  static void rl_ifmedia_sts(struct ifnet *, struct ifmediareq *);
  static int rl_ioctl(struct ifnet *, u_long, caddr_t);
 @@ -269,22 +271,6 @@ DRIVER_MODULE(miibus, rl, miibus_driver,
  	CSR_WRITE_1(sc, RL_EECMD,			\
  		CSR_READ_1(sc, RL_EECMD) & ~x)
  
 -static void
 -rl_dma_map_rxbuf(void *arg, bus_dma_segment_t *segs, int nseg, int error)
 -{
 -	struct rl_softc *sc = arg;
 -
 -	CSR_WRITE_4(sc, RL_RXADDR, segs->ds_addr & 0xFFFFFFFF);
 -}
 -
 -static void
 -rl_dma_map_txbuf(void *arg, bus_dma_segment_t *segs, int nseg, int error)
 -{
 -	struct rl_softc *sc = arg;
 -
 -	CSR_WRITE_4(sc, RL_CUR_TXADDR(sc), segs->ds_addr & 0xFFFFFFFF);
 -}
 -
  /*
   * Send a read command and address to the EEPROM, check for ACK.
   */
 @@ -756,6 +742,24 @@ rl_probe(device_t dev)
  	return (ENXIO);
  }
  
 +struct rl_dmamap_arg {
 +	bus_addr_t	rl_busaddr;
 +};
 +
 +static void
 +rl_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
 +{
 +	struct rl_dmamap_arg	*ctx;
 +
 +	if (error != 0)
 +		return;
 +
 +	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
 +
 +        ctx = (struct rl_dmamap_arg *)arg;
 +        ctx->rl_busaddr = segs[0].ds_addr;
 +}
 +
  /*
   * Attach the interface. Allocate softc structures, do ifmedia
   * setup and ethernet/BPF attach.
 @@ -868,59 +872,9 @@ rl_attach(device_t dev)
  			eaddr[i] = CSR_READ_1(sc, RL_IDR0 + i);
  	}
  
 -	/*
 -	 * Allocate the parent bus DMA tag appropriate for PCI.
 -	 */
 -#define RL_NSEG_NEW 32
 -	error = bus_dma_tag_create(bus_get_dma_tag(dev),	/* parent */
 -			1, 0,			/* alignment, boundary */
 -			BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
 -			BUS_SPACE_MAXADDR,	/* highaddr */
 -			NULL, NULL,		/* filter, filterarg */
 -			MAXBSIZE, RL_NSEG_NEW,	/* maxsize, nsegments */
 -			BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
 -			BUS_DMA_ALLOCNOW,	/* flags */
 -			NULL, NULL,		/* lockfunc, lockarg */
 -			&sc->rl_parent_tag);
 -	if (error)
 +	if ((error = rl_dma_alloc(sc)) != 0)
  		goto fail;
  
 -	/*
 -	 * Now allocate a tag for the DMA descriptor lists.
 -	 * All of our lists are allocated as a contiguous block
 -	 * of memory.
 -	 */
 -	error = bus_dma_tag_create(sc->rl_parent_tag,	/* parent */
 -			1, 0,			/* alignment, boundary */
 -			BUS_SPACE_MAXADDR,	/* lowaddr */
 -			BUS_SPACE_MAXADDR,	/* highaddr */
 -			NULL, NULL,		/* filter, filterarg */
 -			RL_RXBUFLEN + 1518, 1,	/* maxsize,nsegments */
 -			BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
 -			BUS_DMA_ALLOCNOW,		/* flags */
 -			NULL, NULL,		/* lockfunc, lockarg */
 -			&sc->rl_tag);
 -	if (error)
 -		goto fail;
 -
 -	/*
 -	 * Now allocate a chunk of DMA-able memory based on the
 -	 * tag we just created.
 -	 */
 -	error = bus_dmamem_alloc(sc->rl_tag,
 -	    (void **)&sc->rl_cdata.rl_rx_buf, BUS_DMA_NOWAIT | BUS_DMA_ZERO,
 -	    &sc->rl_cdata.rl_rx_dmamap);
 -	if (error) {
 -		device_printf(dev, "no memory for list buffers!\n");
 -		bus_dma_tag_destroy(sc->rl_tag);
 -		sc->rl_tag = NULL;
 -		goto fail;
 -	}
 -
 -	/* Leave a few bytes before the start of the RX ring buffer. */
 -	sc->rl_cdata.rl_rx_buf_ptr = sc->rl_cdata.rl_rx_buf;
 -	sc->rl_cdata.rl_rx_buf += sizeof(uint64_t);
 -
  	ifp = sc->rl_ifp = if_alloc(IFT_ETHER);
  	if (ifp == NULL) {
  		device_printf(dev, "can not if_alloc()\n");
 @@ -1019,20 +973,155 @@ rl_detach(device_t dev)
  	if (ifp)
  		if_free(ifp);
  
 -	if (sc->rl_tag) {
 -		bus_dmamap_unload(sc->rl_tag, sc->rl_cdata.rl_rx_dmamap);
 -		bus_dmamem_free(sc->rl_tag, sc->rl_cdata.rl_rx_buf,
 -		    sc->rl_cdata.rl_rx_dmamap);
 -		bus_dma_tag_destroy(sc->rl_tag);
 -	}
 -	if (sc->rl_parent_tag)
 -		bus_dma_tag_destroy(sc->rl_parent_tag);
 +	rl_dma_free(sc);
  
  	mtx_destroy(&sc->rl_mtx);
  
  	return (0);
  }
  
 +static int
 +rl_dma_alloc(struct rl_softc *sc)
 +{
 +	struct rl_dmamap_arg	ctx;
 +	int			error, i;
 +
 +	/*
 +	 * Allocate the parent bus DMA tag appropriate for PCI.
 +	 */
 +	error = bus_dma_tag_create(bus_get_dma_tag(sc->rl_dev),	/* parent */
 +	    1, 0,			/* alignment, boundary */
 +	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
 +	    BUS_SPACE_MAXADDR,		/* highaddr */
 +	    NULL, NULL,			/* filter, filterarg */
 +	    BUS_SPACE_MAXSIZE_32BIT, 0,	/* maxsize, nsegments */
 +	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
 +	    0,				/* flags */
 +	    NULL, NULL,			/* lockfunc, lockarg */
 +	    &sc->rl_parent_tag);
 +	if (error) {
 +                device_printf(sc->rl_dev,
 +		    "failed to create parent DMA tag.\n");
 +		goto fail;
 +	}
 +	/* Create DMA tag for Rx memory block. */
 +	error = bus_dma_tag_create(sc->rl_parent_tag,	/* parent */
 +	    RL_RX_8139_BUF_ALIGN, 0,	/* alignment, boundary */
 +	    BUS_SPACE_MAXADDR,		/* lowaddr */
 +	    BUS_SPACE_MAXADDR,		/* highaddr */
 +	    NULL, NULL,			/* filter, filterarg */
 +	    RL_RXBUFLEN + RL_RX_8139_BUF_GUARD_SZ, 1,	/* maxsize,nsegments */
 +	    RL_RXBUFLEN + RL_RX_8139_BUF_GUARD_SZ,	/* maxsegsize */
 +	    0,				/* flags */
 +	    NULL, NULL,			/* lockfunc, lockarg */
 +	    &sc->rl_cdata.rl_rx_tag);
 +	if (error) {
 +                device_printf(sc->rl_dev,
 +		    "failed to create Rx memory block DMA tag.\n");
 +		goto fail;
 +	}
 +	/* Create DMA tag for Tx buffer. */
 +	error = bus_dma_tag_create(sc->rl_parent_tag,	/* parent */
 +	    RL_TX_8139_BUF_ALIGN, 0,	/* alignment, boundary */
 +	    BUS_SPACE_MAXADDR,		/* lowaddr */
 +	    BUS_SPACE_MAXADDR,		/* highaddr */
 +	    NULL, NULL,			/* filter, filterarg */
 +	    MCLBYTES, 1,		/* maxsize, nsegments */
 +	    MCLBYTES,			/* maxsegsize */
 +	    0,				/* flags */
 +	    NULL, NULL,			/* lockfunc, lockarg */
 +	    &sc->rl_cdata.rl_tx_tag);
 +	if (error) {
 +                device_printf(sc->rl_dev, "failed to create Tx DMA tag.\n");
 +		goto fail;
 +	}
 +
 +	/*
 +	 * Allocate DMA'able memory and load DMA map for Rx memory block.
 +	 */
 +	error = bus_dmamem_alloc(sc->rl_cdata.rl_rx_tag,
 +	    (void **)&sc->rl_cdata.rl_rx_buf, BUS_DMA_WAITOK |
 +	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->rl_cdata.rl_rx_dmamap);
 +	if (error != 0) {
 +		device_printf(sc->rl_dev,
 +		    "failed to allocate Rx DMA memory block.\n");
 +		goto fail;
 +	}
 +	ctx.rl_busaddr = 0;
 +	error = bus_dmamap_load(sc->rl_cdata.rl_rx_tag,
 +	    sc->rl_cdata.rl_rx_dmamap, sc->rl_cdata.rl_rx_buf,
 +	    RL_RXBUFLEN + RL_RX_8139_BUF_GUARD_SZ, rl_dmamap_cb, &ctx,
 +	    BUS_DMA_NOWAIT);
 +	if (error != 0 || ctx.rl_busaddr == 0) {
 +		device_printf(sc->rl_dev,
 +		    "could not load Rx DMA memory block.\n");
 +		goto fail;
 +	}
 +	sc->rl_cdata.rl_rx_buf_paddr = ctx.rl_busaddr;
 +
 +	/* Create DMA maps for Tx buffers. */
 +	for (i = 0; i < RL_TX_LIST_CNT; i++) {
 +		sc->rl_cdata.rl_tx_chain[i] = NULL;
 +		sc->rl_cdata.rl_tx_dmamap[i] = NULL;
 +		error = bus_dmamap_create(sc->rl_cdata.rl_tx_tag, 0,
 +		    &sc->rl_cdata.rl_tx_dmamap[i]);
 +		if (error != 0) {
 +			device_printf(sc->rl_dev,
 +			    "could not create Tx dmamap.\n");
 +			goto fail;
 +		}
 +	}
 +
 +	/* Leave a few bytes before the start of the RX ring buffer. */
 +	sc->rl_cdata.rl_rx_buf_ptr = sc->rl_cdata.rl_rx_buf;
 +	sc->rl_cdata.rl_rx_buf += RL_RX_8139_BUF_RESERVE;
 +
 +fail:
 +	return (error);
 +}
 +
 +static void
 +rl_dma_free(struct rl_softc *sc)
 +{
 +	int			i;
 +
 +	/* Rx memory block. */
 +	if (sc->rl_cdata.rl_rx_tag != NULL) {
 +		if (sc->rl_cdata.rl_rx_dmamap != NULL)
 +			bus_dmamap_unload(sc->rl_cdata.rl_rx_tag,
 +			    sc->rl_cdata.rl_rx_dmamap);
 +		if (sc->rl_cdata.rl_rx_dmamap != NULL &&
 +		    sc->rl_cdata.rl_rx_buf_ptr != NULL)
 +			bus_dmamem_free(sc->rl_cdata.rl_rx_tag,
 +			    sc->rl_cdata.rl_rx_buf_ptr,
 +			    sc->rl_cdata.rl_rx_dmamap);
 +		sc->rl_cdata.rl_rx_buf_ptr = NULL;
 +		sc->rl_cdata.rl_rx_buf = NULL;
 +		sc->rl_cdata.rl_rx_dmamap = NULL;
 +		bus_dma_tag_destroy(sc->rl_cdata.rl_rx_tag);
 +		sc->rl_cdata.rl_tx_tag = NULL;
 +	}
 +
 +	/* Tx buffers. */
 +	if (sc->rl_cdata.rl_tx_tag != NULL) {
 +		for (i = 0; i < RL_TX_LIST_CNT; i++) {
 +			if (sc->rl_cdata.rl_tx_dmamap[i] != NULL) {
 +				bus_dmamap_destroy(
 +				    sc->rl_cdata.rl_tx_tag,
 +				    sc->rl_cdata.rl_tx_dmamap[i]);
 +				sc->rl_cdata.rl_tx_dmamap[i] = NULL;
 +			}
 +		bus_dma_tag_destroy(sc->rl_cdata.rl_tx_tag);
 +		sc->rl_cdata.rl_tx_tag = NULL;
 +		}
 +	}
 +
 +	if (sc->rl_parent_tag != NULL) {
 +		bus_dma_tag_destroy(sc->rl_parent_tag);
 +		sc->rl_parent_tag = NULL;
 +	}
 +}
 +
  /*
   * Initialize the transmit descriptors.
   */
 @@ -1057,6 +1146,20 @@ rl_list_tx_init(struct rl_softc *sc)
  	return (0);
  }
  
 +static int
 +rl_list_rx_init(struct rl_softc *sc)
 +{
 +
 +	RL_LOCK_ASSERT(sc);
 +
 +	bzero(sc->rl_cdata.rl_rx_buf_ptr,
 +	    RL_RXBUFLEN + RL_RX_8139_BUF_GUARD_SZ);
 +	bus_dmamap_sync(sc->rl_cdata.rl_tx_tag, sc->rl_cdata.rl_rx_dmamap,
 +	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 +
 +	return (0);
 +}
 +
  /*
   * A frame has been uploaded: pass the resulting mbuf chain up to
   * the higher level protocols.
 @@ -1093,8 +1196,8 @@ rl_rxeof(struct rl_softc *sc)
  
  	RL_LOCK_ASSERT(sc);
  
 -	bus_dmamap_sync(sc->rl_tag, sc->rl_cdata.rl_rx_dmamap,
 -	    BUS_DMASYNC_POSTREAD);
 +	bus_dmamap_sync(sc->rl_cdata.rl_rx_tag, sc->rl_cdata.rl_rx_dmamap,
 +	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
  
  	cur_rx = (CSR_READ_2(sc, RL_CURRXADDR) + 16) % RL_RXBUFLEN;
  
 @@ -1192,6 +1295,8 @@ rl_rxeof(struct rl_softc *sc)
  		(*ifp->if_input)(ifp, m);
  		RL_LOCK(sc);
  	}
 +
 +	/* No need to sync Rx memory block as we didn't mofify it. */
  }
  
  /*
 @@ -1220,8 +1325,9 @@ rl_txeof(struct rl_softc *sc)
  
  		ifp->if_collisions += (txstat & RL_TXSTAT_COLLCNT) >> 24;
  
 -		bus_dmamap_unload(sc->rl_tag, RL_LAST_DMAMAP(sc));
 -		bus_dmamap_destroy(sc->rl_tag, RL_LAST_DMAMAP(sc));
 +		bus_dmamap_sync(sc->rl_cdata.rl_tx_tag, RL_LAST_DMAMAP(sc),
 +		    BUS_DMASYNC_POSTWRITE);
 +		bus_dmamap_unload(sc->rl_cdata.rl_tx_tag, RL_LAST_DMAMAP(sc));
  		m_freem(RL_LAST_TXMBUF(sc));
  		RL_LAST_TXMBUF(sc) = NULL;
  		/*
 @@ -1369,41 +1475,64 @@ done_locked:
   * pointers to the fragment pointers.
   */
  static int
 -rl_encap(struct rl_softc *sc, struct mbuf *m_head)
 +rl_encap(struct rl_softc *sc, struct mbuf **m_head)
  {
 -	struct mbuf		*m_new = NULL;
 +	struct mbuf		*m;
 +	bus_dma_segment_t	txsegs[1];
 +	int			error, nsegs, padlen;
  
  	RL_LOCK_ASSERT(sc);
  
 +	m = *m_head;
 +	padlen = 0;
 +	/*
 +	 * Hardware doesn't auto-pad, so we have to make sure
 +	 * pad short frames out to the minimum frame length.
 +	 */
 +	if (m->m_pkthdr.len < RL_MIN_FRAMELEN)
 +		padlen = RL_MIN_FRAMELEN - m->m_pkthdr.len;
  	/*
  	 * The RealTek is brain damaged and wants longword-aligned
  	 * TX buffers, plus we can only have one fragment buffer
  	 * per packet. We have to copy pretty much all the time.
  	 */
 -	m_new = m_defrag(m_head, M_DONTWAIT);
 -
 -	if (m_new == NULL) {
 -		m_freem(m_head);
 -		return (1);
 +	if (m->m_next != NULL || (mtod(m, uintptr_t) & 3) != 0 ||
 +	    (padlen > 0 && M_TRAILINGSPACE(m) < padlen)) {
 +		m = m_defrag(*m_head, M_DONTWAIT);
 +		if (m == NULL) {
 +			m_freem(*m_head);
 +			*m_head = NULL;
 +			return (ENOMEM);
 +		}
  	}
 -	m_head = m_new;
 +	*m_head = m;
  
 -	/* Pad frames to at least 60 bytes. */
 -	if (m_head->m_pkthdr.len < RL_MIN_FRAMELEN) {
 +	if (padlen > 0) {
  		/*
  		 * Make security concious people happy: zero out the
  		 * bytes in the pad area, since we don't know what
  		 * this mbuf cluster buffer's previous user might
  		 * have left in it.
  		 */
 -		bzero(mtod(m_head, char *) + m_head->m_pkthdr.len,
 -		     RL_MIN_FRAMELEN - m_head->m_pkthdr.len);
 -		m_head->m_pkthdr.len +=
 -		    (RL_MIN_FRAMELEN - m_head->m_pkthdr.len);
 -		m_head->m_len = m_head->m_pkthdr.len;
 +		bzero(mtod(m, char *) + m->m_pkthdr.len, padlen);
 +		m->m_pkthdr.len += padlen;
 +		m->m_len = m->m_pkthdr.len;
 +	}
 +
 +	error = bus_dmamap_load_mbuf_sg(sc->rl_cdata.rl_tx_tag,
 +	    RL_CUR_DMAMAP(sc), m, txsegs, &nsegs, 0);
 +	if (error != 0)
 +		return (error);
 +	if (nsegs == 0) {
 +		m_freem(*m_head);
 +		*m_head = NULL;
 +		return (EIO);
  	}
  
 -	RL_CUR_TXMBUF(sc) = m_head;
 +	RL_CUR_TXMBUF(sc) = m;
 +	bus_dmamap_sync(sc->rl_cdata.rl_tx_tag, RL_CUR_DMAMAP(sc),
 +	    BUS_DMASYNC_PREWRITE);
 +	CSR_WRITE_4(sc, RL_CUR_TXADDR(sc), RL_ADDR_LO(txsegs[0].ds_addr));
  
  	return (0);
  }
 @@ -1436,19 +1565,18 @@ rl_start_locked(struct ifnet *ifp)
  		if (m_head == NULL)
  			break;
  
 -		if (rl_encap(sc, m_head))
 +		if (rl_encap(sc, &m_head)) {
 +			if (m_head == NULL)
 +				break;
 +			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
 +			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
  			break;
 +		}
  
  		/* Pass a copy of this mbuf chain to the bpf subsystem. */
  		BPF_MTAP(ifp, RL_CUR_TXMBUF(sc));
  
  		/* Transmit the frame. */
 -		bus_dmamap_create(sc->rl_tag, 0, &RL_CUR_DMAMAP(sc));
 -		bus_dmamap_load(sc->rl_tag, RL_CUR_DMAMAP(sc),
 -		    mtod(RL_CUR_TXMBUF(sc), void *),
 -		    RL_CUR_TXMBUF(sc)->m_pkthdr.len, rl_dma_map_txbuf, sc, 0);
 -		bus_dmamap_sync(sc->rl_tag, RL_CUR_DMAMAP(sc),
 -		    BUS_DMASYNC_PREREAD);
  		CSR_WRITE_4(sc, RL_CUR_TXSTAT(sc),
  		    RL_TXTHRESH(sc->rl_txthresh) |
  		    RL_CUR_TXMBUF(sc)->m_pkthdr.len);
 @@ -1507,14 +1635,13 @@ rl_init_locked(struct rl_softc *sc)
  	CSR_WRITE_STREAM_4(sc, RL_IDR4, eaddr[1]);
  	CSR_WRITE_1(sc, RL_EECMD, RL_EEMODE_OFF);
  
 -	/* Init the RX buffer pointer register. */
 -	bus_dmamap_load(sc->rl_tag, sc->rl_cdata.rl_rx_dmamap,
 -	    sc->rl_cdata.rl_rx_buf, RL_RXBUFLEN, rl_dma_map_rxbuf, sc, 0);
 -	bus_dmamap_sync(sc->rl_tag, sc->rl_cdata.rl_rx_dmamap,
 -	    BUS_DMASYNC_PREWRITE);
 -
 +	/* Init the RX memory block pointer register. */
 +	CSR_WRITE_4(sc, RL_RXADDR, sc->rl_cdata.rl_rx_buf_paddr +
 +	    RL_RX_8139_BUF_RESERVE);
  	/* Init TX descriptors. */
  	rl_list_tx_init(sc);
 +	/* Init Rx memory block. */
 +	rl_list_rx_init(sc);
  
  	/*
  	 * Enable transmit and receive.
 @@ -1718,19 +1845,21 @@ rl_stop(struct rl_softc *sc)
  
  	CSR_WRITE_1(sc, RL_COMMAND, 0x00);
  	CSR_WRITE_2(sc, RL_IMR, 0x0000);
 -	bus_dmamap_unload(sc->rl_tag, sc->rl_cdata.rl_rx_dmamap);
  
  	/*
  	 * Free the TX list buffers.
  	 */
  	for (i = 0; i < RL_TX_LIST_CNT; i++) {
  		if (sc->rl_cdata.rl_tx_chain[i] != NULL) {
 -			bus_dmamap_unload(sc->rl_tag,
 -			    sc->rl_cdata.rl_tx_dmamap[i]);
 -			bus_dmamap_destroy(sc->rl_tag,
 -			    sc->rl_cdata.rl_tx_dmamap[i]);
 -			m_freem(sc->rl_cdata.rl_tx_chain[i]);
 -			sc->rl_cdata.rl_tx_chain[i] = NULL;
 +			if (sc->rl_cdata.rl_tx_chain[i] != NULL) {
 +				bus_dmamap_sync(sc->rl_cdata.rl_tx_tag,
 +				    sc->rl_cdata.rl_tx_dmamap[i],
 +				    BUS_DMASYNC_POSTWRITE);
 +				bus_dmamap_unload(sc->rl_cdata.rl_tx_tag,
 +				    sc->rl_cdata.rl_tx_dmamap[i]);
 +				m_freem(sc->rl_cdata.rl_tx_chain[i]);
 +				sc->rl_cdata.rl_tx_chain[i] = NULL;
 +			}
  			CSR_WRITE_4(sc, RL_TXADDR0 + (i * sizeof(uint32_t)),
  			    0x0000000);
  		}
 
 Modified: stable/7/sys/pci/if_rlreg.h
 ==============================================================================
 --- stable/7/sys/pci/if_rlreg.h	Mon Jan 12 03:33:48 2009	(r187079)
 +++ stable/7/sys/pci/if_rlreg.h	Mon Jan 12 03:48:25 2009	(r187080)
 @@ -502,6 +502,11 @@
  #define RL_RXBUFLEN		(1 << ((RL_RX_BUF_SZ >> 11) + 13))
  #define RL_TX_LIST_CNT		4
  #define RL_MIN_FRAMELEN		60
 +#define	RL_TX_8139_BUF_ALIGN	4
 +#define	RL_RX_8139_BUF_ALIGN	8
 +#define	RL_RX_8139_BUF_RESERVE	sizeof(int64_t)
 +#define	RL_RX_8139_BUF_GUARD_SZ	\
 +	(ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN + RL_RX_8139_BUF_RESERVE)	
  #define RL_TXTHRESH(x)		((x) << 11)
  #define RL_TX_THRESH_INIT	96
  #define RL_RX_FIFOTHRESH	RL_RXFIFO_NOTHRESH
 @@ -523,10 +528,13 @@ struct rl_chain_data {
  	uint16_t		cur_rx;
  	uint8_t			*rl_rx_buf;
  	uint8_t			*rl_rx_buf_ptr;
 -	bus_dmamap_t		rl_rx_dmamap;
  
  	struct mbuf		*rl_tx_chain[RL_TX_LIST_CNT];
  	bus_dmamap_t		rl_tx_dmamap[RL_TX_LIST_CNT];
 +	bus_dma_tag_t		rl_tx_tag;
 +	bus_dma_tag_t		rl_rx_tag;
 +	bus_dmamap_t		rl_rx_dmamap;
 +	bus_addr_t		rl_rx_buf_paddr;
  	uint8_t			last_tx;
  	uint8_t			cur_tx;
  };
 @@ -814,7 +822,6 @@ struct rl_softc {
  	void			*rl_intrhand[RL_MSI_MESSAGES];
  	device_t		rl_miibus;
  	bus_dma_tag_t		rl_parent_tag;
 -	bus_dma_tag_t		rl_tag;
  	uint8_t			rl_type;
  	int			rl_eecmd_read;
  	int			rl_eewidth;
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: yongari 
State-Changed-When: Mon Jan 12 03:55:52 UTC 2009 
State-Changed-Why:  
MFC to stable/7 done. Thanks! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=128143 
>Unformatted:
