Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 15 Nov 2012 16:01:49 +0000 (UTC)
From:      Andre Oppermann <andre@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r243089 - user/andre/tcp_workqueue/sys/dev/fxp
Message-ID:  <201211151601.qAFG1nOW012716@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: andre
Date: Thu Nov 15 16:01:49 2012
New Revision: 243089
URL: http://svnweb.freebsd.org/changeset/base/243089

Log:
  Fix wedge issue by correctly accounting for out-of-rx-descriptors
  (RNR) condition and adjust the packet acceptance tests.
  
  Rename a few bit definitions in the rx descriptor to better match
  their purpose.
  
  Reduce the locking scope in fxp_ithread().
  
  Add and update more comments.
  
  Work in progress.

Modified:
  user/andre/tcp_workqueue/sys/dev/fxp/if_fxp.c
  user/andre/tcp_workqueue/sys/dev/fxp/if_fxpreg.h

Modified: user/andre/tcp_workqueue/sys/dev/fxp/if_fxp.c
==============================================================================
--- user/andre/tcp_workqueue/sys/dev/fxp/if_fxp.c	Thu Nov 15 15:55:49 2012	(r243088)
+++ user/andre/tcp_workqueue/sys/dev/fxp/if_fxp.c	Thu Nov 15 16:01:49 2012	(r243089)
@@ -221,7 +221,7 @@ static int		fxp_resume(device_t dev);
 static const struct fxp_ident *fxp_find_ident(device_t dev);
 static void		fxp_rxcsum(struct fxp_softc *sc, struct ifnet *ifp,
 			    struct mbuf *m, uint16_t status, int pos);
-static struct mbuf *	fxp_rx(struct fxp_softc *sc, struct ifnet *ifp);
+static struct mbuf *	fxp_rx(struct fxp_softc *sc, struct ifnet *ifp, int rnr);
 static int		fxp_intr(void *xsc);
 static void		fxp_ithread(void *xsc);
 static void 		fxp_init(void *xsc);
@@ -903,6 +903,7 @@ fxp_attach(device_t dev)
 		ether_ifdetach(sc->ifp);
 		goto fail;
 	}
+	bus_describe_intr(dev, sc->fxp_res[1], sc->ih, "rx/tx ithread");
 
 	/*
 	 * Configure hardware to reject magic frames otherwise
@@ -1690,6 +1691,10 @@ fxp_intr(void *xsc)
 		ret = FILTER_STRAY;
 		break;
 	default:
+		/*
+		 * Disable further interrupts until the ithread
+		 * is done with TXeof/RX and link state handling.
+		 */
 		CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, FXP_SCB_INTR_DISABLE);
 		ret = FILTER_SCHEDULE_THREAD;
 		break;
@@ -1815,25 +1820,17 @@ fxp_rxcsum(struct fxp_softc *sc, struct 
 }
 
 /*
- * Process receiver interrupts. If a no-resource (RNR)
- * condition exists, get whatever packets we can and
- * re-start the receiver.
- *
- * When using polling, we do not process the list to completion,
- * so when we get an RNR interrupt we must defer the restart
- * until we hit the last buffer with the C bit set.
- * If we run out of cycles and rfa_headm has the C bit set,
- * record the pending RNR in the FXP_FLAG_DEFERRED_RNR flag so
- * that the info will be used in the subsequent polling cycle.
+ * Process frames on the receive DMA ring.
+ * If a no-resource (RNR) condition exists,
+ * restart the receiver.
  */
 static struct mbuf *
