svn commit: r242980 - user/andre/tcp_workqueue/sys/dev/fxp

Andre Oppermann andre at FreeBSD.org
Tue Nov 13 16:35:45 UTC 2012


Author: andre
Date: Tue Nov 13 16:35:44 2012
New Revision: 242980
URL: http://svnweb.freebsd.org/changeset/base/242980

Log:
  Convert fxp(4) to hybrid interrupt and polling mode with
  life-lock prevention.
  
  fxp_intr() only tests whether the irq was really for us
  and then disabled interrupts until further notice.
  
  fxp_intr_body() is converted into fxp_ithread() and loops
  around
  
  fxp_rx() is added to handle pulling packets from the RX DMA
  ring.
  
  fxp_encap() simplifies TSO setup haggling.  The pseudo csum
  is normally already set by the stack.  Have to double-check.
  
  Use ETHER_ALIGN instead of RFA_ALIGNMENT_FUDGE.
  
  Work in progress.

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

Modified: user/andre/tcp_workqueue/sys/dev/fxp/if_fxp.c
==============================================================================
--- user/andre/tcp_workqueue/sys/dev/fxp/if_fxp.c	Tue Nov 13 15:35:15 2012	(r242979)
+++ user/andre/tcp_workqueue/sys/dev/fxp/if_fxp.c	Tue Nov 13 16:35:44 2012	(r242980)
@@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/lock.h>
 #include <sys/module.h>
 #include <sys/mutex.h>
+#include <sys/proc.h>
 #include <sys/rman.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
@@ -218,11 +219,11 @@ static int		fxp_suspend(device_t dev);
 static int		fxp_resume(device_t dev);
 
 static const struct fxp_ident *fxp_find_ident(device_t dev);
-static void		fxp_intr(void *xsc);
 static void		fxp_rxcsum(struct fxp_softc *sc, struct ifnet *ifp,
 			    struct mbuf *m, uint16_t status, int pos);
-static int		fxp_intr_body(struct fxp_softc *sc, struct ifnet *ifp,
-			    uint8_t statack, int count);
+static struct mbuf *	fxp_rx(struct fxp_softc *sc, struct ifnet *ifp);
+static int		fxp_intr(void *xsc);
+static void		fxp_ithread(void *xsc);
 static void 		fxp_init(void *xsc);
 static void 		fxp_init_body(struct fxp_softc *sc, int);
 static void 		fxp_tick(void *xsc);
