aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjoern A. Zeeb <bz@FreeBSD.org>2022-05-05 20:43:34 +0000
committerBjoern A. Zeeb <bz@FreeBSD.org>2022-05-05 20:54:44 +0000
commit6a50157090f2d0c5ab8c570d9cf2e2e3535dbdbf (patch)
treee2c983cb8e5782c66b3780fe42d83582ec17ce69
parentadbe6e6435a2d6021d90532d1fc9c6e89db0742a (diff)
downloadsrc-6a50157090f2d0c5ab8c570d9cf2e2e3535dbdbf.tar.gz
src-6a50157090f2d0c5ab8c570d9cf2e2e3535dbdbf.zip
LinuxKPI: skbuff: add memlimit tunable for 64bit systems
Some drivers, such as Realtek's rtw88, require 32bit DMA in a single segment. busdma(9) has a hard time providing this currently for 3-ish pages at large quantities (see lkpi_pci_nseg1_fail in linux_pci.c e86707418c8e8). Work around this for now by allowing a tunable to enforce physical addresses allocation limits on 64bit platforms (ignoring PAE) using "old-school" contigmalloc(9) to avoid bouncing. A patch needing a custom kernel compiled was tested in the last weeks by rtw88 users providing the 32bit limit only hardcoded. The 36bit limit can be found in iwlwifi so is added as a testing option along. This is put in as a bandaid for now, so people no longer need to patch and compile their own kernels to use rtw88 and to allow us to MFC the driver as well before the amounts of commits to track increases by much more. Sponsored by: The FreeBSD Foundation MFC after: 3 days
-rw-r--r--sys/compat/linuxkpi/common/src/linux_skbuff.c48
1 files changed, 47 insertions, 1 deletions
diff --git a/sys/compat/linuxkpi/common/src/linux_skbuff.c b/sys/compat/linuxkpi/common/src/linux_skbuff.c
index df1f6439c694..fb0fcaf99239 100644
--- a/sys/compat/linuxkpi/common/src/linux_skbuff.c
+++ b/sys/compat/linuxkpi/common/src/linux_skbuff.c
@@ -53,17 +53,35 @@ __FBSDID("$FreeBSD$");
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/gfp.h>
+#ifdef __LP64__
+#include <linux/log2.h>
+#endif
-#ifdef SKB_DEBUG
SYSCTL_DECL(_compat_linuxkpi);
SYSCTL_NODE(_compat_linuxkpi, OID_AUTO, skb, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
"LinuxKPI skbuff");
+#ifdef SKB_DEBUG
int linuxkpi_debug_skb;
SYSCTL_INT(_compat_linuxkpi_skb, OID_AUTO, debug, CTLFLAG_RWTUN,
&linuxkpi_debug_skb, 0, "SKB debug level");
#endif
+#ifdef __LP64__
+/*
+ * Realtek wireless drivers (e.g., rtw88) require 32bit DMA in a single segment.
+ * busdma(9) has a hard time providing this currently for 3-ish pages at large
+ * quantities (see lkpi_pci_nseg1_fail in linux_pci.c).
+ * Work around this for now by allowing a tunable to enforce physical addresses
+ * allocation limits on 64bit platforms using "old-school" contigmalloc(9) to
+ * avoid bouncing.
+ */
+static int linuxkpi_skb_memlimit;
+SYSCTL_INT(_compat_linuxkpi_skb, OID_AUTO, mem_limit, CTLFLAG_RDTUN,
+ &linuxkpi_skb_memlimit, 0, "SKB memory limit: 0=no limit, "
+ "1=32bit, 2=36bit, other=undef (currently 32bit)");
+#endif
+
static MALLOC_DEFINE(M_LKPISKB, "lkpiskb", "Linux KPI skbuff compat");
struct sk_buff *
@@ -77,7 +95,28 @@ linuxkpi_alloc_skb(size_t size, gfp_t gfp)
* Using our own type here not backing my kmalloc.
* We assume no one calls kfree directly on the skb.
*/
+#ifdef __LP64__
+ if (__predict_true(linuxkpi_skb_memlimit == 0)) {
+ skb = malloc(len, M_LKPISKB, linux_check_m_flags(gfp) | M_ZERO);
+ } else {
+ vm_paddr_t high;
+
+ switch (linuxkpi_skb_memlimit) {
+ case 2:
+ high = (0xfffffffff); /* 1<<36 really. */
+ break;
+ case 1:
+ default:
+ high = (0xffffffff); /* 1<<32 really. */
+ break;
+ }
+ len = roundup_pow_of_two(len);
+ skb = contigmalloc(len, M_LKPISKB,
+ linux_check_m_flags(gfp) | M_ZERO, 0, high, PAGE_SIZE, 0);
+ }
+#else
skb = malloc(len, M_LKPISKB, linux_check_m_flags(gfp) | M_ZERO);
+#endif
if (skb == NULL)
return (skb);
skb->_alloc_len = len;
@@ -194,7 +233,14 @@ linuxkpi_kfree_skb(struct sk_buff *skb)
}
}
+#ifdef __LP64__
+ if (__predict_true(linuxkpi_skb_memlimit == 0))
+ free(skb, M_LKPISKB);
+ else
+ contigfree(skb, skb->_alloc_len, M_LKPISKB);
+#else
free(skb, M_LKPISKB);
+#endif
}
#ifdef DDB