-fxp_rx(struct fxp_softc *sc, struct ifnet *ifp)
+fxp_rx(struct fxp_softc *sc, struct ifnet *ifp, int rnr)
 {
 	struct fxp_rx *rxp;
 	struct fxp_rfa *rfa;
 	struct mbuf *m, *n, *m0;
-	int rnr = 0;
-	uint16_t len, status, vlan;
+	uint16_t len, status, asize, vlan;
 
 	m = n = NULL;		/* gcc */
 
@@ -1846,40 +1843,56 @@ fxp_rx(struct fxp_softc *sc, struct ifne
 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 
 		status = le16toh(rfa->rfa_status);
-		if (!(status & FXP_RFA_STATUS_C))
+		asize = le16toh(rfa->actual_size);
+
+		/*
+		 * Stop if we hit the head of the RX queue
+		 * or the controller isn't yet done with
+		 * DMA'ing the packet.
+		 */
+		if (!(status & FXP_RFA_STATUS_C) ||
+		    !(asize & FXP_PFA_ASIZE_EOF))
 			break;
-		if (status & FXP_RFA_STATUS_RNR)
-			rnr++;
 
 		/* Advance head forward. */
 		sc->fxp_desc.rx_head = rxp->rx_next;
 
 		/*
+		 * Drop packet and reuse mbuf when errors
+		 * during reception were encountered.
+		 */
+		if (!(status & FXP_RFA_STATUS_OK)) {
+			fxp_discard_rfabuf(sc, rxp);
+			fxp_add_rfabuf(sc, rxp);
+			continue;
+		}
+
+		/*
 		 * Fetch packet length (the top 2 bits of
 		 * actual_size are flags set by the controller
-		 * upon completion), and drop the packet in case
-		 * of bogus length or CRC errors.
-		 * Adjust for appended checksum word for 559
+		 * upon completion).
+		 * Adjust for appended checksum word for 82559
 		 * checksum offload 'feature'.
 		 */
-		len = le16toh(rfa->actual_size) & 0x3fff;
+		len = (asize & 0x3fff);
 		if ((sc->flags & FXP_FLAG_82559_RXCSUM) &&
 		    (ifp->if_capenable & IFCAP_RXCSUM))
 			len -= 2;
 
-		if (len < (int)sizeof(struct ether_header) ||
-		    len > (MCLBYTES - ETHER_ALIGN - sc->rfa_size) ||
-		    (status & (FXP_RFA_STATUS_CRC | FXP_RFA_STATUS_ALIGN |
-		    FXP_RFA_STATUS_OVERRUN))) {
-			fxp_discard_rfabuf(sc, rxp);
-			fxp_add_rfabuf(sc, rxp);
-			continue;
-		}
+		/*
+		 * Save vlan information before losing access
+		 * to receive descriptor.
+		 */
 		vlan = ntohs(rfa->rfax_vlan_id);
 
+		/*
+		 * If the packet fits an mbuf then allocate
+		 * one and copy it over.  The mbuf cluster
+		 * can remain in the RX DMA ring and gets
+		 * recycled for another packet.
+		 */
 		if (len <= MHLEN - ETHER_ALIGN &&
 		    (m0 = m_gethdr(M_NOWAIT, MT_DATA)) != NULL) {
-			/* Copy stuff over. */
 			m0->m_data += ETHER_ALIGN;
 			(void)m_append(m0, len, mtod(rxp->rx_mbuf, caddr_t));
 			rfa = NULL;
@@ -1896,7 +1909,7 @@ fxp_rx(struct fxp_softc *sc, struct ifne
 			continue;
 		}
 		fxp_add_rfabuf(sc, rxp);
-		
+
 		m0->m_pkthdr.len = m0->m_len = len;
 		m0->m_pkthdr.rcvif = ifp;
 
@@ -1937,12 +1950,15 @@ fxp_ithread(void *xsc)
 	struct mbuf *m, *n;
 	uint8_t statack;
 
-	FXP_LOCK(sc);
-
+	/*
+	 * Loop while the chip indicates work.
+	 * The control status register is contiguously updated,
+	 * even when raising interrupts is disabled.
+	 */
 	while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0x00) {
 		/*
-		 * Read and acknowledge all interrupt sources.
-		 * Further interrupts are already disabled.
+		 * Read and acknowledge all interrupt sources
+		 * unless we have an eject event.
 		 */
 		if (statack == 0xff) {
 			FXP_UNLOCK(sc);
@@ -1950,6 +1966,8 @@ fxp_ithread(void *xsc)
 		}
 		CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack);
 
+		FXP_LOCK(sc);
+
 		/*
 		 * Free any finished transmit mbuf chains.
 		 *
@@ -1966,7 +1984,7 @@ fxp_ithread(void *xsc)
 		if (statack & (FXP_SCB_STATACK_CXTNO | FXP_SCB_STATACK_CNA))
 			fxp_txeof(sc);
 
-		/* Try to start more packets transmitting. */
+		/* Add more packets to the tx DMA ring. */
 		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
 			fxp_start_body(ifp);
 
@@ -1975,7 +1993,7 @@ fxp_ithread(void *xsc)
 			break;
 
 		/* Pull packets from rx DMA ring and refill the ring. */
-		m = fxp_rx(sc, ifp);
+		m = fxp_rx(sc, ifp, (statack & FXP_SCB_STATACK_RNR));
 
 		/*
 		 * Push rx packets up into the stack.
@@ -1991,11 +2009,11 @@ fxp_ithread(void *xsc)
 			(*ifp->if_input)(ifp, n);
 			maybe_yield();
 		}
-		FXP_LOCK(sc);
 	}
 
-	FXP_UNLOCK(sc);
-	/* Re-enable interrupts. */
+	/*
+	 * Enable interrupts again.
+	 */
 	CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, 0);
 }
 
