summaryrefslogtreecommitdiff
path: root/sys/dev/pci/if_rge.c
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2024-08-21 01:12:53 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2024-08-21 01:12:53 +0000
commitf3e934410fd68fc4fee2921b36a784d9cf9ea98b (patch)
treeaea197097c78728cdc33ad8c3e500db557923351 /sys/dev/pci/if_rge.c
parent8ddfb1d70123b25e9ef2c69935b897635d237cbd (diff)
support building a single packet out of multiple rx descriptors.
rge is a bit like intel nics where you can put small mbufs on the rx ring and it will chain them together to make a jumbo packet. except unlike intel you can use any sized mbufs for the rx descriptors. this adds the handling of these packets to the rx path. we're still putting 9k frames on the ring though.
Diffstat (limited to 'sys/dev/pci/if_rge.c')
-rw-r--r--sys/dev/pci/if_rge.c47
1 files changed, 38 insertions, 9 deletions
diff --git a/sys/dev/pci/if_rge.c b/sys/dev/pci/if_rge.c
index 01eae86de51..44ce8f0d7c1 100644
--- a/sys/dev/pci/if_rge.c
+++ b/sys/dev/pci/if_rge.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_rge.c,v 1.31 2024/08/21 00:56:58 dlg Exp $ */
+/* $OpenBSD: if_rge.c,v 1.32 2024/08/21 01:12:52 dlg Exp $ */
/*
* Copyright (c) 2019, 2020, 2023, 2024
@@ -883,6 +883,12 @@ rge_stop(struct ifnet *ifp)
ifq_barrier(&ifp->if_snd);
ifq_clr_oactive(&ifp->if_snd);
+ if (q->q_rx.rge_head != NULL) {
+ m_freem(q->q_rx.rge_head);
+ q->q_rx.rge_head = NULL;
+ q->q_rx.rge_tail = &q->q_rx.rge_head;
+ }
+
/* Free the TX list buffers. */
for (i = 0; i < RGE_TX_LIST_CNT; i++) {
if (q->q_tx.rge_txq[i].txq_mbuf != NULL) {
@@ -1193,6 +1199,8 @@ rge_rx_list_init(struct rge_queues *q)
memset(q->q_rx.rge_rx_list, 0, RGE_RX_LIST_SZ);
q->q_rx.rge_rxq_prodidx = q->q_rx.rge_rxq_considx = 0;
+ q->q_rx.rge_head = NULL;
+ q->q_rx.rge_tail = &q->q_rx.rge_head;
if_rxr_init(&q->q_rx.rge_rx_ring, 32, RGE_RX_LIST_CNT - 1);
rge_fill_rx_ring(q);
@@ -1244,7 +1252,7 @@ rge_rxeof(struct rge_queues *q)
struct rge_rx_desc *cur_rx;
struct rge_rxq *rxq;
uint32_t rxstat, extsts;
- int i, total_len, rx = 0;
+ int i, mlen, rx = 0;
int cons;
i = cons = q->q_rx.rge_rxq_considx;
@@ -1274,23 +1282,44 @@ rge_rxeof(struct rge_queues *q)
if_rxr_put(rxr, 1);
rx = 1;
- total_len = rxstat & RGE_RDCMDSTS_FRAGLEN;
+ if (ISSET(rxstat, RGE_RDCMDSTS_SOF)) {
+ if (q->q_rx.rge_head != NULL) {
+ ifp->if_ierrors++;
+ m_freem(q->q_rx.rge_head);
+ q->q_rx.rge_tail = &q->q_rx.rge_head;
+ }
- /* We only handle a packet per rx descriptor at the moment */
- if ((rxstat & (RGE_RDCMDSTS_SOF | RGE_RDCMDSTS_EOF)) !=
- (RGE_RDCMDSTS_SOF | RGE_RDCMDSTS_EOF)) {
- ifp->if_ierrors++;
+ m->m_pkthdr.len = 0;
+ } else if (q->q_rx.rge_head == NULL) {
m_freem(m);
continue;
- }
+ } else
+ CLR(m->m_flags, M_PKTHDR);
+
+ *q->q_rx.rge_tail = m;
+ q->q_rx.rge_tail = &m->m_next;
+
+ mlen = rxstat & RGE_RDCMDSTS_FRAGLEN;
+ m->m_len = mlen;
+
+ m = q->q_rx.rge_head;
+ m->m_pkthdr.len += mlen;
if (rxstat & RGE_RDCMDSTS_RXERRSUM) {
ifp->if_ierrors++;
m_freem(m);
+ q->q_rx.rge_head = NULL;
+ q->q_rx.rge_tail = &q->q_rx.rge_head;
continue;
}
- m->m_pkthdr.len = m->m_len = (total_len - ETHER_CRC_LEN);
+ if (!ISSET(rxstat, RGE_RDCMDSTS_EOF))
+ continue;
+
+ q->q_rx.rge_head = NULL;
+ q->q_rx.rge_tail = &q->q_rx.rge_head;
+
+ m_adj(m, -ETHER_CRC_LEN);
extsts = letoh32(cur_rx->hi_qword1.rx_qword4.rge_extsts);