aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjoern A. Zeeb <bz@FreeBSD.org>2026-02-03 22:13:24 +0000
committerBjoern A. Zeeb <bz@FreeBSD.org>2026-07-17 15:48:53 +0000
commit9de11cc26ab61d7f80e8af84dbc55d8cbd6f832d (patch)
tree6c04d6202d8f67e6c3b8c3249be1012764ec7a1b
parentb36460e5ec4659d0fa14b35c9342c5a154b3db7d (diff)
LinuxKPI: skbuff: implement __skb_linearize()
skb_linearize() is used by mt7921, mt7925, and in the general mt76 tx dma code. __skb_linearize() is used in the general iwlwifi TX code but given the way we currently create TX skbs in LinuxKPI 802.11 we never hit that case. Sponsored by: The FreeBSD Foundation MFC after: 3 days
-rw-r--r--sys/compat/linuxkpi/common/include/linux/skbuff.h6
-rw-r--r--sys/compat/linuxkpi/common/src/linux_skbuff.c60
2 files changed, 63 insertions, 3 deletions
diff --git a/sys/compat/linuxkpi/common/include/linux/skbuff.h b/sys/compat/linuxkpi/common/include/linux/skbuff.h
index a0724803e732..9434655fc9f4 100644
--- a/sys/compat/linuxkpi/common/include/linux/skbuff.h
+++ b/sys/compat/linuxkpi/common/include/linux/skbuff.h
@@ -209,6 +209,8 @@ void linuxkpi_kfree_skb(struct sk_buff *);
struct sk_buff *linuxkpi_skb_copy(const struct sk_buff *, gfp_t);
+int lkpi___skb_linearize(struct sk_buff *);
+
/* -------------------------------------------------------------------------- */
static inline struct sk_buff *
@@ -978,9 +980,7 @@ skb_network_header(struct sk_buff *skb)
static inline int
__skb_linearize(struct sk_buff *skb)
{
- SKB_TRACE(skb);
- SKB_TODO();
- return (-ENXIO);
+ return (lkpi___skb_linearize(skb));
}
static inline int
diff --git a/sys/compat/linuxkpi/common/src/linux_skbuff.c b/sys/compat/linuxkpi/common/src/linux_skbuff.c
index abfb642ba708..a2aa601d594e 100644
--- a/sys/compat/linuxkpi/common/src/linux_skbuff.c
+++ b/sys/compat/linuxkpi/common/src/linux_skbuff.c
@@ -222,6 +222,66 @@ linuxkpi_skb_copy(const struct sk_buff *skb, gfp_t gfp)
return (new);
}
+int
+lkpi___skb_linearize(struct sk_buff *skb)
+{
+ struct sk_buff *new;
+ struct skb_shared_info *shinfo;
+ uint16_t fragno, count;
+
+ SKB_TRACE(skb);
+ SKB_IMPROVE("Hack completely re-allocating and freeing; FIXME");
+ new = skb_copy(skb, GFP_NOWAIT);
+ if (new == NULL)
+ return (-ENOMEM);
+
+ /* Now need to swap head, data, tail, ... and free from old (and then new). */
+ shinfo = skb->shinfo;
+ for (count = fragno = 0;
+ count < shinfo->nr_frags && fragno < nitems(shinfo->frags);
+ fragno++) {
+
+ if (shinfo->frags[fragno].page != NULL) {
+ struct page *p;
+
+ p = shinfo->frags[fragno].page;
+ shinfo->frags[fragno].size = 0;
+ shinfo->frags[fragno].offset = 0;
+ shinfo->frags[fragno].page = NULL;
+ __free_page(p);
+ count++;
+ }
+ }
+
+ if ((skb->_flags & _SKB_FLAGS_SKBEXTFRAG) != 0) {
+ void *p;
+
+ p = skb->head;
+ skb_free_frag(p);
+ skb->head = NULL;
+ skb->_flags &= ~_SKB_FLAGS_SKBEXTFRAG;
+ }
+
+#ifdef SKB_DMA32_MALLOC
+ if (__predict_false(linuxkpi_skb_memlimit != 0))
+ free(skb->head, M_LKPISKB);
+ else
+#endif
+ kfree(skb->head);
+
+ skb->head = new->head;
+ skb->data = new->data;
+ skb->tail = new->tail;
+ skb->end = new->end;
+ skb->len = new->len;
+ skb->data_len = new->data_len;
+ skb->truesize = new->truesize;
+
+ uma_zfree(skbzone, new);
+
+ return (0);
+}
+
void
linuxkpi_kfree_skb(struct sk_buff *skb)
{