aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/usb/net
diff options
context:
space:
mode:
authorDamien Broka <git@damien.sh>2023-09-13 08:23:47 +0000
committerEd Maste <emaste@FreeBSD.org>2023-09-13 14:08:11 +0000
commit70fbcd451b68b7f6038d8a602cd8d5e1bb890f1d (patch)
tree729f066bc05c3c8a5b072d12ad18a9bf0ae4dd2d /sys/dev/usb/net
parentbb56b36d7188e004840294d0bd5dfdf7f3392a05 (diff)
Diffstat (limited to 'sys/dev/usb/net')
-rw-r--r--sys/dev/usb/net/if_axge.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/sys/dev/usb/net/if_axge.c b/sys/dev/usb/net/if_axge.c
index a3b459a553e0..385a982afd9d 100644
--- a/sys/dev/usb/net/if_axge.c
+++ b/sys/dev/usb/net/if_axge.c
@@ -959,8 +959,16 @@ axge_rx_frame(struct usb_ether *ue, struct usb_page_cache *pc, int actlen)
hdr_off = pkt_end = (rxhdr >> 16) & 0xFFFF;
/*
+ * On older firmware:
* <----------------------- actlen ------------------------>
* [frame #0]...[frame #N][pkt_hdr #0]...[pkt_hdr #N][rxhdr]
+ *
+ * On newer firmware:
+ * <----------------------- actlen -----------------
+ * [frame #0]...[frame #N][pkt_hdr #0][dummy_hdr]...
+ * -------------------------------->
+ * ...[pkt_hdr #N][dummy_hdr][rxhdr]
+ *
* Each RX frame would be aligned on 8 bytes boundary. If
* RCR_IPE bit is set in AXGE_RCR register, there would be 2
* padding bytes and 6 dummy bytes(as the padding also should
@@ -968,6 +976,10 @@ axge_rx_frame(struct usb_ether *ue, struct usb_page_cache *pc, int actlen)
* IP header on 32bits boundary. Driver don't set RCR_IPE bit
* of AXGE_RCR register, so there should be no padding bytes
* which simplifies RX logic a lot.
+ *
+ * Further, newer firmware interweaves dummy headers that have
+ * pktlen == 0 and should be skipped without being seen as
+ * dropped frames.
*/
while (pkt_cnt--) {
/* verify the header offset */
@@ -978,6 +990,12 @@ axge_rx_frame(struct usb_ether *ue, struct usb_page_cache *pc, int actlen)
usbd_copy_out(pc, hdr_off, &pkt_hdr, sizeof(pkt_hdr));
pkt_hdr.status = le32toh(pkt_hdr.status);
pktlen = AXGE_RXBYTES(pkt_hdr.status);
+ hdr_off += sizeof(pkt_hdr);
+
+ /* Skip dummy packet header. */
+ if (pktlen == 0)
+ continue;
+
if (pos + pktlen > pkt_end) {
DPRINTF("Data position reached end\n");
break;
@@ -989,7 +1007,6 @@ axge_rx_frame(struct usb_ether *ue, struct usb_page_cache *pc, int actlen)
} else
axge_rxeof(ue, pc, pos, pktlen, pkt_hdr.status);
pos += (pktlen + 7) & ~7;
- hdr_off += sizeof(pkt_hdr);
}
}