svn commit: r207254 - user/jmallett/octeon/sys/mips/cavium/octe
Juli Mallett
jmallett at FreeBSD.org
Tue Apr 27 00:44:41 UTC 2010
Author: jmallett
Date: Tue Apr 27 00:44:40 2010
New Revision: 207254
URL: http://svn.freebsd.org/changeset/base/207254
Log:
Use a gather list to transmit a fragmented packet rather than defragging it.
This improves transmit performance 100%.
Modified:
user/jmallett/octeon/sys/mips/cavium/octe/ethernet-tx.c
Modified: user/jmallett/octeon/sys/mips/cavium/octe/ethernet-tx.c
==============================================================================
--- user/jmallett/octeon/sys/mips/cavium/octe/ethernet-tx.c Mon Apr 26 23:57:07 2010 (r207253)
+++ user/jmallett/octeon/sys/mips/cavium/octe/ethernet-tx.c Tue Apr 27 00:44:40 2010 (r207254)
@@ -74,6 +74,7 @@ int cvm_oct_xmit(struct mbuf *m, struct
#if REUSE_MBUFS_WITHOUT_FREE
unsigned char *fpa_head;
#endif
+ cvmx_wqe_t *work;
/* Prefetch the private data structure.
It is larger that one cache line */
@@ -130,28 +131,72 @@ int cvm_oct_xmit(struct mbuf *m, struct
}
}
- /* Build the PKO buffer pointer */
- if (m->m_pkthdr.len != m->m_len) {
- m = m_defrag(m, M_DONTWAIT);
- if (m->m_pkthdr.len != m->m_len)
- panic("%s: need to load multiple segments.", __func__);
- }
+ /*
+ * If the packet is not fragmented.
+ */
+ if (m->m_pkthdr.len == m->m_len) {
+ /* Build the PKO buffer pointer */
+ hw_buffer.u64 = 0;
+ hw_buffer.s.addr = cvmx_ptr_to_phys(m->m_data);
+ hw_buffer.s.pool = 0;
+ hw_buffer.s.size = m->m_len;
+
+ /* Build the PKO command */
+ pko_command.u64 = 0;
+ pko_command.s.segs = 1;
- hw_buffer.u64 = 0;
- hw_buffer.s.addr = cvmx_ptr_to_phys(m->m_data);
- hw_buffer.s.pool = 0;
- hw_buffer.s.size = m->m_len;
+ work = NULL;
+ } else {
+ struct mbuf *n;
+ unsigned segs;
+ uint64_t *gp;
- /* Build the PKO command */
- pko_command.u64 = 0;
+ /*
+ * The packet is fragmented, we need to send a list of segments
+ * in memory we borrow from the WQE pool.
+ */
+ work = cvmx_fpa_alloc(CVMX_FPA_WQE_POOL);
+ gp = (uint64_t *)work;
+
+ segs = 0;
+ for (n = m; n != NULL; n = n->m_next) {
+ if (segs == CVMX_FPA_WQE_POOL_SIZE / sizeof (uint64_t))
+ panic("%s: too many segments in packet; call m_collapse().", __func__);
+
+ /* Build the PKO buffer pointer */
+ hw_buffer.u64 = 0;
+ hw_buffer.s.addr = cvmx_ptr_to_phys(n->m_data);
+ hw_buffer.s.pool = 0;
+ hw_buffer.s.size = n->m_len;
+
+ *gp++ = hw_buffer.u64;
+ segs++;
+ }
+
+ /* Build the PKO buffer gather list pointer */
+ hw_buffer.u64 = 0;
+ hw_buffer.s.addr = cvmx_ptr_to_phys(work);
+ hw_buffer.s.pool = CVMX_FPA_WQE_POOL;
+ hw_buffer.s.size = segs;
+
+ /* Build the PKO command */
+ pko_command.u64 = 0;
+ pko_command.s.segs = segs;
+ pko_command.s.gather = 1;
+ }
+
+ /* Finish building the PKO command */
pko_command.s.n2 = 1; /* Don't pollute L2 with the outgoing packet */
- pko_command.s.segs = 1;
+ pko_command.s.dontfree = 1;
+ pko_command.s.reg0 = priv->fau+qos*4;
+ pko_command.s.reg0 = priv->fau+qos*4;
pko_command.s.total_bytes = m->m_pkthdr.len;
pko_command.s.size0 = CVMX_FAU_OP_SIZE_32;
pko_command.s.subone0 = 1;
pko_command.s.dontfree = 1;
pko_command.s.reg0 = priv->fau+qos*4;
+
/* See if we can put this m in the FPA pool. Any strange behavior
from the Linux networking stack will most likely be caused by a bug
in the following code. If some field is in use by the network stack
@@ -311,6 +356,8 @@ dont_put_mbuf_in_hw:
IF_ENQUEUE(&priv->tx_free_queue[qos], m);
}
}
+ if (work != NULL)
+ cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1));
/* Free mbufs not in use by the hardware */
if (_IF_QLEN(&priv->tx_free_queue[qos]) > in_use) {
More information about the svn-src-user
mailing list