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) {