@@ -2674,7 +2692,7 @@ fxp_add_rfabuf(struct fxp_softc *sc, str
 		    (p_rx->rx_mbuf->m_ext.ext_buf + ETHER_ALIGN);
 		p_rx->rx_next = rxp;
 		le32enc(&p_rfa->link_addr, rxp->rx_addr);
-		p_rfa->rfa_control = 0;
+		p_rfa->rfa_control = 0;		/* No longer EL. */
 		bus_dmamap_sync(sc->fxp_rxmtag, p_rx->rx_map,
 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
 	} else {

Modified: user/andre/tcp_workqueue/sys/dev/fxp/if_fxpreg.h
==============================================================================
--- user/andre/tcp_workqueue/sys/dev/fxp/if_fxpreg.h	Thu Nov 15 15:55:49 2012	(r243088)
+++ user/andre/tcp_workqueue/sys/dev/fxp/if_fxpreg.h	Thu Nov 15 16:01:49 2012	(r243089)
@@ -375,8 +375,8 @@ struct fxp_rfa {
 #define FXP_RFA_STATUS_TL	0x0020	/* type/length */
 #define FXP_RFA_STATUS_FTS	0x0080	/* frame too short */
 #define FXP_RFA_STATUS_OVERRUN	0x0100	/* DMA overrun */
-#define FXP_RFA_STATUS_RNR	0x0200	/* no resources */
-#define FXP_RFA_STATUS_ALIGN	0x0400	/* alignment error */
+#define FXP_RFA_STATUS_RBS	0x0200	/* ran out of buffer space */
+#define FXP_RFA_STATUS_CRCALIGN	0x0400	/* alignment error */
 #define FXP_RFA_STATUS_CRC	0x0800	/* CRC error */
 #define FXP_RFA_STATUS_VLAN	0x1000	/* VLAN tagged frame */
 #define FXP_RFA_STATUS_OK	0x2000	/* packet received okay */
@@ -385,6 +385,8 @@ struct fxp_rfa {
 #define FXP_RFA_CONTROL_H	0x10	/* header RFD */
 #define FXP_RFA_CONTROL_S	0x4000	/* suspend after reception */
 #define FXP_RFA_CONTROL_EL	0x8000	/* end of list */
+#define FXP_PFA_ASIZE_EOF	0x8000	/* completed placing data */
+#define FXP_PFA_ASIZE_F		0x4000	/* updated count field */
 
 /* Bits in the 'csum_sts' byte */
 #define FXP_RFDX_CS_TCPUDP_CSUM_BIT_VALID	0x10



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