@@ -898,7 +899,7 @@ fxp_attach(device_t dev)
 	 * Hook our interrupt after all initialization is complete.
 	 */
 	error = bus_setup_intr(dev, sc->fxp_res[1], INTR_TYPE_NET | INTR_MPSAFE,
-			       NULL, fxp_intr, sc, &sc->ih);
+			       fxp_intr, fxp_ithread, sc, &sc->ih);
 	if (error) {
 		device_printf(dev, "could not setup irq\n");
 		ether_ifdetach(sc->ifp);
@@ -1445,50 +1446,15 @@ fxp_encap(struct fxp_softc *sc, struct m
 		struct ip *ip;
 		uint32_t ip_off, poff;
 
-		if (M_WRITABLE(*m_head) == 0) {
-			/* Get a writable copy. */
-			m = m_dup(*m_head, M_DONTWAIT);
-			m_freem(*m_head);
-			if (m == NULL) {
-				*m_head = NULL;
-				return (ENOBUFS);
-			}
-			*m_head = m;
-		}
 		ip_off = sizeof(struct ether_header);
-		m = m_pullup(*m_head, ip_off);
-		if (m == NULL) {
-			*m_head = NULL;
-			return (ENOBUFS);
-		}
 		eh = mtod(m, struct ether_header *);
 		/* Check the existence of VLAN tag. */
 		if (eh->ether_type == htons(ETHERTYPE_VLAN)) {
 			ip_off = sizeof(struct ether_vlan_header);
-			m = m_pullup(m, ip_off);
-			if (m == NULL) {
-				*m_head = NULL;
-				return (ENOBUFS);
-			}
-		}
-		m = m_pullup(m, ip_off + sizeof(struct ip));
-		if (m == NULL) {
-			*m_head = NULL;
-			return (ENOBUFS);
 		}
 		ip = (struct ip *)(mtod(m, char *) + ip_off);
 		poff = ip_off + (ip->ip_hl << 2);
-		m = m_pullup(m, poff + sizeof(struct tcphdr));
-		if (m == NULL) {
-			*m_head = NULL;
-			return (ENOBUFS);
-		}
 		tcp = (struct tcphdr *)(mtod(m, char *) + poff);
-		m = m_pullup(m, poff + (tcp->th_off << 2));
-		if (m == NULL) {
-			*m_head = NULL;
-			return (ENOBUFS);
-		}
 
 		/*
 		 * Since 82550/82551 doesn't modify IP length and pseudo
@@ -1707,45 +1673,31 @@ fxp_poll(struct ifnet *ifp, enum poll_cm
 /*
  * Process interface interrupts.
  */
-static void
+static int
 fxp_intr(void *xsc)
 {
 	struct fxp_softc *sc = xsc;
-	struct ifnet *ifp = sc->ifp;
+	int ret;
 	uint8_t statack;
 
-	FXP_LOCK(sc);
-	if (sc->suspended) {
-		FXP_UNLOCK(sc);
-		return;
-	}
-
-#ifdef DEVICE_POLLING
-	if (ifp->if_capenable & IFCAP_POLLING) {
-		FXP_UNLOCK(sc);
-		return;
-	}
-#endif
-	while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {
-		/*
-		 * It should not be possible to have all bits set; the
-		 * FXP_SCB_INTR_SWI bit always returns 0 on a read.  If
-		 * all bits are set, this may indicate that the card has
-		 * been physically ejected, so ignore it.
-		 */
-		if (statack == 0xff) {
-			FXP_UNLOCK(sc);
-			return;
-		}
-
-		/*
-		 * First ACK all the interrupts in this pass.
-		 */
-		CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack);
-		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
-			fxp_intr_body(sc, ifp, statack, -1);
+	statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK);
+	/*
+	 * It should not be possible to have all bits set; the
+	 * FXP_SCB_INTR_SWI bit always returns 0 on a read.  If
+	 * all bits are set, this may indicate that the card has
+	 * been physically ejected, so ignore it.
+	 */
+	switch (statack) {
+	case 0x00:		/* Not our interrupt. */
+	case 0xff:		/* Card ejected. */
+		ret = FILTER_STRAY;
+		break;
+	default:
+		CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, FXP_SCB_INTR_DISABLE);
+		ret = FILTER_SCHEDULE_THREAD;
+		break;
 	}
-	FXP_UNLOCK(sc);
+	return (ret);
 }
 
 static void
@@ -1857,173 +1809,199 @@ fxp_rxcsum(struct fxp_softc *sc, struct 
 	m->m_pkthdr.csum_data = csum;
 }
 
