The branch main has been updated by bz:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=9de11cc26ab61d7f80e8af84dbc55d8cbd6f832d

commit 9de11cc26ab61d7f80e8af84dbc55d8cbd6f832d
Author:     Bjoern A. Zeeb <[email protected]>
AuthorDate: 2026-02-03 22:13:24 +0000
Commit:     Bjoern A. Zeeb <[email protected]>
CommitDate: 2026-07-17 15:48:53 +0000

    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
---
 sys/compat/linuxkpi/common/include/linux/skbuff.h |  6 +--
 sys/compat/linuxkpi/common/src/linux_skbuff.c     | 60 +++++++++++++++++++++++
 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)
 {

Reply via email to