summaryrefslogtreecommitdiffstats
path: root/sys/dev/em
diff options
context:
space:
mode:
authorpdeuskar <pdeuskar@FreeBSD.org>2002-08-21 23:44:15 +0000
committerpdeuskar <pdeuskar@FreeBSD.org>2002-08-21 23:44:15 +0000
commit7e6b0a1f9d0a3a3e0203c024f7e575767d9cd196 (patch)
treef7d51d6945172cd4e17af5f081548cc0cad62930 /sys/dev/em
parent5ea3052c0e0ddd257c2631b341c26580d485f5a2 (diff)
downloadFreeBSD-src-7e6b0a1f9d0a3a3e0203c024f7e575767d9cd196.zip
FreeBSD-src-7e6b0a1f9d0a3a3e0203c024f7e575767d9cd196.tar.gz
TX/RX descriptor/buffer management changes.
Use array based scheme instead of queueing macros. Submitted by: Luigi Rizzo (rizzo@icir.org) MFC after: 3 days
Diffstat (limited to 'sys/dev/em')
-rw-r--r--sys/dev/em/if_em.c468
-rw-r--r--sys/dev/em/if_em.h60
2 files changed, 216 insertions, 312 deletions
diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c
index f28143a..d430a12 100644
--- a/sys/dev/em/if_em.c
+++ b/sys/dev/em/if_em.c
@@ -53,7 +53,7 @@ struct adapter *em_adapter_list = NULL;
* Driver version
*********************************************************************/
-char em_driver_version[] = "1.3.14";
+char em_driver_version[] = "1.3.15";
/*********************************************************************
@@ -130,9 +130,8 @@ static void em_process_receive_interrupts(struct adapter *);
static void em_receive_checksum(struct adapter *,
struct em_rx_desc * rx_desc,
struct mbuf *);
-static void em_transmit_checksum_setup(struct adapter *,
+static int em_transmit_checksum_setup(struct adapter *,
struct mbuf *,
- struct em_tx_buffer *,
u_int32_t *,
u_int32_t *);
static void em_set_promisc(struct adapter *);
@@ -140,7 +139,7 @@ static void em_disable_promisc(struct adapter *);
static void em_set_multi(struct adapter *);
static void em_print_hw_stats(struct adapter *);
static void em_print_link_status(struct adapter *);
-static int em_get_buf(struct em_rx_buffer *, struct adapter *,
+static int em_get_buf(int i, struct adapter *,
struct mbuf *);
static void em_enable_vlans(struct adapter *adapter);
@@ -276,10 +275,10 @@ em_attach(device_t dev)
/* Set the max frame size assuming standard ethernet sized frames */
adapter->hw.max_frame_size =
- ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN;
+ ETHERMTU + ETHER_HDR_LEN + ETHER_CRC_LEN;
adapter->hw.min_frame_size =
- MINIMUM_ETHERNET_PACKET_SIZE + ETHER_CRC_LEN;
+ MINIMUM_ETHERNET_PACKET_SIZE + ETHER_CRC_LEN;
/* This controls when hardware reports transmit completion status. */
if ((EM_REPORT_TX_EARLY == 0) || (EM_REPORT_TX_EARLY == 1)) {
@@ -469,15 +468,22 @@ em_start(struct ifnet *ifp)
s = splimp();
while (ifp->if_snd.ifq_head != NULL) {
+ int i, count = 0;
struct ifvlan *ifv = NULL;
IF_DEQUEUE(&ifp->if_snd, m_head);
if (m_head == NULL) break;
+ /* If num_tx_desc_avail is less than threshold, call
+ * clean_transmit_interrupts to reclaim TX descriptors
+ */
if (adapter->num_tx_desc_avail <= TX_CLEANUP_THRESHOLD)
em_clean_transmit_interrupts(adapter);
+ /* If num_tx_desc_avail is still less than threshold,
+ * prepend the mbuf to the head of the queue.
+ */
if (adapter->num_tx_desc_avail <= TX_CLEANUP_THRESHOLD) {
ifp->if_flags |= IFF_OACTIVE;
IF_PREPEND(&ifp->if_snd, m_head);
@@ -485,66 +491,52 @@ em_start(struct ifnet *ifp)
break;
}
- tx_buffer = STAILQ_FIRST(&adapter->free_tx_buffer_list);
- if (!tx_buffer) {
- adapter->no_tx_buffer_avail1++;
- /*
- * OK so we should not get here but I've seen it so let
- * us try to clean up and then try to get a tx_buffer
- * again and only break if we still don't get one.
- */
- em_clean_transmit_interrupts(adapter);
- tx_buffer = STAILQ_FIRST(&adapter->free_tx_buffer_list);
- if (!tx_buffer) {
- ifp->if_flags |= IFF_OACTIVE;
- IF_PREPEND(&ifp->if_snd, m_head);
- adapter->no_tx_buffer_avail2++;
- break;
- }
- }
- STAILQ_REMOVE_HEAD(&adapter->free_tx_buffer_list, em_tx_entry);
-
+ i = adapter->next_avail_tx_desc;
+ tx_buffer = &adapter->tx_buffer_area[i];
+ tx_buffer->m_head = m_head;
tx_buffer->num_tx_desc_used = 0;
- tx_buffer->m_head = m_head;
if (ifp->if_hwassist > 0) {
- em_transmit_checksum_setup(adapter, m_head, tx_buffer,
- &txd_upper, &txd_lower);
- } else {
- txd_upper = 0;
- txd_lower = 0;
- }
-
- /* Find out if we are in vlan mode */
- if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) &&
- m_head->m_pkthdr.rcvif != NULL &&
- m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN)
- ifv = m_head->m_pkthdr.rcvif->if_softc;
-
+ if (em_transmit_checksum_setup(adapter, m_head,
+ &txd_upper, &txd_lower)) {
+ /*
+ * if we change context, one tx_desc is used,
+ * so count it and advance pointer (i)
+ */
+ count = 1;
+ if (++i == adapter->num_tx_desc)
+ i = 0;
+ }
+ }
+ else
+ txd_upper = txd_lower = 0;
+
for (mp = m_head; mp != NULL; mp = mp->m_next) {
if (mp->m_len == 0)
continue;
- current_tx_desc = adapter->next_avail_tx_desc;
+ current_tx_desc = &adapter->tx_desc_base[i];
virtual_addr = mtod(mp, vm_offset_t);
current_tx_desc->buffer_addr = vtophys(virtual_addr);
current_tx_desc->lower.data = (txd_lower | mp->m_len);
current_tx_desc->upper.data = (txd_upper);
- if (current_tx_desc == adapter->last_tx_desc)
- adapter->next_avail_tx_desc =
- adapter->first_tx_desc;
- else
- adapter->next_avail_tx_desc++;
+ if (++i == adapter->num_tx_desc)
+ i = 0;
+ count++;
- adapter->num_tx_desc_avail--;
- tx_buffer->num_tx_desc_used++;
}
- /* Put this tx_buffer at the end in the "in use" list */
- STAILQ_INSERT_TAIL(&adapter->used_tx_buffer_list, tx_buffer,
- em_tx_entry);
+ tx_buffer->num_tx_desc_used = count;
+ adapter->num_tx_desc_avail -= count;
+ adapter->next_avail_tx_desc = i;
+
+ /* Find out if we are in vlan mode */
+ if ((m_head->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) &&
+ m_head->m_pkthdr.rcvif != NULL &&
+ m_head->m_pkthdr.rcvif->if_type == IFT_L2VLAN)
+ ifv = m_head->m_pkthdr.rcvif->if_softc;
if (ifv != NULL) {
/* Tell hardware to add tag */
@@ -568,9 +560,7 @@ em_start(struct ifnet *ifp)
* Advance the Transmit Descriptor Tail (Tdt), this tells the E1000
* that this frame is available to transmit.
*/
- E1000_WRITE_REG(&adapter->hw, TDT,
- (((uintptr_t) adapter->next_avail_tx_desc -
- (uintptr_t) adapter->first_tx_desc) >> 4));
+ E1000_WRITE_REG(&adapter->hw, TDT, i);
} /* end of while loop */
splx(s);
@@ -1439,35 +1429,13 @@ em_allocate_transmit_structures(struct adapter * adapter)
static int
em_setup_transmit_structures(struct adapter * adapter)
{
- struct em_tx_buffer *tx_buffer;
- int i;
-
if (em_allocate_transmit_structures(adapter))
return ENOMEM;
- adapter->first_tx_desc = adapter->tx_desc_base;
- adapter->last_tx_desc =
- adapter->first_tx_desc + (adapter->num_tx_desc - 1);
-
-
- STAILQ_INIT(&adapter->free_tx_buffer_list);
- STAILQ_INIT(&adapter->used_tx_buffer_list);
-
- tx_buffer = adapter->tx_buffer_area;
-
- /* Setup the linked list of the tx_buffer's */
- for (i = 0; i < adapter->num_tx_desc; i++, tx_buffer++) {
- bzero((void *) tx_buffer, sizeof(struct em_tx_buffer));
- STAILQ_INSERT_TAIL(&adapter->free_tx_buffer_list,
- tx_buffer, em_tx_entry);
- }
-
- bzero((void *) adapter->first_tx_desc,
- (sizeof(struct em_tx_desc)) * adapter->num_tx_desc);
-
- /* Setup TX descriptor pointers */
- adapter->next_avail_tx_desc = adapter->first_tx_desc;
- adapter->oldest_used_tx_desc = adapter->first_tx_desc;
+ bzero((void *) adapter->tx_desc_base,
+ (sizeof(struct em_tx_desc)) * adapter->num_tx_desc);
+
+ adapter->next_avail_tx_desc = 0;
/* Set number of descriptors available */
adapter->num_tx_desc_avail = adapter->num_tx_desc;
@@ -1590,17 +1558,16 @@ em_free_transmit_structures(struct adapter * adapter)
* The offload context needs to be set when we transfer the first
* packet of a particular protocol (TCP/UDP). We change the
* context only if the protocol type changes.
+ * Return 1 on context change, 0 otherwise.
*
**********************************************************************/
-static void
+static int
em_transmit_checksum_setup(struct adapter * adapter,
struct mbuf *mp,
- struct em_tx_buffer *tx_buffer,
u_int32_t *txd_upper,
u_int32_t *txd_lower)
{
struct em_context_desc *TXD;
- struct em_tx_desc * current_tx_desc;
if (mp->m_pkthdr.csum_flags) {
@@ -1608,7 +1575,7 @@ em_transmit_checksum_setup(struct adapter * adapter,
*txd_upper = E1000_TXD_POPTS_TXSM << 8;
*txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
if (adapter->active_checksum_context == OFFLOAD_TCP_IP)
- return;
+ return (0);
else
adapter->active_checksum_context = OFFLOAD_TCP_IP;
@@ -1616,25 +1583,25 @@ em_transmit_checksum_setup(struct adapter * adapter,
*txd_upper = E1000_TXD_POPTS_TXSM << 8;
*txd_lower = E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
if (adapter->active_checksum_context == OFFLOAD_UDP_IP)
- return;
+ return(0);
else
adapter->active_checksum_context = OFFLOAD_UDP_IP;
} else {
*txd_upper = 0;
*txd_lower = 0;
- return;
+ return (0);
}
} else {
*txd_upper = 0;
*txd_lower = 0;
- return;
+ return (0);
}
/* If we reach this point, the checksum offload context
* needs to be reset.
*/
- current_tx_desc = adapter->next_avail_tx_desc;
- TXD = (struct em_context_desc *)current_tx_desc;
+ TXD = (struct em_context_desc *)
+ &adapter->tx_desc_base[adapter->next_avail_tx_desc];
TXD->lower_setup.ip_fields.ipcss = ETHER_HDR_LEN;
TXD->lower_setup.ip_fields.ipcso =
@@ -1659,15 +1626,7 @@ em_transmit_checksum_setup(struct adapter * adapter,
TXD->tcp_seg_setup.data = 0;
TXD->cmd_and_length = E1000_TXD_CMD_DEXT;
- if (current_tx_desc == adapter->last_tx_desc)
- adapter->next_avail_tx_desc = adapter->first_tx_desc;
- else
- adapter->next_avail_tx_desc++;
-
- adapter->num_tx_desc_avail--;
-
- tx_buffer->num_tx_desc_used++;
- return;
+ return(1);
}
@@ -1677,40 +1636,40 @@ em_transmit_checksum_setup(struct adapter * adapter,
*
**********************************************************************/
static int
-em_get_buf(struct em_rx_buffer *rx_buffer, struct adapter *adapter,
- struct mbuf *mp)
+em_get_buf(int i, struct adapter *adapter,
+ struct mbuf *nmp)
{
- struct mbuf *nmp;
+ register struct mbuf *mp = nmp;
struct ifnet *ifp;
ifp = &adapter->interface_data.ac_if;
if (mp == NULL) {
- MGETHDR(nmp, M_DONTWAIT, MT_DATA);
- if (nmp == NULL) {
+ MGETHDR(mp, M_DONTWAIT, MT_DATA);
+ if (mp == NULL) {
adapter->mbuf_alloc_failed++;
return(ENOBUFS);
}
- MCLGET(nmp, M_DONTWAIT);
- if ((nmp->m_flags & M_EXT) == 0) {
- m_freem(nmp);
+ MCLGET(mp, M_DONTWAIT);
+ if ((mp->m_flags & M_EXT) == 0) {
+ m_freem(mp);
adapter->mbuf_cluster_failed++;
return(ENOBUFS);
}
- nmp->m_len = nmp->m_pkthdr.len = MCLBYTES;
+ mp->m_len = mp->m_pkthdr.len = MCLBYTES;
} else {
- nmp = mp;
- nmp->m_len = nmp->m_pkthdr.len = MCLBYTES;
- nmp->m_data = nmp->m_ext.ext_buf;
- nmp->m_next = NULL;
+ mp->m_len = mp->m_pkthdr.len = MCLBYTES;
+ mp->m_data = mp->m_ext.ext_buf;
+ mp->m_next = NULL;
}
if (ifp->if_mtu <= ETHERMTU) {
- m_adj(nmp, ETHER_ALIGN);
+ m_adj(mp, ETHER_ALIGN);
}
-
- rx_buffer->m_head = nmp;
- rx_buffer->buffer_addr = vtophys(mtod(nmp, vm_offset_t));
+
+ adapter->rx_buffer_area[i].m_head = mp;
+ adapter->rx_desc_base[i].buffer_addr =
+ vtophys(mtod(mp, vm_offset_t));
return(0);
}
@@ -1727,7 +1686,6 @@ static int
em_allocate_receive_structures(struct adapter * adapter)
{
int i;
- struct em_rx_buffer *rx_buffer;
if (!(adapter->rx_buffer_area =
(struct em_rx_buffer *) malloc(sizeof(struct em_rx_buffer) *
@@ -1741,11 +1699,10 @@ em_allocate_receive_structures(struct adapter * adapter)
bzero(adapter->rx_buffer_area,
sizeof(struct em_rx_buffer) * adapter->num_rx_desc);
- for (i = 0, rx_buffer = adapter->rx_buffer_area;
- i < adapter->num_rx_desc; i++, rx_buffer++) {
-
- if (em_get_buf(rx_buffer, adapter, NULL) == ENOBUFS) {
- rx_buffer->m_head = NULL;
+ for (i = 0; i < adapter->num_rx_desc; i++) {
+ if (em_get_buf(i, adapter, NULL) == ENOBUFS) {
+ adapter->rx_buffer_area[i].m_head = NULL;
+ adapter->rx_desc_base[i].buffer_addr = 0;
return(ENOBUFS);
}
}
@@ -1761,42 +1718,14 @@ em_allocate_receive_structures(struct adapter * adapter)
static int
em_setup_receive_structures(struct adapter * adapter)
{
- struct em_rx_buffer *rx_buffer;
- struct em_rx_desc *rx_desc;
- int i;
+ bzero((void *) adapter->rx_desc_base,
+ (sizeof(struct em_rx_desc)) * adapter->num_rx_desc);
if (em_allocate_receive_structures(adapter))
return ENOMEM;
- STAILQ_INIT(&adapter->rx_buffer_list);
-
- adapter->first_rx_desc =
- (struct em_rx_desc *) adapter->rx_desc_base;
- adapter->last_rx_desc =
- adapter->first_rx_desc + (adapter->num_rx_desc - 1);
-
- rx_buffer = (struct em_rx_buffer *) adapter->rx_buffer_area;
-
- bzero((void *) adapter->first_rx_desc,
- (sizeof(struct em_rx_desc)) * adapter->num_rx_desc);
-
- /* Build a linked list of rx_buffer's */
- for (i = 0, rx_desc = adapter->first_rx_desc;
- i < adapter->num_rx_desc;
- i++, rx_buffer++, rx_desc++) {
- if (rx_buffer->m_head == NULL)
- printf("em%d: Receive buffer memory not allocated",
- adapter->unit);
- else {
- rx_desc->buffer_addr = rx_buffer->buffer_addr;
- STAILQ_INSERT_TAIL(&adapter->rx_buffer_list,
- rx_buffer, em_rx_entry);
- }
- }
-
/* Setup our descriptor pointers */
- adapter->next_rx_desc_to_check = adapter->first_rx_desc;
-
+ adapter->next_rx_desc_to_check = 0;
return(0);
}
@@ -1830,9 +1759,7 @@ em_initialize_receive_unit(struct adapter * adapter)
/* Setup the HW Rx Head and Tail Descriptor Pointers */
E1000_WRITE_REG(&adapter->hw, RDH, 0);
- E1000_WRITE_REG(&adapter->hw, RDT,
- (((uintptr_t) adapter->last_rx_desc -
- (uintptr_t) adapter->first_rx_desc) >> 4));
+ E1000_WRITE_REG(&adapter->hw, RDT, adapter->num_rx_desc - 1);
/* Setup the Receive Control Register */
reg_rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_LBM_NO |
@@ -1914,22 +1841,17 @@ em_free_receive_structures(struct adapter * adapter)
static void
em_process_receive_interrupts(struct adapter * adapter)
{
- struct mbuf *mp;
struct ifnet *ifp;
struct ether_header *eh;
- u_int16_t len;
- u_int8_t last_byte;
u_int8_t accept_frame = 0;
- u_int8_t eop = 0;
- u_int32_t pkt_len = 0;
+ int i;
/* Pointer to the receive descriptor being examined. */
struct em_rx_desc *current_desc;
- struct em_rx_desc *last_desc_processed;
- struct em_rx_buffer *rx_buffer;
ifp = &adapter->interface_data.ac_if;
- current_desc = adapter->next_rx_desc_to_check;
+ i = adapter->next_rx_desc_to_check;
+ current_desc = &adapter->rx_desc_base[i];
if (!((current_desc->status) & E1000_RXD_STAT_DD)) {
#ifdef DBG_STATS
@@ -1939,18 +1861,10 @@ em_process_receive_interrupts(struct adapter * adapter)
}
while (current_desc->status & E1000_RXD_STAT_DD) {
+ struct mbuf *mp = adapter->rx_buffer_area[i].m_head;
+ int eop, len;
- /* Get a pointer to the actual receive buffer */
- rx_buffer = STAILQ_FIRST(&adapter->rx_buffer_list);
-
- if (rx_buffer == NULL) {
- printf("em%d: Found null rx_buffer\n", adapter->unit);
- return;
- }
-
- mp = rx_buffer->m_head;
accept_frame = 1;
-
if (current_desc->status & E1000_RXD_STAT_EOP) {
eop = 1;
len = current_desc->length - ETHER_CRC_LEN;
@@ -1960,15 +1874,14 @@ em_process_receive_interrupts(struct adapter * adapter)
}
if (current_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
+ u_int8_t last_byte;
+ u_int32_t pkt_len = current_desc->length;
- /* Compute packet length for tbi_accept macro */
- pkt_len = current_desc->length;
- if (adapter->fmp != NULL) {
+ if (adapter->fmp != NULL)
pkt_len += adapter->fmp->m_pkthdr.len;
- }
-
- last_byte = *(mtod(rx_buffer->m_head,caddr_t) +
- current_desc->length - 1);
+
+ last_byte = *(mtod(mp, caddr_t) +
+ current_desc->length - 1);
if (TBI_ACCEPT(&adapter->hw, current_desc->status,
current_desc->errors,
@@ -1978,17 +1891,19 @@ em_process_receive_interrupts(struct adapter * adapter)
pkt_len,
adapter->hw.mac_addr);
len--;
- } else {
+ }
+ else {
accept_frame = 0;
}
}
if (accept_frame) {
- if (em_get_buf(rx_buffer, adapter, NULL) == ENOBUFS) {
+ if (em_get_buf(i, adapter, NULL) == ENOBUFS) {
adapter->dropped_pkts++;
- em_get_buf(rx_buffer, adapter, mp);
- if (adapter->fmp != NULL) m_freem(adapter->fmp);
+ em_get_buf(i, adapter, mp);
+ if (adapter->fmp != NULL)
+ m_freem(adapter->fmp);
adapter->fmp = NULL;
adapter->lmp = NULL;
break;
@@ -2029,39 +1944,27 @@ em_process_receive_interrupts(struct adapter * adapter)
}
} else {
adapter->dropped_pkts++;
- em_get_buf(rx_buffer, adapter, mp);
- if (adapter->fmp != NULL) m_freem(adapter->fmp);
+ em_get_buf(i, adapter, mp);
+ if (adapter->fmp != NULL)
+ m_freem(adapter->fmp);
adapter->fmp = NULL;
adapter->lmp = NULL;
}
/* Zero out the receive descriptors status */
current_desc->status = 0;
-
- if (rx_buffer->m_head != NULL) {
- current_desc->buffer_addr = rx_buffer->buffer_addr;
- }
-
- /* Advance our pointers to the next descriptor (checking for wrap). */
- if (current_desc == adapter->last_rx_desc)
- adapter->next_rx_desc_to_check = adapter->first_rx_desc;
- else
- ((adapter)->next_rx_desc_to_check)++;
-
- last_desc_processed = current_desc;
- current_desc = adapter->next_rx_desc_to_check;
- /*
- * Put the buffer that we just indicated back at the end of our list
- */
- STAILQ_REMOVE_HEAD(&adapter->rx_buffer_list, em_rx_entry);
- STAILQ_INSERT_TAIL(&adapter->rx_buffer_list,
- rx_buffer, em_rx_entry);
-
+
/* Advance the E1000's Receive Queue #0 "Tail Pointer". */
- E1000_WRITE_REG(&adapter->hw, RDT,
- (((u_long) last_desc_processed -
- (u_long) adapter->first_rx_desc) >> 4));
+ E1000_WRITE_REG(&adapter->hw, RDT, i);
+
+ /* Advance our pointers to the next descriptor */
+ if (++i == adapter->num_rx_desc) {
+ i = 0;
+ current_desc = adapter->rx_desc_base;
+ } else
+ current_desc++;
}
+ adapter->next_rx_desc_to_check = i;
return;
}
@@ -2347,87 +2250,88 @@ em_print_hw_stats(struct adapter *adapter)
*
* Examine each tx_buffer in the used queue. If the hardware is done
* processing the packet then free associated resources. The
- * tx_buffer is put back on the free queue.
+ * tx_buffer is put back on the free queue.
*
**********************************************************************/
static void
em_clean_transmit_interrupts(struct adapter * adapter)
{
- struct em_tx_buffer *tx_buffer;
- struct em_tx_desc *tx_desc;
- int s;
- struct ifnet *ifp;
+ int s;
+ int i, num_avail;
- s = splimp();
+ if (adapter->num_tx_desc_avail == adapter->num_tx_desc)
+ return;
+
+ s = splimp();
#ifdef DBG_STATS
- adapter->clean_tx_interrupts++;
+ adapter->clean_tx_interrupts++;
#endif
-
- for (tx_buffer = STAILQ_FIRST(&adapter->used_tx_buffer_list);
- tx_buffer;
- tx_buffer = STAILQ_FIRST(&adapter->used_tx_buffer_list)) {
-
- /*
- * Get hold of the next descriptor that the em will report status
- * back to (this will be the last descriptor of a given tx_buffer). We
- * only want to free the tx_buffer (and it resources) if the driver is
- * done with ALL of the descriptors. If the driver is done with the
- * last one then it is done with all of them.
- */
-
- tx_desc = adapter->oldest_used_tx_desc +
- (tx_buffer->num_tx_desc_used - 1);
-
- /* Check for wrap case */
- if (tx_desc > adapter->last_tx_desc)
- tx_desc -= adapter->num_tx_desc;
-
-
- /*
- * If the descriptor done bit is set free tx_buffer and associated
- * resources
- */
- if (tx_desc->upper.fields.status & E1000_TXD_STAT_DD) {
-
- STAILQ_REMOVE_HEAD(&adapter->used_tx_buffer_list,
- em_tx_entry);
-
- if ((tx_desc == adapter->last_tx_desc))
- adapter->oldest_used_tx_desc =
- adapter->first_tx_desc;
- else
- adapter->oldest_used_tx_desc = (tx_desc + 1);
-
- /* Make available the descriptors that were previously used */
- adapter->num_tx_desc_avail +=
- tx_buffer->num_tx_desc_used;
-
- tx_buffer->num_tx_desc_used = 0;
-
- if (tx_buffer->m_head) {
- m_freem(tx_buffer->m_head);
- tx_buffer->m_head = NULL;
- }
- /* Return this "Software packet" back to the "free" list */
- STAILQ_INSERT_TAIL(&adapter->free_tx_buffer_list,
- tx_buffer, em_tx_entry);
- } else {
- /*
- * Found a tx_buffer that the em is not done with then there is
- * no reason to check the rest of the queue.
- */
- break;
- }
- } /* end for each tx_buffer */
-
- ifp = &adapter->interface_data.ac_if;
-
- /* Tell the stack that it is OK to send packets */
- if (adapter->num_tx_desc_avail > TX_CLEANUP_THRESHOLD) {
- ifp->if_timer = 0;
- ifp->if_flags &= ~IFF_OACTIVE;
- }
- splx(s);
- return;
+ /*
+ * Keep the number of descriptors available in a local
+ * variable (to ease updates and also check if some descriptors
+ * have been freed).
+ * Set i to the oldest used buffer (and descriptor), which is
+ * i = (next_avail + num_avail) % num_tx_desc
+ * This is the index of the buffer we look at.
+ */
+ num_avail = adapter->num_tx_desc_avail;
+ i = adapter->next_avail_tx_desc + num_avail;
+ if (i >= adapter->num_tx_desc)
+ i -= adapter->num_tx_desc;
+
+ for (;;) {
+ struct em_tx_buffer *tx_buffer = &adapter->tx_buffer_area[i];
+
+ /*
+ * Exit from the loop if the buffer is not in use.
+ * Otherwise locate the last descriptor of the buffer, and
+ * check its status as reported by the hardware. If the
+ * hardware is done with it (E1000_TXD_STAT_DD is set)
+ * we can free the buffer and all of its resources (mbuf
+ * and descriptors), otherwise we exit from the loop.
+ */
+ if (tx_buffer->num_tx_desc_used == 0)
+ break;
+
+ i += (tx_buffer->num_tx_desc_used - 1);
+ if (i >= adapter->num_tx_desc)
+ i -= adapter->num_tx_desc;
+
+ if (!(adapter->tx_desc_base[i].upper.fields.status
+ & E1000_TXD_STAT_DD))
+ break;
+
+ /*
+ * Free tx_buffer, mbuf and descriptors.
+ * Advance index (i) to oldest used tx buffer.
+ */
+ if (tx_buffer->m_head) {
+ m_freem(tx_buffer->m_head);
+ tx_buffer->m_head = NULL;
+ }
+ num_avail += tx_buffer->num_tx_desc_used;
+ tx_buffer->num_tx_desc_used = 0;
+ if (++i == adapter->num_tx_desc)
+ i = 0;
+ }
+
+ /*
+ * If we have enough room, clear IFF_OACTIVE to tell the stack
+ * that it is OK to send packets.
+ * If there are no pending descriptors, clear the timeout. Otherwise,
+ * if some descriptors have been freed, restart the timeout.
+ */
+ if (num_avail > TX_CLEANUP_THRESHOLD) {
+ struct ifnet *ifp = &adapter->interface_data.ac_if;
+
+ ifp->if_flags &= ~IFF_OACTIVE;
+ if (num_avail == adapter->num_tx_desc)
+ ifp->if_timer = 0;
+ else if (num_avail == adapter->num_tx_desc_avail)
+ ifp->if_timer = EM_TX_TIMEOUT;
+ }
+ adapter->num_tx_desc_avail = num_avail;
+ splx(s);
+ return;
}
diff --git a/sys/dev/em/if_em.h b/sys/dev/em/if_em.h
index d548437..3eba5b8 100644
--- a/sys/dev/em/if_em.h
+++ b/sys/dev/em/if_em.h
@@ -151,20 +151,12 @@ typedef struct _em_vendor_info_t
struct em_tx_buffer {
- STAILQ_ENTRY(em_tx_buffer) em_tx_entry;
struct mbuf *m_head;
u_int32_t num_tx_desc_used;
};
-
-/* ******************************************************************************
- * This structure stores information about the 2k aligned receive buffer
- * into which the E1000 DMA's frames.
- * ******************************************************************************/
struct em_rx_buffer {
- STAILQ_ENTRY(em_rx_buffer) em_rx_entry;
struct mbuf *m_head;
- u_int64_t buffer_addr;
};
typedef enum _XSUM_CONTEXT_T {
@@ -202,28 +194,36 @@ struct adapter {
XSUM_CONTEXT_T active_checksum_context;
- /* Transmit definitions */
- struct em_tx_desc *first_tx_desc;
- struct em_tx_desc *last_tx_desc;
- struct em_tx_desc *next_avail_tx_desc;
- struct em_tx_desc *oldest_used_tx_desc;
- struct em_tx_desc *tx_desc_base;
- volatile u_int16_t num_tx_desc_avail;
- u_int16_t num_tx_desc;
- u_int32_t txd_cmd;
- struct em_tx_buffer *tx_buffer_area;
- STAILQ_HEAD(__em_tx_buffer_free, em_tx_buffer) free_tx_buffer_list;
- STAILQ_HEAD(__em_tx_buffer_used, em_tx_buffer) used_tx_buffer_list;
-
- /* Receive definitions */
- struct em_rx_desc *first_rx_desc;
- struct em_rx_desc *last_rx_desc;
- struct em_rx_desc *next_rx_desc_to_check;
- struct em_rx_desc *rx_desc_base;
- u_int16_t num_rx_desc;
- u_int32_t rx_buffer_len;
- struct em_rx_buffer *rx_buffer_area;
- STAILQ_HEAD(__em_rx_buffer, em_rx_buffer) rx_buffer_list;
+ /*
+ * Transmit definitions
+ *
+ * We have an array of num_tx_desc descriptors (handled
+ * by the controller) paired with an array of tx_buffers
+ * (at tx_buffer_area).
+ * The index of the next available descriptor is next_avail_tx_desc.
+ * The number of remaining tx_desc is num_tx_desc_avail.
+ */
+ struct em_tx_desc *tx_desc_base;
+ u_int32_t next_avail_tx_desc;
+ volatile u_int16_t num_tx_desc_avail;
+ u_int16_t num_tx_desc;
+ u_int32_t txd_cmd;
+ struct em_tx_buffer *tx_buffer_area;
+
+ /*
+ * Receive definitions
+ *
+ * we have an array of num_rx_desc rx_desc (handled by the
+ * controller), and paired with an array of rx_buffers
+ * (at rx_buffer_area).
+ * The next pair to check on receive is at offset next_rx_desc_to_check
+ */
+ struct em_rx_desc *rx_desc_base;
+ u_int32_t next_rx_desc_to_check;
+ u_int16_t num_rx_desc;
+ u_int32_t rx_buffer_len;
+ struct em_rx_buffer *rx_buffer_area;
+
/* Jumbo frame */
struct mbuf *fmp;
OpenPOWER on IntegriCloud