-static int
-fxp_intr_body(struct fxp_softc *sc, struct ifnet *ifp, uint8_t statack,
-    int count)
+/*
+ * 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.
+ */
+static struct mbuf *
+fxp_rx(struct fxp_softc *sc, struct ifnet *ifp)
 {
-	struct mbuf *m;
 	struct fxp_rx *rxp;
 	struct fxp_rfa *rfa;
-	int rnr = (statack & FXP_SCB_STATACK_RNR) ? 1 : 0;
-	int rx_npkts;
+	struct mbuf *m, *n, *m0;
+	int len, rnr = 0;
 	uint16_t status;
 
-	rx_npkts = 0;
-	FXP_LOCK_ASSERT(sc, MA_OWNED);
-
-	if (rnr)
-		sc->rnr++;
-#ifdef DEVICE_POLLING
-	/* Pick up a deferred RNR condition if `count' ran out last time. */
-	if (sc->flags & FXP_FLAG_DEFERRED_RNR) {
-		sc->flags &= ~FXP_FLAG_DEFERRED_RNR;
-		rnr = 1;
-	}
-#endif
-
-	/*
-	 * Free any finished transmit mbuf chains.
-	 *
-	 * Handle the CNA event likt a CXTNO event. It used to
-	 * be that this event (control unit not ready) was not
-	 * encountered, but it is now with the SMPng modifications.
-	 * The exact sequence of events that occur when the interface
-	 * is brought up are different now, and if this event
-	 * goes unhandled, the configuration/rxfilter setup sequence
-	 * can stall for several seconds. The result is that no
-	 * packets go out onto the wire for about 5 to 10 seconds
-	 * after the interface is ifconfig'ed for the first time.
-	 */
-	if (statack & (FXP_SCB_STATACK_CXTNO | FXP_SCB_STATACK_CNA))
-		fxp_txeof(sc);
-
-	/*
-	 * Try to start more packets transmitting.
-	 */
-	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
-		fxp_start_body(ifp);
-
-	/*
-	 * Just return if nothing happened on the receive side.
-	 */
-	if (!rnr && (statack & FXP_SCB_STATACK_FR) == 0)
-		return (rx_npkts);
-
-	/*
-	 * 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.
-	 */
 	for (;;) {
 		rxp = sc->fxp_desc.rx_head;
-		m = rxp->rx_mbuf;
-		rfa = (struct fxp_rfa *)(m->m_ext.ext_buf +
-		    RFA_ALIGNMENT_FUDGE);
+		m0 = rxp->rx_mbuf;
+		rfa = (struct fxp_rfa *)(m0->m_ext.ext_buf + ETHER_ALIGN);
+
 		bus_dmamap_sync(sc->fxp_rxmtag, rxp->rx_map,
 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 
-#ifdef DEVICE_POLLING /* loop at most count times if count >=0 */
-		if (count >= 0 && count-- == 0) {
-			if (rnr) {
-				/* Defer RNR processing until the next time. */
-				sc->flags |= FXP_FLAG_DEFERRED_RNR;
-				rnr = 0;
-			}
-			break;
-		}
-#endif /* DEVICE_POLLING */
-
 		status = le16toh(rfa->rfa_status);
-		if ((status & FXP_RFA_STATUS_C) == 0)
+		if (!(status & FXP_RFA_STATUS_C))
 			break;
-
-		if ((status & FXP_RFA_STATUS_RNR) != 0)
+		if (status & FXP_RFA_STATUS_RNR)
 			rnr++;
-		/*
-		 * Advance head forward.
-		 */
+
+		/* Advance head forward. */
 		sc->fxp_desc.rx_head = rxp->rx_next;
 
 		/*
-		 * Add a new buffer to the receive chain.
-		 * If this fails, the old buffer is recycled
-		 * instead.
+		 * 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 bytes.
 		 */
-		if (fxp_new_rfabuf(sc, rxp) == 0) {
-			int total_len;
-
-			/*
-			 * 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.
-			 */
-			total_len = le16toh(rfa->actual_size) & 0x3fff;
-			if ((sc->flags & FXP_FLAG_82559_RXCSUM) != 0 &&
-			    (ifp->if_capenable & IFCAP_RXCSUM) != 0) {
-				/* Adjust for appended checksum bytes. */
-				total_len -= 2;
-			}
-			if (total_len < (int)sizeof(struct ether_header) ||
-			    total_len > (MCLBYTES - RFA_ALIGNMENT_FUDGE -
-			    sc->rfa_size) ||
-			    status & (FXP_RFA_STATUS_CRC |
-			    FXP_RFA_STATUS_ALIGN | FXP_RFA_STATUS_OVERRUN)) {
-				m_freem(m);
-				fxp_add_rfabuf(sc, rxp);
-				continue;
-			}
-
-			m->m_pkthdr.len = m->m_len = total_len;
-			m->m_pkthdr.rcvif = ifp;
-
-                        /* Do IP checksum checking. */
-			if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
-				fxp_rxcsum(sc, ifp, m, status, total_len);
-			if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0 &&
-			    (status & FXP_RFA_STATUS_VLAN) != 0) {
-				m->m_pkthdr.ether_vtag =
-				    ntohs(rfa->rfax_vlan_id);
-				m->m_flags |= M_VLANTAG;
-			}
+		len = le16toh(rfa->actual_size) & 0x3fff;
+		if ((sc->flags & FXP_FLAG_82559_RXCSUM) &&
+		    (ifp->if_capenable & IFCAP_RXCSUM))
+			len -= ETHER_CRC_LEN;
+
+		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;
+		}
+		if (1 == 0 && len <= MHLEN - ETHER_ALIGN &&
+		    (m0 = m_get(M_NOWAIT, MT_DATA)) != NULL) {
+			/* Copy stuff over. */
+			m_adj(m0, ETHER_ALIGN);
+			(void)m_append(m0, len,
+			    (caddr_t)(&rxp->rx_mbuf->m_ext.ext_buf));
+			fxp_discard_rfabuf(sc, rxp);
+		} else if (fxp_new_rfabuf(sc, rxp) > 0) {
 			/*
-			 * Drop locks before calling if_input() since it
-			 * may re-enter fxp_start() in the netisr case.
-			 * This would result in a lock reversal.  Better
-			 * performance might be obtained by chaining all
-			 * packets received, dropping the lock, and then
-			 * calling if_input() on each one.
+			 * Adding a new buffer to the receive chain failed,
+			 * the old buffer is recycled instead.
+			 * Reuse RFA and loaded DMA map.
 			 */
-			FXP_UNLOCK(sc);
-			(*ifp->if_input)(ifp, m);
-			FXP_LOCK(sc);
-			rx_npkts++;
-			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
-				return (rx_npkts);
-		} else {
-			/* Reuse RFA and loaded DMA map. */
-			ifp->if_iqdrops++;
 			fxp_discard_rfabuf(sc, rxp);
+			fxp_add_rfabuf(sc, rxp);
+			ifp->if_iqdrops++;
+			continue;
 		}
 		fxp_add_rfabuf(sc, rxp);
+		
+		m0->m_pkthdr.len = m0->m_len = len;
+		m0->m_pkthdr.rcvif = ifp;
+
+		/* Do IP checksum checking. */
+		if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
+			fxp_rxcsum(sc, ifp, m0, status, len);
+
+		if ((ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0 &&
+		    (status & FXP_RFA_STATUS_VLAN) != 0) {
+			m0->m_pkthdr.ether_vtag =
+			    ntohs(rfa->rfax_vlan_id);
+			m0->m_flags |= M_VLANTAG;
+		}
+
+		/* Append mbuf. */
+		if (m != NULL) {
+			n->m_nextpkt = m0;
+			n = m0;
+		} else
+			m = n = m0;
 	}
+
+	/* Restart rx microengine after out of rx buffer event. */
 	if (rnr) {
 		fxp_scb_wait(sc);
 		CSR_WRITE_4(sc, FXP_CSR_SCB_GENERAL,
 		    sc->fxp_desc.rx_head->rx_addr);
 		fxp_scb_cmd(sc, FXP_SCB_COMMAND_RU_START);
 	}
-	return (rx_npkts);
+
+	return (m);
 }
 
 static void
+fxp_ithread(void *xsc)
+{
+	struct fxp_softc *sc = xsc;
+	struct ifnet *ifp = sc->ifp;
+	struct mbuf *m, *n;
+	uint8_t statack;
+
+	FXP_LOCK(sc);
+
+	while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0x00) {
+		/*
+		 * Read and acknowledge all interrupt sources.
+		 * Further interrupts are already disabled.
+		 */
+		if (statack == 0xff) {
+			FXP_UNLOCK(sc);
+			return;
+		}
+		CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack);
+
+		/*
+		 * Free any finished transmit mbuf chains.
+		 *
+		 * Handle the CNA event like a CXTNO event. It used to
+		 * be that this event (control unit not ready) was not
+		 * encountered, but it is now with the SMPng modifications.
+		 * The exact sequence of events that occur when the interface
+		 * is brought up are different now, and if this event
+		 * goes unhandled, the configuration/rxfilter setup sequence
+		 * can stall for several seconds. The result is that no
+		 * packets go out onto the wire for about 5 to 10 seconds
+		 * after the interface is ifconfig'ed for the first time.
+		 */
+		if (statack & (FXP_SCB_STATACK_CXTNO | FXP_SCB_STATACK_CNA))
+			fxp_txeof(sc);
+
+		/* Try to start more packets transmitting. */
+		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+			fxp_start_body(ifp);
+
+		/* Just return if nothing happened on the receive side. */
+		if ((statack & (FXP_SCB_STATACK_FR | FXP_SCB_STATACK_RNR)) == 0)
+			break;
+
+		/* Pull packets from rx DMA ring and refill the ring. */
+		m = fxp_rx(sc, ifp);
+
+		/*
+		 * Push rx packets up into the stack.
+		 * Drop locks before calling if_input() since it
+		 * may re-enter fxp_start() in the netisr case.
+		 * This would result in a lock reversal.
+		 */
+		FXP_UNLOCK(sc);
+		while (m != NULL) {
+			n = m;
+			m = n->m_nextpkt;
+			n->m_nextpkt = NULL;
+			(*ifp->if_input)(ifp, n);
+			maybe_yield();
+		}
+		FXP_LOCK(sc);
+	}
+
+	FXP_UNLOCK(sc);
+	/* Re-enable interrupts. */
+	CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, 0);
+}
+
+/*
+ * Update packet in/out/collision statistics. The i82557 doesn't
+ * allow you to access these counters without doing a fairly
+ * expensive DMA to get _all_ of the statistics it maintains, so
+ * we do this operation here only once per second. The statistics
+ * counters in the kernel are updated from the previous dump-stats
+ * DMA and then a new dump-stats DMA is started. The on-chip
+ * counters are zeroed when the DMA completes. If we can't start
+ * the DMA immediately, we don't wait - we just prepare to read
+ * them again next time.
+ */
+static void
 fxp_update_stats(struct fxp_softc *sc)
 {
 	struct ifnet *ifp = sc->ifp;
@@ -2098,17 +2076,6 @@ fxp_update_stats(struct fxp_softc *sc)
 	}
 }
 
