Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 17 Apr 2015 23:49:44 +0000 (UTC)
From:      Luiz Otavio O Souza <loos@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r281673 - head/sys/arm/allwinner
Message-ID:  <201504172349.t3HNnixW070265@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: loos
Date: Fri Apr 17 23:49:43 2015
New Revision: 281673
URL: https://svnweb.freebsd.org/changeset/base/281673

Log:
  Add the necessary support to use both TX queues available on if_emac.
  
  Each TX queue can hold one packet (yes, if_emac can send only two(!)
  packets at a time).
  
  Even with this change the very limited FIFO buffer (3 KiB for TX and 13 KiB
  for RX) fill up too quick to sustain higher throughput.
  
  For the TCP case it turns out that TX isn't the limiting factor, but the RX
  side is (the FIFO fill up and starts to discard packets, so the sender has
  to slow down).

Modified:
  head/sys/arm/allwinner/if_emac.c
  head/sys/arm/allwinner/if_emacreg.h

Modified: head/sys/arm/allwinner/if_emac.c
==============================================================================
--- head/sys/arm/allwinner/if_emac.c	Fri Apr 17 22:44:44 2015	(r281672)
+++ head/sys/arm/allwinner/if_emac.c	Fri Apr 17 23:49:43 2015	(r281673)
@@ -101,6 +101,7 @@ struct emac_softc {
 	int			emac_watchdog_timer;
 	int			emac_rx_process_limit;
 	int			emac_link;
+	uint32_t		emac_fifo_mask;
 };
 
 static int	emac_probe(device_t);
@@ -121,7 +122,7 @@ static void	emac_intr(void *);
 static int	emac_ioctl(struct ifnet *, u_long, caddr_t);
 
 static void	emac_rxeof(struct emac_softc *, int);
-static void	emac_txeof(struct emac_softc *);
+static void	emac_txeof(struct emac_softc *, uint32_t);
 
 static int	emac_miibus_readreg(device_t, int, int);
 static int	emac_miibus_writereg(device_t, int, int, int);
@@ -253,14 +254,19 @@ emac_reset(struct emac_softc *sc)
 }
 
 static void
-emac_txeof(struct emac_softc *sc)
+emac_txeof(struct emac_softc *sc, uint32_t status)
 {
 	struct ifnet *ifp;
 
 	EMAC_ASSERT_LOCKED(sc);
 
 	ifp = sc->emac_ifp;
-	if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
+	status &= (EMAC_TX_FIFO0 | EMAC_TX_FIFO1);
+	sc->emac_fifo_mask &= ~status;
+	if (status == (EMAC_TX_FIFO0 | EMAC_TX_FIFO1))
+		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 2);
+	else
+		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 
 	/* Unarm watchdog timer if no TX */
@@ -580,11 +586,13 @@ emac_start_locked(struct ifnet *ifp)
 {
 	struct emac_softc *sc;
 	struct mbuf *m, *m0;
-	uint32_t reg_val;
+	uint32_t fifo, reg;
 
 	sc = ifp->if_softc;
 	if (ifp->if_drv_flags & IFF_DRV_OACTIVE)
 		return;
+	if (sc->emac_fifo_mask == (EMAC_TX_FIFO0 | EMAC_TX_FIFO1))
+		return;
 	if (sc->emac_link == 0)
 		return;
 	IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
@@ -592,7 +600,14 @@ emac_start_locked(struct ifnet *ifp)
 		return;
 
 	/* Select channel */
-	EMAC_WRITE_REG(sc, EMAC_TX_INS, 0);
+	if (sc->emac_fifo_mask & EMAC_TX_FIFO0)
+		fifo = 1;
+	else
+		fifo = 0;
+	sc->emac_fifo_mask |= (1 << fifo);
+	if (sc->emac_fifo_mask == (EMAC_TX_FIFO0 | EMAC_TX_FIFO1))
+		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+	EMAC_WRITE_REG(sc, EMAC_TX_INS, fifo);
 
 	/*
 	 * Emac controller wants 4 byte aligned TX buffers.
@@ -613,17 +628,17 @@ emac_start_locked(struct ifnet *ifp)
 	    roundup2(m->m_len, 4) / 4);
 
 	/* Send the data lengh. */
-	EMAC_WRITE_REG(sc, EMAC_TX_PL0, m->m_len);
+	reg = (fifo == 0) ? EMAC_TX_PL0 : EMAC_TX_PL1;
+	EMAC_WRITE_REG(sc, reg, m->m_len);
 
 	/* Start translate from fifo to phy. */
-	reg_val = EMAC_READ_REG(sc, EMAC_TX_CTL0);
-	reg_val |= 1;
-	EMAC_WRITE_REG(sc, EMAC_TX_CTL0, reg_val);
+	reg = (fifo == 0) ? EMAC_TX_CTL0 : EMAC_TX_CTL1;
+	EMAC_WRITE_REG(sc, reg, EMAC_READ_REG(sc, reg) | 1);
 
 	/* Set timeout */
 	sc->emac_watchdog_timer = 5;
 
-	ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+	/* Data have been sent to hardware, it is okay to free the mbuf now. */
 	BPF_MTAP(ifp, m);
 	m_freem(m);
 }
@@ -676,7 +691,7 @@ emac_intr(void *arg)
 
 	/* Transmit Interrupt check */
 	if (reg_val & EMAC_INT_STA_TX) {
-		emac_txeof(sc);
+		emac_txeof(sc, reg_val);
 		ifp = sc->emac_ifp;
 		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
 			emac_start_locked(ifp);

Modified: head/sys/arm/allwinner/if_emacreg.h
==============================================================================
--- head/sys/arm/allwinner/if_emacreg.h	Fri Apr 17 22:44:44 2015	(r281672)
+++ head/sys/arm/allwinner/if_emacreg.h	Fri Apr 17 23:49:43 2015	(r281673)
@@ -51,6 +51,8 @@
 #define	EMAC_TX_TSVH0		0x30
 #define	EMAC_TX_TSVL1		0x34
 #define	EMAC_TX_TSVH1		0x38
+#define	EMAC_TX_FIFO0		(1 << 0)
+#define	EMAC_TX_FIFO1		(1 << 1)
 
 #define	EMAC_RX_CTL		0x3C
 #define	EMAC_RX_HASH0		0x40
@@ -61,7 +63,7 @@
 
 #define	EMAC_INT_CTL		0x54
 #define	EMAC_INT_STA		0x58
-#define	EMAC_INT_STA_TX		(0x01 | 0x02)
+#define	EMAC_INT_STA_TX		(EMAC_TX_FIFO0 | EMAC_TX_FIFO1)
 #define	EMAC_INT_STA_RX		0x100
 #define	EMAC_INT_EN		(0xf << 0) | (1 << 8)
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201504172349.t3HNnixW070265>