aboutsummaryrefslogtreecommitdiff
path: root/sys/compat/linuxkpi/common/include
diff options
context:
space:
mode:
Diffstat (limited to 'sys/compat/linuxkpi/common/include')
-rw-r--r--sys/compat/linuxkpi/common/include/asm/pgtable.h34
-rw-r--r--sys/compat/linuxkpi/common/include/asm/set_memory.h6
-rw-r--r--sys/compat/linuxkpi/common/include/asm/unaligned.h7
-rw-r--r--sys/compat/linuxkpi/common/include/linux/acpi.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/array_size.h17
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ascii85.h46
-rw-r--r--sys/compat/linuxkpi/common/include/linux/atomic.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/atomic/atomic-arch-fallback.h16
-rw-r--r--sys/compat/linuxkpi/common/include/linux/atomic/atomic-instrumented.h16
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bcm47xx_nvram.h21
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bcma/bcma.h29
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bcma/bcma_regs.h17
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bitops.h28
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bits.h14
-rw-r--r--sys/compat/linuxkpi/common/include/linux/cec-funcs.h16
-rw-r--r--sys/compat/linuxkpi/common/include/linux/cec.h3
-rw-r--r--sys/compat/linuxkpi/common/include/linux/cgroup.h9
-rw-r--r--sys/compat/linuxkpi/common/include/linux/cleanup.h127
-rw-r--r--sys/compat/linuxkpi/common/include/linux/compiler.h51
-rw-r--r--sys/compat/linuxkpi/common/include/linux/compiler_attributes.h49
-rw-r--r--sys/compat/linuxkpi/common/include/linux/compiler_types.h58
-rw-r--r--sys/compat/linuxkpi/common/include/linux/device.h31
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dma-mapping.h21
-rw-r--r--sys/compat/linuxkpi/common/include/linux/eventfd.h54
-rw-r--r--sys/compat/linuxkpi/common/include/linux/file.h7
-rw-r--r--sys/compat/linuxkpi/common/include/linux/font.h33
-rw-r--r--sys/compat/linuxkpi/common/include/linux/fs.h45
-rw-r--r--sys/compat/linuxkpi/common/include/linux/gfp.h8
-rw-r--r--sys/compat/linuxkpi/common/include/linux/hardirq.h1
-rw-r--r--sys/compat/linuxkpi/common/include/linux/hex.h44
-rw-r--r--sys/compat/linuxkpi/common/include/linux/highmem.h27
-rw-r--r--sys/compat/linuxkpi/common/include/linux/i2c.h7
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ieee80211.h44
-rw-r--r--sys/compat/linuxkpi/common/include/linux/instruction_pointer.h15
-rw-r--r--sys/compat/linuxkpi/common/include/linux/io.h4
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ioport.h1
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kconfig.h35
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kdev_t.h15
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kernel.h83
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kfifo.h27
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kmsg_dump.h102
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kstrtox.h57
-rw-r--r--sys/compat/linuxkpi/common/include/linux/linux_logo.h19
-rw-r--r--sys/compat/linuxkpi/common/include/linux/math64.h9
-rw-r--r--sys/compat/linuxkpi/common/include/linux/memcontrol.h43
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mfd/core.h49
-rw-r--r--sys/compat/linuxkpi/common/include/linux/minmax.h16
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mm.h1
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mod_devicetable.h7
-rw-r--r--sys/compat/linuxkpi/common/include/linux/module.h18
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mutex.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/netdevice.h24
-rw-r--r--sys/compat/linuxkpi/common/include/linux/notifier.h5
-rw-r--r--sys/compat/linuxkpi/common/include/linux/overflow.h144
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pci.h77
-rw-r--r--sys/compat/linuxkpi/common/include/linux/platform_data/brcmfmac.h185
-rw-r--r--sys/compat/linuxkpi/common/include/linux/printk.h10
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ptp_clock_kernel.h1
-rw-r--r--sys/compat/linuxkpi/common/include/linux/radix-tree.h35
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ratelimit.h7
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rbtree.h20
-rw-r--r--sys/compat/linuxkpi/common/include/linux/regulator/consumer.h17
-rw-r--r--sys/compat/linuxkpi/common/include/linux/scatterlist.h4
-rw-r--r--sys/compat/linuxkpi/common/include/linux/seq_buf.h73
-rw-r--r--sys/compat/linuxkpi/common/include/linux/seq_file.h6
-rw-r--r--sys/compat/linuxkpi/common/include/linux/siphash.h168
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sizes.h11
-rw-r--r--sys/compat/linuxkpi/common/include/linux/skbuff.h9
-rw-r--r--sys/compat/linuxkpi/common/include/linux/slab.h67
-rw-r--r--sys/compat/linuxkpi/common/include/linux/soc/airoha/airoha_offload.h48
-rw-r--r--sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h14
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sort.h7
-rw-r--r--sys/compat/linuxkpi/common/include/linux/spinlock.h31
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ssb/ssb_regs.h25
-rw-r--r--sys/compat/linuxkpi/common/include/linux/string.h40
-rw-r--r--sys/compat/linuxkpi/common/include/linux/string_choices.h26
-rw-r--r--sys/compat/linuxkpi/common/include/linux/suspend.h27
-rw-r--r--sys/compat/linuxkpi/common/include/linux/swap.h7
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sysfs.h34
-rw-r--r--sys/compat/linuxkpi/common/include/linux/unaligned.h12
-rw-r--r--sys/compat/linuxkpi/common/include/linux/uuid.h27
-rw-r--r--sys/compat/linuxkpi/common/include/linux/wait.h7
-rw-r--r--sys/compat/linuxkpi/common/include/linux/wordpart.h13
-rw-r--r--sys/compat/linuxkpi/common/include/media/cec-notifier.h17
-rw-r--r--sys/compat/linuxkpi/common/include/media/cec.h23
-rw-r--r--sys/compat/linuxkpi/common/include/net/cfg80211.h99
-rw-r--r--sys/compat/linuxkpi/common/include/net/mac80211.h107
87 files changed, 2452 insertions, 368 deletions
diff --git a/sys/compat/linuxkpi/common/include/asm/pgtable.h b/sys/compat/linuxkpi/common/include/asm/pgtable.h
index 865662d587db..166d6142d51c 100644
--- a/sys/compat/linuxkpi/common/include/asm/pgtable.h
+++ b/sys/compat/linuxkpi/common/include/asm/pgtable.h
@@ -53,6 +53,40 @@ typedef struct page *pgtable_t;
#define _PAGE_PWT (((pteval_t) 1) << _PAGE_BIT_PWT)
#define _PAGE_PCD (((pteval_t) 1) << _PAGE_BIT_PCD)
#define _PAGE_PAT (((pteval_t) 1) << _PAGE_BIT_PAT)
+
+/*
+ * On Linux, the value of `PMD_SHIFT` is hard-coded to 21. This corresponds to
+ * the FreeBSD `PDRSHIFT` constant.
+ */
+#define PMD_SHIFT PDRSHIFT
+
+#elif defined(__aarch64__)
+
+/*
+ * On Linux, the value of `PMD_SHIFT` is computed from `CONFIG_PGTABLE_LEVELS`.
+ * The result corresponds to one of the FreeBSD `L*_SHIFT` constants. Here, we
+ * take the value 21 computed from `CONFIG_PGTABLE_LEVELS = 4`, the default on
+ * aarch64, which equals to `L2_SHIFT`.
+ */
+#define PMD_SHIFT L2_SHIFT
+
+#elif defined(__powerpc__)
+
+/*
+ * On Linux, the value of `PMD_SHIFT` is the addition of `PAGE_SHIFT` and
+ * `PTE_INDEX_SIZE` (hard-coded to 9). The result corresponds to the FreeBSD
+ * `L3_PAGE_SIZE_SHIFT` constant.
+ */
+#define PMD_SHIFT L3_PAGE_SIZE_SHIFT
+
+#elif defined(__riscv)
+
+/*
+ * On Linux, the value of `PMD_SHIFT` is hard-coded to 21. This corresponds to
+ * the FreeBSD `L2_SHIFT` constant.
+ */
+#define PMD_SHIFT L2_SHIFT
+
#endif
#endif /* _LINUXKPI_ASM_PGTABLE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/asm/set_memory.h b/sys/compat/linuxkpi/common/include/asm/set_memory.h
index 1019aaf264a0..f328fcabd243 100644
--- a/sys/compat/linuxkpi/common/include/asm/set_memory.h
+++ b/sys/compat/linuxkpi/common/include/asm/set_memory.h
@@ -37,7 +37,7 @@ set_memory_uc(unsigned long addr, int numpages)
vm_size_t len;
len = (vm_size_t)numpages << PAGE_SHIFT;
- return (-pmap_change_attr(addr, len, VM_MEMATTR_UNCACHEABLE));
+ return (-pmap_change_attr((void *)addr, len, VM_MEMATTR_UNCACHEABLE));
}
static inline int
@@ -47,7 +47,7 @@ set_memory_wc(unsigned long addr, int numpages)
vm_size_t len;
len = (vm_size_t)numpages << PAGE_SHIFT;
- return (-pmap_change_attr(addr, len, VM_MEMATTR_WRITE_COMBINING));
+ return (-pmap_change_attr((void *)addr, len, VM_MEMATTR_WRITE_COMBINING));
#else
return (set_memory_uc(addr, numpages));
#endif
@@ -59,7 +59,7 @@ set_memory_wb(unsigned long addr, int numpages)
vm_size_t len;
len = (vm_size_t)numpages << PAGE_SHIFT;
- return (-pmap_change_attr(addr, len, VM_MEMATTR_WRITE_BACK));
+ return (-pmap_change_attr((void *)addr, len, VM_MEMATTR_WRITE_BACK));
}
static inline int
diff --git a/sys/compat/linuxkpi/common/include/asm/unaligned.h b/sys/compat/linuxkpi/common/include/asm/unaligned.h
index e45846a3b543..6778e9fcede1 100644
--- a/sys/compat/linuxkpi/common/include/asm/unaligned.h
+++ b/sys/compat/linuxkpi/common/include/asm/unaligned.h
@@ -48,6 +48,13 @@ get_unaligned_le32(const void *p)
return (le32_to_cpup((const __le32 *)p));
}
+static __inline uint64_t
+get_unaligned_le64(const void *p)
+{
+
+ return (le64_to_cpup((const __le64 *)p));
+}
+
static __inline void
put_unaligned_le16(__le16 v, void *p)
{
diff --git a/sys/compat/linuxkpi/common/include/linux/acpi.h b/sys/compat/linuxkpi/common/include/linux/acpi.h
index 3e1ec1b20626..a764a975c983 100644
--- a/sys/compat/linuxkpi/common/include/linux/acpi.h
+++ b/sys/compat/linuxkpi/common/include/linux/acpi.h
@@ -32,7 +32,7 @@
#include <linux/device.h>
#include <linux/uuid.h>
-#if defined(__aarch64__) || defined(__amd64__) || defined(__i386__)
+#if defined(__aarch64__) || defined(__amd64__) || defined(__i386__) || defined(__riscv)
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>
diff --git a/sys/compat/linuxkpi/common/include/linux/array_size.h b/sys/compat/linuxkpi/common/include/linux/array_size.h
new file mode 100644
index 000000000000..ebfaeccc9536
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/array_size.h
@@ -0,0 +1,17 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _LINUXKPI_LINUX_ARRAY_SIZE_H_
+#define _LINUXKPI_LINUX_ARRAY_SIZE_H_
+
+#include <linux/compiler.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#endif /* _LINUXKPI_LINUX_ARRAY_SIZE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/ascii85.h b/sys/compat/linuxkpi/common/include/linux/ascii85.h
new file mode 100644
index 000000000000..06777a130e41
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/ascii85.h
@@ -0,0 +1,46 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 The FreeBSD Foundation
+ */
+
+#ifndef _LINUXKPI_LINUX_ASCII85_H_
+#define _LINUXKPI_LINUX_ASCII85_H_
+
+#include <sys/param.h>
+
+#define ASCII85_BUFSZ 6
+
+static inline long
+ascii85_encode_len(long in_len)
+{
+ long out_len;
+
+ out_len = howmany(in_len, 4);
+
+ return (out_len);
+}
+
+static inline const char *
+ascii85_encode(uint32_t in, char *out)
+{
+ int i;
+
+ if (in == 0) {
+ out[0] = 'z';
+ out[1] = '\0';
+ return (out);
+ }
+
+ for (i = ASCII85_BUFSZ - 2; i >= 0; i--) {
+ out[i] = in % 85;
+ out[i] += 33;
+
+ in /= 85;
+ }
+ out[ASCII85_BUFSZ - 1] = '\0';
+
+ return (out);
+}
+
+#endif /* _LINUXKPI_LINUX_ASCII85_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/atomic.h b/sys/compat/linuxkpi/common/include/linux/atomic.h
index bc76928a7d67..9ba2c4d86076 100644
--- a/sys/compat/linuxkpi/common/include/linux/atomic.h
+++ b/sys/compat/linuxkpi/common/include/linux/atomic.h
@@ -29,7 +29,9 @@
#include <asm/atomic.h>
#include <asm/atomic64.h>
+#include <linux/atomic/atomic-arch-fallback.h>
#include <asm/atomic-long.h>
+#include <linux/atomic/atomic-instrumented.h>
#include <asm/barrier.h>
#endif /* _LINUXKPI_LINUX_ATOMIC_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/atomic/atomic-arch-fallback.h b/sys/compat/linuxkpi/common/include/linux/atomic/atomic-arch-fallback.h
new file mode 100644
index 000000000000..2980c364cb88
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/atomic/atomic-arch-fallback.h
@@ -0,0 +1,16 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 The FreeBSD Foundation
+ */
+
+#ifndef _LINUXKPI_LINUX_ATOMIC_ATOMIC_ARCH_FALLBACK_H_
+#define _LINUXKPI_LINUX_ATOMIC_ATOMIC_ARCH_FALLBACK_H_
+
+static inline int
+raw_atomic_read_acquire(const atomic_t *v)
+{
+ return (atomic_load_acq_int(&v->counter));
+}
+
+#endif /* _LINUXKPI_LINUX_ATOMIC_ATOMIC_ARCH_FALLBACK_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/atomic/atomic-instrumented.h b/sys/compat/linuxkpi/common/include/linux/atomic/atomic-instrumented.h
new file mode 100644
index 000000000000..af0b6af2ecfa
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/atomic/atomic-instrumented.h
@@ -0,0 +1,16 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 The FreeBSD Foundation
+ */
+
+#ifndef _LINUXKPI_LINUX_ATOMIC_ATOMIC_INSTRUMENTED_H_
+#define _LINUXKPI_LINUX_ATOMIC_ATOMIC_INSTRUMENTED_H_
+
+static inline int
+atomic_read_acquire(const atomic_t *v)
+{
+ return (raw_atomic_read_acquire(v));
+}
+
+#endif /* _LINUXKPI_LINUX_ATOMIC_ATOMIC_INSTRUMENTED_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/bcm47xx_nvram.h b/sys/compat/linuxkpi/common/include/linux/bcm47xx_nvram.h
new file mode 100644
index 000000000000..744101a2f8b1
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/bcm47xx_nvram.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2025 Bjoern A. Zeeb
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef _LINUXKPI_LINUX_BCM47XX_NVRAM_H
+#define _LINUXKPI_LINUX_BCM47XX_NVRAM_H
+
+static inline char *
+bcm47xx_nvram_get_contents(size_t *x __unused)
+{
+ return (NULL);
+};
+
+static inline void
+bcm47xx_nvram_release_contents(const char *x __unused)
+{
+};
+
+#endif /* _LINUXKPI_LINUX_BCM47XX_NVRAM_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/bcma/bcma.h b/sys/compat/linuxkpi/common/include/linux/bcma/bcma.h
new file mode 100644
index 000000000000..3840c3a420e5
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/bcma/bcma.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2025 Bjoern A. Zeeb
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef _LINUXKPI_LINUX_BCMA_BCMA_H
+#define _LINUXKPI_LINUX_BCMA_BCMA_H
+
+#define BCMA_CORE_80211 0x812
+#define BCMA_CORE_ARM_CA7 0x847
+#define BCMA_CORE_ARM_CM3 0x82A
+#define BCMA_CORE_ARM_CR4 0x83E
+#define BCMA_CORE_CHIPCOMMON 0x800
+#define BCMA_CORE_GCI 0x840
+#define BCMA_CORE_INTERNAL_MEM 0x80E
+#define BCMA_CORE_PCIE2 0x83C
+#define BCMA_CORE_PMU 0x827
+#define BCMA_CORE_SDIO_DEV 0x829
+#define BCMA_CORE_SYS_MEM 0x849
+
+/* XXX not sure where these belong. */
+#define BCMA_CC_CAP_EXT_AOB_PRESENT 0x00000040
+#define BCMA_CC_PMU_CTL_RES_SHIFT 13
+#define BCMA_CC_PMU_CTL_RES_RELOAD 0x2
+#define BCMA_CC_SROM_CONTROL_OTPSEL 0x00000010
+#define BCMA_CC_SROM_CONTROL_OTP_PRESENT 0x00000020
+
+#endif /* _LINUXKPI_LINUX_BCMA_BCMA_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/bcma/bcma_regs.h b/sys/compat/linuxkpi/common/include/linux/bcma/bcma_regs.h
new file mode 100644
index 000000000000..0a4cdddf7a73
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/bcma/bcma_regs.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2025 Bjoern A. Zeeb
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef _LINUXKPI_LINUX_BCMA_BCMA_REGS_H
+#define _LINUXKPI_LINUX_BCMA_BCMA_REGS_H
+
+#define BCMA_IOCTL 0x0408
+#define BCMA_IOCTL_CLK 0x0001
+#define BCMA_IOCTL_FGC 0x0002
+
+#define BCMA_RESET_CTL 0x0800
+#define BCMA_RESET_CTL_RESET 0x0001
+
+#endif /* _LINUXKPI_LINUX_BCMA_BCMA_REGS_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/bitops.h b/sys/compat/linuxkpi/common/include/linux/bitops.h
index 8fac80820f30..0244c7d6f476 100644
--- a/sys/compat/linuxkpi/common/include/linux/bitops.h
+++ b/sys/compat/linuxkpi/common/include/linux/bitops.h
@@ -35,6 +35,8 @@
#include <sys/errno.h>
#include <sys/libkern.h>
+#include <linux/bits.h>
+
#define BIT(nr) (1UL << (nr))
#define BIT_ULL(nr) (1ULL << (nr))
#define BITS_PER_LONG (__SIZEOF_LONG__ * __CHAR_BIT__)
@@ -45,18 +47,10 @@
#define BITS_TO_LONGS(n) howmany((n), BITS_PER_LONG)
#define BIT_MASK(nr) (1UL << ((nr) & (BITS_PER_LONG - 1)))
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
-#define GENMASK(h, l) (((~0UL) >> (BITS_PER_LONG - (h) - 1)) & ((~0UL) << (l)))
-#define GENMASK_ULL(h, l) (((~0ULL) >> (BITS_PER_LONG_LONG - (h) - 1)) & ((~0ULL) << (l)))
#define BITS_PER_BYTE 8
#define BITS_PER_TYPE(t) (sizeof(t) * BITS_PER_BYTE)
#define BITS_TO_BYTES(n) howmany((n), BITS_PER_BYTE)
-#define hweight8(x) bitcount((uint8_t)(x))
-#define hweight16(x) bitcount16(x)
-#define hweight32(x) bitcount32(x)
-#define hweight64(x) bitcount64(x)
-#define hweight_long(x) bitcountl(x)
-
#if __has_builtin(__builtin_popcountg)
#define HWEIGHT8(x) (__builtin_popcountg((uint8_t)(x)))
#define HWEIGHT16(x) (__builtin_popcountg((uint16_t)(x)))
@@ -70,6 +64,12 @@
#define HWEIGHT64(x) (__const_bitcount64((uint64_t)(x)))
#endif
+#define hweight8(x) (__builtin_constant_p(x) ? HWEIGHT8(x) : bitcount((uint8_t)(x)))
+#define hweight16(x) (__builtin_constant_p(x) ? HWEIGHT16(x) : bitcount16(x))
+#define hweight32(x) (__builtin_constant_p(x) ? HWEIGHT32(x) : bitcount32(x))
+#define hweight64(x) (__builtin_constant_p(x) ? HWEIGHT64(x) : bitcount64(x))
+#define hweight_long(x) bitcountl(x)
+
static inline int
__ffs(int mask)
{
@@ -437,4 +437,16 @@ sign_extend32(uint32_t value, int index)
return ((int32_t)(value << shift) >> shift);
}
+static inline uint64_t
+rol64(uint64_t word, unsigned int shift)
+{
+ return ((word << (shift & 63)) | (word >> ((-shift) & 63)));
+}
+
+static inline uint32_t
+rol32(uint32_t word, unsigned int shift)
+{
+ return ((word << (shift & 31)) | (word >> ((-shift) & 31)));
+}
+
#endif /* _LINUXKPI_LINUX_BITOPS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/bits.h b/sys/compat/linuxkpi/common/include/linux/bits.h
new file mode 100644
index 000000000000..53deb7cbbe88
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/bits.h
@@ -0,0 +1,14 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2016 Kip Macy
+ * Copyright (c) 2018 Johannes Lundberg
+ */
+
+#ifndef _LINUXKPI_LINUX_BITS_H_
+#define _LINUXKPI_LINUX_BITS_H_
+
+#define GENMASK(h, l) (((~0UL) >> (BITS_PER_LONG - (h) - 1)) & ((~0UL) << (l)))
+#define GENMASK_ULL(h, l) (((~0ULL) >> (BITS_PER_LONG_LONG - (h) - 1)) & ((~0ULL) << (l)))
+
+#endif /* _LINUXKPI_LINUX_BITS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/cec-funcs.h b/sys/compat/linuxkpi/common/include/linux/cec-funcs.h
new file mode 100644
index 000000000000..1107b04e4e08
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/cec-funcs.h
@@ -0,0 +1,16 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025-2026 The FreeBSD Foundation
+ * Copyright (c) 2025-2026 Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
+ *
+ * This software was developed by Jean-Sébastien Pédron under sponsorship
+ * from the FreeBSD Foundation.
+ */
+
+#ifndef _LINUXKPI_LINUX_CEC_FUNCS_H_
+#define _LINUXKPI_LINUX_CEC_FUNCS_H_
+
+#include <linux/cec.h>
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/cec.h b/sys/compat/linuxkpi/common/include/linux/cec.h
index e0854d87d85c..b08d891537a9 100644
--- a/sys/compat/linuxkpi/common/include/linux/cec.h
+++ b/sys/compat/linuxkpi/common/include/linux/cec.h
@@ -3,6 +3,9 @@
#ifndef _LINUXKPI_LINUX_CEC_H_
#define _LINUXKPI_LINUX_CEC_H_
+#include <linux/types.h>
+#include <linux/string.h>
+
#define CEC_PHYS_ADDR_INVALID 0xffff
#endif /* _LINUXKPI_LINUX_CEC_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/cgroup.h b/sys/compat/linuxkpi/common/include/linux/cgroup.h
index a9dd22fd0f4c..c75404fd6cf3 100644
--- a/sys/compat/linuxkpi/common/include/linux/cgroup.h
+++ b/sys/compat/linuxkpi/common/include/linux/cgroup.h
@@ -29,6 +29,15 @@
#ifndef _LINUXKPI_LINUX_CGROUP_H_
#define _LINUXKPI_LINUX_CGROUP_H_
+#include <linux/sched.h>
+#include <linux/nodemask.h>
+#include <linux/list.h>
+#include <linux/rculist.h>
+#include <linux/fs.h>
+#include <linux/seq_file.h>
+#include <linux/jump_label.h>
+#include <linux/types.h>
+#include <linux/refcount.h>
#include <linux/kernel_stat.h>
#endif /* _LINUXKPI_LINUX_CGROUP_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/cleanup.h b/sys/compat/linuxkpi/common/include/linux/cleanup.h
index 5bb146f082ed..fb21a81f121b 100644
--- a/sys/compat/linuxkpi/common/include/linux/cleanup.h
+++ b/sys/compat/linuxkpi/common/include/linux/cleanup.h
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2024-2025 The FreeBSD Foundation
+ * Copyright (c) 2024-2026 The FreeBSD Foundation
*
* This software was developed by Björn Zeeb under sponsorship from
* the FreeBSD Foundation.
@@ -10,18 +10,26 @@
#ifndef _LINUXKPI_LINUX_CLEANUP_H
#define _LINUXKPI_LINUX_CLEANUP_H
+#include <linux/err.h>
+
+#define CLEANUP_NAME(_n, _s) __CONCAT(__CONCAT(cleanup_, _n), _s)
+
#define __cleanup(_f) __attribute__((__cleanup__(_f)))
+#define DECLARE(_n, _x) \
+ CLEANUP_NAME(_n, _t) _x __cleanup(CLEANUP_NAME(_n, _destroy)) = \
+ CLEANUP_NAME(_n, _create)
+
/*
* Note: "_T" are special as they are exposed into common code for
* statements. Extra care should be taken when changing the code.
*/
#define DEFINE_GUARD(_n, _dt, _lock, _unlock) \
\
- typedef _dt guard_ ## _n ## _t; \
+ typedef _dt CLEANUP_NAME(_n, _t); \
\
static inline _dt \
- guard_ ## _n ## _create( _dt _T) \
+ CLEANUP_NAME(_n, _create)( _dt _T) \
{ \
_dt c; \
\
@@ -30,7 +38,7 @@
} \
\
static inline void \
- guard_ ## _n ## _destroy(_dt *t) \
+ CLEANUP_NAME(_n, _destroy)(_dt *t) \
{ \
_dt _T; \
\
@@ -39,9 +47,10 @@
}
/* We need to keep these calls unique. */
+#define _guard(_n, _x) \
+ DECLARE(_n, _x)
#define guard(_n) \
- guard_ ## _n ## _t guard_ ## _n ## _ ## __COUNTER__ \
- __cleanup(guard_ ## _n ## _destroy) = guard_ ## _n ## _create
+ _guard(_n, guard_ ## _n ## _ ## __COUNTER__)
#define DEFINE_FREE(_n, _t, _f) \
static inline void \
@@ -56,38 +65,100 @@
#define __free(_n) __cleanup(__free_##_n)
/*
- * Given this is a _0 version it should likely be broken up into parts.
- * But we have no idead what a _1, _2, ... version would do different
- * until we see a call.
- * This is used for a not-real-type (rcu). We use a bool to "simulate"
- * the lock held. Also _T still special, may not always be used, so tag
- * with __unused (or better the LinuxKPI __maybe_unused).
+ * Our initial version go broken up. Some simplifications like using
+ * "bool" for the lock had to be changed to a more general type.
+ * _T is still special and, like other bits, may not always be used,
+ * so tag with __unused (or better the LinuxKPI __maybe_unused).
*/
-#define DEFINE_LOCK_GUARD_0(_n, _lock, _unlock, ...) \
+#define _DEFINE_LOCK_GUARD_0(_n, _lock) \
+ static inline CLEANUP_NAME(_n, _t) \
+ CLEANUP_NAME(_n, _create)(void) \
+ { \
+ CLEANUP_NAME(_n, _t) _tmp; \
+ CLEANUP_NAME(_n, _t) *_T __maybe_unused; \
+ \
+ _tmp.lock = (void *)1; \
+ _T = &_tmp; \
+ _lock; \
+ return (_tmp); \
+ }
+
+#define _DEFINE_LOCK_GUARD_1(_n, _type, _lock) \
+ static inline CLEANUP_NAME(_n, _t) \
+ CLEANUP_NAME(_n, _create)(_type *l) \
+ { \
+ CLEANUP_NAME(_n, _t) _tmp; \
+ CLEANUP_NAME(_n, _t) *_T __maybe_unused; \
\
+ _tmp.lock = l; \
+ _T = &_tmp; \
+ _lock; \
+ return (_tmp); \
+ }
+
+#define _GUARD_IS_ERR(_v) \
+ ({ \
+ uintptr_t x = (uintptr_t)(void *)(_v); \
+ IS_ERR_VALUE(x); \
+ })
+
+#define __is_cond_ptr(_n) \
+ CLEANUP_NAME(_n, _is_cond)
+#define __guard_ptr(_n) \
+ CLEANUP_NAME(_n, _ptr)
+
+#define _DEFINE_CLEANUP_IS_CONDITIONAL(_n, _b) \
+ static const bool CLEANUP_NAME(_n, _is_cond) __maybe_unused = _b
+
+#define _DEFINE_GUARD_LOCK_PTR(_n, _lp) \
+ static inline void * \
+ CLEANUP_NAME(_n, _lock_ptr)(CLEANUP_NAME(_n, _t) *_T) \
+ { \
+ void *_p; \
+ \
+ _p = (void *)(uintptr_t)*(_lp); \
+ if (IS_ERR(_p)) \
+ _p = NULL; \
+ return (_p); \
+ }
+
+#define _DEFINE_UNLOCK_GUARD(_n, _type, _unlock, ...) \
typedef struct { \
- bool lock; \
+ _type *lock; \
__VA_ARGS__; \
- } guard_ ## _n ## _t; \
+ } CLEANUP_NAME(_n, _t); \
\
static inline void \
- guard_ ## _n ## _destroy(guard_ ## _n ## _t *_T) \
+ CLEANUP_NAME(_n, _destroy)(CLEANUP_NAME(_n, _t) *_T) \
{ \
- if (_T->lock) { \
+ if (!_GUARD_IS_ERR(_T->lock)) { \
_unlock; \
} \
} \
\
- static inline guard_ ## _n ## _t \
- guard_ ## _n ## _create(void) \
- { \
- guard_ ## _n ## _t _tmp; \
- guard_ ## _n ## _t *_T __maybe_unused; \
- \
- _tmp.lock = true; \
- _T = &_tmp; \
- _lock; \
- return (_tmp); \
- }
+ _DEFINE_GUARD_LOCK_PTR(_n, &_T->lock)
+
+#define DEFINE_LOCK_GUARD_0(_n, _lock, _unlock, ...) \
+ _DEFINE_CLEANUP_IS_CONDITIONAL(_n, false); \
+ _DEFINE_UNLOCK_GUARD(_n, void, _unlock, __VA_ARGS__) \
+ _DEFINE_LOCK_GUARD_0(_n, _lock)
+
+/* This allows the type to be set. */
+#define DEFINE_LOCK_GUARD_1(_n, _t, _lock, _unlock, ...) \
+ _DEFINE_CLEANUP_IS_CONDITIONAL(_n, false); \
+ _DEFINE_UNLOCK_GUARD(_n, _t, _unlock, __VA_ARGS__) \
+ _DEFINE_LOCK_GUARD_1(_n, _t, _lock)
+
+#define _scoped_guard(_n, _l, ...) \
+ for (DECLARE(_n, _scoped)(__VA_ARGS__); \
+ 1 /*__guard_ptr(_n)(&_scoped) || !__is_cond_ptr(_n) */; \
+ ({ goto _l; })) \
+ if (0) { \
+_l: \
+ break; \
+ } else
+
+#define scoped_guard(_n, ...) \
+ _scoped_guard(_n, ___label_ ## __COUNTER__, ##__VA_ARGS__)
#endif /* _LINUXKPI_LINUX_CLEANUP_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/compiler.h b/sys/compat/linuxkpi/common/include/linux/compiler.h
index 4146c829b936..4fcd1f9f342b 100644
--- a/sys/compat/linuxkpi/common/include/linux/compiler.h
+++ b/sys/compat/linuxkpi/common/include/linux/compiler.h
@@ -33,48 +33,18 @@
#include <sys/cdefs.h>
#include <sys/endian.h>
-#define __user
-#define __kernel
-#define __safe
-#define __force
-#define __nocast
-#define __iomem
-#define __chk_user_ptr(x) ((void)0)
-#define __chk_io_ptr(x) ((void)0)
-#define __builtin_warning(x, y...) (1)
-#define __acquires(x)
-#define __releases(x)
-#define __acquire(x) do { } while (0)
-#define __release(x) do { } while (0)
-#define __cond_lock(x,c) (c)
+#include <compat/linuxkpi/common/include/linux/compiler_types.h>
+
#define __bitwise
#define __devinitdata
-#ifndef __deprecated
-#define __deprecated
-#endif
#define __init
#define __initconst
#define __devinit
#define __devexit
#define __exit
-#define __rcu
-#define __percpu
-#define __weak __weak_symbol
-#define __malloc
-#define __attribute_const__ __attribute__((__const__))
-#undef __always_inline
-#define __always_inline inline
-#define noinline __noinline
-#define noinline_for_stack __noinline
#define ____cacheline_aligned __aligned(CACHE_LINE_SIZE)
#define ____cacheline_aligned_in_smp __aligned(CACHE_LINE_SIZE)
-#define fallthrough /* FALLTHROUGH */ do { } while(0)
-#if __has_attribute(__nonstring__)
-#define __nonstring __attribute__((__nonstring__))
-#else
-#define __nonstring
-#endif
#if __has_attribute(__counted_by__)
#define __counted_by(_x) __attribute__((__counted_by__(_x)))
#else
@@ -93,24 +63,9 @@
#define typeof(x) __typeof(x)
#define uninitialized_var(x) x = x
-#define __maybe_unused __unused
-#define __always_unused __unused
-#define __must_check __result_use_check
-
-#define __printf(a,b) __printflike(a,b)
-
-#define __diag_push()
-#define __diag_pop()
-#define __diag_ignore_all(...)
#define barrier() __asm__ __volatile__("": : :"memory")
-#define lower_32_bits(n) ((u32)(n))
-#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16))
-
-#define ___PASTE(a,b) a##b
-#define __PASTE(a,b) ___PASTE(a,b)
-
#define WRITE_ONCE(x,v) do { \
barrier(); \
(*(volatile __typeof(x) *)(uintptr_t)&(x)) = (v); \
@@ -129,8 +84,6 @@
#define lockless_dereference(p) READ_ONCE(p)
#define _AT(T,X) ((T)(X))
-
-#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
#define __must_be_array(a) __same_type(a, &(a)[0])
#define sizeof_field(_s, _m) sizeof(((_s *)0)->_m)
diff --git a/sys/compat/linuxkpi/common/include/linux/compiler_attributes.h b/sys/compat/linuxkpi/common/include/linux/compiler_attributes.h
new file mode 100644
index 000000000000..42908bb6c2b5
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/compiler_attributes.h
@@ -0,0 +1,49 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * Copyright (c) 2015 François Tigeot
+ * All rights reserved.
+ */
+
+#ifndef _LINUXKPI_LINUX_COMPILER_ATTRIBUTES_H_
+#define _LINUXKPI_LINUX_COMPILER_ATTRIBUTES_H_
+
+#include <sys/cdefs.h>
+
+#define __attribute_const__ __attribute__((__const__))
+
+#ifndef __deprecated
+#define __deprecated
+#endif
+
+#define fallthrough /* FALLTHROUGH */ do { } while(0)
+
+#undef __always_inline
+#define __always_inline inline
+
+#define __printf(a,b) __printflike(a,b)
+
+#define __malloc
+
+#define noinline __noinline
+
+#if __has_attribute(__nonstring__)
+#define __nonstring __attribute__((__nonstring__))
+#else
+#define __nonstring
+#endif
+
+#define noinline_for_stack __noinline
+
+#define __maybe_unused __unused
+#define __always_unused __unused
+
+#define __must_check __result_use_check
+
+#define __weak __weak_symbol
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/compiler_types.h b/sys/compat/linuxkpi/common/include/linux/compiler_types.h
new file mode 100644
index 000000000000..25e69f5afd8e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/compiler_types.h
@@ -0,0 +1,58 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * Copyright (c) 2015 François Tigeot
+ * All rights reserved.
+ */
+
+#ifndef _LINUXKPI_LINUX_COMPILER_TYPES_H_
+#define _LINUXKPI_LINUX_COMPILER_TYPES_H_
+
+#include <sys/cdefs.h>
+
+#include <compat/linuxkpi/common/include/linux/compiler_attributes.h>
+
+#define __kernel
+#define __user
+#define __iomem
+#define __percpu
+#define __rcu
+#define __chk_user_ptr(x) ((void)0)
+#define __chk_io_ptr(x) ((void)0)
+#define __acquires(x)
+#define __releases(x)
+#define __acquire(x) do { } while (0)
+#define __release(x) do { } while (0)
+#define __cond_lock(x,c) (c)
+#define __force
+#define __nocast
+#define __safe
+#define __builtin_warning(x, y...) (1)
+
+#define ___PASTE(a,b) a##b
+#define __PASTE(a,b) ___PASTE(a,b)
+
+#define __diag_push()
+#define __diag_pop()
+#define __diag_ignore_all(...)
+
+#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
+
+/*
+ * __builtin_counted_by_ref was introduced to
+ * - gcc in e7380688fa59 with a first release tag of gcc-15.1.0,
+ * - llvm in 7475156d49406 with a first release tag of llvmorg-20.1.0-rc1
+ * but cannot be used before 23 (22.x.y possibly) (see 09a3d830a888).
+ */
+#if (__has_builtin(__builtin_counted_by_ref)) && \
+ (!defined(__clang__) || (__clang_major__ >= 23))
+#define __flex_counter(_field) __builtin_counted_by_ref(_field)
+#else
+#define __flex_counter(_field) ((void *)NULL)
+#endif
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/device.h b/sys/compat/linuxkpi/common/include/linux/device.h
index 8834f1799e61..2913810923f1 100644
--- a/sys/compat/linuxkpi/common/include/linux/device.h
+++ b/sys/compat/linuxkpi/common/include/linux/device.h
@@ -267,6 +267,30 @@ show_class_attr_string(struct class *class,
dev_dbg(dev, __VA_ARGS__); \
} while (0)
+static inline int
+dev_err_probe(const struct device *dev, int err, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+
+ /*
+ * On Linux, they look at the error code to determine if the message
+ * should be logged (not logged if -ENOMEM) and at which log level.
+ */
+ device_printf(dev->bsddev, fmt, args);
+
+ va_end(args);
+
+ return (err);
+}
+
+#define dev_err_ptr_probe(dev, err, fmt, ...) \
+ ERR_PTR(dev_err_probe((dev), (err), fmt, ##__VA_ARGS__)
+
+#define dev_err_cast_probe(dev, err, fmt, ...) \
+ ERR_PTR(dev_err_probe((dev), PTR_ERR(err), fmt, ##__VA_ARGS__)
+
/* Public and LinuxKPI internal devres functions. */
void *lkpi_devres_alloc(void(*release)(struct device *, void *), size_t, gfp_t);
void lkpi_devres_add(struct device *, void *);
@@ -701,6 +725,13 @@ devm_kmemdup(struct device *dev, const void *src, size_t len, gfp_t gfp)
return (dst);
}
+static inline void *
+devm_kmemdup_array(struct device *dev, const void *src, size_t n, size_t len,
+ gfp_t gfp)
+{
+ return (devm_kmemdup(dev, src, size_mul(n, len), gfp));
+}
+
#define devm_kzalloc(_dev, _size, _gfp) \
devm_kmalloc((_dev), (_size), (_gfp) | __GFP_ZERO)
diff --git a/sys/compat/linuxkpi/common/include/linux/dma-mapping.h b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h
index 2d8e1196d3d3..5e5d40ef8339 100644
--- a/sys/compat/linuxkpi/common/include/linux/dma-mapping.h
+++ b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h
@@ -96,6 +96,8 @@ void *linux_dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flag);
void *linuxkpi_dmam_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flag);
+void linuxkpi_dmam_free_coherent(struct device *dev, size_t size,
+ void *addr, dma_addr_t dma_handle);
dma_addr_t linux_dma_map_phys(struct device *dev, vm_paddr_t phys, size_t len); /* backward compat */
dma_addr_t lkpi_dma_map_phys(struct device *, vm_paddr_t, size_t,
enum dma_data_direction, unsigned long);
@@ -104,10 +106,10 @@ void lkpi_dma_unmap(struct device *, dma_addr_t, size_t,
enum dma_data_direction, unsigned long);
int linux_dma_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
int nents, enum dma_data_direction direction,
- unsigned long attrs __unused);
+ unsigned long attrs);
void linux_dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg,
int nents __unused, enum dma_data_direction direction,
- unsigned long attrs __unused);
+ unsigned long attrs);
void linuxkpi_dma_sync(struct device *, dma_addr_t, size_t, bus_dmasync_op_t);
static inline int
@@ -181,6 +183,13 @@ dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
kmem_free(cpu_addr, size);
}
+static inline void
+dmam_free_coherent(struct device *dev, size_t size, void *addr,
+ dma_addr_t dma_handle)
+{
+ linuxkpi_dmam_free_coherent(dev, size, addr, dma_handle);
+}
+
static inline dma_addr_t
dma_map_page_attrs(struct device *dev, struct page *page, size_t offset,
size_t size, enum dma_data_direction direction, unsigned long attrs)
@@ -192,10 +201,10 @@ dma_map_page_attrs(struct device *dev, struct page *page, size_t offset,
/* linux_dma_(un)map_sg_attrs does not support attrs yet */
#define dma_map_sg_attrs(dev, sgl, nents, dir, attrs) \
- linux_dma_map_sg_attrs(dev, sgl, nents, dir, 0)
+ linux_dma_map_sg_attrs(dev, sgl, nents, dir, attrs)
#define dma_unmap_sg_attrs(dev, sg, nents, dir, attrs) \
- linux_dma_unmap_sg_attrs(dev, sg, nents, dir, 0)
+ linux_dma_unmap_sg_attrs(dev, sg, nents, dir, attrs)
static inline dma_addr_t
dma_map_page(struct device *dev, struct page *page,
@@ -352,10 +361,10 @@ dma_max_mapping_size(struct device *dev)
}
#define dma_map_single_attrs(dev, ptr, size, dir, attrs) \
- _dma_map_single_attrs(dev, ptr, size, dir, 0)
+ _dma_map_single_attrs(dev, ptr, size, dir, attrs)
#define dma_unmap_single_attrs(dev, dma_addr, size, dir, attrs) \
- _dma_unmap_single_attrs(dev, dma_addr, size, dir, 0)
+ _dma_unmap_single_attrs(dev, dma_addr, size, dir, attrs)
#define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, 0)
#define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, 0)
diff --git a/sys/compat/linuxkpi/common/include/linux/eventfd.h b/sys/compat/linuxkpi/common/include/linux/eventfd.h
new file mode 100644
index 000000000000..d167d4b7d189
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/eventfd.h
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2025 The FreeBSD Foundation
+ * Copyright (c) 2025 Jean-Sébastien Pédron
+ *
+ * This software was developed by Jean-Sébastien Pédron under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_LINUX_EVENTFD_H_
+#define _LINUXKPI_LINUX_EVENTFD_H_
+
+#include <sys/eventfd.h>
+
+#include <linux/wait.h>
+#include <linux/err.h>
+#include <linux/percpu-defs.h>
+#include <linux/percpu.h>
+#include <linux/sched.h>
+
+/*
+ * Linux uses `struct eventfd_ctx`, but FreeBSD defines `struct eventfd`. Here,
+ * we define a synonym to the FreeBSD structure. This allows to keep Linux code
+ * unmodified.
+ */
+#define eventfd_ctx eventfd
+
+#define eventfd_ctx_fdget lkpi_eventfd_ctx_fdget
+struct eventfd_ctx *lkpi_eventfd_ctx_fdget(int fd);
+
+#define eventfd_ctx_put lkpi_eventfd_ctx_put
+void lkpi_eventfd_ctx_put(struct eventfd_ctx *ctx);
+
+#endif /* _LINUXKPI_LINUX_EVENTFD_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/file.h b/sys/compat/linuxkpi/common/include/linux/file.h
index f6e988c2d88e..4d8f8fba7fab 100644
--- a/sys/compat/linuxkpi/common/include/linux/file.h
+++ b/sys/compat/linuxkpi/common/include/linux/file.h
@@ -39,6 +39,11 @@
#include <linux/fs.h>
#include <linux/slab.h>
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/cleanup.h>
+
struct linux_file;
#undef file
@@ -179,6 +184,8 @@ static inline struct fd fdget(unsigned int fd)
return (struct fd){f};
}
+#define fd_file(fd) ((fd).linux_file)
+
#define file linux_file
#define fget(...) linux_fget(__VA_ARGS__)
diff --git a/sys/compat/linuxkpi/common/include/linux/font.h b/sys/compat/linuxkpi/common/include/linux/font.h
new file mode 100644
index 000000000000..45daa00b61f0
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/font.h
@@ -0,0 +1,33 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025-2026 The FreeBSD Foundation
+ * Copyright (c) 2025-2026 Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
+ *
+ * This software was developed by Jean-Sébastien Pédron under sponsorship
+ * from the FreeBSD Foundation.
+ */
+
+#ifndef _LINUXKPI_LINUX_FONT_H_
+#define _LINUXKPI_LINUX_FONT_H_
+
+#include <linux/types.h>
+
+struct font_desc {
+ const char *name;
+ const void *data;
+ int idx;
+ unsigned int width;
+ unsigned int height;
+ unsigned int charcount;
+ int pref;
+};
+
+static inline const struct font_desc *
+get_default_font(int xres, int yres, unsigned long *font_w,
+ unsigned long *font_h)
+{
+ return (NULL);
+}
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/fs.h b/sys/compat/linuxkpi/common/include/linux/fs.h
index f1568ad6282d..749a9fd22d3d 100644
--- a/sys/compat/linuxkpi/common/include/linux/fs.h
+++ b/sys/compat/linuxkpi/common/include/linux/fs.h
@@ -133,8 +133,11 @@ do { \
typedef int (*filldir_t)(void *, const char *, int, off_t, u64, unsigned);
+typedef unsigned int fop_flags_t;
+
struct file_operations {
struct module *owner;
+ fop_flags_t fop_flags; /* Unused on FreeBSD. */
ssize_t (*read)(struct linux_file *, char __user *, size_t, off_t *);
ssize_t (*write)(struct linux_file *, const char __user *, size_t, off_t *);
unsigned int (*poll) (struct linux_file *, struct poll_table_struct *);
@@ -182,6 +185,14 @@ struct file_operations {
int (*setlease)(struct file *, long, struct file_lock **);
#endif
};
+
+#define FOP_BUFFER_RASYNC (1 << 0)
+#define FOP_BUFFER_WASYNC (1 << 1)
+#define FOP_MMAP_SYNC (1 << 2)
+#define FOP_DIO_PARALLEL_WRITE (1 << 3)
+#define FOP_HUGE_PAGES (1 << 4)
+#define FOP_UNSIGNED_OFFSET (1 << 5)
+
#define fops_get(fops) (fops)
#define replace_fops(f, fops) ((f)->f_op = (fops))
@@ -364,27 +375,23 @@ static inline ssize_t
simple_read_from_buffer(void __user *dest, size_t read_size, loff_t *ppos,
void *orig, size_t buf_size)
{
- void *p, *read_pos = ((char *) orig) + *ppos;
+ void *read_pos = ((char *) orig) + *ppos;
size_t buf_remain = buf_size - *ppos;
+ ssize_t num_read;
- if (buf_remain < 0 || buf_remain > buf_size)
- return -EINVAL;
+ if (*ppos >= buf_size || read_size == 0)
+ return (0);
if (read_size > buf_remain)
read_size = buf_remain;
- /*
- * XXX At time of commit only debugfs consumers could be
- * identified. If others will use this function we may
- * have to revise this: normally we would call copy_to_user()
- * here but lindebugfs will return the result and the
- * copyout is done elsewhere for us.
- */
- p = memcpy(dest, read_pos, read_size);
- if (p != NULL)
- *ppos += read_size;
-
- return (read_size);
+ /* copy_to_user returns number of bytes NOT read */
+ num_read = read_size - copy_to_user(dest, read_pos, read_size);
+ if (num_read == 0)
+ return -EFAULT;
+ *ppos += num_read;
+
+ return (num_read);
}
MALLOC_DECLARE(M_LSATTR);
@@ -415,11 +422,13 @@ int simple_attr_open(struct inode *inode, struct file *filp,
int simple_attr_release(struct inode *inode, struct file *filp);
-ssize_t simple_attr_read(struct file *filp, char *buf, size_t read_size, loff_t *ppos);
+ssize_t simple_attr_read(struct file *filp, char __user *buf, size_t read_size,
+ loff_t *ppos);
-ssize_t simple_attr_write(struct file *filp, const char *buf, size_t write_size, loff_t *ppos);
+ssize_t simple_attr_write(struct file *filp, const char __user *buf,
+ size_t write_size, loff_t *ppos);
-ssize_t simple_attr_write_signed(struct file *filp, const char *buf,
+ssize_t simple_attr_write_signed(struct file *filp, const char __user *buf,
size_t write_size, loff_t *ppos);
#endif /* _LINUXKPI_LINUX_FS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/gfp.h b/sys/compat/linuxkpi/common/include/linux/gfp.h
index 7a32e7862338..5c638be92beb 100644
--- a/sys/compat/linuxkpi/common/include/linux/gfp.h
+++ b/sys/compat/linuxkpi/common/include/linux/gfp.h
@@ -55,16 +55,19 @@
#define __GFP_IO 0
#define __GFP_NO_KSWAPD 0
#define __GFP_KSWAPD_RECLAIM 0
+#define __GFP_ACCOUNT 0
#define __GFP_WAIT M_WAITOK
#define __GFP_DMA32 (1U << 24) /* LinuxKPI only */
#define __GFP_NORETRY (1U << 25) /* LinuxKPI only */
-#define __GFP_BITS_SHIFT 26
+#define __GFP_THISNODE (1U << 26)
+#define __GFP_BITS_SHIFT 27
#define __GFP_BITS_MASK ((1 << __GFP_BITS_SHIFT) - 1)
#define __GFP_NOFAIL M_WAITOK
#define GFP_NOWAIT M_NOWAIT
#define GFP_ATOMIC (M_NOWAIT | M_USE_RESERVE)
#define GFP_KERNEL M_WAITOK
+#define GFP_KERNEL_ACCOUNT (GFP_KERNEL | __GFP_ACCOUNT)
#define GFP_USER M_WAITOK
#define GFP_HIGHUSER M_WAITOK
#define GFP_HIGHUSER_MOVABLE M_WAITOK
@@ -80,6 +83,9 @@
CTASSERT((__GFP_DMA32 & GFP_NATIVE_MASK) == 0);
CTASSERT((__GFP_BITS_MASK & GFP_NATIVE_MASK) == GFP_NATIVE_MASK);
+#define __default_gfp(_discard, _arg_or_default, ...) _arg_or_default
+#define default_gfp(...) __default_gfp(, ##__VA_ARGS__, GFP_KERNEL)
+
struct page_frag_cache {
void *va;
int pagecnt_bias;
diff --git a/sys/compat/linuxkpi/common/include/linux/hardirq.h b/sys/compat/linuxkpi/common/include/linux/hardirq.h
index f79451dd0d35..c6cbf1a34f14 100644
--- a/sys/compat/linuxkpi/common/include/linux/hardirq.h
+++ b/sys/compat/linuxkpi/common/include/linux/hardirq.h
@@ -31,6 +31,7 @@
#include <linux/types.h>
#include <linux/lockdep.h>
+#include <linux/preempt.h>
#include <sys/param.h>
#include <sys/bus.h>
diff --git a/sys/compat/linuxkpi/common/include/linux/hex.h b/sys/compat/linuxkpi/common/include/linux/hex.h
new file mode 100644
index 000000000000..7e9f499cfb1b
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/hex.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2022-2026 Bjoern A. Zeeb
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef _LINUXKPI_LINUX_HEX_H_
+#define _LINUXKPI_LINUX_HEX_H_
+
+#include <linux/types.h>
+#include <linux/errno.h>
+
+static inline int
+_h2b(const char c)
+{
+
+ if (c >= '0' && c <= '9')
+ return (c - '0');
+ if (c >= 'a' && c <= 'f')
+ return (10 + c - 'a');
+ if (c >= 'A' && c <= 'F')
+ return (10 + c - 'A');
+ return (-EINVAL);
+}
+
+static inline int
+hex2bin(uint8_t *bindst, const char *hexsrc, size_t binlen)
+{
+ int hi4, lo4;
+
+ while (binlen > 0) {
+ hi4 = _h2b(*hexsrc++);
+ lo4 = _h2b(*hexsrc++);
+ if (hi4 < 0 || lo4 < 0)
+ return (-EINVAL);
+
+ *bindst++ = (hi4 << 4) | lo4;
+ binlen--;
+ }
+
+ return (0);
+}
+
+#endif /* _LINUXKPI_LINUX_HEX_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/highmem.h b/sys/compat/linuxkpi/common/include/linux/highmem.h
index 58a9cdcdf60f..b704e77b6c2f 100644
--- a/sys/compat/linuxkpi/common/include/linux/highmem.h
+++ b/sys/compat/linuxkpi/common/include/linux/highmem.h
@@ -45,6 +45,7 @@
#include <linux/mm.h>
#include <linux/page.h>
+#include <linux/hardirq.h>
#define PageHighMem(p) (0)
@@ -61,7 +62,7 @@ kmap(struct page *page)
struct sf_buf *sf;
if (PMAP_HAS_DMAP) {
- return ((void *)PHYS_TO_DMAP(page_to_phys(page)));
+ return (PHYS_TO_DMAP(page_to_phys(page)));
} else {
sched_pin();
sf = sf_buf_alloc(page, SFB_NOWAIT | SFB_CPUPRIVATE);
@@ -69,7 +70,7 @@ kmap(struct page *page)
sched_unpin();
return (NULL);
}
- return ((void *)sf_buf_kva(sf));
+ return (sf_buf_kva(sf));
}
}
@@ -99,6 +100,19 @@ kmap_local_page(struct page *page)
}
static inline void *
+kmap_local_folio(struct folio *folio, size_t offset)
+{
+ struct page *page;
+ char *vaddr;
+
+ page = &folio->page;
+ vaddr = kmap_local_page(page);
+ vaddr += offset;
+
+ return (vaddr);
+}
+
+static inline void *
kmap_local_page_prot(struct page *page, pgprot_t prot)
{
@@ -167,4 +181,13 @@ memcpy_to_page(struct page *page, size_t offset, const char *from, size_t len)
kunmap_local(to);
}
+static inline void
+memcpy_to_folio(struct folio *folio, size_t offset, const char *from, size_t len)
+{
+ struct page *page;
+
+ page = &folio->page;
+ memcpy_to_page(page, offset, from, len);
+}
+
#endif /* _LINUXKPI_LINUX_HIGHMEM_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/i2c.h b/sys/compat/linuxkpi/common/include/linux/i2c.h
index f24d282586f6..a6a4ee85d584 100644
--- a/sys/compat/linuxkpi/common/include/linux/i2c.h
+++ b/sys/compat/linuxkpi/common/include/linux/i2c.h
@@ -31,7 +31,14 @@
#include <sys/errno.h>
#include <sys/systm.h>
+#include <linux/bits.h>
+#include <linux/mod_devicetable.h>
#include <linux/device.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/regulator/consumer.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
#define I2C_MAX_ADAPTER_NAME_LENGTH 32
diff --git a/sys/compat/linuxkpi/common/include/linux/ieee80211.h b/sys/compat/linuxkpi/common/include/linux/ieee80211.h
index 12160df43915..b8f29560f200 100644
--- a/sys/compat/linuxkpi/common/include/linux/ieee80211.h
+++ b/sys/compat/linuxkpi/common/include/linux/ieee80211.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2020-2025 The FreeBSD Foundation
+ * Copyright (c) 2020-2026 The FreeBSD Foundation
*
* This software was developed by Björn Zeeb under sponsorship from
* the FreeBSD Foundation.
@@ -51,8 +51,16 @@ extern int linuxkpi_debug_80211;
#define IMPROVE(fmt, ...) if (linuxkpi_debug_80211 & D80211_IMPROVE) \
printf("%s:%d: XXX LKPI80211 IMPROVE " fmt "\n", __func__, __LINE__, ##__VA_ARGS__)
-
-/* 9.4.2.55 Management MIC element (CMAC-256, GMAC-128, and GMAC-256). */
+/* 802.11-2024, 9.4.2.53 MME. */
+/* BIP-CMAC-128 */
+struct ieee80211_mmie {
+ uint8_t element_id;
+ uint8_t length;
+ uint16_t key_id;
+ uint8_t ipn[6];
+ uint8_t mic[8];
+};
+/* BIP-CMAC-256, BIP-GMAC-128, BIP-GMAC-256 */
struct ieee80211_mmie_16 {
uint8_t element_id;
uint8_t length;
@@ -92,8 +100,6 @@ struct ieee80211_mmie_16 {
#define IEEE80211_MAX_RTS_THRESHOLD 2346 /* net80211::IEEE80211_RTS_MAX */
-#define IEEE80211_MIN_ACTION_SIZE 23 /* ? */
-
/* Wi-Fi Peer-to-Peer (P2P) Technical Specification */
#define IEEE80211_P2P_OPPPS_CTWINDOW_MASK 0x7f
#define IEEE80211_P2P_OPPPS_ENABLE_BIT BIT(7)
@@ -108,7 +114,18 @@ struct ieee80211_mmie_16 {
#define IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT 0x0100
enum ieee80211_rate_flags {
- IEEE80211_RATE_SHORT_PREAMBLE = BIT(0),
+ IEEE80211_RATE_SHORT_PREAMBLE = BIT(0), /* 2.4Ghz, CCK */
+ IEEE80211_RATE_SUPPORTS_5MHZ = BIT(1),
+ IEEE80211_RATE_SUPPORTS_10MHZ = BIT(2),
+ IEEE80211_RATE_ERP_G = BIT(3),
+
+ /*
+ * According to documentation these are flags initialized internally.
+ * See lkpi_wiphy_band_annotate().
+ */
+ IEEE80211_RATE_MANDATORY_A = BIT(4),
+ IEEE80211_RATE_MANDATORY_G = BIT(5),
+ IEEE80211_RATE_MANDATORY_B = BIT(6),
};
enum ieee80211_rate_control_changed_flags {
@@ -200,6 +217,7 @@ enum ieee80211_min_mpdu_start_spacing {
#define IEEE80211_FCTL_TODS (IEEE80211_FC1_DIR_TODS << 8)
#define IEEE80211_FCTL_MOREFRAGS (IEEE80211_FC1_MORE_FRAG << 8)
#define IEEE80211_FCTL_PM (IEEE80211_FC1_PWR_MGT << 8)
+#define IEEE80211_FCTL_MOREDATA (IEEE80211_FC1_MORE_DATA << 8)
#define IEEE80211_FTYPE_MGMT IEEE80211_FC0_TYPE_MGT
#define IEEE80211_FTYPE_CTL IEEE80211_FC0_TYPE_CTL
@@ -461,18 +479,6 @@ enum ieee80211_tx_control_flags {
IEEE80211_TX_CTRL_MLO_LINK = 0xF0000000, /* This is IEEE80211_LINK_UNSPECIFIED on the high bits. */
};
-enum ieee80211_tx_rate_flags {
- /* XXX TODO .. right shift numbers */
- IEEE80211_TX_RC_40_MHZ_WIDTH = BIT(0),
- IEEE80211_TX_RC_80_MHZ_WIDTH = BIT(1),
- IEEE80211_TX_RC_160_MHZ_WIDTH = BIT(2),
- IEEE80211_TX_RC_GREEN_FIELD = BIT(3),
- IEEE80211_TX_RC_MCS = BIT(4),
- IEEE80211_TX_RC_SHORT_GI = BIT(5),
- IEEE80211_TX_RC_VHT_MCS = BIT(6),
- IEEE80211_TX_RC_USE_SHORT_PREAMBLE = BIT(7),
-};
-
#define IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED -128
#define IEEE80211_HT_CTL_LEN 4
@@ -614,6 +620,8 @@ struct ieee80211_mgmt {
} u;
} __packed __aligned(2);
+#define IEEE80211_MIN_ACTION_SIZE offsetof(struct ieee80211_mgmt, u.action.u)
+
struct ieee80211_cts { /* net80211::ieee80211_frame_cts */
__le16 frame_control;
__le16 duration;
diff --git a/sys/compat/linuxkpi/common/include/linux/instruction_pointer.h b/sys/compat/linuxkpi/common/include/linux/instruction_pointer.h
new file mode 100644
index 000000000000..200a8c3f1d5e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/instruction_pointer.h
@@ -0,0 +1,15 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Neel Chauhan
+ * Copyright (c) 2026 The FreeBSD Foundation
+ */
+
+#ifndef _LINUXKPI_LINUX_INSTRUCTION_POINTER_H_
+#define _LINUXKPI_LINUX_INSTRUCTION_POINTER_H_
+
+#define _RET_IP_ __builtin_return_address(0)
+
+#define _THIS_IP_ ((unsigned long)0) /* TODO: _THIS_IP_ not implemented. */
+
+#endif /* _LINUXKPI_LINUX_INSTRUCTION_POINTER_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/io.h b/sys/compat/linuxkpi/common/include/linux/io.h
index 2d6fef4e7c52..f89c150e7a3b 100644
--- a/sys/compat/linuxkpi/common/include/linux/io.h
+++ b/sys/compat/linuxkpi/common/include/linux/io.h
@@ -542,7 +542,7 @@ static inline int
arch_io_reserve_memtype_wc(resource_size_t start, resource_size_t size)
{
#if defined(__amd64__)
- vm_offset_t va;
+ void *va;
va = PHYS_TO_DMAP(start);
return (-pmap_change_attr(va, size, VM_MEMATTR_WRITE_COMBINING));
@@ -555,7 +555,7 @@ static inline void
arch_io_free_memtype_wc(resource_size_t start, resource_size_t size)
{
#if defined(__amd64__)
- vm_offset_t va;
+ void *va;
va = PHYS_TO_DMAP(start);
diff --git a/sys/compat/linuxkpi/common/include/linux/ioport.h b/sys/compat/linuxkpi/common/include/linux/ioport.h
index 763af2de7c4f..68f28cec4ec4 100644
--- a/sys/compat/linuxkpi/common/include/linux/ioport.h
+++ b/sys/compat/linuxkpi/common/include/linux/ioport.h
@@ -41,6 +41,7 @@ struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
+ unsigned long flags;
};
static inline resource_size_t
diff --git a/sys/compat/linuxkpi/common/include/linux/kconfig.h b/sys/compat/linuxkpi/common/include/linux/kconfig.h
index c1d186b56e1f..529d41991900 100644
--- a/sys/compat/linuxkpi/common/include/linux/kconfig.h
+++ b/sys/compat/linuxkpi/common/include/linux/kconfig.h
@@ -73,4 +73,39 @@
#define IS_REACHABLE(_x) (IS_BUILTIN(_x) || \
(IS_MODULE(_x) && IS_BUILTIN(MODULE)))
+/*
+ * On Linux, the CONFIG_PGTABLE_LEVELS value is defined by the config/build
+ * system. Here, we take the per-architecture default value defined in
+ * `arch/$ARCH/Kconfig` files upstream.
+ */
+#if defined(__amd64__)
+
+#define CONFIG_PGTABLE_LEVELS 4
+
+#elif defined(__aarch64__)
+
+#define CONFIG_PGTABLE_LEVELS 4
+
+#elif defined(__i386__)
+
+#define CONFIG_PGTABLE_LEVELS 2
+
+#elif defined(__powerpc__)
+
+#if defined(__powerpc64__)
+#define CONFIG_PGTABLE_LEVELS 4
+#else
+#define CONFIG_PGTABLE_LEVELS 2
+#endif
+
+#elif defined(__riscv)
+
+#if defined(__riscv_xlen) && __riscv_xlen == 64
+#define CONFIG_PGTABLE_LEVELS 5
+#else
+#define CONFIG_PGTABLE_LEVELS 2
+#endif
+
+#endif
+
#endif /* _LINUXKPI_LINUX_KCONFIG_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kdev_t.h b/sys/compat/linuxkpi/common/include/linux/kdev_t.h
index 988dd771254a..964b7078e7f5 100644
--- a/sys/compat/linuxkpi/common/include/linux/kdev_t.h
+++ b/sys/compat/linuxkpi/common/include/linux/kdev_t.h
@@ -31,6 +31,21 @@
#include <sys/types.h>
+/*
+ * The encoding of major/minor on FreeBSD is complex to take into account the
+ * compatibility with 16-bit dev_t (see <sys/types.h>). It is not possible to
+ * use a simple shift and thus, we can't have a proper definition of
+ * `MINORBITS`.
+ *
+ * At the time this is added to linuxkpi, this is used by the DRM generic code
+ * as the upper limit to allocate an ID using an xarray. It is not used to
+ * decode a minor, therefore any arbitrary value here is fine in this context.
+ *
+ * On Linux, the value is set to 20. Because of the above, we reuse this value,
+ * even so it does not correspond to the actual minor encoding on FreeBSD.
+ */
+#define MINORBITS 20
+
#define MAJOR(dev) major(dev)
#define MINOR(dev) minor(dev)
#define MKDEV(ma, mi) makedev(ma, mi)
diff --git a/sys/compat/linuxkpi/common/include/linux/kernel.h b/sys/compat/linuxkpi/common/include/linux/kernel.h
index 11a13cbd49b4..afbd9208a410 100644
--- a/sys/compat/linuxkpi/common/include/linux/kernel.h
+++ b/sys/compat/linuxkpi/common/include/linux/kernel.h
@@ -40,6 +40,7 @@
#include <sys/syslog.h>
#include <sys/time.h>
+#include <linux/array_size.h>
#include <linux/bitops.h>
#include <linux/build_bug.h>
#include <linux/compiler.h>
@@ -55,6 +56,9 @@
#include <linux/jiffies.h>
#include <linux/log2.h>
#include <linux/kconfig.h>
+#include <linux/instruction_pointer.h>
+#include <linux/hex.h>
+#include <linux/wordpart.h>
#include <asm/byteorder.h>
#include <asm/cpufeature.h>
@@ -263,12 +267,8 @@ extern int linuxkpi_debug;
})
#endif
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
#define u64_to_user_ptr(val) ((void *)(uintptr_t)(val))
-#define _RET_IP_ __builtin_return_address(0)
-
#define offsetofend(t, m) \
(offsetof(t, m) + sizeof((((t *)0)->m)))
@@ -306,37 +306,6 @@ linux_ratelimited(linux_ratelimit_t *rl)
#define add_taint(x,y) do { \
} while (0)
-static inline int
-_h2b(const char c)
-{
-
- if (c >= '0' && c <= '9')
- return (c - '0');
- if (c >= 'a' && c <= 'f')
- return (10 + c - 'a');
- if (c >= 'A' && c <= 'F')
- return (10 + c - 'A');
- return (-EINVAL);
-}
-
-static inline int
-hex2bin(uint8_t *bindst, const char *hexsrc, size_t binlen)
-{
- int hi4, lo4;
-
- while (binlen > 0) {
- hi4 = _h2b(*hexsrc++);
- lo4 = _h2b(*hexsrc++);
- if (hi4 < 0 || lo4 < 0)
- return (-EINVAL);
-
- *bindst++ = (hi4 << 4) | lo4;
- binlen--;
- }
-
- return (0);
-}
-
static inline bool
mac_pton(const char *macin, uint8_t *macout)
{
@@ -382,4 +351,48 @@ mac_pton(const char *macin, uint8_t *macout)
#define DECLARE_FLEX_ARRAY(_t, _n) \
struct { struct { } __dummy_ ## _n; _t _n[0]; }
+/*
+ * The following functions/macros are debug/diagnostics tools. They default to
+ * no-ops, except `might_sleep()` which uses `WITNESS_WARN()` on FreeBSD.
+ */
+static inline void
+__might_resched(const char *file, int line, unsigned int offsets)
+{
+}
+
+static inline void
+__might_sleep(const char *file, int line)
+{
+}
+
+static inline void
+might_fault(void)
+{
+}
+
+#define might_sleep() \
+ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "might_sleep()")
+
+#define might_sleep_if(cond) do { \
+ if (cond) { might_sleep(); } \
+} while (0)
+
+#define might_resched() do { } while (0)
+#define cant_sleep() do { } while (0)
+#define cant_migrate() do { } while (0)
+#define sched_annotate_sleep() do { } while (0)
+#define non_block_start() do { } while (0)
+#define non_block_end() do { } while (0)
+
+extern enum system_states {
+ SYSTEM_BOOTING,
+ SYSTEM_SCHEDULING,
+ SYSTEM_FREEING_INITMEM,
+ SYSTEM_RUNNING,
+ SYSTEM_HALT,
+ SYSTEM_POWER_OFF,
+ SYSTEM_RESTART,
+ SYSTEM_SUSPEND,
+} system_state;
+
#endif /* _LINUXKPI_LINUX_KERNEL_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kfifo.h b/sys/compat/linuxkpi/common/include/linux/kfifo.h
index d2f570781661..c8cea1226b3c 100644
--- a/sys/compat/linuxkpi/common/include/linux/kfifo.h
+++ b/sys/compat/linuxkpi/common/include/linux/kfifo.h
@@ -30,11 +30,30 @@
#include <sys/types.h>
+#include <linux/array_size.h>
#include <linux/slab.h>
#include <linux/gfp.h>
-#define INIT_KFIFO(x) 0
-#define DECLARE_KFIFO(x, y, z)
+/*
+ * INIT_KFIFO() is used to initialize the structure declared with
+ * DECLARE_KFIFO(). It doesn't work with DECLARE_KFIFO_PTR().
+ */
+#define INIT_KFIFO(_kf) \
+ ({ \
+ (_kf).total = nitems((_kf).head); \
+ (_kf).count = 0; \
+ (_kf).first = 0; \
+ (_kf).last = 0; \
+ })
+
+#define DECLARE_KFIFO(_name, _type, _size) \
+ struct kfifo_ ## _name { \
+ size_t total; \
+ size_t count; \
+ size_t first; \
+ size_t last; \
+ _type head[_size]; \
+ } _name
#define DECLARE_KFIFO_PTR(_name, _type) \
struct kfifo_ ## _name { \
@@ -71,7 +90,7 @@
(_kf)->head[(_kf)->last] = (_e); \
(_kf)->count++; \
(_kf)->last++; \
- if ((_kf)->last > (_kf)->total) \
+ if ((_kf)->last >= (_kf)->total) \
(_kf)->last = 0; \
_rc = true; \
} \
@@ -89,7 +108,7 @@
*(_e) = (_kf)->head[(_kf)->first]; \
(_kf)->count--; \
(_kf)->first++; \
- if ((_kf)->first > (_kf)->total) \
+ if ((_kf)->first >= (_kf)->total) \
(_kf)->first = 0; \
_rc = true; \
} \
diff --git a/sys/compat/linuxkpi/common/include/linux/kmsg_dump.h b/sys/compat/linuxkpi/common/include/linux/kmsg_dump.h
new file mode 100644
index 000000000000..e7f95ced3047
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/kmsg_dump.h
@@ -0,0 +1,102 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025-2026 The FreeBSD Foundation
+ * Copyright (c) 2025-2026 Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
+ *
+ * This software was developed by Jean-Sébastien Pédron under sponsorship
+ * from the FreeBSD Foundation.
+ */
+
+#ifndef _LINUXKPI_LINUX_KMSG_DUMP_H_
+#define _LINUXKPI_LINUX_KMSG_DUMP_H_
+
+#include <linux/errno.h>
+#include <linux/list.h>
+
+#include <linux/kernel.h> /* For pr_debug() */
+
+enum kmsg_dump_reason {
+ KMSG_DUMP_UNDEF,
+ KMSG_DUMP_PANIC,
+ KMSG_DUMP_OOPS,
+ KMSG_DUMP_EMERG,
+ KMSG_DUMP_SHUTDOWN,
+ KMSG_DUMP_MAX
+};
+
+struct kmsg_dump_iter {
+ uint64_t cur_seq;
+ uint64_t next_seq;
+};
+
+struct kmsg_dump_detail {
+ enum kmsg_dump_reason reason;
+ const char *description;
+};
+
+struct kmsg_dumper {
+ struct list_head list;
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION < 61200
+ void (*dump)(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason);
+#else
+ void (*dump)(struct kmsg_dumper *dumper, struct kmsg_dump_detail *detail);
+#endif
+ enum kmsg_dump_reason max_reason;
+ bool registered;
+};
+
+static inline void
+kmsg_dump(enum kmsg_dump_reason reason)
+{
+ pr_debug("TODO");
+}
+
+static inline bool
+kmsg_dump_get_line(struct kmsg_dump_iter *iter, bool syslog,
+ const char *line, size_t size, size_t *len)
+{
+ pr_debug("TODO");
+
+ return (false);
+}
+
+static inline bool
+kmsg_dump_get_buffer(struct kmsg_dump_iter *iter, bool syslog,
+ char *buf, size_t size, size_t *len)
+{
+ pr_debug("TODO");
+
+ return (false);
+}
+
+static inline void
+kmsg_dump_rewind(struct kmsg_dump_iter *iter)
+{
+ pr_debug("TODO");
+}
+
+static inline int
+kmsg_dump_register(struct kmsg_dumper *dumper)
+{
+ pr_debug("TODO");
+
+ return (-EINVAL);
+}
+
+static inline int
+kmsg_dump_unregister(struct kmsg_dumper *dumper)
+{
+ pr_debug("TODO");
+
+ return (-EINVAL);
+}
+
+static inline const char *
+kmsg_dump_reason_str(enum kmsg_dump_reason reason)
+{
+ pr_debug("TODO");
+
+ return ("Unknown");
+}
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/kstrtox.h b/sys/compat/linuxkpi/common/include/linux/kstrtox.h
index 5da99de24197..05bf94dd375d 100644
--- a/sys/compat/linuxkpi/common/include/linux/kstrtox.h
+++ b/sys/compat/linuxkpi/common/include/linux/kstrtox.h
@@ -74,14 +74,17 @@ static inline int
kstrtoul(const char *cp, unsigned int base, unsigned long *res)
{
char *end;
+ unsigned long temp;
- *res = strtoul(cp, &end, base);
+ temp = strtoul(cp, &end, base);
/* skip newline character, if any */
if (*end == '\n')
end++;
if (*cp == 0 || *end != 0)
return (-EINVAL);
+
+ *res = temp;
return (0);
}
@@ -89,14 +92,17 @@ static inline int
kstrtol(const char *cp, unsigned int base, long *res)
{
char *end;
+ long temp;
- *res = strtol(cp, &end, base);
+ temp = strtol(cp, &end, base);
/* skip newline character, if any */
if (*end == '\n')
end++;
if (*cp == 0 || *end != 0)
return (-EINVAL);
+
+ *res = temp;
return (0);
}
@@ -106,7 +112,7 @@ kstrtoint(const char *cp, unsigned int base, int *res)
char *end;
long temp;
- *res = temp = strtol(cp, &end, base);
+ temp = strtol(cp, &end, base);
/* skip newline character, if any */
if (*end == '\n')
@@ -115,6 +121,8 @@ kstrtoint(const char *cp, unsigned int base, int *res)
return (-EINVAL);
if (temp != (int)temp)
return (-ERANGE);
+
+ *res = (int)temp;
return (0);
}
@@ -124,7 +132,7 @@ kstrtouint(const char *cp, unsigned int base, unsigned int *res)
char *end;
unsigned long temp;
- *res = temp = strtoul(cp, &end, base);
+ temp = strtoul(cp, &end, base);
/* skip newline character, if any */
if (*end == '\n')
@@ -133,6 +141,8 @@ kstrtouint(const char *cp, unsigned int base, unsigned int *res)
return (-EINVAL);
if (temp != (unsigned int)temp)
return (-ERANGE);
+
+ *res = (unsigned int)temp;
return (0);
}
@@ -142,7 +152,7 @@ kstrtou8(const char *cp, unsigned int base, uint8_t *res)
char *end;
unsigned long temp;
- *res = temp = strtoul(cp, &end, base);
+ temp = strtoul(cp, &end, base);
/* skip newline character, if any */
if (*end == '\n')
@@ -151,6 +161,8 @@ kstrtou8(const char *cp, unsigned int base, uint8_t *res)
return (-EINVAL);
if (temp != (uint8_t)temp)
return (-ERANGE);
+
+ *res = (uint8_t)temp;
return (0);
}
@@ -160,7 +172,7 @@ kstrtou16(const char *cp, unsigned int base, uint16_t *res)
char *end;
unsigned long temp;
- *res = temp = strtoul(cp, &end, base);
+ temp = strtoul(cp, &end, base);
/* skip newline character, if any */
if (*end == '\n')
@@ -169,20 +181,20 @@ kstrtou16(const char *cp, unsigned int base, uint16_t *res)
return (-EINVAL);
if (temp != (uint16_t)temp)
return (-ERANGE);
+
+ *res = (uint16_t)temp;
return (0);
}
static inline int
kstrtou32(const char *cp, unsigned int base, uint32_t *res)
{
-
return (kstrtouint(cp, base, res));
}
static inline int
kstrtos32(const char *cp, unsigned int base, int32_t *res)
{
-
return (kstrtoint(cp, base, res));
}
@@ -190,14 +202,17 @@ static inline int
kstrtos64(const char *cp, unsigned int base, int64_t *res)
{
char *end;
+ quad_t temp;
- *res = strtoq(cp, &end, base);
+ temp = strtoq(cp, &end, base);
/* skip newline character, if any */
if (*end == '\n')
end++;
if (*cp == 0 || *end != 0)
return (-EINVAL);
+
+ *res = (int64_t)temp;
return (0);
}
@@ -208,17 +223,20 @@ kstrtoll(const char *cp, unsigned int base, long long *res)
}
static inline int
-kstrtou64(const char *cp, unsigned int base, u64 *res)
+kstrtou64(const char *cp, unsigned int base, uint64_t *res)
{
char *end;
+ u_quad_t temp;
- *res = strtouq(cp, &end, base);
+ temp = strtouq(cp, &end, base);
/* skip newline character, if any */
if (*end == '\n')
end++;
if (*cp == 0 || *end != 0)
return (-EINVAL);
+
+ *res = (uint64_t)temp;
return (0);
}
@@ -231,22 +249,16 @@ kstrtoull(const char *cp, unsigned int base, unsigned long long *res)
static inline int
kstrtobool(const char *s, bool *res)
{
- int len;
-
- if (s == NULL || (len = strlen(s)) == 0 || res == NULL)
+ if (s == NULL || *s == '\0')
return (-EINVAL);
- /* skip newline character, if any */
- if (s[len - 1] == '\n')
- len--;
-
- if (len == 1 && strchr("yY1", s[0]) != NULL)
+ if (strchr("eEtTyY1", s[0]) != NULL)
*res = true;
- else if (len == 1 && strchr("nN0", s[0]) != NULL)
+ else if (strchr("dDfFnN0", s[0]) != NULL)
*res = false;
- else if (strncasecmp("on", s, len) == 0)
+ else if (strncasecmp("on", s, 2) == 0)
*res = true;
- else if (strncasecmp("off", s, len) == 0)
+ else if (strncasecmp("of", s, 2) == 0)
*res = false;
else
return (-EINVAL);
@@ -302,7 +314,6 @@ static inline int
kstrtou32_from_user(const char __user *s, size_t count, unsigned int base,
unsigned int *p)
{
-
return (kstrtouint_from_user(s, count, base, p));
}
diff --git a/sys/compat/linuxkpi/common/include/linux/linux_logo.h b/sys/compat/linuxkpi/common/include/linux/linux_logo.h
new file mode 100644
index 000000000000..cb60ba50f6a5
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/linux_logo.h
@@ -0,0 +1,19 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 The FreeBSD Foundation
+ */
+
+#ifndef _LINUXKPI_LINUX_LINUX_LOGO_H_
+#define _LINUXKPI_LINUX_LINUX_LOGO_H_
+
+struct linux_logo {
+ int type;
+ unsigned int width;
+ unsigned int height;
+ unsigned int clutsize;
+ const unsigned char *clut;
+ const unsigned char *data;
+};
+
+#endif /* _LINUXKPI_LINUX_LINUX_LOGO_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/math64.h b/sys/compat/linuxkpi/common/include/linux/math64.h
index 25ca9da1b622..e35aae67fa27 100644
--- a/sys/compat/linuxkpi/common/include/linux/math64.h
+++ b/sys/compat/linuxkpi/common/include/linux/math64.h
@@ -93,6 +93,12 @@ mul_u32_u32(uint32_t a, uint32_t b)
}
static inline uint64_t
+div_u64_round_up(uint64_t dividend, uint32_t divisor)
+{
+ return ((dividend + divisor - 1) / divisor);
+}
+
+static inline uint64_t
div64_u64_round_up(uint64_t dividend, uint64_t divisor)
{
return ((dividend + divisor - 1) / divisor);
@@ -104,6 +110,9 @@ roundup_u64(uint64_t x1, uint32_t x2)
return (div_u64(x1 + x2 - 1, x2) * x2);
}
+#define DIV_U64_ROUND_UP(...) \
+ div_u64_round_up(__VA_ARGS__)
+
#define DIV64_U64_ROUND_UP(...) \
div64_u64_round_up(__VA_ARGS__)
diff --git a/sys/compat/linuxkpi/common/include/linux/memcontrol.h b/sys/compat/linuxkpi/common/include/linux/memcontrol.h
new file mode 100644
index 000000000000..57fadf9af60f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/memcontrol.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2025 The FreeBSD Foundation
+ * Copyright (c) 2025 Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
+ *
+ * This software was developed by Jean-Sébastien Pédron under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#ifndef _LINUXKPI_LINUX_MEMCONTROL_H_
+#define _LINUXKPI_LINUX_MEMCONTROL_H_
+
+#include <linux/cgroup.h>
+#include <linux/hardirq.h>
+#include <linux/jump_label.h>
+#include <linux/kernel.h>
+#include <linux/eventfd.h>
+#include <linux/mm.h>
+#include <linux/page-flags.h>
+#include <linux/shrinker.h>
+
+#endif /* defined(_LINUXKPI_LINUX_MEMCONTROL_H_) */
diff --git a/sys/compat/linuxkpi/common/include/linux/mfd/core.h b/sys/compat/linuxkpi/common/include/linux/mfd/core.h
new file mode 100644
index 000000000000..1a69a3803b5d
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/mfd/core.h
@@ -0,0 +1,49 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 The FreeBSD Foundation
+ */
+
+#ifndef _LINUXKPI_LINUX_MFD_CORE_H_
+#define _LINUXKPI_LINUX_MFD_CORE_H_
+
+#include <linux/platform_device.h>
+
+/*
+ * <linux/ioport.h> is not included by Linux, but we need it here to get the
+ * definition of `struct resource`.
+ *
+ * At least the amdgpu DRM driver (amdgpu_isp.c at the time of this writing)
+ * needs the structure without including this header: it relies on an implicit
+ * include of <linux/ioport.h> from <linux/pci.h>, which we can't have due to
+ * conflict with the FreeBSD native `struct resource`.
+ */
+#include <linux/ioport.h>
+
+#include <linux/kernel.h> /* pr_debug */
+
+struct resource;
+struct mfd_cell {
+ const char *name;
+ void *platform_data;
+ size_t pdata_size;
+ int num_resources;
+ const struct resource *resources;
+};
+
+static inline int
+mfd_add_hotplug_devices(struct device *parent,
+ const struct mfd_cell *cells, int n_devs)
+{
+ pr_debug("%s: TODO\n", __func__);
+
+ return (0);
+}
+
+static inline void
+mfd_remove_devices(struct device *parent)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+#endif /* _LINUXKPI_LINUX_MFD_CORE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/minmax.h b/sys/compat/linuxkpi/common/include/linux/minmax.h
index d48958f0899f..161d0174554a 100644
--- a/sys/compat/linuxkpi/common/include/linux/minmax.h
+++ b/sys/compat/linuxkpi/common/include/linux/minmax.h
@@ -60,6 +60,9 @@
type __max2 = (y); \
__max1 > __max2 ? __max1 : __max2; })
+#define MIN_T(type, x, y) MIN((type)(x), (type)(y))
+#define MAX_T(type, x, y) MAX((type)(x), (type)(y))
+
#define clamp_t(type, _x, min, max) min_t(type, max_t(type, _x, min), max)
#define clamp(x, lo, hi) min(max(x, lo), hi)
#define clamp_val(val, lo, hi) clamp_t(typeof(val), val, lo, hi)
@@ -71,4 +74,17 @@
b = _swap_tmp; \
} while (0)
+/* XXX would have to make sure both are unsigned. */
+#define umin(x, y) MIN(x, y)
+
+/* This macro assumes that the array has elements inside. */
+#define __minmax_array(op, array, len) ({ \
+ typeof(array[0]) __val = array[0]; \
+ for (typeof(len) __i = 1; __i < len; __i++) \
+ __val = op(__val, array[__i]); \
+ __val; })
+
+#define min_array(array, len) __minmax_array(min, array, len)
+#define max_array(array, len) __minmax_array(max, array, len)
+
#endif /* _LINUXKPI_LINUX_MINMAX_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/mm.h b/sys/compat/linuxkpi/common/include/linux/mm.h
index 156b00a0c0f0..a639c0947031 100644
--- a/sys/compat/linuxkpi/common/include/linux/mm.h
+++ b/sys/compat/linuxkpi/common/include/linux/mm.h
@@ -264,6 +264,7 @@ vma_pages(struct vm_area_struct *vma)
}
#define offset_in_page(off) ((unsigned long)(off) & (PAGE_SIZE - 1))
+#define offset_in_folio(folio, p) ((unsigned long)(p) & (folio_size(folio) - 1))
static inline void
set_page_dirty(struct page *page)
diff --git a/sys/compat/linuxkpi/common/include/linux/mod_devicetable.h b/sys/compat/linuxkpi/common/include/linux/mod_devicetable.h
index 87bd6ec24bce..b345b98325e1 100644
--- a/sys/compat/linuxkpi/common/include/linux/mod_devicetable.h
+++ b/sys/compat/linuxkpi/common/include/linux/mod_devicetable.h
@@ -30,6 +30,7 @@
#define __LINUXKPI_LINUX_MOD_DEVICETABLE_H__
#include <linux/types.h>
+#include <linux/uuid.h>
enum dmi_field {
DMI_NONE,
@@ -80,4 +81,10 @@ struct dmi_system_id {
#define ACPI_ID_LEN 16
+/* -----------------------------------------------------------------------------
+ * USB
+ */
+/* struct usb_device_id is defined in sys/dev/usb/usbdi.h. */
+/* MODULE_DEVICE_TABLE_BUS_usb we have in usb.h. */
+
#endif /* __LINUXKPI_LINUX_MOD_DEVICETABLE_H__ */
diff --git a/sys/compat/linuxkpi/common/include/linux/module.h b/sys/compat/linuxkpi/common/include/linux/module.h
index 079dacf8df6c..fbe57cbbed82 100644
--- a/sys/compat/linuxkpi/common/include/linux/module.h
+++ b/sys/compat/linuxkpi/common/include/linux/module.h
@@ -53,6 +53,24 @@
#define MODULE_SUPPORTED_DEVICE(name)
#define MODULE_IMPORT_NS(_name)
+/* Linux has an empty element at the end of the ID table -> nitems() - 1. */
+#define MODULE_DEVICE_TABLE(_bus, _table) \
+ \
+static device_method_t _ ## _bus ## _ ## _table ## _methods[] = { \
+ DEVMETHOD_END \
+}; \
+ \
+static driver_t _ ## _bus ## _ ## _table ## _driver = { \
+ "lkpi_" #_bus #_table, \
+ _ ## _bus ## _ ## _table ## _methods, \
+ 0 \
+}; \
+ \
+DRIVER_MODULE(lkpi_ ## _table, _bus, _ ## _bus ## _ ## _table ## _driver,\
+ 0, 0); \
+ \
+MODULE_DEVICE_TABLE_BUS_ ## _bus(_bus, _table)
+
/*
* THIS_MODULE is used to differentiate modules on Linux. We currently
* completely stub out any Linux struct module usage, but THIS_MODULE is still
diff --git a/sys/compat/linuxkpi/common/include/linux/mutex.h b/sys/compat/linuxkpi/common/include/linux/mutex.h
index 6fb6a7744a89..64d76491a76f 100644
--- a/sys/compat/linuxkpi/common/include/linux/mutex.h
+++ b/sys/compat/linuxkpi/common/include/linux/mutex.h
@@ -174,4 +174,6 @@ linux_mutex_destroy(mutex_t *m)
extern int linux_mutex_lock_interruptible(mutex_t *m);
+DEFINE_GUARD(mutex, struct mutex *, mutex_lock(_T), mutex_unlock(_T))
+
#endif /* _LINUXKPI_LINUX_MUTEX_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/netdevice.h b/sys/compat/linuxkpi/common/include/linux/netdevice.h
index cf27753bcb80..dfed5fbd61b4 100644
--- a/sys/compat/linuxkpi/common/include/linux/netdevice.h
+++ b/sys/compat/linuxkpi/common/include/linux/netdevice.h
@@ -160,6 +160,30 @@ struct net_device {
#define SET_NETDEV_DEV(_ndev, _dev) (_ndev)->dev.parent = _dev;
+enum net_device_path_type {
+ DEV_PATH_MTK_WDMA,
+};
+
+struct net_device_path {
+ enum net_device_path_type type;
+ const struct net_device *dev;
+ /* We assume there's a struct per type. */
+ union {
+ struct {
+ uint16_t wcid;
+ uint8_t wdma_idx;
+ uint8_t queue;
+ uint8_t bss;
+ uint8_t amsdu;
+ } mtk_wdma;
+ };
+};
+
+struct net_device_path_ctx {
+ const struct net_device *dev;
+};
+
+
/* -------------------------------------------------------------------------- */
/* According to linux::ipoib_main.c. */
struct netdev_notifier_info {
diff --git a/sys/compat/linuxkpi/common/include/linux/notifier.h b/sys/compat/linuxkpi/common/include/linux/notifier.h
index 9302a1ce4606..4fe43255c648 100644
--- a/sys/compat/linuxkpi/common/include/linux/notifier.h
+++ b/sys/compat/linuxkpi/common/include/linux/notifier.h
@@ -32,6 +32,11 @@
#include <sys/types.h>
#include <sys/eventhandler.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/rwsem.h>
+#include <linux/srcu.h>
+
#define NOTIFY_DONE 0
#define NOTIFY_OK 0x0001
#define NOTIFY_STOP_MASK 0x8000
diff --git a/sys/compat/linuxkpi/common/include/linux/overflow.h b/sys/compat/linuxkpi/common/include/linux/overflow.h
index e811037b8ecc..4326f05e6d07 100644
--- a/sys/compat/linuxkpi/common/include/linux/overflow.h
+++ b/sys/compat/linuxkpi/common/include/linux/overflow.h
@@ -4,9 +4,7 @@
#include <linux/compiler.h>
#include <linux/limits.h>
-#ifdef __linux__
#include <linux/const.h>
-#endif
/*
* We need to compute the minimum and maximum values representable in a given
@@ -38,19 +36,13 @@
#define __type_min(T) ((T)((T)-type_max(T)-(T)1))
#define type_min(t) __type_min(typeof(t))
-/*
- * Avoids triggering -Wtype-limits compilation warning,
- * while using unsigned data types to check a < 0.
- */
-#define is_non_negative(a) ((a) > 0 || (a) == 0)
-#define is_negative(a) (!(is_non_negative(a)))
/*
* Allows for effectively applying __must_check to a macro so we can have
* both the type-agnostic benefits of the macros while also being able to
* enforce that the return value is, in fact, checked.
*/
-static inline bool __must_check __must_check_overflow(bool overflow)
+static __always_inline bool __must_check __must_check_overflow(bool overflow)
{
return unlikely(overflow);
}
@@ -203,9 +195,9 @@ static inline bool __must_check __must_check_overflow(bool overflow)
typeof(d) _d = d; \
unsigned long long _a_full = _a; \
unsigned int _to_shift = \
- is_non_negative(_s) && _s < 8 * sizeof(*d) ? _s : 0; \
+ _s >= 0 && _s < 8 * sizeof(*d) ? _s : 0; \
*_d = (_a_full << _to_shift); \
- (_to_shift != _s || is_negative(*_d) || is_negative(_a) || \
+ (_to_shift != _s || *_d < 0 || _a < 0 || \
(*_d >> _to_shift) != _a); \
}))
@@ -241,6 +233,76 @@ static inline bool __must_check __must_check_overflow(bool overflow)
__overflows_type(n, T))
/**
+ * range_overflows() - Check if a range is out of bounds
+ * @start: Start of the range.
+ * @size: Size of the range.
+ * @max: Exclusive upper boundary.
+ *
+ * A strict check to determine if the range [@start, @start + @size) is
+ * invalid with respect to the allowable range [0, @max). Any range
+ * starting at or beyond @max is considered an overflow, even if @size is 0.
+ *
+ * Returns: true if the range is out of bounds.
+ */
+#define range_overflows(start, size, max) ({ \
+ typeof(start) start__ = (start); \
+ typeof(size) size__ = (size); \
+ typeof(max) max__ = (max); \
+ (void)(&start__ == &size__); \
+ (void)(&start__ == &max__); \
+ start__ >= max__ || size__ > max__ - start__; \
+})
+
+/**
+ * range_overflows_t() - Check if a range is out of bounds
+ * @type: Data type to use.
+ * @start: Start of the range.
+ * @size: Size of the range.
+ * @max: Exclusive upper boundary.
+ *
+ * Same as range_overflows() but forcing the parameters to @type.
+ *
+ * Returns: true if the range is out of bounds.
+ */
+#define range_overflows_t(type, start, size, max) \
+ range_overflows((type)(start), (type)(size), (type)(max))
+
+/**
+ * range_end_overflows() - Check if a range's endpoint is out of bounds
+ * @start: Start of the range.
+ * @size: Size of the range.
+ * @max: Exclusive upper boundary.
+ *
+ * Checks only if the endpoint of a range (@start + @size) exceeds @max.
+ * Unlike range_overflows(), a zero-sized range at the boundary (@start == @max)
+ * is not considered an overflow. Useful for iterator-style checks.
+ *
+ * Returns: true if the endpoint exceeds the boundary.
+ */
+#define range_end_overflows(start, size, max) ({ \
+ typeof(start) start__ = (start); \
+ typeof(size) size__ = (size); \
+ typeof(max) max__ = (max); \
+ (void)(&start__ == &size__); \
+ (void)(&start__ == &max__); \
+ start__ > max__ || size__ > max__ - start__; \
+})
+
+/**
+ * range_end_overflows_t() - Check if a range's endpoint is out of bounds
+ * @type: Data type to use.
+ * @start: Start of the range.
+ * @size: Size of the range.
+ * @max: Exclusive upper boundary.
+ *
+ * Same as range_end_overflows() but forcing the parameters to @type.
+ *
+ * Returns: true if the endpoint exceeds the boundary.
+ */
+#define range_end_overflows_t(type, start, size, max) \
+ range_end_overflows((type)(start), (type)(size), (type)(max))
+
+/**
* castable_to_type - like __same_type(), but also allows for casted literals
*
* @n: variable or constant value
@@ -265,7 +327,7 @@ static inline bool __must_check __must_check_overflow(bool overflow)
* with any overflow causing the return value to be SIZE_MAX. The
* lvalue must be size_t to avoid implicit type conversion.
*/
-static inline size_t __must_check size_mul(size_t factor1, size_t factor2)
+static __always_inline size_t __must_check size_mul(size_t factor1, size_t factor2)
{
size_t bytes;
@@ -284,7 +346,7 @@ static inline size_t __must_check size_mul(size_t factor1, size_t factor2)
* with any overflow causing the return value to be SIZE_MAX. The
* lvalue must be size_t to avoid implicit type conversion.
*/
-static inline size_t __must_check size_add(size_t addend1, size_t addend2)
+static __always_inline size_t __must_check size_add(size_t addend1, size_t addend2)
{
size_t bytes;
@@ -305,7 +367,7 @@ static inline size_t __must_check size_add(size_t addend1, size_t addend2)
* argument may be SIZE_MAX (or the result with be forced to SIZE_MAX).
* The lvalue must be size_t to avoid implicit type conversion.
*/
-static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend)
+static __always_inline size_t __must_check size_sub(size_t minuend, size_t subtrahend)
{
size_t bytes;
@@ -391,6 +453,18 @@ static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend)
struct_size((type *)NULL, member, count)
/**
+ * struct_offset() - Calculate the offset of a member within a struct
+ * @p: Pointer to the struct
+ * @member: Name of the member to get the offset of
+ *
+ * Calculates the offset of a particular @member of the structure pointed
+ * to by @p.
+ *
+ * Return: number of bytes to the location of @member.
+ */
+#define struct_offset(p, member) (offsetof(typeof(*(p)), member))
+
+/**
* __DEFINE_FLEX() - helper macro for DEFINE_FLEX() family.
* Enables caller macro to pass arbitrary trailing expressions
*
@@ -472,4 +546,46 @@ static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend)
(__member_size((name)->array) / sizeof(*(name)->array) + \
__must_be_array((name)->array))
+/**
+ * typeof_flex_counter() - Return the type of the counter variable of a given
+ * flexible array member annotated by __counted_by().
+ * @FAM: Instance of flexible array member within a given struct.
+ *
+ * Returns: "size_t" if no annotation exists.
+ */
+#define typeof_flex_counter(FAM) \
+ typeof(_Generic(__flex_counter(FAM), \
+ void *: (size_t)0, \
+ default: *__flex_counter(FAM)))
+
+/**
+ * overflows_flex_counter_type() - Check if the counter associated with the
+ * given flexible array member can represent
+ * a value.
+ * @TYPE: Type of the struct that contains the @FAM.
+ * @FAM: Member name of the FAM within @TYPE.
+ * @COUNT: Value to check against the __counted_by annotated @FAM's counter.
+ *
+ * Returns: true if @COUNT can be represented in the @FAM's counter. When
+ * @FAM is not annotated with __counted_by(), always returns true.
+ */
+#define overflows_flex_counter_type(TYPE, FAM, COUNT) \
+ (overflows_type(COUNT, typeof_flex_counter(((TYPE *)NULL)->FAM)))
+
+/**
+ * __set_flex_counter() - Set the counter associated with the given flexible
+ * array member that has been annoated by __counted_by().
+ * @FAM: Instance of flexible array member within a given struct.
+ * @COUNT: Value to store to the __counted_by annotated @FAM_PTR's counter.
+ *
+ * This is a no-op if no annotation exists. Count needs to be checked with
+ * overflows_flex_counter_type() before using this function.
+ */
+#define __set_flex_counter(FAM, COUNT) \
+({ \
+ *_Generic(__flex_counter(FAM), \
+ void *: &(size_t){ 0 }, \
+ default: __flex_counter(FAM)) = (COUNT); \
+})
+
#endif /* _LINUXKPI_LINUX_OVERFLOW_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/pci.h b/sys/compat/linuxkpi/common/include/linux/pci.h
index 06336bf963d6..5cd87ff091bc 100644
--- a/sys/compat/linuxkpi/common/include/linux/pci.h
+++ b/sys/compat/linuxkpi/common/include/linux/pci.h
@@ -60,6 +60,17 @@
#include <linux/pci_ids.h>
#include <linux/pm.h>
+/*
+ * <linux/ioport.h> should be included here, like Linux, but we can't have that
+ * because Linux `struct resource` definition would conflict with FreeBSD
+ * native definition.
+ *
+ * At least the amdgpu DRM driver (amdgpu_isp.c at the time of this writing)
+ * relies on this indirect include to get the definition of Linux `struct
+ * resource`. As a workaround, we include <linux/ioport.h> from
+ * <linux/mfd/core.h>.
+ */
+
#include <linux/kernel.h> /* pr_debug */
struct pci_device_id {
@@ -76,24 +87,6 @@ struct pci_device_id {
MODULE_PNP_INFO("U32:vendor;U32:device;V32:subvendor;V32:subdevice", \
_bus, lkpi_ ## _table, _table, nitems(_table) - 1)
-/* Linux has an empty element at the end of the ID table -> nitems() - 1. */
-#define MODULE_DEVICE_TABLE(_bus, _table) \
- \
-static device_method_t _ ## _bus ## _ ## _table ## _methods[] = { \
- DEVMETHOD_END \
-}; \
- \
-static driver_t _ ## _bus ## _ ## _table ## _driver = { \
- "lkpi_" #_bus #_table, \
- _ ## _bus ## _ ## _table ## _methods, \
- 0 \
-}; \
- \
-DRIVER_MODULE(lkpi_ ## _table, _bus, _ ## _bus ## _ ## _table ## _driver,\
- 0, 0); \
- \
-MODULE_DEVICE_TABLE_BUS_ ## _bus(_bus, _table)
-
#define PCI_ANY_ID -1U
#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
@@ -253,6 +246,20 @@ extern const char *pci_power_names[6];
#define PCI_IRQ_LEGACY PCI_IRQ_INTX
#endif
+/*
+ * Linux PCI code uses `PCI_SET_ERROR_RESPONSE()` to indicate to the caller of
+ * a `pci_read_*()` function that the read failed. An example of failure is
+ * whether the device was disconnected. It is a bit weird because Linux
+ * `pci_read_*()` can return an error value, as the read value is stored in a
+ * integer passed by pointer.
+ *
+ * We don't set PCI_ERROR_RESPONSE anywhere as of this commit, but the DRM
+ * drivers started to use `PCI_POSSIBLE_ERROR()`.
+ */
+#define PCI_ERROR_RESPONSE (~0ULL)
+#define PCI_SET_ERROR_RESPONSE(val) (*(val) = ((typeof(*(val))) PCI_ERROR_RESPONSE))
+#define PCI_POSSIBLE_ERROR(val) ((val) == ((typeof(val)) PCI_ERROR_RESPONSE))
+
struct pci_dev;
struct pci_driver {
@@ -1122,19 +1129,28 @@ pci_num_vf(struct pci_dev *dev)
static inline enum pci_bus_speed
pcie_get_speed_cap(struct pci_dev *dev)
{
+ struct pci_dev *pbus;
device_t root;
uint32_t lnkcap, lnkcap2;
int error, pos;
- root = device_get_parent(dev->dev.bsddev);
- if (root == NULL)
- return (PCI_SPEED_UNKNOWN);
- root = device_get_parent(root);
- if (root == NULL)
- return (PCI_SPEED_UNKNOWN);
- root = device_get_parent(root);
- if (root == NULL)
- return (PCI_SPEED_UNKNOWN);
+ /*
+ * We should always be called on a PCI device.
+ * The only current consumer I could find was amdgpu which either
+ * calls us directly on a pdev(drmn?) or with the result of
+ * pci_upstream_bridge().
+ *
+ * Treat "drmn" as special again as it is not a PCI device.
+ */
+ if (dev->pdrv != NULL && dev->pdrv->isdrm) {
+ pbus = pci_upstream_bridge(dev);
+ if (pbus == NULL)
+ return (PCI_SPEED_UNKNOWN);
+ } else
+ pbus = dev;
+
+ /* "root" may be misleading as it may not be that. */
+ root = pbus->dev.bsddev;
if (pci_get_vendor(root) == PCI_VENDOR_ID_VIA ||
pci_get_vendor(root) == PCI_VENDOR_ID_SERVERWORKS)
@@ -1317,6 +1333,13 @@ pci_dev_present(const struct pci_device_id *cur)
return (0);
}
+static inline bool
+pci_dev_is_disconnected(const struct pci_dev *pdev)
+{
+ pr_debug("TODO: %s\n", __func__);
+ return (false);
+}
+
static inline const struct pci_device_id *
pci_match_id(const struct pci_device_id *ids, struct pci_dev *pdev)
{
diff --git a/sys/compat/linuxkpi/common/include/linux/platform_data/brcmfmac.h b/sys/compat/linuxkpi/common/include/linux/platform_data/brcmfmac.h
new file mode 100644
index 000000000000..ec99b7b73d1d
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/platform_data/brcmfmac.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2016 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _LINUX_BRCMFMAC_PLATFORM_H
+#define _LINUX_BRCMFMAC_PLATFORM_H
+
+
+#define BRCMFMAC_PDATA_NAME "brcmfmac"
+
+#define BRCMFMAC_COUNTRY_BUF_SZ 4
+
+
+/*
+ * Platform specific driver functions and data. Through the platform specific
+ * device data functions and data can be provided to help the brcmfmac driver to
+ * operate with the device in combination with the used platform.
+ */
+
+
+/**
+ * Note: the brcmfmac can be loaded as module or be statically built-in into
+ * the kernel. If built-in then do note that it uses module_init (and
+ * module_exit) routines which equal device_initcall. So if you intend to
+ * create a module with the platform specific data for the brcmfmac and have
+ * it built-in to the kernel then use a higher initcall then device_initcall
+ * (see init.h). If this is not done then brcmfmac will load without problems
+ * but will not pickup the platform data.
+ *
+ * When the driver does not "detect" platform driver data then it will continue
+ * without reporting anything and just assume there is no data needed. Which is
+ * probably true for most platforms.
+ */
+
+/**
+ * enum brcmf_bus_type - Bus type identifier. Currently SDIO, USB and PCIE are
+ * supported.
+ */
+enum brcmf_bus_type {
+ BRCMF_BUSTYPE_SDIO,
+ BRCMF_BUSTYPE_USB,
+ BRCMF_BUSTYPE_PCIE
+};
+
+
+/**
+ * struct brcmfmac_sdio_pd - SDIO Device specific platform data.
+ *
+ * @txglomsz: SDIO txglom size. Use 0 if default of driver is to be
+ * used.
+ * @drive_strength: is the preferred drive_strength to be used for the SDIO
+ * pins. If 0 then a default value will be used. This is
+ * the target drive strength, the exact drive strength
+ * which will be used depends on the capabilities of the
+ * device.
+ * @oob_irq_supported: does the board have support for OOB interrupts. SDIO
+ * in-band interrupts are relatively slow and for having
+ * less overhead on interrupt processing an out of band
+ * interrupt can be used. If the HW supports this then
+ * enable this by setting this field to true and configure
+ * the oob related fields.
+ * @oob_irq_nr,
+ * @oob_irq_flags: the OOB interrupt information. The values are used for
+ * registering the irq using request_irq function.
+ * @broken_sg_support: flag for broken sg list support of SDIO host controller.
+ * Set this to true if the SDIO host controller has higher
+ * align requirement than 32 bytes for each scatterlist
+ * item.
+ * @sd_head_align: alignment requirement for start of data buffer.
+ * @sd_sgentry_align: length alignment requirement for each sg entry.
+ * @reset: This function can get called if the device communication
+ * broke down. This functionality is particularly useful in
+ * case of SDIO type devices. It is possible to reset a
+ * dongle via sdio data interface, but it requires that
+ * this is fully functional. This function is chip/module
+ * specific and this function should return only after the
+ * complete reset has completed.
+ */
+struct brcmfmac_sdio_pd {
+ int txglomsz;
+ unsigned int drive_strength;
+ bool oob_irq_supported;
+ unsigned int oob_irq_nr;
+ unsigned long oob_irq_flags;
+ bool broken_sg_support;
+ unsigned short sd_head_align;
+ unsigned short sd_sgentry_align;
+ void (*reset)(void);
+};
+
+/**
+ * struct brcmfmac_pd_cc_entry - Struct for translating user space country code
+ * (iso3166) to firmware country code and
+ * revision.
+ *
+ * @iso3166: iso3166 alpha 2 country code string.
+ * @cc: firmware country code string.
+ * @rev: firmware country code revision.
+ */
+struct brcmfmac_pd_cc_entry {
+ char iso3166[BRCMFMAC_COUNTRY_BUF_SZ];
+ char cc[BRCMFMAC_COUNTRY_BUF_SZ];
+ s32 rev;
+};
+
+/**
+ * struct brcmfmac_pd_cc - Struct for translating country codes as set by user
+ * space to a country code and rev which can be used by
+ * firmware.
+ *
+ * @table_size: number of entries in table (> 0)
+ * @table: array of 1 or more elements with translation information.
+ */
+struct brcmfmac_pd_cc {
+ int table_size;
+ struct brcmfmac_pd_cc_entry table[];
+};
+
+/**
+ * struct brcmfmac_pd_device - Device specific platform data. (id/rev/bus_type)
+ * is the unique identifier of the device.
+ *
+ * @id: ID of the device for which this data is. In case of SDIO
+ * or PCIE this is the chipid as identified by chip.c In
+ * case of USB this is the chipid as identified by the
+ * device query.
+ * @rev: chip revision, see id.
+ * @bus_type: The type of bus. Some chipid/rev exist for different bus
+ * types. Each bus type has its own set of settings.
+ * @feature_disable: Bitmask of features to disable (override), See feature.c
+ * in brcmfmac for details.
+ * @country_codes: If available, pointer to struct for translating country
+ * codes.
+ * @bus: Bus specific (union) device settings. Currently only
+ * SDIO.
+ */
+struct brcmfmac_pd_device {
+ unsigned int id;
+ unsigned int rev;
+ enum brcmf_bus_type bus_type;
+ unsigned int feature_disable;
+ struct brcmfmac_pd_cc *country_codes;
+ union {
+ struct brcmfmac_sdio_pd sdio;
+ } bus;
+};
+
+/**
+ * struct brcmfmac_platform_data - BRCMFMAC specific platform data.
+ *
+ * @power_on: This function is called by the brcmfmac driver when the module
+ * gets loaded. This can be particularly useful for low power
+ * devices. The platform spcific routine may for example decide to
+ * power up the complete device. If there is no use-case for this
+ * function then provide NULL.
+ * @power_off: This function is called by the brcmfmac when the module gets
+ * unloaded. At this point the devices can be powered down or
+ * otherwise be reset. So if an actual power_off is not supported
+ * but reset is supported by the devices then reset the devices
+ * when this function gets called. This can be particularly useful
+ * for low power devices. If there is no use-case for this
+ * function then provide NULL.
+ */
+struct brcmfmac_platform_data {
+ void (*power_on)(void);
+ void (*power_off)(void);
+ char *fw_alternative_path;
+ int device_count;
+ struct brcmfmac_pd_device devices[];
+};
+
+
+#endif /* _LINUX_BRCMFMAC_PLATFORM_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/printk.h b/sys/compat/linuxkpi/common/include/linux/printk.h
index d2d197682782..066ec900f04e 100644
--- a/sys/compat/linuxkpi/common/include/linux/printk.h
+++ b/sys/compat/linuxkpi/common/include/linux/printk.h
@@ -48,7 +48,13 @@ int __lkpi_hexdump_printf(void *, const char *, ...) __printflike(2, 3);
void lkpi_hex_dump(int(*)(void *, const char *, ...), void *arg1,
const char *, const char *, const int, const int, const int,
- const void *, size_t, const bool);
+ const void *, size_t, const bool, const bool);
+
+#define hex_dump_to_buffer(buf, len, rowsize, groupsize, linebuf, linebuflen, ascii) \
+ lkpi_hex_dump_to_buffer((buf), (len), (rowsize), (groupsize), (linebuf), (linebuflen), (ascii))
+
+int lkpi_hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
+ int groupsize, char *linebuf, size_t linebuflen, bool ascii);
static inline void
print_hex_dump(const char *level, const char *prefix_str,
@@ -56,7 +62,7 @@ print_hex_dump(const char *level, const char *prefix_str,
const void *buf, size_t len, const bool ascii)
{
lkpi_hex_dump(__lkpi_hexdump_printf, NULL, level, prefix_str, prefix_type,
- rowsize, groupsize, buf, len, ascii);
+ rowsize, groupsize, buf, len, ascii, true);
}
static inline void
diff --git a/sys/compat/linuxkpi/common/include/linux/ptp_clock_kernel.h b/sys/compat/linuxkpi/common/include/linux/ptp_clock_kernel.h
index aad46cc25b1b..6491cbeab7e2 100644
--- a/sys/compat/linuxkpi/common/include/linux/ptp_clock_kernel.h
+++ b/sys/compat/linuxkpi/common/include/linux/ptp_clock_kernel.h
@@ -49,6 +49,7 @@ struct ptp_clock_info {
int (*adjtime)(struct ptp_clock_info *, s64);
int (*getcrosststamp)(struct ptp_clock_info *, struct system_device_crosststamp *);
int (*gettime64)(struct ptp_clock_info *, struct timespec *);
+ int (*settime64)(struct ptp_clock_info *, const struct timespec *);
};
static inline struct ptp_clock *
diff --git a/sys/compat/linuxkpi/common/include/linux/radix-tree.h b/sys/compat/linuxkpi/common/include/linux/radix-tree.h
index 1019697303db..7182f4a9e407 100644
--- a/sys/compat/linuxkpi/common/include/linux/radix-tree.h
+++ b/sys/compat/linuxkpi/common/include/linux/radix-tree.h
@@ -38,12 +38,19 @@
#define RADIX_TREE_MAX_HEIGHT \
howmany(sizeof(long) * NBBY, RADIX_TREE_MAP_SHIFT)
+#define RADIX_TREE_MAX_TAGS 3
+#define RADIX_TREE_TAG_LONGS RADIX_TREE_MAP_SIZE
+
#define RADIX_TREE_ENTRY_MASK 3UL
#define RADIX_TREE_EXCEPTIONAL_ENTRY 2UL
#define RADIX_TREE_EXCEPTIONAL_SHIFT 2
+#define RADIX_TREE_ITER_TAG_MASK 0x0f
+#define RADIX_TREE_ITER_TAGGED 0x10
+
struct radix_tree_node {
void *slots[RADIX_TREE_MAP_SIZE];
+ unsigned long tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS];
int count;
};
@@ -51,6 +58,8 @@ struct radix_tree_root {
struct radix_tree_node *rnode;
gfp_t gfp_mask;
int height;
+ /* Linux stores root tags inside `gfp_mask`. */
+ unsigned long tags[RADIX_TREE_MAX_TAGS];
};
struct radix_tree_iter {
@@ -64,9 +73,22 @@ struct radix_tree_iter {
#define RADIX_TREE(name, mask) \
struct radix_tree_root name = RADIX_TREE_INIT(mask)
-#define radix_tree_for_each_slot(slot, root, iter, start) \
- for ((iter)->index = (start); \
- radix_tree_iter_find(root, iter, &(slot)); (iter)->index++)
+#define radix_tree_for_each_slot(slot, root, iter, start) \
+ for ((iter)->index = (start); \
+ radix_tree_iter_find(root, iter, &(slot), 0); \
+ (iter)->index++)
+
+#define radix_tree_for_each_slot_tagged(slot, root, iter, start, tag) \
+ for ((iter)->index = (start); \
+ radix_tree_iter_find(root, iter, &(slot), \
+ RADIX_TREE_ITER_TAGGED | tag); \
+ (iter)->index++)
+
+static inline void *
+radix_tree_deref_slot(void **slot)
+{
+ return (*slot);
+}
static inline int
radix_tree_exception(void *arg)
@@ -78,7 +100,12 @@ void *radix_tree_lookup(const struct radix_tree_root *, unsigned long);
void *radix_tree_delete(struct radix_tree_root *, unsigned long);
int radix_tree_insert(struct radix_tree_root *, unsigned long, void *);
int radix_tree_store(struct radix_tree_root *, unsigned long, void **);
-bool radix_tree_iter_find(const struct radix_tree_root *, struct radix_tree_iter *, void ***);
+bool radix_tree_iter_find(const struct radix_tree_root *, struct radix_tree_iter *, void ***, int);
void radix_tree_iter_delete(struct radix_tree_root *, struct radix_tree_iter *, void **);
+void *radix_tree_tag_set(struct radix_tree_root *root, unsigned long index, unsigned int tag);
+void *radix_tree_tag_clear(struct radix_tree_root *root, unsigned long index, unsigned int tag);
+int radix_tree_tagged(const struct radix_tree_root *root, unsigned int tag);
+unsigned int radix_tree_gang_lookup(const struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items);
+unsigned int radix_tree_gang_lookup_tag(const struct radix_tree_root *root, void **results, unsigned long first_index, unsigned int max_items, unsigned int tag);
#endif /* _LINUXKPI_LINUX_RADIX_TREE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/ratelimit.h b/sys/compat/linuxkpi/common/include/linux/ratelimit.h
index 9585b4b994d7..fdef57c7882d 100644
--- a/sys/compat/linuxkpi/common/include/linux/ratelimit.h
+++ b/sys/compat/linuxkpi/common/include/linux/ratelimit.h
@@ -14,4 +14,11 @@ struct ratelimit_state {
#define ratelimit_state_init(x, y, z)
#define ratelimit_set_flags(x, y)
+#define WARN_RATELIMIT(condition, ...) ({ \
+ bool __ret_warn_on = (condition); \
+ if (unlikely(__ret_warn_on)) \
+ pr_warn_ratelimited(__VA_ARGS__); \
+ unlikely(__ret_warn_on); \
+})
+
#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/rbtree.h b/sys/compat/linuxkpi/common/include/linux/rbtree.h
index e6033cfd760d..834e5645e991 100644
--- a/sys/compat/linuxkpi/common/include/linux/rbtree.h
+++ b/sys/compat/linuxkpi/common/include/linux/rbtree.h
@@ -199,6 +199,26 @@ rb_add_cached(struct rb_node *node, struct rb_root_cached *tree,
return (leftmost ? node : NULL);
}
+static inline void
+rb_add(struct rb_node *node, struct rb_root *tree,
+ bool (*less)(struct rb_node *, const struct rb_node *))
+{
+ struct rb_node **link = &tree->rb_node;
+ struct rb_node *parent = NULL;
+
+ while (*link != NULL) {
+ parent = *link;
+ if (less(node, parent)) {
+ link = &RB_LEFT(parent, __entry);
+ } else {
+ link = &RB_RIGHT(parent, __entry);
+ }
+ }
+
+ rb_link_node(node, parent, link);
+ rb_insert_color(node, tree);
+}
+
#undef RB_ROOT
#define RB_ROOT (struct rb_root) { NULL }
#define RB_ROOT_CACHED (struct rb_root_cached) { RB_ROOT, NULL }
diff --git a/sys/compat/linuxkpi/common/include/linux/regulator/consumer.h b/sys/compat/linuxkpi/common/include/linux/regulator/consumer.h
new file mode 100644
index 000000000000..d6c23575bc83
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/regulator/consumer.h
@@ -0,0 +1,17 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025-2026 The FreeBSD Foundation
+ * Copyright (c) 2025-2026 Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
+ *
+ * This software was developed by Jean-Sébastien Pédron under sponsorship
+ * from the FreeBSD Foundation.
+ */
+
+#ifndef _LINUXKPI_LINUX_REGULATOR_CONSUMER_H_
+#define _LINUXKPI_LINUX_REGULATOR_CONSUMER_H_
+
+#include <linux/err.h>
+#include <linux/suspend.h>
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/scatterlist.h b/sys/compat/linuxkpi/common/include/linux/scatterlist.h
index 537f5bebc5aa..c49c2179d359 100644
--- a/sys/compat/linuxkpi/common/include/linux/scatterlist.h
+++ b/sys/compat/linuxkpi/common/include/linux/scatterlist.h
@@ -654,9 +654,9 @@ sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents,
sf = sf_buf_alloc(page, SFB_CPUPRIVATE | SFB_NOWAIT);
if (sf == NULL)
break;
- vaddr = (char *)sf_buf_kva(sf);
+ vaddr = sf_buf_kva(sf);
} else
- vaddr = (char *)PHYS_TO_DMAP(page_to_phys(page));
+ vaddr = PHYS_TO_DMAP(page_to_phys(page));
memcpy(buf, vaddr + sg->offset + offset, len);
if (!PMAP_HAS_DMAP)
sf_buf_free(sf);
diff --git a/sys/compat/linuxkpi/common/include/linux/seq_buf.h b/sys/compat/linuxkpi/common/include/linux/seq_buf.h
new file mode 100644
index 000000000000..d6246a40e6f7
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/seq_buf.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2025-2026 The FreeBSD Foundation
+ * Copyright (c) 2025-2026 Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
+ *
+ * This software was developed by Jean-Sébastien Pédron under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef _LINUXKPI_LINUX_SEQ_BUF_H_
+#define _LINUXKPI_LINUX_SEQ_BUF_H_
+
+#include <linux/bug.h>
+#include <linux/minmax.h>
+#include <linux/seq_file.h>
+#include <linux/types.h>
+
+struct seq_buf {
+ char *buffer;
+ size_t size;
+ size_t len;
+};
+
+#define DECLARE_SEQ_BUF(NAME, SIZE) \
+ struct seq_buf NAME = { \
+ .buffer = (char[SIZE]) { 0 }, \
+ .size = SIZE, \
+ }
+
+static inline void
+seq_buf_clear(struct seq_buf *s)
+{
+ s->len = 0;
+ if (s->size > 0)
+ s->buffer[0] = '\0';
+}
+
+static inline void
+seq_buf_set_overflow(struct seq_buf *s)
+{
+ s->len = s->size + 1;
+}
+
+static inline bool
+seq_buf_has_overflowed(struct seq_buf *s)
+{
+ return (s->len > s->size);
+}
+
+static inline bool
+seq_buf_buffer_left(struct seq_buf *s)
+{
+ if (seq_buf_has_overflowed(s))
+ return (0);
+
+ return (s->size - s->len);
+}
+
+#define seq_buf_init(s, buf, size) linuxkpi_seq_buf_init((s), (buf), (size))
+void linuxkpi_seq_buf_init(struct seq_buf *s, char *buf, unsigned int size);
+
+#define seq_buf_printf(s, f, ...) linuxkpi_seq_buf_printf((s), (f), __VA_ARGS__)
+int linuxkpi_seq_buf_printf(struct seq_buf *s, const char *fmt, ...) \
+ __printflike(2, 3);
+
+#define seq_buf_vprintf(s, f, a) linuxkpi_seq_buf_vprintf((s), (f), (a))
+int linuxkpi_seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args);
+
+#define seq_buf_str(s) linuxkpi_seq_buf_str((s))
+const char * linuxkpi_seq_buf_str(struct seq_buf *s);
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/seq_file.h b/sys/compat/linuxkpi/common/include/linux/seq_file.h
index 47da16ab8688..be03c4768b07 100644
--- a/sys/compat/linuxkpi/common/include/linux/seq_file.h
+++ b/sys/compat/linuxkpi/common/include/linux/seq_file.h
@@ -39,6 +39,8 @@
#undef file
#define inode vnode
+#define SEQ_SKIP 1
+
MALLOC_DECLARE(M_LSEQ);
#define DEFINE_SHOW_ATTRIBUTE(__name) \
@@ -85,7 +87,7 @@ struct seq_operations {
int (*show) (struct seq_file *m, void *v);
};
-ssize_t seq_read(struct linux_file *, char *, size_t, off_t *);
+ssize_t seq_read(struct linux_file *, char __user *, size_t, off_t *);
int seq_write(struct seq_file *seq, const void *data, size_t len);
void seq_putc(struct seq_file *m, char c);
void seq_puts(struct seq_file *m, const char *str);
@@ -115,7 +117,7 @@ seq_hex_dump(struct seq_file *m, const char *prefix_str, int prefix_type,
int rowsize, int groupsize, const void *buf, size_t len, bool ascii)
{
lkpi_hex_dump(__lkpi_hexdump_sbuf_printf, m->buf, NULL, prefix_str, prefix_type,
- rowsize, groupsize, buf, len, ascii);
+ rowsize, groupsize, buf, len, ascii, true);
}
#define file linux_file
diff --git a/sys/compat/linuxkpi/common/include/linux/siphash.h b/sys/compat/linuxkpi/common/include/linux/siphash.h
new file mode 100644
index 000000000000..9153e77382e1
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/siphash.h
@@ -0,0 +1,168 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/* Copyright (C) 2016-2022 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ *
+ * SipHash: a fast short-input PRF
+ * https://131002.net/siphash/
+ *
+ * This implementation is specifically for SipHash2-4 for a secure PRF
+ * and HalfSipHash1-3/SipHash1-3 for an insecure PRF only suitable for
+ * hashtables.
+ */
+
+#ifndef _LINUX_SIPHASH_H
+#define _LINUX_SIPHASH_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#define SIPHASH_ALIGNMENT __alignof__(u64)
+typedef struct {
+ u64 key[2];
+} siphash_key_t;
+
+#define siphash_aligned_key_t siphash_key_t __aligned(16)
+
+static inline bool siphash_key_is_zero(const siphash_key_t *key)
+{
+ return !(key->key[0] | key->key[1]);
+}
+
+u64 __siphash_aligned(const void *data, size_t len, const siphash_key_t *key);
+u64 __siphash_unaligned(const void *data, size_t len, const siphash_key_t *key);
+
+u64 siphash_1u64(const u64 a, const siphash_key_t *key);
+u64 siphash_2u64(const u64 a, const u64 b, const siphash_key_t *key);
+u64 siphash_3u64(const u64 a, const u64 b, const u64 c,
+ const siphash_key_t *key);
+u64 siphash_4u64(const u64 a, const u64 b, const u64 c, const u64 d,
+ const siphash_key_t *key);
+u64 siphash_1u32(const u32 a, const siphash_key_t *key);
+u64 siphash_3u32(const u32 a, const u32 b, const u32 c,
+ const siphash_key_t *key);
+
+static inline u64 siphash_2u32(const u32 a, const u32 b,
+ const siphash_key_t *key)
+{
+ return siphash_1u64((u64)b << 32 | a, key);
+}
+static inline u64 siphash_4u32(const u32 a, const u32 b, const u32 c,
+ const u32 d, const siphash_key_t *key)
+{
+ return siphash_2u64((u64)b << 32 | a, (u64)d << 32 | c, key);
+}
+
+
+static inline u64 ___siphash_aligned(const __le64 *data, size_t len,
+ const siphash_key_t *key)
+{
+ if (__builtin_constant_p(len) && len == 4)
+ return siphash_1u32(le32_to_cpup((const __le32 *)data), key);
+ if (__builtin_constant_p(len) && len == 8)
+ return siphash_1u64(le64_to_cpu(data[0]), key);
+ if (__builtin_constant_p(len) && len == 16)
+ return siphash_2u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]),
+ key);
+ if (__builtin_constant_p(len) && len == 24)
+ return siphash_3u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]),
+ le64_to_cpu(data[2]), key);
+ if (__builtin_constant_p(len) && len == 32)
+ return siphash_4u64(le64_to_cpu(data[0]), le64_to_cpu(data[1]),
+ le64_to_cpu(data[2]), le64_to_cpu(data[3]),
+ key);
+ return __siphash_aligned(data, len, key);
+}
+
+/**
+ * siphash - compute 64-bit siphash PRF value
+ * @data: buffer to hash
+ * @size: size of @data
+ * @key: the siphash key
+ */
+static inline u64 siphash(const void *data, size_t len,
+ const siphash_key_t *key)
+{
+ if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ||
+ !IS_ALIGNED((unsigned long)data, SIPHASH_ALIGNMENT))
+ return __siphash_unaligned(data, len, key);
+ return ___siphash_aligned(data, len, key);
+}
+
+#define HSIPHASH_ALIGNMENT __alignof__(unsigned long)
+typedef struct {
+ unsigned long key[2];
+} hsiphash_key_t;
+
+u32 __hsiphash_aligned(const void *data, size_t len,
+ const hsiphash_key_t *key);
+u32 __hsiphash_unaligned(const void *data, size_t len,
+ const hsiphash_key_t *key);
+
+u32 hsiphash_1u32(const u32 a, const hsiphash_key_t *key);
+u32 hsiphash_2u32(const u32 a, const u32 b, const hsiphash_key_t *key);
+u32 hsiphash_3u32(const u32 a, const u32 b, const u32 c,
+ const hsiphash_key_t *key);
+u32 hsiphash_4u32(const u32 a, const u32 b, const u32 c, const u32 d,
+ const hsiphash_key_t *key);
+
+static inline u32 ___hsiphash_aligned(const __le32 *data, size_t len,
+ const hsiphash_key_t *key)
+{
+ if (__builtin_constant_p(len) && len == 4)
+ return hsiphash_1u32(le32_to_cpu(data[0]), key);
+ if (__builtin_constant_p(len) && len == 8)
+ return hsiphash_2u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]),
+ key);
+ if (__builtin_constant_p(len) && len == 12)
+ return hsiphash_3u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]),
+ le32_to_cpu(data[2]), key);
+ if (__builtin_constant_p(len) && len == 16)
+ return hsiphash_4u32(le32_to_cpu(data[0]), le32_to_cpu(data[1]),
+ le32_to_cpu(data[2]), le32_to_cpu(data[3]),
+ key);
+ return __hsiphash_aligned(data, len, key);
+}
+
+/**
+ * hsiphash - compute 32-bit hsiphash PRF value
+ * @data: buffer to hash
+ * @size: size of @data
+ * @key: the hsiphash key
+ */
+static inline u32 hsiphash(const void *data, size_t len,
+ const hsiphash_key_t *key)
+{
+ if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ||
+ !IS_ALIGNED((unsigned long)data, HSIPHASH_ALIGNMENT))
+ return __hsiphash_unaligned(data, len, key);
+ return ___hsiphash_aligned(data, len, key);
+}
+
+/*
+ * These macros expose the raw SipHash and HalfSipHash permutations.
+ * Do not use them directly! If you think you have a use for them,
+ * be sure to CC the maintainer of this file explaining why.
+ */
+
+#define SIPHASH_PERMUTATION(a, b, c, d) ( \
+ (a) += (b), (b) = rol64((b), 13), (b) ^= (a), (a) = rol64((a), 32), \
+ (c) += (d), (d) = rol64((d), 16), (d) ^= (c), \
+ (a) += (d), (d) = rol64((d), 21), (d) ^= (a), \
+ (c) += (b), (b) = rol64((b), 17), (b) ^= (c), (c) = rol64((c), 32))
+
+#define SIPHASH_CONST_0 0x736f6d6570736575ULL
+#define SIPHASH_CONST_1 0x646f72616e646f6dULL
+#define SIPHASH_CONST_2 0x6c7967656e657261ULL
+#define SIPHASH_CONST_3 0x7465646279746573ULL
+
+#define HSIPHASH_PERMUTATION(a, b, c, d) ( \
+ (a) += (b), (b) = rol32((b), 5), (b) ^= (a), (a) = rol32((a), 16), \
+ (c) += (d), (d) = rol32((d), 8), (d) ^= (c), \
+ (a) += (d), (d) = rol32((d), 7), (d) ^= (a), \
+ (c) += (b), (b) = rol32((b), 13), (b) ^= (c), (c) = rol32((c), 16))
+
+#define HSIPHASH_CONST_0 0U
+#define HSIPHASH_CONST_1 0U
+#define HSIPHASH_CONST_2 0x6c796765U
+#define HSIPHASH_CONST_3 0x74656462U
+
+#endif /* _LINUX_SIPHASH_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/sizes.h b/sys/compat/linuxkpi/common/include/linux/sizes.h
index d8a6e75192f6..430ad3ec427d 100644
--- a/sys/compat/linuxkpi/common/include/linux/sizes.h
+++ b/sys/compat/linuxkpi/common/include/linux/sizes.h
@@ -29,6 +29,17 @@
#ifndef _LINUXKPI_LINUX_SIZES_H_
#define _LINUXKPI_LINUX_SIZES_H_
+#define SZ_1 1
+#define SZ_2 2
+#define SZ_4 4
+#define SZ_8 8
+#define SZ_16 16
+#define SZ_32 32
+#define SZ_64 64
+#define SZ_128 128
+#define SZ_256 256
+#define SZ_512 512
+
#define SZ_1K (1024 * 1)
#define SZ_2K (1024 * 2)
#define SZ_4K (1024 * 4)
diff --git a/sys/compat/linuxkpi/common/include/linux/skbuff.h b/sys/compat/linuxkpi/common/include/linux/skbuff.h
index 2e560a120e41..c43d6daff5ee 100644
--- a/sys/compat/linuxkpi/common/include/linux/skbuff.h
+++ b/sys/compat/linuxkpi/common/include/linux/skbuff.h
@@ -770,7 +770,7 @@ ___skb_queue_splice(const struct sk_buff_head *from,
}
static inline void
-skb_queue_splice_init(struct sk_buff_head *from, struct sk_buff_head *to)
+skb_queue_splice(const struct sk_buff_head *from, struct sk_buff_head *to)
{
SKB_TRACE2(from, to);
@@ -780,6 +780,13 @@ skb_queue_splice_init(struct sk_buff_head *from, struct sk_buff_head *to)
___skb_queue_splice(from, (struct sk_buff *)to, to->next);
to->qlen += from->qlen;
+}
+
+static inline void
+skb_queue_splice_init(struct sk_buff_head *from, struct sk_buff_head *to)
+{
+
+ skb_queue_splice(from, to);
__skb_queue_head_init(from);
}
diff --git a/sys/compat/linuxkpi/common/include/linux/slab.h b/sys/compat/linuxkpi/common/include/linux/slab.h
index 0e649e1e3c4a..b529a6303085 100644
--- a/sys/compat/linuxkpi/common/include/linux/slab.h
+++ b/sys/compat/linuxkpi/common/include/linux/slab.h
@@ -4,7 +4,7 @@
* Copyright (c) 2010 Panasas, Inc.
* Copyright (c) 2013-2021 Mellanox Technologies, Ltd.
* All rights reserved.
- * Copyright (c) 2024-2025 The FreeBSD Foundation
+ * Copyright (c) 2024-2026 The FreeBSD Foundation
*
* Portions of this software were developed by Björn Zeeb
* under sponsorship from the FreeBSD Foundation.
@@ -51,6 +51,22 @@ MALLOC_DECLARE(M_KMALLOC);
#define kvcalloc(n, size, flags) kvmalloc_array(n, size, (flags) | __GFP_ZERO)
#define kzalloc(size, flags) kmalloc(size, (flags) | __GFP_ZERO)
#define kzalloc_node(size, flags, node) kmalloc_node(size, (flags) | __GFP_ZERO, node)
+#define kzalloc_obj(_p, ...) \
+ kzalloc(sizeof(typeof(_p)), default_gfp(__VA_ARGS__))
+#define kzalloc_objs(_p, _n, ...) \
+ kzalloc(size_mul((_n), sizeof(typeof(_p))), default_gfp(__VA_ARGS__))
+#define kzalloc_flex(_p, _field, _n, ...) \
+({ \
+ const size_t __n = (_n); \
+ const size_t __psize = struct_size_t(typeof(_p), _field, __n); \
+ typeof(_p) *__p_obj; \
+ \
+ __p_obj = kzalloc(__psize, default_gfp(__VA_ARGS__)); \
+ if (__p_obj != NULL) \
+ __set_flex_counter(__p_obj->_field, __n); \
+ \
+ __p_obj; \
+})
#define kfree_const(ptr) kfree(ptr)
#define kfree_async(ptr) kfree(ptr) /* drm-kmod 5.4 compat */
#define vzalloc(size) __vmalloc(size, GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO, 0)
@@ -104,7 +120,7 @@ void *lkpi_kmalloc(size_t, gfp_t);
void *lkpi_kvmalloc(size_t, gfp_t);
void *lkpi___kmalloc(size_t, gfp_t);
void *lkpi___kmalloc_node(size_t, gfp_t, int);
-void *lkpi_krealloc(void *, size_t, gfp_t);
+void *lkpi_krealloc(const void *, size_t, gfp_t);
void lkpi_kfree(const void *);
static inline gfp_t
@@ -125,6 +141,13 @@ linux_check_m_flags(gfp_t flags)
/*
* Base functions with a native implementation.
*/
+
+static inline size_t
+ksize(const void *ptr)
+{
+ return (malloc_usable_size(ptr));
+}
+
static inline void *
kmalloc(size_t size, gfp_t flags)
{
@@ -143,8 +166,14 @@ kmalloc_node(size_t size, gfp_t flags, int node)
return (lkpi___kmalloc_node(size, flags, node));
}
+#define kmalloc_obj(_p, ...) \
+ kmalloc(sizeof(typeof(_p)), default_gfp(__VA_ARGS__))
+
+#define kmalloc_objs(_p, _n, ...) \
+ kmalloc(size_mul((_n) * sizeof(typeof(_p))), default_gfp(__VA_ARGS__))
+
static inline void *
-krealloc(void *ptr, size_t size, gfp_t flags)
+krealloc(const void *ptr, size_t size, gfp_t flags)
{
return (lkpi_krealloc(ptr, size, flags));
}
@@ -242,22 +271,28 @@ kvmalloc_array(size_t n, size_t size, gfp_t flags)
return (kvmalloc(size * n, flags));
}
+void * lkpi_kvrealloc(const void *ptr, size_t oldsize, size_t newsize, gfp_t flags);
+
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION < 61200
static inline void *
kvrealloc(const void *ptr, size_t oldsize, size_t newsize, gfp_t flags)
{
- void *newptr;
-
- if (newsize <= oldsize)
- return (__DECONST(void *, ptr));
+ return (lkpi_kvrealloc(ptr, oldsize, newsize, flags));
+}
+#else
+static inline void *
+kvrealloc(const void *ptr, size_t newsize, gfp_t flags)
+{
+ size_t oldsize;
- newptr = kvmalloc(newsize, flags);
- if (newptr != NULL) {
- memcpy(newptr, ptr, oldsize);
- kvfree(ptr);
- }
+ if (!ZERO_OR_NULL_PTR(ptr))
+ oldsize = ksize(ptr);
+ else
+ oldsize = 0;
- return (newptr);
+ return (lkpi_kvrealloc(ptr, oldsize, newsize, flags));
}
+#endif
/*
* Misc.
@@ -273,12 +308,6 @@ kfree_sensitive(const void *ptr)
}
static inline size_t
-ksize(const void *ptr)
-{
- return (malloc_usable_size(ptr));
-}
-
-static inline size_t
kmalloc_size_roundup(size_t size)
{
if (unlikely(size == 0 || size == SIZE_MAX))
diff --git a/sys/compat/linuxkpi/common/include/linux/soc/airoha/airoha_offload.h b/sys/compat/linuxkpi/common/include/linux/soc/airoha/airoha_offload.h
new file mode 100644
index 000000000000..ade0b06d839f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/soc/airoha/airoha_offload.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2026 Bjoern A. Zeeb
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef _LINUXKPI_LINUX_SOC_AIROHA_AIROHA_OFFLOAD_H
+#define _LINUXKPI_LINUX_SOC_AIROHA_AIROHA_OFFLOAD_H
+
+#include <linux/kernel.h> /* pr_debug */
+
+enum airoha_npu_wlan_get_cmd {
+ __dummy_airoha_npu_wlan_get_cmd,
+};
+enum airoha_npu_wlan_set_cmd {
+ __dummy_airoha_npu_wlan_set_cmd,
+};
+
+struct airoha_npu {
+};
+struct airoha_npu_rx_dma_desc {
+};
+struct airoha_npu_tx_dma_desc {
+};
+
+static __inline int
+airoha_npu_wlan_send_msg(void *npu, int ifindex,
+ enum airoha_npu_wlan_set_cmd cmd, void *val, size_t len, gfp_t gfp)
+{
+ pr_debug("%s: TODO\n", __func__);
+ return (-EOPNOTSUPP);
+}
+
+static __inline int
+airoha_npu_wlan_get_msg(void *npu, int ifindex,
+ enum airoha_npu_wlan_get_cmd cmd, void *val, size_t len, gfp_t gfp)
+{
+ pr_debug("%s: TODO\n", __func__);
+ return (-EOPNOTSUPP);
+}
+
+static __inline void
+airoha_npu_wlan_enable_irq(struct airoha_npu *npu, int q)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+#endif /* _LINUXKPI_LINUX_SOC_AIROHA_AIROHA_OFFLOAD_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h b/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h
index 2b9c6ae4911e..64daa8c78c9d 100644
--- a/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h
+++ b/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2022-2025 Bjoern A. Zeeb
+ * Copyright (c) 2022-2026 Bjoern A. Zeeb
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@@ -37,7 +37,13 @@ mtk_wed_device_active(struct mtk_wed_device *dev __unused)
static inline bool
mtk_wed_get_rx_capa(struct mtk_wed_device *dev __unused)
{
+ pr_debug("%s: TODO\n", __func__);
+ return (false);
+}
+static inline bool
+mtk_wed_is_amsdu_supported(struct mtk_wed_device *dev __unused)
+{
pr_debug("%s: TODO\n", __func__);
return (false);
}
@@ -66,6 +72,12 @@ mtk_wed_get_rx_capa(struct mtk_wed_device *dev __unused)
{
return (false);
}
+
+static inline bool
+mtk_wed_is_amsdu_supported(struct mtk_wed_device *dev __unused)
+{
+ return (false);
+}
#endif /* CONFIG_NET_MEDIATEK_SOC_WED */
#endif /* _LINUXKPI_LINUX_SOC_MEDIATEK_MTK_WED_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/sort.h b/sys/compat/linuxkpi/common/include/linux/sort.h
index e6196d1f41c7..972c8514e6fb 100644
--- a/sys/compat/linuxkpi/common/include/linux/sort.h
+++ b/sys/compat/linuxkpi/common/include/linux/sort.h
@@ -34,8 +34,13 @@
#include <sys/libkern.h>
#define sort(base, num, size, cmp, swap) do { \
- BUILD_BUG_ON_ZERO(swap); \
+ BUILD_BUG_ON(swap); \
qsort(base, num, size, cmp); \
} while (0)
+#define sort_r(base, num, size, cmp, swap, priv) do { \
+ BUILD_BUG_ON(swap); \
+ qsort_r(base, num, size, cmp, priv); \
+} while (0)
+
#endif /* _LINUXKPI_LINUX_SORT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/spinlock.h b/sys/compat/linuxkpi/common/include/linux/spinlock.h
index dc10b0457153..a786cbab5e13 100644
--- a/sys/compat/linuxkpi/common/include/linux/spinlock.h
+++ b/sys/compat/linuxkpi/common/include/linux/spinlock.h
@@ -36,10 +36,12 @@
#include <sys/mutex.h>
#include <sys/kdb.h>
+#include <linux/cleanup.h>
#include <linux/compiler.h>
#include <linux/rwlock.h>
#include <linux/bottom_half.h>
#include <linux/lockdep.h>
+#include <linux/preempt.h>
typedef struct mtx spinlock_t;
@@ -178,4 +180,33 @@ _atomic_dec_and_lock_irqsave(atomic_t *cnt, spinlock_t *lock,
return (0);
}
+/*
+ * struct raw_spinlock
+ */
+
+typedef struct raw_spinlock {
+ struct mtx lock;
+} raw_spinlock_t;
+
+#define raw_spin_lock_init(rlock) \
+ mtx_init(&(rlock)->lock, spin_lock_name("lnxspin_raw"), \
+ NULL, MTX_DEF | MTX_NOWITNESS | MTX_NEW)
+
+#define raw_spin_lock(rl) spin_lock(&(rl)->lock)
+#define raw_spin_trylock(rl) spin_trylock(&(rl)->lock)
+#define raw_spin_unlock(rl) spin_unlock(&(rl)->lock)
+
+#define raw_spin_lock_irqsave(rl, f) spin_lock_irqsave(&(rl)->lock, (f))
+#define raw_spin_trylock_irqsave(rl, f) spin_trylock_irqsave(&(rl)->lock, (f))
+#define raw_spin_unlock_irqrestore(rl, f) spin_unlock_irqrestore(&(rl)->lock, (f))
+
+/*
+ * cleanup.h related pre-defined cases.
+ */
+DEFINE_LOCK_GUARD_1(spinlock_irqsave,
+ spinlock_t,
+ spin_lock_irqsave(_T->lock, _T->flags),
+ spin_unlock_irqrestore(_T->lock, _T->flags),
+ unsigned long flags)
+
#endif /* _LINUXKPI_LINUX_SPINLOCK_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/ssb/ssb_regs.h b/sys/compat/linuxkpi/common/include/linux/ssb/ssb_regs.h
new file mode 100644
index 000000000000..e1c18b6b632a
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/ssb/ssb_regs.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2025 Bjoern A. Zeeb
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef _LINUXKPI_LINUX_SSB_SSB_REGS_H
+#define _LINUXKPI_LINUX_SSB_SSB_REGS_H
+
+#define SSB_IDHIGH_RCHI 0x00007000
+#define SSB_IDHIGH_RCHI_SHIFT 8
+#define SSB_IDHIGH_RCLO 0x0000000F
+#define SSB_IDLOW_INITIATOR 0x00000080
+#define SSB_IMSTATE_BUSY 0x01800000
+#define SSB_IMSTATE_IBE 0x00020000
+#define SSB_IMSTATE_REJECT 0x02000000
+#define SSB_IMSTATE_TO 0x00040000
+#define SSB_TMSHIGH_BUSY 0x00000004
+#define SSB_TMSHIGH_SERR 0x00000001
+#define SSB_TMSLOW_CLOCK 0x00010000
+#define SSB_TMSLOW_FGC 0x00020000
+#define SSB_TMSLOW_REJECT 0x00000002
+#define SSB_TMSLOW_RESET 0x00000001
+
+#endif /* _LINUXKPI_LINUX_SSB_SSB_REGS_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/string.h b/sys/compat/linuxkpi/common/include/linux/string.h
index f7b64560d254..b195dcc8fe9b 100644
--- a/sys/compat/linuxkpi/common/include/linux/string.h
+++ b/sys/compat/linuxkpi/common/include/linux/string.h
@@ -31,6 +31,7 @@
#include <sys/ctype.h>
+#include <linux/array_size.h>
#include <linux/types.h>
#include <linux/gfp.h>
#include <linux/slab.h>
@@ -88,6 +89,17 @@ memdup_user_nul(const void *ptr, size_t len)
}
static inline void *
+memdup_array_user(const void *src, size_t n, size_t size)
+{
+ size_t len;
+
+ if (check_mul_overflow(n, size, &len))
+ return (ERR_PTR(-EOVERFLOW));
+
+ return (memdup_user(src, len));
+}
+
+static inline void *
kmemdup(const void *src, size_t len, gfp_t gfp)
{
void *dst;
@@ -98,6 +110,12 @@ kmemdup(const void *src, size_t len, gfp_t gfp)
return (dst);
}
+static inline void *
+kmemdup_array(const void *src, size_t count, size_t element_size, gfp_t gfp)
+{
+ return (kmemdup(src, size_mul(count, element_size), gfp));
+}
+
/* See slab.h for kvmalloc/kvfree(). */
static inline void *
kvmemdup(const void *src, size_t len, gfp_t gfp)
@@ -198,6 +216,12 @@ memchr_inv(const void *start, int c, size_t length)
return (NULL);
}
+static inline bool
+mem_is_zero(const void *start, size_t length)
+{
+ return (memchr_inv(start, 0, length) == NULL);
+}
+
static inline size_t
str_has_prefix(const char *str, const char *prefix)
{
@@ -303,6 +327,22 @@ memcpy_and_pad(void *dst, size_t dstlen, const void *src, size_t len, int ch)
}
}
+#define strtomem(dst, src) do { \
+ size_t dstlen = ARRAY_SIZE(dst); \
+ size_t srclen = __builtin_object_size(src, 1); \
+ srclen = MIN(srclen, dstlen); \
+ srclen = strnlen(src, srclen); \
+ memcpy(dst, src, srclen); \
+} while (0)
+
+#define strtomem_pad(dst, src, pad) do { \
+ size_t dstlen = ARRAY_SIZE(dst); \
+ size_t srclen = __builtin_object_size(src, 1); \
+ srclen = MIN(srclen, dstlen); \
+ srclen = strnlen(src, srclen); \
+ memcpy_and_pad(dst, dstlen, src, srclen, pad); \
+} while (0)
+
#define memset_startat(ptr, bytepat, smember) \
({ \
uint8_t *_ptr = (uint8_t *)(ptr); \
diff --git a/sys/compat/linuxkpi/common/include/linux/string_choices.h b/sys/compat/linuxkpi/common/include/linux/string_choices.h
index 74aa3fd019b2..db540d3e7d40 100644
--- a/sys/compat/linuxkpi/common/include/linux/string_choices.h
+++ b/sys/compat/linuxkpi/common/include/linux/string_choices.h
@@ -33,39 +33,33 @@
static inline const char *
str_yes_no(bool value)
{
- if (value)
- return "yes";
- else
- return "no";
+ return (value ? "yes" : "no");
}
static inline const char *
str_on_off(bool value)
{
- if (value)
- return "on";
- else
- return "off";
+ return (value ? "on" : "off");
}
static inline const char *
str_enabled_disabled(bool value)
{
- if (value)
- return "enabled";
- else
- return "disabled";
+ return (value ? "enabled" : "disabled");
}
static inline const char *
str_enable_disable(bool value)
{
- if (value)
- return "enable";
- else
- return "disable";
+ return (value ? "enable" : "disable");
}
#define str_disable_enable(_v) str_enable_disable(!(_v))
+static inline const char *
+str_read_write(bool value)
+{
+ return (value ? "read" : "write");
+}
+
#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/suspend.h b/sys/compat/linuxkpi/common/include/linux/suspend.h
index dacecbebdc08..3a8bec392437 100644
--- a/sys/compat/linuxkpi/common/include/linux/suspend.h
+++ b/sys/compat/linuxkpi/common/include/linux/suspend.h
@@ -3,6 +3,12 @@
#ifndef _LINUXKPI_LINUX_SUSPEND_H_
#define _LINUXKPI_LINUX_SUSPEND_H_
+#include <linux/swap.h>
+#include <linux/notifier.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/mm.h>
+
typedef int suspend_state_t;
extern suspend_state_t pm_suspend_target_state;
@@ -14,10 +20,29 @@ extern suspend_state_t pm_suspend_target_state;
#define PM_SUSPEND_MIN PM_SUSPEND_TO_IDLE
#define PM_SUSPEND_MAX 4
+#define PM_HIBERNATION_PREPARE 0x0001
+#define PM_POST_HIBERNATION 0x0002
+#define PM_SUSPEND_PREPARE 0x0003
+#define PM_POST_SUSPEND 0x0004
+#define PM_RESTORE_PREPARE 0x0005
+#define PM_POST_RESTORE 0x0006
+
static inline int
pm_suspend_via_firmware(void)
{
- return 0;
+ return (0);
+}
+
+static inline int
+register_pm_notifier(struct notifier_block *nb)
+{
+ return (0);
+}
+
+static inline int
+unregister_pm_notifier(struct notifier_block *nb)
+{
+ return (0);
}
#endif /* _LINUXKPI_LINUX_SUSPEND_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/swap.h b/sys/compat/linuxkpi/common/include/linux/swap.h
index 5828db7ae392..9c1db9677f9e 100644
--- a/sys/compat/linuxkpi/common/include/linux/swap.h
+++ b/sys/compat/linuxkpi/common/include/linux/swap.h
@@ -37,7 +37,14 @@
#include <vm/swap_pager.h>
#include <vm/vm_pageout.h>
+#include <linux/spinlock.h>
+#include <linux/mmzone.h>
+#include <linux/list.h>
+#include <linux/memcontrol.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
#include <linux/pagemap.h>
+#include <linux/atomic.h>
#include <linux/page-flags.h>
static inline long
diff --git a/sys/compat/linuxkpi/common/include/linux/sysfs.h b/sys/compat/linuxkpi/common/include/linux/sysfs.h
index 470c224a9778..7c8c4e2e32b9 100644
--- a/sys/compat/linuxkpi/common/include/linux/sysfs.h
+++ b/sys/compat/linuxkpi/common/include/linux/sysfs.h
@@ -43,13 +43,6 @@ struct sysfs_ops {
size_t);
};
-struct attribute_group {
- const char *name;
- mode_t (*is_visible)(struct kobject *,
- struct attribute *, int);
- struct attribute **attrs;
-};
-
struct bin_attribute {
struct attribute attr;
size_t size;
@@ -59,6 +52,14 @@ struct bin_attribute {
struct bin_attribute *, char *, loff_t, size_t);
};
+struct attribute_group {
+ const char *name;
+ mode_t (*is_visible)(struct kobject *,
+ struct attribute *, int);
+ struct attribute **attrs;
+ struct bin_attribute **bin_attrs;
+};
+
#define __ATTR(_name, _mode, _show, _store) { \
.attr = { .name = __stringify(_name), .mode = _mode }, \
.show = _show, .store = _store, \
@@ -370,6 +371,7 @@ static inline int
sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp)
{
struct attribute **attr;
+ struct bin_attribute **bin_attr;
struct sysctl_oid *oidp;
/* Don't create the group node if grp->name is undefined. */
@@ -378,11 +380,19 @@ sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp)
OID_AUTO, grp->name, CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, grp->name);
else
oidp = kobj->oidp;
- for (attr = grp->attrs; *attr != NULL; attr++) {
+ for (attr = grp->attrs; attr != NULL && *attr != NULL; attr++) {
SYSCTL_ADD_OID(NULL, SYSCTL_CHILDREN(oidp), OID_AUTO,
(*attr)->name, CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_MPSAFE,
kobj, (uintptr_t)*attr, sysctl_handle_attr, "A", "");
}
+ for (bin_attr = grp->bin_attrs;
+ bin_attr != NULL && *bin_attr != NULL;
+ bin_attr++) {
+ SYSCTL_ADD_OID(NULL, SYSCTL_CHILDREN(oidp), OID_AUTO,
+ (*bin_attr)->attr.name,
+ CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_MPSAFE,
+ kobj, (uintptr_t)*bin_attr, sysctl_handle_bin_attr, "", "");
+ }
return (0);
}
@@ -434,14 +444,20 @@ static inline void
sysfs_unmerge_group(struct kobject *kobj, const struct attribute_group *grp)
{
struct attribute **attr;
+ struct bin_attribute **bin_attr;
struct sysctl_oid *oidp;
SYSCTL_FOREACH(oidp, SYSCTL_CHILDREN(kobj->oidp)) {
if (strcmp(oidp->oid_name, grp->name) != 0)
continue;
- for (attr = grp->attrs; *attr != NULL; attr++) {
+ for (attr = grp->attrs; attr != NULL && *attr != NULL; attr++) {
sysctl_remove_name(oidp, (*attr)->name, 1, 1);
}
+ for (bin_attr = grp->bin_attrs;
+ bin_attr != NULL && *bin_attr != NULL;
+ bin_attr++) {
+ sysctl_remove_name(oidp, (*bin_attr)->attr.name, 1, 1);
+ }
}
}
diff --git a/sys/compat/linuxkpi/common/include/linux/unaligned.h b/sys/compat/linuxkpi/common/include/linux/unaligned.h
new file mode 100644
index 000000000000..5a59a4b36b4f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/unaligned.h
@@ -0,0 +1,12 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 The FreeBSD Foundation
+ */
+
+#ifndef _LINUXKPI_LINUX_UNALIGNED_H
+#define _LINUXKPI_LINUX_UNALIGNED_H
+
+#include <asm/unaligned.h>
+
+#endif /* _LINUXKPI_LINUX_UNALIGNED_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/uuid.h b/sys/compat/linuxkpi/common/include/linux/uuid.h
index 4f6f4a8b34f0..0765ef4dcc1e 100644
--- a/sys/compat/linuxkpi/common/include/linux/uuid.h
+++ b/sys/compat/linuxkpi/common/include/linux/uuid.h
@@ -33,6 +33,7 @@
#include <linux/random.h>
+#define UUID_SIZE 16
#define UUID_STRING_LEN 36
#define GUID_INIT(x0_3, x4_5, x6_7, x8, x9, x10, x11, x12, x13, x14, x15) \
@@ -59,6 +60,8 @@ typedef struct {
char x[16];
} guid_t;
+extern const guid_t guid_null;
+
static inline void
guid_gen(guid_t *g)
{
@@ -68,10 +71,34 @@ guid_gen(guid_t *g)
g->x[8] = (g->x[8] & 0x3f) | 0x80;
}
+static inline bool
+guid_equal(const guid_t *u1, const guid_t *u2)
+{
+ return (memcmp(u1, u2, sizeof(guid_t)) == 0);
+}
+
static inline void
guid_copy(guid_t *dst, const guid_t *src)
{
memcpy(dst, src, sizeof(*dst));
}
+static inline void
+import_guid(guid_t *dst, const uint8_t *src)
+{
+ memcpy(dst, src, sizeof(guid_t));
+}
+
+static inline void
+export_guid(uint8_t *dst, const guid_t *src)
+{
+ memcpy(dst, src, sizeof(guid_t));
+}
+
+static inline bool
+guid_is_null(const guid_t *guid)
+{
+ return (guid_equal(guid, &guid_null));
+}
+
#endif /* _LINUXKPI_LINUX_UUID_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/wait.h b/sys/compat/linuxkpi/common/include/linux/wait.h
index 03ddce2c06f5..698a1056b713 100644
--- a/sys/compat/linuxkpi/common/include/linux/wait.h
+++ b/sys/compat/linuxkpi/common/include/linux/wait.h
@@ -43,13 +43,6 @@
#define SKIP_SLEEP() (SCHEDULER_STOPPED() || kdb_active)
-#define might_sleep() \
- WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "might_sleep()")
-
-#define might_sleep_if(cond) do { \
- if (cond) { might_sleep(); } \
-} while (0)
-
struct wait_queue;
struct wait_queue_head;
diff --git a/sys/compat/linuxkpi/common/include/linux/wordpart.h b/sys/compat/linuxkpi/common/include/linux/wordpart.h
new file mode 100644
index 000000000000..ce697bbef3b3
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/wordpart.h
@@ -0,0 +1,13 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Jean-Sébastien Pédron
+ */
+
+#ifndef _LINUXKPI_LINUX_WORDPART_H_
+#define _LINUXKPI_LINUX_WORDPART_H_
+
+#define lower_32_bits(n) ((u32)(n))
+#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16))
+
+#endif /* _LINUXKPI_LINUX_WORDPART_H_ */
diff --git a/sys/compat/linuxkpi/common/include/media/cec-notifier.h b/sys/compat/linuxkpi/common/include/media/cec-notifier.h
new file mode 100644
index 000000000000..8d6fc452b907
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/media/cec-notifier.h
@@ -0,0 +1,17 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025-2026 The FreeBSD Foundation
+ * Copyright (c) 2025-2026 Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
+ *
+ * This software was developed by Jean-Sébastien Pédron under sponsorship
+ * from the FreeBSD Foundation.
+ */
+
+#ifndef _LINUXKPI_MEDIA_CEC_NOTIFIER_H_
+#define _LINUXKPI_MEDIA_CEC_NOTIFIER_H_
+
+#include <linux/err.h>
+#include <media/cec.h>
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/media/cec.h b/sys/compat/linuxkpi/common/include/media/cec.h
new file mode 100644
index 000000000000..c96b57868e23
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/media/cec.h
@@ -0,0 +1,23 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025-2026 The FreeBSD Foundation
+ * Copyright (c) 2025-2026 Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
+ *
+ * This software was developed by Jean-Sébastien Pédron under sponsorship
+ * from the FreeBSD Foundation.
+ */
+
+#ifndef _LINUXKPI_MEDIA_CEC_H_
+#define _LINUXKPI_MEDIA_CEC_H_
+
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/kthread.h>
+#include <linux/timer.h>
+#include <linux/cec-funcs.h>
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/net/cfg80211.h b/sys/compat/linuxkpi/common/include/net/cfg80211.h
index d7ed2bc97c98..dedf687d6530 100644
--- a/sys/compat/linuxkpi/common/include/net/cfg80211.h
+++ b/sys/compat/linuxkpi/common/include/net/cfg80211.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2020-2025 The FreeBSD Foundation
+ * Copyright (c) 2020-2026 The FreeBSD Foundation
* Copyright (c) 2021-2022 Bjoern A. Zeeb
*
* This software was developed by Björn Zeeb under sponsorship from
@@ -124,6 +124,7 @@ enum ieee80211_channel_flags {
IEEE80211_CHAN_PSD = BIT(12),
IEEE80211_CHAN_ALLOW_6GHZ_VLP_AP = BIT(13),
IEEE80211_CHAN_CAN_MONITOR = BIT(14),
+ IEEE80211_CHAN_NO_EHT = BIT(15),
};
#define IEEE80211_CHAN_NO_HT40 (IEEE80211_CHAN_NO_HT40MINUS|IEEE80211_CHAN_NO_HT40PLUS)
@@ -152,6 +153,8 @@ struct linuxkpi_ieee80211_channel {
int orig_mpwr;
};
+#define NL80211_EHT_NSS_MAX 16
+
struct cfg80211_bitrate_mask {
/* TODO FIXME */
struct {
@@ -159,9 +162,12 @@ struct cfg80211_bitrate_mask {
uint8_t ht_mcs[IEEE80211_HT_MCS_MASK_LEN];
uint16_t vht_mcs[8];
uint16_t he_mcs[8];
+ uint16_t eht_mcs[NL80211_EHT_NSS_MAX];
enum nl80211_txrate_gi gi;
enum nl80211_he_gi he_gi;
- uint8_t he_ltf; /* XXX enum? */
+ enum nl80211_he_ltf he_ltf;
+ enum nl80211_eht_gi eht_gi;
+ uint8_t eht_ltf; /* XXX enum? */
} control[NUM_NL80211_BANDS];
};
@@ -324,6 +330,53 @@ struct cfg80211_chan_def {
uint16_t punctured;
};
+struct cfg80211_nan_band_config {
+ /* XXX TODO */
+ struct linuxkpi_ieee80211_channel *chan;
+ uint8_t rssi_middle;
+ uint8_t rssi_close;
+ uint8_t awake_dw_interval;
+};
+
+struct cfg80211_nan_conf {
+ uint8_t bands;
+ uint8_t discovery_beacon_interval;
+ uint8_t master_pref;
+ bool enable_dw_notification;
+
+ uint16_t scan_dwell_time;
+ uint16_t scan_period;
+ uint16_t extra_nan_attrs_len;
+ uint16_t vendor_elems_len;
+
+ uint8_t *cluster_id;
+ struct cfg80211_nan_band_config band_cfgs[NUM_NL80211_BANDS];
+ uint8_t *extra_nan_attrs;
+ uint8_t *vendor_elems;
+};
+
+enum wiphy_nan_flags {
+ WIPHY_NAN_FLAGS_CONFIGURABLE_SYNC = BIT(0),
+ WIPHY_NAN_FLAGS_USERSPACE_DE = BIT(1),
+};
+
+/* Wi-Fi Aware (TM) specification, 9.5.15 Device Capability attribute. */
+/* Misplaced here for the moment. */
+#define NAN_OP_MODE_PHY_MODE_MASK 0x11 /* b0 0=HT, 1=VHT, b4=1 HE supported */
+#define NAN_OP_MODE_80P80MHZ 0x2 /* b1 */
+#define NAN_OP_MODE_160MHZ 0x4 /* b2 */
+
+#define NAN_DEV_CAPA_EXT_KEY_ID_SUPPORTED 0x2 /* b1 */
+#define NAN_DEV_CAPA_NDPE_SUPPORTED 0x8 /* b3 */
+
+struct wiphy_nan_capa {
+ uint32_t flags; /* enum wiphy_nan_flags */
+ uint8_t op_mode;
+ uint8_t dev_capabilities;
+ uint8_t n_antennas; /* Tx/Rx bitmask, e.g., 0x22 */
+ uint16_t max_channel_switch_time;
+};
+
struct cfg80211_ftm_responder_stats {
/* XXX TODO */
int asap_num, failed_num, filled, non_asap_num, out_of_window_triggers_num, partial_num, reschedule_requests_num, success_num, total_duration_ms, unknown_triggers_num;
@@ -1017,6 +1070,14 @@ struct survey_info { /* net80211::struct ieee80211_channel_survey */
struct linuxkpi_ieee80211_channel *channel;
};
+enum wiphy_bss_param_flags {
+ WIPHY_BSS_PARAM_AP_ISOLATE = BIT(0),
+};
+
+struct bss_parameters {
+ int ap_isolate;
+};
+
enum wiphy_vendor_cmd_need_flags {
WIPHY_VENDOR_CMD_NEED_NETDEV = 0x01,
WIPHY_VENDOR_CMD_NEED_RUNNING = 0x02,
@@ -1138,6 +1199,11 @@ struct wiphy {
int n_radio;
const struct wiphy_radio *radio;
+ uint32_t bss_param_support; /* enum wiphy_bss_param_flags */
+
+ uint8_t nan_supported_bands;
+ struct wiphy_nan_capa nan_capa;
+
int features, hw_version;
int interface_modes, max_match_sets, max_remain_on_channel_duration, max_scan_ssids, max_sched_scan_ie_len, max_sched_scan_plan_interval, max_sched_scan_plan_iterations, max_sched_scan_plans, max_sched_scan_reqs, max_sched_scan_ssids;
int num_iftype_ext_capab;
@@ -1220,7 +1286,7 @@ struct cfg80211_ops {
int (*dump_survey)(struct wiphy *, struct net_device *, int, struct survey_info *);
int (*external_auth)(struct wiphy *, struct net_device *, struct cfg80211_external_auth_params *);
int (*set_cqm_rssi_range_config)(struct wiphy *, struct net_device *, int, int);
-
+ int (*change_bss)(struct wiphy *, struct net_device *, struct bss_parameters *);
};
@@ -1230,6 +1296,7 @@ struct cfg80211_ops {
struct wiphy *linuxkpi_wiphy_new(const struct cfg80211_ops *, size_t);
void linuxkpi_wiphy_free(struct wiphy *wiphy);
+int linuxkpi_80211_wiphy_register(struct wiphy *);
void linuxkpi_wiphy_work_queue(struct wiphy *, struct wiphy_work *);
void linuxkpi_wiphy_work_cancel(struct wiphy *, struct wiphy_work *);
@@ -1294,8 +1361,11 @@ wiphy_dev(struct wiphy *wiphy)
return (wiphy->dev);
}
-#define wiphy_dereference(_w, p) \
- rcu_dereference_check(p, lockdep_is_held(&(_w)->mtx))
+#define wiphy_dereference(_w, _p) \
+ rcu_dereference_protected(_p, lockdep_is_held(&(_w)->mtx))
+
+#define rcu_dereference_wiphy(_w, _p) \
+ rcu_dereference_check(_p, lockdep_is_held(&(_w)->mtx))
#define wiphy_lock(_w) mutex_lock(&(_w)->mtx)
#define wiphy_unlock(_w) mutex_unlock(&(_w)->mtx)
@@ -1749,8 +1819,7 @@ wiphy_net(struct wiphy *wiphy)
static __inline int
wiphy_register(struct wiphy *wiphy)
{
- TODO();
- return (0);
+ return (linuxkpi_80211_wiphy_register(wiphy));
}
static __inline void
@@ -2194,6 +2263,22 @@ cfg80211_cqm_rssi_notify(struct net_device *dev,
/* -------------------------------------------------------------------------- */
static inline void
+cfg80211_nan_cluster_joined(struct wireless_dev *wdev, const uint8_t *cluster_id,
+ bool new_cluster, gfp_t gfp)
+{
+ TODO("NAN");
+}
+
+static inline void
+cfg80211_next_nan_dw_notif(struct wireless_dev *wdev,
+ struct linuxkpi_ieee80211_channel *chan, gfp_t gfp)
+{
+ TODO("NAN");
+}
+
+/* -------------------------------------------------------------------------- */
+
+static inline void
wiphy_work_init(struct wiphy_work *wwk, wiphy_work_fn fn)
{
INIT_LIST_HEAD(&wwk->entry);
diff --git a/sys/compat/linuxkpi/common/include/net/mac80211.h b/sys/compat/linuxkpi/common/include/net/mac80211.h
index 6e2f3f2d8781..3c783d1f3c8a 100644
--- a/sys/compat/linuxkpi/common/include/net/mac80211.h
+++ b/sys/compat/linuxkpi/common/include/net/mac80211.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2020-2025 The FreeBSD Foundation
+ * Copyright (c) 2020-2026 The FreeBSD Foundation
* Copyright (c) 2020-2025 Bjoern A. Zeeb
*
* This software was developed by Björn Zeeb under sponsorship from
@@ -431,7 +431,6 @@ enum ieee80211_hw_flags {
IEEE80211_HW_BUFF_MMPDU_TXQ,
IEEE80211_HW_CHANCTX_STA_CSA,
IEEE80211_HW_CONNECTION_MONITOR,
- IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP,
IEEE80211_HW_HAS_RATE_CONTROL,
IEEE80211_HW_MFP_CAPABLE,
IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR,
@@ -604,7 +603,7 @@ enum ieee80211_rx_status_flags {
RX_FLAG_AMPDU_IS_LAST = BIT(21),
RX_FLAG_AMPDU_LAST_KNOWN = BIT(22),
RX_FLAG_AMSDU_MORE = BIT(23),
- /* = BIT(24), */
+ RX_FLAG_RADIOTAP_VHT = BIT(24),
RX_FLAG_ONLY_MONITOR = BIT(25),
RX_FLAG_SKIP_MONITOR = BIT(26),
RX_FLAG_8023 = BIT(27),
@@ -789,10 +788,21 @@ struct ieee80211_tx_queue_params {
struct ieee80211_he_mu_edca_param_ac_rec mu_edca_param_rec;
};
+enum mac80211_rate_control_flags {
+ IEEE80211_TX_RC_40_MHZ_WIDTH = BIT(0),
+ IEEE80211_TX_RC_80_MHZ_WIDTH = BIT(1),
+ IEEE80211_TX_RC_160_MHZ_WIDTH = BIT(2),
+ IEEE80211_TX_RC_GREEN_FIELD = BIT(3),
+ IEEE80211_TX_RC_MCS = BIT(4),
+ IEEE80211_TX_RC_SHORT_GI = BIT(5),
+ IEEE80211_TX_RC_VHT_MCS = BIT(6),
+ IEEE80211_TX_RC_USE_SHORT_PREAMBLE = BIT(7),
+};
+
struct ieee80211_tx_rate {
uint8_t idx;
uint16_t count:5,
- flags:11;
+ flags:11; /* enum mac80211_rate_control_flags */
};
enum ieee80211_vif_driver_flags {
@@ -1092,6 +1102,12 @@ struct ieee80211_ops {
void (*rfkill_poll)(struct ieee80211_hw *);
+ int (*net_fill_forward_path)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_sta *, struct net_device_path_ctx *, struct net_device_path *);
+
+ int (*start_nan)(struct ieee80211_hw *, struct ieee80211_vif *, struct cfg80211_nan_conf *);
+ int (*stop_nan)(struct ieee80211_hw *, struct ieee80211_vif *);
+ int (*nan_change_conf)(struct ieee80211_hw *, struct ieee80211_vif *, struct cfg80211_nan_conf *, uint32_t changes);
+
/* #ifdef CONFIG_MAC80211_DEBUGFS */ /* Do not change depending on compile-time option. */
void (*sta_add_debugfs)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_sta *, struct dentry *);
void (*vif_add_debugfs)(struct ieee80211_hw *, struct ieee80211_vif *);
@@ -1184,6 +1200,22 @@ void linuxkpi_ieee80211_handle_wake_tx_queue(struct ieee80211_hw *,
/* -------------------------------------------------------------------------- */
+/*
+ * Emulate chanctx operations. We cannot rename/prefix the functions
+ * as we rely on the (function)pointers being the same everywhere.
+ */
+int ieee80211_emulate_add_chanctx(struct ieee80211_hw *,
+ struct ieee80211_chanctx_conf *);
+void ieee80211_emulate_remove_chanctx(struct ieee80211_hw *,
+ struct ieee80211_chanctx_conf *);
+void ieee80211_emulate_change_chanctx(struct ieee80211_hw *,
+ struct ieee80211_chanctx_conf *, uint32_t);
+int ieee80211_emulate_switch_vif_chanctx(struct ieee80211_hw *,
+ struct ieee80211_vif_chanctx_switch *, int,
+ enum ieee80211_chanctx_switch_mode);
+
+/* -------------------------------------------------------------------------- */
+
static __inline void
_ieee80211_hw_set(struct ieee80211_hw *hw, enum ieee80211_hw_flags flag)
{
@@ -1549,6 +1581,16 @@ ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw,
linuxkpi_ieee80211_iterate_stations_atomic(hw, iterfunc, arg);
}
+static inline void
+ieee80211_iterate_stations_mtx(struct ieee80211_hw *hw,
+ void (*iterfunc)(void *, struct ieee80211_sta *), void *arg)
+{
+
+ lockdep_assert_wiphy(hw->wiphy);
+ IMPROVE("we could simplify this if we had a sta list on the lhw");
+ linuxkpi_ieee80211_iterate_stations_atomic(hw, iterfunc, arg);
+}
+
static __inline struct wireless_dev *
ieee80211_vif_to_wdev(struct ieee80211_vif *vif)
{
@@ -2622,60 +2664,11 @@ ieee80211_cqm_beacon_loss_notify(struct ieee80211_vif *vif, gfp_t gfp __unused)
/* -------------------------------------------------------------------------- */
-int lkpi_80211_update_chandef(struct ieee80211_hw *,
- struct ieee80211_chanctx_conf *);
-
-static inline int
-ieee80211_emulate_add_chanctx(struct ieee80211_hw *hw,
- struct ieee80211_chanctx_conf *chanctx_conf)
-{
- int error;
-
- hw->conf.radar_enabled = chanctx_conf->radar_enabled;
- error = lkpi_80211_update_chandef(hw, chanctx_conf);
- return (error);
-}
-
-static inline void
-ieee80211_emulate_remove_chanctx(struct ieee80211_hw *hw,
- struct ieee80211_chanctx_conf *chanctx_conf __unused)
-{
- hw->conf.radar_enabled = false;
- lkpi_80211_update_chandef(hw, NULL);
-}
-
-static inline void
-ieee80211_emulate_change_chanctx(struct ieee80211_hw *hw,
- struct ieee80211_chanctx_conf *chanctx_conf, uint32_t changed __unused)
-{
- hw->conf.radar_enabled = chanctx_conf->radar_enabled;
- lkpi_80211_update_chandef(hw, chanctx_conf);
-}
-
-static inline int
-ieee80211_emulate_switch_vif_chanctx(struct ieee80211_hw *hw,
- struct ieee80211_vif_chanctx_switch *vifs, int n_vifs,
- enum ieee80211_chanctx_switch_mode mode __unused)
+static inline bool
+ieee80211_vif_nan_started(struct ieee80211_vif *vif)
{
- struct ieee80211_chanctx_conf *chanctx_conf;
- int error;
-
- /* Sanity check. */
- if (n_vifs <= 0)
- return (-EINVAL);
- if (vifs == NULL || vifs[0].new_ctx == NULL)
- return (-EINVAL);
-
- /*
- * What to do if n_vifs > 1?
- * Does that make sense for drivers not supporting chanctx?
- */
- hw->conf.radar_enabled = vifs[0].new_ctx->radar_enabled;
- chanctx_conf = vifs[0].new_ctx;
- error = lkpi_80211_update_chandef(hw, chanctx_conf);
- return (error);
+ IMPROVE("NAN");
+ return (false);
}
-/* -------------------------------------------------------------------------- */
-
#endif /* _LINUXKPI_NET_MAC80211_H */