-/*
- * Update packet in/out/collision statistics. The i82557 doesn't
- * allow you to access these counters without doing a fairly
- * expensive DMA to get _all_ of the statistics it maintains, so
- * we do this operation here only once per second. The statistics
- * counters in the kernel are updated from the previous dump-stats
- * DMA and then a new dump-stats DMA is started. The on-chip
- * counters are zeroed when the DMA completes. If we can't start
- * the DMA immediately, we don't wait - we just prepare to read
- * them again next time.
- */
 static void
 fxp_tick(void *xsc)
 {
@@ -2636,7 +2603,7 @@ fxp_new_rfabuf(struct fxp_softc *sc, str
 	 * Move the data pointer up so that the incoming data packet
 	 * will be 32-bit aligned.
 	 */
-	m->m_data += RFA_ALIGNMENT_FUDGE;
+	m->m_data += ETHER_ALIGN;
 
 	/*
 	 * Get a pointer to the base of the mbuf cluster and move
@@ -2644,12 +2611,12 @@ fxp_new_rfabuf(struct fxp_softc *sc, str
 	 */
 	rfa = mtod(m, struct fxp_rfa *);
 	m->m_data += sc->rfa_size;
-	rfa->size = htole16(MCLBYTES - sc->rfa_size - RFA_ALIGNMENT_FUDGE);
+	rfa->size = htole16(MCLBYTES - sc->rfa_size - ETHER_ALIGN);
 
 	rfa->rfa_status = 0;
 	rfa->rfa_control = htole16(FXP_RFA_CONTROL_EL);
 	rfa->actual_size = 0;
-	m->m_len = m->m_pkthdr.len = MCLBYTES - RFA_ALIGNMENT_FUDGE -
+	m->m_len = m->m_pkthdr.len = MCLBYTES - ETHER_ALIGN -
 	    sc->rfa_size;
 
 	/*
@@ -2663,7 +2630,7 @@ fxp_new_rfabuf(struct fxp_softc *sc, str
 
 	/* Map the RFA into DMA memory. */
 	error = bus_dmamap_load(sc->fxp_rxmtag, sc->spare_map, rfa,
-	    MCLBYTES - RFA_ALIGNMENT_FUDGE, fxp_dma_map_addr,
+	    MCLBYTES - ETHER_ALIGN, fxp_dma_map_addr,
 	    &rxp->rx_addr, BUS_DMA_NOWAIT);
 	if (error) {
 		m_freem(m);
@@ -2695,7 +2662,7 @@ fxp_add_rfabuf(struct fxp_softc *sc, str
 	if (sc->fxp_desc.rx_head != NULL) {
 		p_rx = sc->fxp_desc.rx_tail;
 		p_rfa = (struct fxp_rfa *)
-		    (p_rx->rx_mbuf->m_ext.ext_buf + RFA_ALIGNMENT_FUDGE);
+		    (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;
@@ -2720,7 +2687,7 @@ fxp_discard_rfabuf(struct fxp_softc *sc,
 	 * Move the data pointer up so that the incoming data packet
 	 * will be 32-bit aligned.
 	 */
-	m->m_data += RFA_ALIGNMENT_FUDGE;
+	m->m_data += ETHER_ALIGN;
 
 	/*
 	 * Get a pointer to the base of the mbuf cluster and move
@@ -2728,7 +2695,7 @@ fxp_discard_rfabuf(struct fxp_softc *sc,
 	 */
 	rfa = mtod(m, struct fxp_rfa *);
 	m->m_data += sc->rfa_size;
-	rfa->size = htole16(MCLBYTES - sc->rfa_size - RFA_ALIGNMENT_FUDGE);
+	rfa->size = htole16(MCLBYTES - sc->rfa_size - ETHER_ALIGN);
 
 	rfa->rfa_status = 0;
 	rfa->rfa_control = htole16(FXP_RFA_CONTROL_EL);


More information about the svn-src-user mailing list