aboutsummaryrefslogtreecommitdiff
path: root/sys/compat/linuxkpi/common/include/linux
diff options
context:
space:
mode:
Diffstat (limited to 'sys/compat/linuxkpi/common/include/linux')
-rw-r--r--sys/compat/linuxkpi/common/include/linux/acpi.h49
-rw-r--r--sys/compat/linuxkpi/common/include/linux/acpi_amd_wbrf.h97
-rw-r--r--sys/compat/linuxkpi/common/include/linux/agp_backend.h28
-rw-r--r--sys/compat/linuxkpi/common/include/linux/anon_inodes.h48
-rw-r--r--sys/compat/linuxkpi/common/include/linux/aperture.h64
-rw-r--r--sys/compat/linuxkpi/common/include/linux/apple-gmux.h12
-rw-r--r--sys/compat/linuxkpi/common/include/linux/atomic.h35
-rw-r--r--sys/compat/linuxkpi/common/include/linux/average.h90
-rw-r--r--sys/compat/linuxkpi/common/include/linux/backlight.h134
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bcd.h43
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bitfield.h141
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bitmap.h450
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bitops.h437
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bottom_half.h32
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bsearch.h36
-rw-r--r--sys/compat/linuxkpi/common/include/linux/build_bug.h65
-rw-r--r--sys/compat/linuxkpi/common/include/linux/cache.h40
-rw-r--r--sys/compat/linuxkpi/common/include/linux/capability.h51
-rw-r--r--sys/compat/linuxkpi/common/include/linux/cc_platform.h21
-rw-r--r--sys/compat/linuxkpi/common/include/linux/cdev.h146
-rw-r--r--sys/compat/linuxkpi/common/include/linux/cec.h8
-rw-r--r--sys/compat/linuxkpi/common/include/linux/cgroup.h34
-rw-r--r--sys/compat/linuxkpi/common/include/linux/circ_buf.h34
-rw-r--r--sys/compat/linuxkpi/common/include/linux/cleanup.h46
-rw-r--r--sys/compat/linuxkpi/common/include/linux/clocksource.h36
-rw-r--r--sys/compat/linuxkpi/common/include/linux/compat.h68
-rw-r--r--sys/compat/linuxkpi/common/include/linux/compiler.h133
-rw-r--r--sys/compat/linuxkpi/common/include/linux/completion.h68
-rw-r--r--sys/compat/linuxkpi/common/include/linux/console.h55
-rw-r--r--sys/compat/linuxkpi/common/include/linux/container_of.h54
-rw-r--r--sys/compat/linuxkpi/common/include/linux/cpu.h78
-rw-r--r--sys/compat/linuxkpi/common/include/linux/cpufeature.h43
-rw-r--r--sys/compat/linuxkpi/common/include/linux/crc32.h43
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dcache.h45
-rw-r--r--sys/compat/linuxkpi/common/include/linux/debugfs.h124
-rw-r--r--sys/compat/linuxkpi/common/include/linux/delay.h87
-rw-r--r--sys/compat/linuxkpi/common/include/linux/devcoredump.h81
-rw-r--r--sys/compat/linuxkpi/common/include/linux/device.h718
-rw-r--r--sys/compat/linuxkpi/common/include/linux/device/driver.h33
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dma-attrs.h54
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dma-buf-map.h91
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dma-mapping.h399
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dmapool.h103
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dmi.h58
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dynamic_debug.h8
-rw-r--r--sys/compat/linuxkpi/common/include/linux/efi.h68
-rw-r--r--sys/compat/linuxkpi/common/include/linux/err.h81
-rw-r--r--sys/compat/linuxkpi/common/include/linux/errno.h73
-rw-r--r--sys/compat/linuxkpi/common/include/linux/etherdevice.h140
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ethtool.h57
-rw-r--r--sys/compat/linuxkpi/common/include/linux/eventpoll.h45
-rw-r--r--sys/compat/linuxkpi/common/include/linux/export.h31
-rw-r--r--sys/compat/linuxkpi/common/include/linux/file.h185
-rw-r--r--sys/compat/linuxkpi/common/include/linux/firmware.h116
-rw-r--r--sys/compat/linuxkpi/common/include/linux/fs.h425
-rw-r--r--sys/compat/linuxkpi/common/include/linux/fwnode.h10
-rw-r--r--sys/compat/linuxkpi/common/include/linux/gcd.h48
-rw-r--r--sys/compat/linuxkpi/common/include/linux/gfp.h214
-rw-r--r--sys/compat/linuxkpi/common/include/linux/gpf.h33
-rw-r--r--sys/compat/linuxkpi/common/include/linux/hardirq.h51
-rw-r--r--sys/compat/linuxkpi/common/include/linux/hash.h76
-rw-r--r--sys/compat/linuxkpi/common/include/linux/hashtable.h183
-rw-r--r--sys/compat/linuxkpi/common/include/linux/hdmi.h447
-rw-r--r--sys/compat/linuxkpi/common/include/linux/highmem.h170
-rw-r--r--sys/compat/linuxkpi/common/include/linux/hrtimer.h90
-rw-r--r--sys/compat/linuxkpi/common/include/linux/i2c-algo-bit.h49
-rw-r--r--sys/compat/linuxkpi/common/include/linux/i2c.h177
-rw-r--r--sys/compat/linuxkpi/common/include/linux/idr.h162
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ieee80211.h1245
-rw-r--r--sys/compat/linuxkpi/common/include/linux/if_arp.h35
-rw-r--r--sys/compat/linuxkpi/common/include/linux/if_ether.h82
-rw-r--r--sys/compat/linuxkpi/common/include/linux/if_vlan.h57
-rw-r--r--sys/compat/linuxkpi/common/include/linux/in.h44
-rw-r--r--sys/compat/linuxkpi/common/include/linux/in6.h34
-rw-r--r--sys/compat/linuxkpi/common/include/linux/inetdevice.h6
-rw-r--r--sys/compat/linuxkpi/common/include/linux/interrupt.h195
-rw-r--r--sys/compat/linuxkpi/common/include/linux/interval_tree.h55
-rw-r--r--sys/compat/linuxkpi/common/include/linux/interval_tree_generic.h99
-rw-r--r--sys/compat/linuxkpi/common/include/linux/io-64-nonatomic-lo-hi.h65
-rw-r--r--sys/compat/linuxkpi/common/include/linux/io-mapping.h130
-rw-r--r--sys/compat/linuxkpi/common/include/linux/io.h566
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ioctl.h38
-rw-r--r--sys/compat/linuxkpi/common/include/linux/iommu.h29
-rw-r--r--sys/compat/linuxkpi/common/include/linux/iopoll.h92
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ioport.h57
-rw-r--r--sys/compat/linuxkpi/common/include/linux/iosys-map.h161
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ip.h73
-rw-r--r--sys/compat/linuxkpi/common/include/linux/irq_work.h90
-rw-r--r--sys/compat/linuxkpi/common/include/linux/irqdomain.h10
-rw-r--r--sys/compat/linuxkpi/common/include/linux/irqreturn.h38
-rw-r--r--sys/compat/linuxkpi/common/include/linux/jhash.h144
-rw-r--r--sys/compat/linuxkpi/common/include/linux/jiffies.h143
-rw-r--r--sys/compat/linuxkpi/common/include/linux/jump_label.h48
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kconfig.h76
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kdev_t.h44
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kernel.h385
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kernel_stat.h34
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kfifo.h122
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kmemleak.h8
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kmod.h48
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kobject.h210
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kref.h129
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kstrtox.h324
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kthread.h166
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ktime.h287
-rw-r--r--sys/compat/linuxkpi/common/include/linux/leds.h41
-rw-r--r--sys/compat/linuxkpi/common/include/linux/limits.h47
-rw-r--r--sys/compat/linuxkpi/common/include/linux/list.h529
-rw-r--r--sys/compat/linuxkpi/common/include/linux/llist.h101
-rw-r--r--sys/compat/linuxkpi/common/include/linux/lockdep.h120
-rw-r--r--sys/compat/linuxkpi/common/include/linux/log2.h41
-rw-r--r--sys/compat/linuxkpi/common/include/linux/math.h76
-rw-r--r--sys/compat/linuxkpi/common/include/linux/math64.h171
-rw-r--r--sys/compat/linuxkpi/common/include/linux/media-bus-format.h8
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mhi.h222
-rw-r--r--sys/compat/linuxkpi/common/include/linux/minmax.h74
-rw-r--r--sys/compat/linuxkpi/common/include/linux/miscdevice.h74
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mm.h479
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mm_types.h93
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mman.h38
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mmap_lock.h54
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mmu_context.h43
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mmu_notifier.h33
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mmzone.h15
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mod_devicetable.h83
-rw-r--r--sys/compat/linuxkpi/common/include/linux/module.h127
-rw-r--r--sys/compat/linuxkpi/common/include/linux/moduleparam.h146
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mutex.h177
-rw-r--r--sys/compat/linuxkpi/common/include/linux/net.h88
-rw-r--r--sys/compat/linuxkpi/common/include/linux/net_dim.h408
-rw-r--r--sys/compat/linuxkpi/common/include/linux/netdev_features.h52
-rw-r--r--sys/compat/linuxkpi/common/include/linux/netdevice.h488
-rw-r--r--sys/compat/linuxkpi/common/include/linux/nl80211.h445
-rw-r--r--sys/compat/linuxkpi/common/include/linux/nodemask.h46
-rw-r--r--sys/compat/linuxkpi/common/include/linux/nospec.h8
-rw-r--r--sys/compat/linuxkpi/common/include/linux/notifier.h58
-rw-r--r--sys/compat/linuxkpi/common/include/linux/numa.h34
-rw-r--r--sys/compat/linuxkpi/common/include/linux/of.h33
-rw-r--r--sys/compat/linuxkpi/common/include/linux/overflow.h349
-rw-r--r--sys/compat/linuxkpi/common/include/linux/page-flags.h41
-rw-r--r--sys/compat/linuxkpi/common/include/linux/page.h130
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pagemap.h49
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pagevec.h137
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pci.h1537
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pci_ids.h78
-rw-r--r--sys/compat/linuxkpi/common/include/linux/perf_event.h34
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pfn.h42
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pfn_t.h54
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pid.h68
-rw-r--r--sys/compat/linuxkpi/common/include/linux/platform_device.h97
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pm.h100
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pm_qos.h57
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pm_runtime.h54
-rw-r--r--sys/compat/linuxkpi/common/include/linux/poison.h9
-rw-r--r--sys/compat/linuxkpi/common/include/linux/poll.h47
-rw-r--r--sys/compat/linuxkpi/common/include/linux/power_supply.h42
-rw-r--r--sys/compat/linuxkpi/common/include/linux/preempt.h41
-rw-r--r--sys/compat/linuxkpi/common/include/linux/prefetch.h34
-rw-r--r--sys/compat/linuxkpi/common/include/linux/printk.h97
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ptp_clock_kernel.h75
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pwm.h100
-rw-r--r--sys/compat/linuxkpi/common/include/linux/qrtr.h41
-rw-r--r--sys/compat/linuxkpi/common/include/linux/radix-tree.h84
-rw-r--r--sys/compat/linuxkpi/common/include/linux/random.h129
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ratelimit.h17
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rbtree.h206
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rculist.h147
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rcupdate.h165
-rw-r--r--sys/compat/linuxkpi/common/include/linux/reboot.h40
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ref_tracker.h93
-rw-r--r--sys/compat/linuxkpi/common/include/linux/refcount.h84
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rhashtable.h87
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rwlock.h57
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rwsem.h85
-rw-r--r--sys/compat/linuxkpi/common/include/linux/scatterlist.h684
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sched.h243
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sched/mm.h43
-rw-r--r--sys/compat/linuxkpi/common/include/linux/semaphore.h68
-rw-r--r--sys/compat/linuxkpi/common/include/linux/seq_file.h108
-rw-r--r--sys/compat/linuxkpi/common/include/linux/seqlock.h184
-rw-r--r--sys/compat/linuxkpi/common/include/linux/shmem_fs.h67
-rw-r--r--sys/compat/linuxkpi/common/include/linux/shrinker.h79
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sizes.h63
-rw-r--r--sys/compat/linuxkpi/common/include/linux/skbuff.h1167
-rw-r--r--sys/compat/linuxkpi/common/include/linux/slab.h284
-rw-r--r--sys/compat/linuxkpi/common/include/linux/smp.h51
-rw-r--r--sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h62
-rw-r--r--sys/compat/linuxkpi/common/include/linux/soc/qcom/qmi.h173
-rw-r--r--sys/compat/linuxkpi/common/include/linux/socket.h78
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sort.h41
-rw-r--r--sys/compat/linuxkpi/common/include/linux/spinlock.h181
-rw-r--r--sys/compat/linuxkpi/common/include/linux/srcu.h54
-rw-r--r--sys/compat/linuxkpi/common/include/linux/stackdepot.h32
-rw-r--r--sys/compat/linuxkpi/common/include/linux/stdarg.h33
-rw-r--r--sys/compat/linuxkpi/common/include/linux/stddef.h31
-rw-r--r--sys/compat/linuxkpi/common/include/linux/string.h329
-rw-r--r--sys/compat/linuxkpi/common/include/linux/string_helpers.h69
-rw-r--r--sys/compat/linuxkpi/common/include/linux/stringify.h35
-rw-r--r--sys/compat/linuxkpi/common/include/linux/suspend.h23
-rw-r--r--sys/compat/linuxkpi/common/include/linux/swap.h71
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sysfs.h487
-rw-r--r--sys/compat/linuxkpi/common/include/linux/tcp.h70
-rw-r--r--sys/compat/linuxkpi/common/include/linux/time.h141
-rw-r--r--sys/compat/linuxkpi/common/include/linux/timer.h94
-rw-r--r--sys/compat/linuxkpi/common/include/linux/tracepoint.h48
-rw-r--r--sys/compat/linuxkpi/common/include/linux/typecheck.h38
-rw-r--r--sys/compat/linuxkpi/common/include/linux/types.h96
-rw-r--r--sys/compat/linuxkpi/common/include/linux/uaccess.h115
-rw-r--r--sys/compat/linuxkpi/common/include/linux/udp.h52
-rw-r--r--sys/compat/linuxkpi/common/include/linux/units.h40
-rw-r--r--sys/compat/linuxkpi/common/include/linux/usb.h318
-rw-r--r--sys/compat/linuxkpi/common/include/linux/utsname.h51
-rw-r--r--sys/compat/linuxkpi/common/include/linux/uuid.h77
-rw-r--r--sys/compat/linuxkpi/common/include/linux/vgaarb.h281
-rw-r--r--sys/compat/linuxkpi/common/include/linux/vmalloc.h42
-rw-r--r--sys/compat/linuxkpi/common/include/linux/wait.h319
-rw-r--r--sys/compat/linuxkpi/common/include/linux/wait_bit.h71
-rw-r--r--sys/compat/linuxkpi/common/include/linux/workqueue.h267
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ww_mutex.h149
-rw-r--r--sys/compat/linuxkpi/common/include/linux/xarray.h149
220 files changed, 28937 insertions, 0 deletions
diff --git a/sys/compat/linuxkpi/common/include/linux/acpi.h b/sys/compat/linuxkpi/common/include/linux/acpi.h
new file mode 100644
index 000000000000..3e1ec1b20626
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/acpi.h
@@ -0,0 +1,49 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
+ *
+ * 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_ACPI_H_
+#define _LINUXKPI_LINUX_ACPI_H_
+
+#include <linux/device.h>
+#include <linux/uuid.h>
+
+#if defined(__aarch64__) || defined(__amd64__) || defined(__i386__)
+
+#include <acpi/acpi.h>
+#include <acpi/acpi_bus.h>
+
+#define ACPI_HANDLE(dev) \
+ ((dev)->bsddev != NULL ? bsd_acpi_get_handle((dev)->bsddev) : NULL)
+#define acpi_device_handle(dev) \
+ ((dev) != NULL ? bsd_acpi_get_handle(dev) : NULL)
+static inline void acpi_dev_put(struct acpi_device *adev) {}
+#define acpi_handle_debug(handle, fmt, ...)
+
+#endif
+
+#endif /* _LINUXKPI_LINUX_ACPI_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/acpi_amd_wbrf.h b/sys/compat/linuxkpi/common/include/linux/acpi_amd_wbrf.h
new file mode 100644
index 000000000000..92c2ead41c45
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/acpi_amd_wbrf.h
@@ -0,0 +1,97 @@
+/*-
+ * 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_ACPI_AMD_WBRF_H_
+#define _LINUXKPI_LINUX_ACPI_AMD_WBRF_H_
+
+#include <linux/device.h>
+#include <linux/notifier.h>
+
+#define MAX_NUM_OF_WBRF_RANGES 11
+
+#define WBRF_RECORD_ADD 0x0
+#define WBRF_RECORD_REMOVE 0x1
+
+struct freq_band_range {
+ uint64_t start;
+ uint64_t end;
+};
+
+struct wbrf_ranges_in_out {
+ uint64_t num_of_ranges;
+ struct freq_band_range band_list[MAX_NUM_OF_WBRF_RANGES];
+};
+
+enum wbrf_notifier_actions {
+ WBRF_CHANGED,
+};
+
+/*
+ * The following functions currently have dummy implementations that, on Linux,
+ * are used when CONFIG_AMD_WBRF is not set at compile time.
+ */
+
+static inline bool
+acpi_amd_wbrf_supported_consumer(struct device *dev)
+{
+ return (false);
+}
+
+static inline int
+acpi_amd_wbrf_add_remove(struct device *dev, uint8_t action,
+ struct wbrf_ranges_in_out *in)
+{
+ return (-ENODEV);
+}
+
+static inline bool
+acpi_amd_wbrf_supported_producer(struct device *dev)
+{
+ return (false);
+}
+
+static inline int
+amd_wbrf_retrieve_freq_band(struct device *dev, struct wbrf_ranges_in_out *out)
+{
+ return (-ENODEV);
+}
+
+static inline int
+amd_wbrf_register_notifier(struct notifier_block *nb)
+{
+ return (-ENODEV);
+}
+
+static inline int
+amd_wbrf_unregister_notifier(struct notifier_block *nb)
+{
+ return (-ENODEV);
+}
+
+#endif /* _LINUXKPI_LINUX_ACPI_AMD_WBRF_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/agp_backend.h b/sys/compat/linuxkpi/common/include/linux/agp_backend.h
new file mode 100644
index 000000000000..c855fd842970
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/agp_backend.h
@@ -0,0 +1,28 @@
+/* Public domain */
+
+#ifndef _LINUXKPI_LINUX_AGP_BACKEND_H_
+#define _LINUXKPI_LINUX_AGP_BACKEND_H_
+
+#include <sys/types.h>
+
+struct agp_version {
+ uint16_t major;
+ uint16_t minor;
+};
+
+struct agp_kern_info {
+ struct agp_version version;
+ uint16_t vendor;
+ uint16_t device;
+ unsigned long mode;
+ unsigned long aper_base;
+ size_t aper_size;
+ int max_memory;
+ int current_memory;
+ bool cant_use_aperture;
+ unsigned long page_mask;
+};
+
+struct agp_memory;
+
+#endif /* _LINUXKPI_LINUX_AGP_BACKEND_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/anon_inodes.h b/sys/compat/linuxkpi/common/include/linux/anon_inodes.h
new file mode 100644
index 000000000000..c69f6e152b17
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/anon_inodes.h
@@ -0,0 +1,48 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
+ *
+ * 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_ANON_INODES_H_
+#define _LINUXKPI_LINUX_ANON_INODES_H_
+
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/types.h>
+
+static inline struct file *
+anon_inode_getfile(const char *name __unused,
+ const struct file_operations *fops, void *priv, int flags __unused)
+{
+ struct file *file;
+
+ file = alloc_file(FMODE_READ, fops);
+ file->private_data = priv;
+
+ return (file);
+}
+
+#endif /* _LINUXKPI_LINUX_ANON_INODES_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/aperture.h b/sys/compat/linuxkpi/common/include/linux/aperture.h
new file mode 100644
index 000000000000..7eced3cc3cb1
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/aperture.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: MIT */
+
+#ifndef _LINUX_APERTURE_H_
+#define _LINUX_APERTURE_H_
+
+#include <linux/types.h>
+
+#define CONFIG_APERTURE_HELPERS
+
+struct pci_dev;
+struct platform_device;
+
+#if defined(CONFIG_APERTURE_HELPERS)
+int devm_aperture_acquire_for_platform_device(struct platform_device *pdev,
+ resource_size_t base,
+ resource_size_t size);
+
+int aperture_remove_conflicting_devices(resource_size_t base, resource_size_t size,
+ const char *name);
+
+int __aperture_remove_legacy_vga_devices(struct pci_dev *pdev);
+
+int aperture_remove_conflicting_pci_devices(struct pci_dev *pdev, const char *name);
+#else
+static inline int devm_aperture_acquire_for_platform_device(struct platform_device *pdev,
+ resource_size_t base,
+ resource_size_t size)
+{
+ return 0;
+}
+
+static inline int aperture_remove_conflicting_devices(resource_size_t base, resource_size_t size,
+ const char *name)
+{
+ return 0;
+}
+
+static inline int __aperture_remove_legacy_vga_devices(struct pci_dev *pdev)
+{
+ return 0;
+}
+
+static inline int aperture_remove_conflicting_pci_devices(struct pci_dev *pdev, const char *name)
+{
+ return 0;
+}
+#endif
+
+/**
+ * aperture_remove_all_conflicting_devices - remove all existing framebuffers
+ * @name: a descriptive name of the requesting driver
+ *
+ * This function removes all graphics device drivers. Use this function on systems
+ * that can have their framebuffer located anywhere in memory.
+ *
+ * Returns:
+ * 0 on success, or a negative errno code otherwise
+ */
+static inline int aperture_remove_all_conflicting_devices(const char *name)
+{
+ return aperture_remove_conflicting_devices(0, (resource_size_t)-1, name);
+}
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/apple-gmux.h b/sys/compat/linuxkpi/common/include/linux/apple-gmux.h
new file mode 100644
index 000000000000..812a782c57d4
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/apple-gmux.h
@@ -0,0 +1,12 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_APPLE_GMUX_H
+#define _LINUXKPI_LINUX_APPLE_GMUX_H
+
+static inline bool
+apple_gmux_detect(void *a, void *b)
+{
+ return false;
+}
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/atomic.h b/sys/compat/linuxkpi/common/include/linux/atomic.h
new file mode 100644
index 000000000000..bc76928a7d67
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/atomic.h
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org>
+ *
+ * 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_ATOMIC_H_
+#define _LINUXKPI_LINUX_ATOMIC_H_
+
+#include <asm/atomic.h>
+#include <asm/atomic64.h>
+#include <asm/atomic-long.h>
+#include <asm/barrier.h>
+
+#endif /* _LINUXKPI_LINUX_ATOMIC_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/average.h b/sys/compat/linuxkpi/common/include/linux/average.h
new file mode 100644
index 000000000000..4191a351c5c6
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/average.h
@@ -0,0 +1,90 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020-2021 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb 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_AVERAGE_H
+#define _LINUXKPI_LINUX_AVERAGE_H
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <linux/log2.h>
+
+/* EWMA stands for Exponentially Weighted Moving Average. */
+/*
+ * Z_t = d X_t + (1 - d) * Z_(t-1); 0 < d <= 1, t >= 1; Roberts (1959).
+ * t : observation number in time.
+ * d : weight for current observation.
+ * Xt : observations over time.
+ * Zt : EWMA value after observation t.
+ *
+ * wmba_*_read seems to return up-to [u]long values; have to deal with 32/64bit.
+ * According to the ath5k.h change log this seems to be a fix-(_p)recision impl.
+ * assert 2/4 bits for frac.
+ * Also all (_d) values seem to be pow2 which simplifies maths (shift by
+ * d = ilog2(_d) instead of doing division (d = 1/_d)). Keep it this way until
+ * we hit the CTASSERT.
+ */
+
+#define DECLARE_EWMA(_name, _p, _d) \
+ \
+ CTASSERT((sizeof(unsigned long) <= 4) ? (_p < 30) : (_p < 60)); \
+ CTASSERT(_d > 0 && powerof2(_d)); \
+ \
+ struct ewma_ ## _name { \
+ unsigned long zt; \
+ }; \
+ \
+ static __inline void \
+ ewma_ ## _name ## _init(struct ewma_ ## _name *ewma) \
+ { \
+ /* No target (no historical data). */ \
+ ewma->zt = 0; \
+ } \
+ \
+ static __inline void \
+ ewma_ ## _name ## _add(struct ewma_ ## _name *ewma, unsigned long x) \
+ { \
+ unsigned long ztm1 = ewma->zt; /* Z_(t-1). */ \
+ int d = ilog2(_d); \
+ \
+ if (ewma->zt == 0) \
+ ewma->zt = x << (_p); \
+ else \
+ ewma->zt = ((x << (_p)) >> d) + \
+ (((ztm1 << d) - ztm1) >> d); \
+ } \
+ \
+ static __inline unsigned long \
+ ewma_ ## _name ## _read(struct ewma_ ## _name *ewma) \
+ { \
+ return (ewma->zt >> (_p)); \
+ } \
+
+#endif /* _LINUXKPI_LINUX_AVERAGE_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/backlight.h b/sys/compat/linuxkpi/common/include/linux/backlight.h
new file mode 100644
index 000000000000..4f8f7440925a
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/backlight.h
@@ -0,0 +1,134 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot 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_BACKLIGHT_H_
+#define _LINUXKPI_LINUX_BACKLIGHT_H_
+
+#include <linux/notifier.h>
+
+struct backlight_device;
+
+enum backlight_type {
+ BACKLIGHT_RAW = 0,
+};
+
+struct backlight_properties {
+ int type;
+ int max_brightness;
+ int brightness;
+ int power;
+};
+
+enum backlight_notification {
+ BACKLIGHT_REGISTERED,
+ BACKLIGHT_UNREGISTERED,
+};
+
+enum backlight_update_reason {
+ BACKLIGHT_UPDATE_HOTKEY = 0
+};
+
+struct backlight_ops {
+ int options;
+#define BL_CORE_SUSPENDRESUME 1
+ int (*update_status)(struct backlight_device *);
+ int (*get_brightness)(struct backlight_device *);
+};
+
+struct backlight_device {
+ const struct backlight_ops *ops;
+ struct backlight_properties props;
+ void *data;
+ struct device *dev;
+ char *name;
+};
+
+#define bl_get_data(bd) (bd)->data
+
+struct backlight_device *linux_backlight_device_register(const char *name,
+ struct device *dev, void *data, const struct backlight_ops *ops, struct backlight_properties *props);
+void linux_backlight_device_unregister(struct backlight_device *bd);
+#define backlight_device_register(name, dev, data, ops, props) \
+ linux_backlight_device_register(name, dev, data, ops, props)
+#define backlight_device_unregister(bd) linux_backlight_device_unregister(bd)
+
+static inline int
+backlight_update_status(struct backlight_device *bd)
+{
+ return (bd->ops->update_status(bd));
+}
+
+static inline void
+backlight_force_update(struct backlight_device *bd, int reason)
+{
+ bd->props.brightness = bd->ops->get_brightness(bd);
+}
+
+static inline int
+backlight_get_brightness(struct backlight_device *bd)
+{
+
+ return (bd->props.brightness);
+}
+
+static inline int
+backlight_device_set_brightness(struct backlight_device *bd, int brightness)
+{
+
+ if (brightness > bd->props.max_brightness)
+ return (EINVAL);
+ bd->props.brightness = brightness;
+ return (bd->ops->update_status(bd));
+}
+
+static inline int
+backlight_enable(struct backlight_device *bd)
+{
+ if (bd == NULL)
+ return (0);
+ bd->props.power = 0/* FB_BLANK_UNBLANK */;
+ return (backlight_update_status(bd));
+}
+
+static inline int
+backlight_disable(struct backlight_device *bd)
+{
+ if (bd == NULL)
+ return (0);
+ bd->props.power = 4/* FB_BLANK_POWERDOWN */;
+ return (backlight_update_status(bd));
+}
+
+static inline bool
+backlight_is_blank(struct backlight_device *bd)
+{
+
+ return (bd->props.power != 0/* FB_BLANK_UNBLANK */);
+}
+
+#endif /* _LINUXKPI_LINUX_BACKLIGHT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/bcd.h b/sys/compat/linuxkpi/common/include/linux/bcd.h
new file mode 100644
index 000000000000..385819910454
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/bcd.h
@@ -0,0 +1,43 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Bjoern A. Zeeb
+ *
+ * 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_BCD_H
+#define _LINUXKPI_LINUX_BCD_H
+
+#include <sys/types.h>
+#include <sys/libkern.h>
+
+/* Compared to the libkern version this one truncates the argument. */
+static inline uint8_t linuxkpi_bcd2bin(uint8_t x)
+{
+
+ return (bcd2bin(x));
+}
+
+#define bcd2bin(_x) linuxkpi_bcd2bin(_x)
+
+#endif /* _LINUXKPI_LINUX_BCD_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/bitfield.h b/sys/compat/linuxkpi/common/include/linux/bitfield.h
new file mode 100644
index 000000000000..8a91b0663f37
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/bitfield.h
@@ -0,0 +1,141 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020-2024 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb 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_BITFIELD_H
+#define _LINUXKPI_LINUX_BITFIELD_H
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+/* Use largest possible type. */
+static inline uint64_t ___lsb(uint64_t f) { return (f & -f); }
+static inline uint64_t ___bitmask(uint64_t f) { return (f / ___lsb(f)); }
+
+#define _uX_get_bits(_n) \
+ static __inline uint ## _n ## _t \
+ u ## _n ## _get_bits(uint ## _n ## _t v, uint ## _n ## _t f) \
+ { \
+ return ((v & f) / ___lsb(f)); \
+ }
+
+_uX_get_bits(64)
+_uX_get_bits(32)
+_uX_get_bits(16)
+_uX_get_bits(8)
+
+#define _leX_get_bits(_n) \
+ static __inline uint ## _n ## _t \
+ le ## _n ## _get_bits(__le ## _n v, uint ## _n ## _t f) \
+ { \
+ return ((le ## _n ## _to_cpu(v) & f) / ___lsb(f)); \
+ }
+
+_leX_get_bits(64)
+_leX_get_bits(32)
+_leX_get_bits(16)
+
+#define _uX_encode_bits(_n) \
+ static __inline uint ## _n ## _t \
+ u ## _n ## _encode_bits(uint ## _n ## _t v, uint ## _n ## _t f) \
+ { \
+ return ((v & ___bitmask(f)) * ___lsb(f)); \
+ }
+
+_uX_encode_bits(64)
+_uX_encode_bits(32)
+_uX_encode_bits(16)
+_uX_encode_bits(8)
+
+#define _leX_encode_bits(_n) \
+ static __inline uint ## _n ## _t \
+ le ## _n ## _encode_bits(__le ## _n v, uint ## _n ## _t f) \
+ { \
+ return (cpu_to_le ## _n((v & ___bitmask(f)) * ___lsb(f))); \
+ }
+
+_leX_encode_bits(64)
+_leX_encode_bits(32)
+_leX_encode_bits(16)
+
+#define _leXp_replace_bits(_n) \
+ static __inline void \
+ le ## _n ## p_replace_bits(uint ## _n ## _t *p, \
+ uint ## _n ## _t v, uint ## _n ## _t f) \
+ { \
+ *p = (*p & ~(cpu_to_le ## _n(f))) | \
+ le ## _n ## _encode_bits(v, f); \
+ }
+
+_leXp_replace_bits(64)
+_leXp_replace_bits(32)
+_leXp_replace_bits(16)
+
+#define _uXp_replace_bits(_n) \
+ static __inline void \
+ u ## _n ## p_replace_bits(uint ## _n ## _t *p, \
+ uint ## _n ## _t v, uint ## _n ## _t f) \
+ { \
+ *p = (*p & ~f) | u ## _n ## _encode_bits(v, f); \
+ }
+
+_uXp_replace_bits(64)
+_uXp_replace_bits(32)
+_uXp_replace_bits(16)
+_uXp_replace_bits(8)
+
+#define _uX_replace_bits(_n) \
+ static __inline uint ## _n ## _t \
+ u ## _n ## _replace_bits(uint ## _n ## _t p, \
+ uint ## _n ## _t v, uint ## _n ## _t f) \
+ { \
+ return ((p & ~f) | u ## _n ## _encode_bits(v, f)); \
+ }
+
+_uX_replace_bits(64)
+_uX_replace_bits(32)
+_uX_replace_bits(16)
+_uX_replace_bits(8)
+
+#define __bf_shf(x) (__builtin_ffsll(x) - 1)
+
+#define FIELD_FIT(_mask, _value) \
+ (!(((typeof(_mask))(_value) << __bf_shf(_mask)) & ~(_mask)))
+
+#define FIELD_PREP(_mask, _value) \
+ (((typeof(_mask))(_value) << __bf_shf(_mask)) & (_mask))
+
+/* Likely would need extra sanity checks compared to FIELD_PREP()? */
+#define FIELD_PREP_CONST(_mask, _value) \
+ (((typeof(_mask))(_value) << __bf_shf(_mask)) & (_mask))
+
+#define FIELD_GET(_mask, _value) \
+ ((typeof(_mask))(((_value) & (_mask)) >> __bf_shf(_mask)))
+
+#endif /* _LINUXKPI_LINUX_BITFIELD_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/bitmap.h b/sys/compat/linuxkpi/common/include/linux/bitmap.h
new file mode 100644
index 000000000000..f26a0f99dc03
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/bitmap.h
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_BITMAP_H_
+#define _LINUXKPI_LINUX_BITMAP_H_
+
+#include <linux/bitops.h>
+#include <linux/slab.h>
+
+static inline void
+bitmap_zero(unsigned long *addr, const unsigned int size)
+{
+ memset(addr, 0, BITS_TO_LONGS(size) * sizeof(long));
+}
+
+static inline void
+bitmap_fill(unsigned long *addr, const unsigned int size)
+{
+ const unsigned int tail = size & (BITS_PER_LONG - 1);
+
+ memset(addr, 0xff, BIT_WORD(size) * sizeof(long));
+
+ if (tail)
+ addr[BIT_WORD(size)] = BITMAP_LAST_WORD_MASK(tail);
+}
+
+static inline int
+bitmap_full(unsigned long *addr, const unsigned int size)
+{
+ const unsigned int end = BIT_WORD(size);
+ const unsigned int tail = size & (BITS_PER_LONG - 1);
+ unsigned int i;
+
+ for (i = 0; i != end; i++) {
+ if (addr[i] != ~0UL)
+ return (0);
+ }
+
+ if (tail) {
+ const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
+
+ if ((addr[end] & mask) != mask)
+ return (0);
+ }
+ return (1);
+}
+
+static inline int
+bitmap_empty(unsigned long *addr, const unsigned int size)
+{
+ const unsigned int end = BIT_WORD(size);
+ const unsigned int tail = size & (BITS_PER_LONG - 1);
+ unsigned int i;
+
+ for (i = 0; i != end; i++) {
+ if (addr[i] != 0)
+ return (0);
+ }
+
+ if (tail) {
+ const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
+
+ if ((addr[end] & mask) != 0)
+ return (0);
+ }
+ return (1);
+}
+
+static inline void
+bitmap_set(unsigned long *map, unsigned int start, int nr)
+{
+ const unsigned int size = start + nr;
+ int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG);
+ unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start);
+
+ map += BIT_WORD(start);
+
+ while (nr - bits_to_set >= 0) {
+ *map |= mask_to_set;
+ nr -= bits_to_set;
+ bits_to_set = BITS_PER_LONG;
+ mask_to_set = ~0UL;
+ map++;
+ }
+
+ if (nr) {
+ mask_to_set &= BITMAP_LAST_WORD_MASK(size);
+ *map |= mask_to_set;
+ }
+}
+
+static inline void
+bitmap_clear(unsigned long *map, unsigned int start, int nr)
+{
+ const unsigned int size = start + nr;
+ int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
+ unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start);
+
+ map += BIT_WORD(start);
+
+ while (nr - bits_to_clear >= 0) {
+ *map &= ~mask_to_clear;
+ nr -= bits_to_clear;
+ bits_to_clear = BITS_PER_LONG;
+ mask_to_clear = ~0UL;
+ map++;
+ }
+
+ if (nr) {
+ mask_to_clear &= BITMAP_LAST_WORD_MASK(size);
+ *map &= ~mask_to_clear;
+ }
+}
+
+static inline unsigned int
+bitmap_find_next_zero_area_off(const unsigned long *map,
+ const unsigned int size, unsigned int start,
+ unsigned int nr, unsigned int align_mask,
+ unsigned int align_offset)
+{
+ unsigned int index;
+ unsigned int end;
+ unsigned int i;
+
+retry:
+ index = find_next_zero_bit(map, size, start);
+
+ index = (((index + align_offset) + align_mask) & ~align_mask) - align_offset;
+
+ end = index + nr;
+ if (end > size)
+ return (end);
+
+ i = find_next_bit(map, end, index);
+ if (i < end) {
+ start = i + 1;
+ goto retry;
+ }
+ return (index);
+}
+
+static inline unsigned int
+bitmap_find_next_zero_area(const unsigned long *map,
+ const unsigned int size, unsigned int start,
+ unsigned int nr, unsigned int align_mask)
+{
+ return (bitmap_find_next_zero_area_off(map, size,
+ start, nr, align_mask, 0));
+}
+
+static inline int
+bitmap_find_free_region(unsigned long *bitmap, int bits, int order)
+{
+ int pos;
+ int end;
+
+ for (pos = 0; (end = pos + (1 << order)) <= bits; pos = end) {
+ if (!linux_reg_op(bitmap, pos, order, REG_OP_ISFREE))
+ continue;
+ linux_reg_op(bitmap, pos, order, REG_OP_ALLOC);
+ return (pos);
+ }
+ return (-ENOMEM);
+}
+
+static inline int
+bitmap_allocate_region(unsigned long *bitmap, int pos, int order)
+{
+ if (!linux_reg_op(bitmap, pos, order, REG_OP_ISFREE))
+ return (-EBUSY);
+ linux_reg_op(bitmap, pos, order, REG_OP_ALLOC);
+ return (0);
+}
+
+static inline void
+bitmap_release_region(unsigned long *bitmap, int pos, int order)
+{
+ linux_reg_op(bitmap, pos, order, REG_OP_RELEASE);
+}
+
+static inline unsigned int
+bitmap_weight(unsigned long *addr, const unsigned int size)
+{
+ const unsigned int end = BIT_WORD(size);
+ const unsigned int tail = size & (BITS_PER_LONG - 1);
+ unsigned int retval = 0;
+ unsigned int i;
+
+ for (i = 0; i != end; i++)
+ retval += hweight_long(addr[i]);
+
+ if (tail) {
+ const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
+
+ retval += hweight_long(addr[end] & mask);
+ }
+ return (retval);
+}
+
+static inline int
+bitmap_equal(const unsigned long *pa,
+ const unsigned long *pb, unsigned size)
+{
+ const unsigned int end = BIT_WORD(size);
+ const unsigned int tail = size & (BITS_PER_LONG - 1);
+ unsigned int i;
+
+ for (i = 0; i != end; i++) {
+ if (pa[i] != pb[i])
+ return (0);
+ }
+
+ if (tail) {
+ const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
+
+ if ((pa[end] ^ pb[end]) & mask)
+ return (0);
+ }
+ return (1);
+}
+
+static inline int
+bitmap_subset(const unsigned long *pa,
+ const unsigned long *pb, unsigned size)
+{
+ const unsigned end = BIT_WORD(size);
+ const unsigned tail = size & (BITS_PER_LONG - 1);
+ unsigned i;
+
+ for (i = 0; i != end; i++) {
+ if (pa[i] & ~pb[i])
+ return (0);
+ }
+
+ if (tail) {
+ const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
+
+ if (pa[end] & ~pb[end] & mask)
+ return (0);
+ }
+ return (1);
+}
+
+static inline bool
+bitmap_intersects(const unsigned long *pa, const unsigned long *pb,
+ unsigned size)
+{
+ const unsigned end = BIT_WORD(size);
+ const unsigned tail = size & (BITS_PER_LONG - 1);
+ unsigned i;
+
+ for (i = 0; i != end; i++)
+ if (pa[i] & pb[i])
+ return (true);
+
+ if (tail) {
+ const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
+
+ if (pa[end] & pb[end] & mask)
+ return (true);
+ }
+ return (false);
+}
+
+static inline void
+bitmap_complement(unsigned long *dst, const unsigned long *src,
+ const unsigned int size)
+{
+ const unsigned int end = BITS_TO_LONGS(size);
+ unsigned int i;
+
+ for (i = 0; i != end; i++)
+ dst[i] = ~src[i];
+}
+
+static inline void
+bitmap_copy(unsigned long *dst, const unsigned long *src,
+ const unsigned int size)
+{
+ const unsigned int end = BITS_TO_LONGS(size);
+ unsigned int i;
+
+ for (i = 0; i != end; i++)
+ dst[i] = src[i];
+}
+
+static inline void
+bitmap_to_arr32(uint32_t *dst, const unsigned long *src, unsigned int size)
+{
+ const unsigned int end = howmany(size, 32);
+
+#ifdef __LP64__
+ unsigned int i = 0;
+ while (i < end) {
+ dst[i++] = (uint32_t)(*src & UINT_MAX);
+ if (i < end)
+ dst[i++] = (uint32_t)(*src >> 32);
+ src++;
+ }
+#else
+ bitmap_copy((unsigned long *)dst, src, size);
+#endif
+ if ((size % 32) != 0) /* Linux uses BITS_PER_LONG. Seems to be a bug */
+ dst[end - 1] &= (uint32_t)(UINT_MAX >> (32 - (size % 32)));
+}
+
+static inline void
+bitmap_from_arr32(unsigned long *dst, const uint32_t *src,
+ unsigned int size)
+{
+ const unsigned int end = BIT_WORD(size);
+ const unsigned int tail = size & (BITS_PER_LONG - 1);
+
+#ifdef __LP64__
+ const unsigned int end32 = howmany(size, 32);
+ unsigned int i = 0;
+
+ while (i < end32) {
+ dst[i++/2] = (unsigned long) *(src++);
+ if (i < end32)
+ dst[i++/2] |= ((unsigned long) *(src++)) << 32;
+ }
+#else
+ bitmap_copy(dst, (const unsigned long *)src, size);
+#endif
+ if ((size % BITS_PER_LONG) != 0)
+ dst[end] &= BITMAP_LAST_WORD_MASK(tail);
+}
+
+static inline void
+bitmap_or(unsigned long *dst, const unsigned long *src1,
+ const unsigned long *src2, const unsigned int size)
+{
+ const unsigned int end = BITS_TO_LONGS(size);
+ unsigned int i;
+
+ for (i = 0; i != end; i++)
+ dst[i] = src1[i] | src2[i];
+}
+
+static inline void
+bitmap_and(unsigned long *dst, const unsigned long *src1,
+ const unsigned long *src2, const unsigned int size)
+{
+ const unsigned int end = BITS_TO_LONGS(size);
+ unsigned int i;
+
+ for (i = 0; i != end; i++)
+ dst[i] = src1[i] & src2[i];
+}
+
+static inline void
+bitmap_andnot(unsigned long *dst, const unsigned long *src1,
+ const unsigned long *src2, const unsigned int size)
+{
+ const unsigned int end = BITS_TO_LONGS(size);
+ unsigned int i;
+
+ for (i = 0; i != end; i++)
+ dst[i] = src1[i] & ~src2[i];
+}
+
+static inline void
+bitmap_xor(unsigned long *dst, const unsigned long *src1,
+ const unsigned long *src2, const unsigned int size)
+{
+ const unsigned int end = BITS_TO_LONGS(size);
+ unsigned int i;
+
+ for (i = 0; i != end; i++)
+ dst[i] = src1[i] ^ src2[i];
+}
+
+static inline void
+bitmap_shift_right(unsigned long *dst, const unsigned long *src,
+ unsigned int shift, unsigned int size)
+{
+ const unsigned int end = BITS_TO_LONGS(size);
+ const unsigned int tail = size & (BITS_PER_LONG - 1);
+ const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
+ const unsigned int off = BIT_WORD(shift);
+ const unsigned int rem = shift & (BITS_PER_LONG - 1);
+ unsigned long left, right;
+ unsigned int i, srcpos;
+
+ for (i = 0, srcpos = off; srcpos < end; i++, srcpos++) {
+ right = src[srcpos];
+ left = 0;
+
+ if (srcpos == end - 1)
+ right &= mask;
+
+ if (rem != 0) {
+ right >>= rem;
+ if (srcpos + 1 < end) {
+ left = src[srcpos + 1];
+ if (srcpos + 1 == end - 1)
+ left &= mask;
+ left <<= (BITS_PER_LONG - rem);
+ }
+ }
+ dst[i] = left | right;
+ }
+ if (off != 0)
+ memset(dst + end - off, 0, off * sizeof(unsigned long));
+}
+
+static inline unsigned long *
+bitmap_alloc(unsigned int size, gfp_t flags)
+{
+ return (kmalloc_array(BITS_TO_LONGS(size),
+ sizeof(unsigned long), flags));
+}
+
+static inline unsigned long *
+bitmap_zalloc(unsigned int size, gfp_t flags)
+{
+ return (bitmap_alloc(size, flags | __GFP_ZERO));
+}
+
+static inline void
+bitmap_free(const unsigned long *bitmap)
+{
+ kfree(bitmap);
+}
+
+#endif /* _LINUXKPI_LINUX_BITMAP_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/bitops.h b/sys/compat/linuxkpi/common/include/linux/bitops.h
new file mode 100644
index 000000000000..bc776a0db9c4
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/bitops.h
@@ -0,0 +1,437 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_BITOPS_H_
+#define _LINUXKPI_LINUX_BITOPS_H_
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/libkern.h>
+
+#define BIT(nr) (1UL << (nr))
+#define BIT_ULL(nr) (1ULL << (nr))
+#ifdef __LP64__
+#define BITS_PER_LONG 64
+#else
+#define BITS_PER_LONG 32
+#endif
+
+#define BITS_PER_LONG_LONG 64
+
+#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG))
+#define BITMAP_LAST_WORD_MASK(n) (~0UL >> (BITS_PER_LONG - (n)))
+#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)
+
+#define HWEIGHT8(x) (bitcount8((uint8_t)(x)))
+#define HWEIGHT16(x) (bitcount16(x))
+#define HWEIGHT32(x) (bitcount32(x))
+#define HWEIGHT64(x) (bitcount64(x))
+
+static inline int
+__ffs(int mask)
+{
+ return (ffs(mask) - 1);
+}
+
+static inline int
+__fls(int mask)
+{
+ return (fls(mask) - 1);
+}
+
+static inline int
+__ffsl(long mask)
+{
+ return (ffsl(mask) - 1);
+}
+
+static inline unsigned long
+__ffs64(uint64_t mask)
+{
+ return (ffsll(mask) - 1);
+}
+
+static inline int
+__flsl(long mask)
+{
+ return (flsl(mask) - 1);
+}
+
+static inline int
+fls64(uint64_t mask)
+{
+ return (flsll(mask));
+}
+
+static inline uint32_t
+ror32(uint32_t word, unsigned int shift)
+{
+ return ((word >> shift) | (word << (32 - shift)));
+}
+
+#define ffz(mask) __ffs(~(mask))
+
+static inline int get_count_order(unsigned int count)
+{
+ int order;
+
+ order = fls(count) - 1;
+ if (count & (count - 1))
+ order++;
+ return order;
+}
+
+static inline unsigned long
+find_first_bit(const unsigned long *addr, unsigned long size)
+{
+ long mask;
+ int bit;
+
+ for (bit = 0; size >= BITS_PER_LONG;
+ size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {
+ if (*addr == 0)
+ continue;
+ return (bit + __ffsl(*addr));
+ }
+ if (size) {
+ mask = (*addr) & BITMAP_LAST_WORD_MASK(size);
+ if (mask)
+ bit += __ffsl(mask);
+ else
+ bit += size;
+ }
+ return (bit);
+}
+
+static inline unsigned long
+find_first_zero_bit(const unsigned long *addr, unsigned long size)
+{
+ long mask;
+ int bit;
+
+ for (bit = 0; size >= BITS_PER_LONG;
+ size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {
+ if (~(*addr) == 0)
+ continue;
+ return (bit + __ffsl(~(*addr)));
+ }
+ if (size) {
+ mask = ~(*addr) & BITMAP_LAST_WORD_MASK(size);
+ if (mask)
+ bit += __ffsl(mask);
+ else
+ bit += size;
+ }
+ return (bit);
+}
+
+static inline unsigned long
+find_last_bit(const unsigned long *addr, unsigned long size)
+{
+ long mask;
+ int offs;
+ int bit;
+ int pos;
+
+ pos = size / BITS_PER_LONG;
+ offs = size % BITS_PER_LONG;
+ bit = BITS_PER_LONG * pos;
+ addr += pos;
+ if (offs) {
+ mask = (*addr) & BITMAP_LAST_WORD_MASK(offs);
+ if (mask)
+ return (bit + __flsl(mask));
+ }
+ while (pos--) {
+ addr--;
+ bit -= BITS_PER_LONG;
+ if (*addr)
+ return (bit + __flsl(*addr));
+ }
+ return (size);
+}
+
+static inline unsigned long
+find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset)
+{
+ long mask;
+ int offs;
+ int bit;
+ int pos;
+
+ if (offset >= size)
+ return (size);
+ pos = offset / BITS_PER_LONG;
+ offs = offset % BITS_PER_LONG;
+ bit = BITS_PER_LONG * pos;
+ addr += pos;
+ if (offs) {
+ mask = (*addr) & ~BITMAP_LAST_WORD_MASK(offs);
+ if (mask)
+ return (bit + __ffsl(mask));
+ if (size - bit <= BITS_PER_LONG)
+ return (size);
+ bit += BITS_PER_LONG;
+ addr++;
+ }
+ for (size -= bit; size >= BITS_PER_LONG;
+ size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {
+ if (*addr == 0)
+ continue;
+ return (bit + __ffsl(*addr));
+ }
+ if (size) {
+ mask = (*addr) & BITMAP_LAST_WORD_MASK(size);
+ if (mask)
+ bit += __ffsl(mask);
+ else
+ bit += size;
+ }
+ return (bit);
+}
+
+static inline unsigned long
+find_next_zero_bit(const unsigned long *addr, unsigned long size,
+ unsigned long offset)
+{
+ long mask;
+ int offs;
+ int bit;
+ int pos;
+
+ if (offset >= size)
+ return (size);
+ pos = offset / BITS_PER_LONG;
+ offs = offset % BITS_PER_LONG;
+ bit = BITS_PER_LONG * pos;
+ addr += pos;
+ if (offs) {
+ mask = ~(*addr) & ~BITMAP_LAST_WORD_MASK(offs);
+ if (mask)
+ return (bit + __ffsl(mask));
+ if (size - bit <= BITS_PER_LONG)
+ return (size);
+ bit += BITS_PER_LONG;
+ addr++;
+ }
+ for (size -= bit; size >= BITS_PER_LONG;
+ size -= BITS_PER_LONG, bit += BITS_PER_LONG, addr++) {
+ if (~(*addr) == 0)
+ continue;
+ return (bit + __ffsl(~(*addr)));
+ }
+ if (size) {
+ mask = ~(*addr) & BITMAP_LAST_WORD_MASK(size);
+ if (mask)
+ bit += __ffsl(mask);
+ else
+ bit += size;
+ }
+ return (bit);
+}
+
+#define __set_bit(i, a) \
+ atomic_set_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))
+
+#define set_bit(i, a) \
+ atomic_set_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))
+
+#define __clear_bit(i, a) \
+ atomic_clear_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))
+
+#define clear_bit(i, a) \
+ atomic_clear_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))
+
+#define clear_bit_unlock(i, a) \
+ atomic_clear_rel_long(&((volatile unsigned long *)(a))[BIT_WORD(i)], BIT_MASK(i))
+
+#define test_bit(i, a) \
+ !!(READ_ONCE(((volatile const unsigned long *)(a))[BIT_WORD(i)]) & BIT_MASK(i))
+
+static inline void
+__assign_bit(long bit, volatile unsigned long *addr, bool value)
+{
+ if (value)
+ __set_bit(bit, addr);
+ else
+ __clear_bit(bit, addr);
+}
+
+static inline int
+test_and_clear_bit(long bit, volatile unsigned long *var)
+{
+ long val;
+
+ var += BIT_WORD(bit);
+ bit %= BITS_PER_LONG;
+ bit = (1UL << bit);
+
+ val = *var;
+ while (!atomic_fcmpset_long(var, &val, val & ~bit))
+ ;
+ return !!(val & bit);
+}
+
+static inline int
+__test_and_clear_bit(long bit, volatile unsigned long *var)
+{
+ long val;
+
+ var += BIT_WORD(bit);
+ bit %= BITS_PER_LONG;
+ bit = (1UL << bit);
+
+ val = *var;
+ *var &= ~bit;
+
+ return !!(val & bit);
+}
+
+static inline int
+test_and_set_bit(long bit, volatile unsigned long *var)
+{
+ long val;
+
+ var += BIT_WORD(bit);
+ bit %= BITS_PER_LONG;
+ bit = (1UL << bit);
+
+ val = *var;
+ while (!atomic_fcmpset_long(var, &val, val | bit))
+ ;
+ return !!(val & bit);
+}
+
+static inline int
+__test_and_set_bit(long bit, volatile unsigned long *var)
+{
+ long val;
+
+ var += BIT_WORD(bit);
+ bit %= BITS_PER_LONG;
+ bit = (1UL << bit);
+
+ val = *var;
+ *var |= bit;
+
+ return !!(val & bit);
+}
+
+enum {
+ REG_OP_ISFREE,
+ REG_OP_ALLOC,
+ REG_OP_RELEASE,
+};
+
+static inline int
+linux_reg_op(unsigned long *bitmap, int pos, int order, int reg_op)
+{
+ int nbits_reg;
+ int index;
+ int offset;
+ int nlongs_reg;
+ int nbitsinlong;
+ unsigned long mask;
+ int i;
+ int ret = 0;
+
+ nbits_reg = 1 << order;
+ index = pos / BITS_PER_LONG;
+ offset = pos - (index * BITS_PER_LONG);
+ nlongs_reg = BITS_TO_LONGS(nbits_reg);
+ nbitsinlong = MIN(nbits_reg, BITS_PER_LONG);
+
+ mask = (1UL << (nbitsinlong - 1));
+ mask += mask - 1;
+ mask <<= offset;
+
+ switch (reg_op) {
+ case REG_OP_ISFREE:
+ for (i = 0; i < nlongs_reg; i++) {
+ if (bitmap[index + i] & mask)
+ goto done;
+ }
+ ret = 1;
+ break;
+
+ case REG_OP_ALLOC:
+ for (i = 0; i < nlongs_reg; i++)
+ bitmap[index + i] |= mask;
+ break;
+
+ case REG_OP_RELEASE:
+ for (i = 0; i < nlongs_reg; i++)
+ bitmap[index + i] &= ~mask;
+ break;
+ }
+done:
+ return ret;
+}
+
+#define for_each_set_bit(bit, addr, size) \
+ for ((bit) = find_first_bit((addr), (size)); \
+ (bit) < (size); \
+ (bit) = find_next_bit((addr), (size), (bit) + 1))
+
+#define for_each_clear_bit(bit, addr, size) \
+ for ((bit) = find_first_zero_bit((addr), (size)); \
+ (bit) < (size); \
+ (bit) = find_next_zero_bit((addr), (size), (bit) + 1))
+
+static inline uint64_t
+sign_extend64(uint64_t value, int index)
+{
+ uint8_t shift = 63 - index;
+
+ return ((int64_t)(value << shift) >> shift);
+}
+
+static inline uint32_t
+sign_extend32(uint32_t value, int index)
+{
+ uint8_t shift = 31 - index;
+
+ return ((int32_t)(value << shift) >> shift);
+}
+
+#endif /* _LINUXKPI_LINUX_BITOPS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/bottom_half.h b/sys/compat/linuxkpi/common/include/linux/bottom_half.h
new file mode 100644
index 000000000000..12b170845cbc
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/bottom_half.h
@@ -0,0 +1,32 @@
+/*-
+ * Copyright (c) 2017 Hans Petter Selasky
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_BOTTOM_HALF_H_
+#define _LINUXKPI_LINUX_BOTTOM_HALF_H_
+
+extern void local_bh_enable(void);
+extern void local_bh_disable(void);
+
+#endif /* _LINUXKPI_LINUX_BOTTOM_HALF_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/bsearch.h b/sys/compat/linuxkpi/common/include/linux/bsearch.h
new file mode 100644
index 000000000000..fb67109e4bba
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/bsearch.h
@@ -0,0 +1,36 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb 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_BSEARCH_H
+#define _LINUXKPI_LINUX_BSEARCH_H
+
+#include <sys/libkern.h>
+
+#endif /* _LINUXKPI_LINUX_BSEARCH_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/build_bug.h b/sys/compat/linuxkpi/common/include/linux/build_bug.h
new file mode 100644
index 000000000000..6a026376cfc8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/build_bug.h
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org>
+ * Copyright (c) 2018 Johannes Lundberg <johalun0@gmail.com>
+ * Copyright (c) 2021 The FreeBSD Foundation
+ * Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
+ * Copyright (c) 2023 Serenity Cyber Security, LLC
+ *
+ * Portions of this software were developed by Bjoern A. Zeeb
+ * 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 unmodified, 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 ``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 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_BUILD_BUG_H_
+#define _LINUXKPI_LINUX_BUILD_BUG_H_
+
+#include <sys/param.h>
+
+#include <linux/compiler.h>
+
+/*
+ * BUILD_BUG_ON() can happen inside functions where _Static_assert() does not
+ * seem to work. Use old-schoold-ish CTASSERT from before commit
+ * a3085588a88fa58eb5b1eaae471999e1995a29cf but also make sure we do not
+ * end up with an unused typedef or variable. The compiler should optimise
+ * it away entirely.
+ */
+#define _O_CTASSERT(x) _O__CTASSERT(x, __LINE__)
+#define _O__CTASSERT(x, y) _O___CTASSERT(x, y)
+#define _O___CTASSERT(x, y) while (0) { \
+ typedef char __assert_line_ ## y[(x) ? 1 : -1]; \
+ __assert_line_ ## y _x __unused; \
+ _x[0] = '\0'; \
+}
+
+#define BUILD_BUG() do { CTASSERT(0); } while (0)
+#define BUILD_BUG_ON(x) do { _O_CTASSERT(!(x)) } while (0)
+#define BUILD_BUG_ON_MSG(x, msg) BUILD_BUG_ON(x)
+#define BUILD_BUG_ON_NOT_POWER_OF_2(x) BUILD_BUG_ON(!powerof2(x))
+#define BUILD_BUG_ON_INVALID(expr) while (0) { (void)(expr); }
+#define BUILD_BUG_ON_ZERO(x) ((int)sizeof(struct { int:-((x) != 0); }))
+
+#define static_assert(x, ...) __static_assert(x, ##__VA_ARGS__, #x)
+#define __static_assert(x, msg, ...) _Static_assert(x, msg)
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/cache.h b/sys/compat/linuxkpi/common/include/linux/cache.h
new file mode 100644
index 000000000000..b02b28d08ea9
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/cache.h
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_CACHE_H_
+#define _LINUXKPI_LINUX_CACHE_H_
+
+#include <sys/param.h>
+
+#define cache_line_size() CACHE_LINE_SIZE
+#define L1_CACHE_BYTES CACHE_LINE_SIZE
+#define L1_CACHE_ALIGN(x) ALIGN(x, CACHE_LINE_SIZE)
+
+#define SMP_CACHE_BYTES L1_CACHE_BYTES
+
+#endif /* _LINUXKPI_LINUX_CACHE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/capability.h b/sys/compat/linuxkpi/common/include/linux/capability.h
new file mode 100644
index 000000000000..e3dacd4e9f15
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/capability.h
@@ -0,0 +1,51 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2015 Rimvydas Jasinskas
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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.
+ */
+
+/*
+ * linux/capability.h
+ *
+ * Simple capable() priv_check helper
+ */
+
+#ifndef _LINUXKPI_LINUX_CAPABILITY_H
+#define _LINUXKPI_LINUX_CAPABILITY_H
+
+#include <sys/types.h>
+#include <sys/proc.h>
+#include <sys/priv.h>
+
+#define CAP_SYS_ADMIN PRIV_DRIVER
+#define CAP_SYS_NICE PRIV_SCHED_SETPRIORITY
+
+static inline bool
+capable(const int tryme)
+{
+ return (priv_check(curthread, tryme) == 0);
+}
+
+#endif /* _LINUXKPI_LINUX_CAPABILITY_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/cc_platform.h b/sys/compat/linuxkpi/common/include/linux/cc_platform.h
new file mode 100644
index 000000000000..1544c141614b
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/cc_platform.h
@@ -0,0 +1,21 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_CC_PLATFORM_H_
+#define _LINUXKPI_LINUX_CC_PLATFORM_H_
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+
+enum cc_attr {
+ CC_ATTR_MEM_ENCRYPT,
+ CC_ATTR_GUEST_MEM_ENCRYPT,
+};
+
+static inline bool
+cc_platform_has(enum cc_attr attr __unused)
+{
+
+ return (false);
+}
+
+#endif /* _LINUXKPI_LINUX_CC_PLATFORM_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/cdev.h b/sys/compat/linuxkpi/common/include/linux/cdev.h
new file mode 100644
index 000000000000..d989db14c2f8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/cdev.h
@@ -0,0 +1,146 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2021 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_CDEV_H_
+#define _LINUXKPI_LINUX_CDEV_H_
+
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/kdev_t.h>
+#include <linux/list.h>
+
+#include <asm/atomic-long.h>
+
+struct device;
+struct file_operations;
+struct inode;
+struct module;
+
+extern struct cdevsw linuxcdevsw;
+extern const struct kobj_type linux_cdev_ktype;
+extern const struct kobj_type linux_cdev_static_ktype;
+
+struct linux_cdev {
+ struct kobject kobj;
+ struct module *owner;
+ struct cdev *cdev;
+ dev_t dev;
+ const struct file_operations *ops;
+ u_int refs;
+ u_int siref;
+};
+
+struct linux_cdev *cdev_alloc(void);
+
+static inline void
+cdev_init(struct linux_cdev *cdev, const struct file_operations *ops)
+{
+
+ kobject_init(&cdev->kobj, &linux_cdev_static_ktype);
+ cdev->ops = ops;
+ cdev->refs = 1;
+}
+
+static inline void
+cdev_put(struct linux_cdev *p)
+{
+ kobject_put(&p->kobj);
+}
+
+static inline int
+cdev_add(struct linux_cdev *cdev, dev_t dev, unsigned count)
+{
+ struct make_dev_args args;
+ int error;
+
+ if (count != 1)
+ return (-EINVAL);
+
+ cdev->dev = dev;
+
+ /* Setup arguments for make_dev_s() */
+ make_dev_args_init(&args);
+ args.mda_devsw = &linuxcdevsw;
+ args.mda_uid = 0;
+ args.mda_gid = 0;
+ args.mda_mode = 0700;
+ args.mda_si_drv1 = cdev;
+
+ error = make_dev_s(&args, &cdev->cdev, "%s",
+ kobject_name(&cdev->kobj));
+ if (error)
+ return (-error);
+
+ kobject_get(cdev->kobj.parent);
+ return (0);
+}
+
+static inline int
+cdev_add_ext(struct linux_cdev *cdev, dev_t dev, uid_t uid, gid_t gid, int mode)
+{
+ struct make_dev_args args;
+ int error;
+
+ cdev->dev = dev;
+
+ /* Setup arguments for make_dev_s() */
+ make_dev_args_init(&args);
+ args.mda_devsw = &linuxcdevsw;
+ args.mda_uid = uid;
+ args.mda_gid = gid;
+ args.mda_mode = mode;
+ args.mda_si_drv1 = cdev;
+
+ error = make_dev_s(&args, &cdev->cdev, "%s/%d",
+ kobject_name(&cdev->kobj), MINOR(dev));
+ if (error)
+ return (-error);
+
+ kobject_get(cdev->kobj.parent);
+ return (0);
+}
+
+static inline void
+cdev_del(struct linux_cdev *cdev)
+{
+ kobject_put(&cdev->kobj);
+}
+
+struct linux_cdev *linux_find_cdev(const char *name, unsigned major, unsigned minor);
+
+int linux_cdev_device_add(struct linux_cdev *, struct device *);
+void linux_cdev_device_del(struct linux_cdev *, struct device *);
+
+#define cdev_device_add(...) \
+ linux_cdev_device_add(__VA_ARGS__)
+#define cdev_device_del(...) \
+ linux_cdev_device_del(__VA_ARGS__)
+
+#define cdev linux_cdev
+
+#endif /* _LINUXKPI_LINUX_CDEV_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/cec.h b/sys/compat/linuxkpi/common/include/linux/cec.h
new file mode 100644
index 000000000000..e0854d87d85c
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/cec.h
@@ -0,0 +1,8 @@
+/* Public domain */
+
+#ifndef _LINUXKPI_LINUX_CEC_H_
+#define _LINUXKPI_LINUX_CEC_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
new file mode 100644
index 000000000000..a9dd22fd0f4c
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/cgroup.h
@@ -0,0 +1,34 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
+ *
+ * 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_CGROUP_H_
+#define _LINUXKPI_LINUX_CGROUP_H_
+
+#include <linux/kernel_stat.h>
+
+#endif /* _LINUXKPI_LINUX_CGROUP_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/circ_buf.h b/sys/compat/linuxkpi/common/include/linux/circ_buf.h
new file mode 100644
index 000000000000..53d7fa736ef8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/circ_buf.h
@@ -0,0 +1,34 @@
+/*-
+ * Copyright (c) 2022 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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_CIRC_BUF_H_
+#define _LINUXKPI_LINUX_CIRC_BUF_H_
+
+#define CIRC_CNT(head,tail,size) (((head) - (tail)) & ((size) - 1))
+#define CIRC_SPACE(head,tail,size) CIRC_CNT((tail),((head) + 1),(size))
+
+#endif /* _LINUXKPI_LINUX_CIRC_BUF_H_ */
+
diff --git a/sys/compat/linuxkpi/common/include/linux/cleanup.h b/sys/compat/linuxkpi/common/include/linux/cleanup.h
new file mode 100644
index 000000000000..01f234f0cbe7
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/cleanup.h
@@ -0,0 +1,46 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb under sponsorship from
+ * the FreeBSD Foundation.
+ */
+
+#ifndef _LINUXKPI_LINUX_CLEANUP_H
+#define _LINUXKPI_LINUX_CLEANUP_H
+
+#define __cleanup(_f) __attribute__((__cleanup__(_f)))
+
+/*
+ * 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; \
+ \
+ static inline _dt \
+ guard_ ## _n ## _create( _dt _T) \
+ { \
+ _dt c; \
+ \
+ c = ({ _lock; _T; }); \
+ return (c); \
+ } \
+ \
+ static inline void \
+ guard_ ## _n ## _destroy(_dt *t) \
+ { \
+ _dt _T; \
+ \
+ _T = *t; \
+ if (_T) { _unlock; }; \
+ }
+
+/* We need to keep these calls unique. */
+#define guard(_n) \
+ guard_ ## _n ## _t guard_ ## _n ## _ ## __COUNTER__ \
+ __cleanup(guard_ ## _n ## _destroy) = guard_ ## _n ## _create
+
+#endif /* _LINUXKPI_LINUX_CLEANUP_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/clocksource.h b/sys/compat/linuxkpi/common/include/linux/clocksource.h
new file mode 100644
index 000000000000..3e7664c3e57e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/clocksource.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_CLOCKSOURCE_H
+#define _LINUXKPI_LINUX_CLOCKSOURCE_H
+
+#include <asm/types.h>
+
+#define CLOCKSOURCE_MASK(x) ((u64)(-1ULL >> ((-(x)) & 63)))
+
+#endif /* _LINUXKPI_LINUX_CLOCKSOURCE_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/compat.h b/sys/compat/linuxkpi/common/include/linux/compat.h
new file mode 100644
index 000000000000..8a5a6918bb7c
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/compat.h
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_COMPAT_H_
+#define _LINUXKPI_LINUX_COMPAT_H_
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+
+struct domainset;
+struct thread;
+struct task_struct;
+
+extern int linux_alloc_current(struct thread *, int flags);
+extern void linux_free_current(struct task_struct *);
+extern struct domainset *linux_get_vm_domain_set(int node);
+
+#define __current_unallocated(td) \
+ __predict_false((td)->td_lkpi_task == NULL)
+
+static inline void
+linux_set_current(struct thread *td)
+{
+ if (__current_unallocated(td))
+ lkpi_alloc_current(td, M_WAITOK);
+}
+
+static inline int
+linux_set_current_flags(struct thread *td, int flags)
+{
+ if (__current_unallocated(td))
+ return (lkpi_alloc_current(td, flags));
+ return (0);
+}
+
+#define compat_ptr(x) ((void *)(uintptr_t)x)
+#define ptr_to_compat(x) ((uintptr_t)x)
+
+typedef void fpu_safe_exec_cb_t(void *ctx);
+void lkpi_fpu_safe_exec(fpu_safe_exec_cb_t func, void *ctx);
+
+#endif /* _LINUXKPI_LINUX_COMPAT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/compiler.h b/sys/compat/linuxkpi/common/include/linux/compiler.h
new file mode 100644
index 000000000000..fb5ad3bf4fe4
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/compiler.h
@@ -0,0 +1,133 @@
+/*-
+ * 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.
+ *
+ * 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 unmodified, 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 ``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 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_COMPILER_H_
+#define _LINUXKPI_LINUX_COMPILER_H_
+
+#include <sys/cdefs.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)
+#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
+#define __counted_by(_x)
+#endif
+
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#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); \
+ barrier(); \
+} while (0)
+
+#define READ_ONCE(x) ({ \
+ __typeof(x) __var = ({ \
+ barrier(); \
+ (*(const volatile __typeof(x) *)&(x)); \
+ }); \
+ barrier(); \
+ __var; \
+})
+
+#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)
+
+#define is_signed_type(t) ((t)-1 < (t)1)
+#define is_unsigned_type(t) ((t)-1 > (t)1)
+
+#endif /* _LINUXKPI_LINUX_COMPILER_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/completion.h b/sys/compat/linuxkpi/common/include/linux/completion.h
new file mode 100644
index 000000000000..9f8bebb4cf82
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/completion.h
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_COMPLETION_H_
+#define _LINUXKPI_LINUX_COMPLETION_H_
+
+#include <linux/errno.h>
+
+struct completion {
+ unsigned int done;
+};
+
+#define INIT_COMPLETION(c) \
+ ((c).done = 0)
+#define init_completion(c) \
+ do { (c)->done = 0; } while (0)
+#define reinit_completion(c) \
+ do { (c)->done = 0; } while (0)
+#define complete(c) \
+ linux_complete_common((c), 0)
+#define complete_all(c) \
+ linux_complete_common((c), 1)
+#define wait_for_completion(c) \
+ linux_wait_for_common((c), 0)
+#define wait_for_completion_interruptible(c) \
+ linux_wait_for_common((c), 1)
+#define wait_for_completion_timeout(c, timeout) \
+ linux_wait_for_timeout_common((c), (timeout), 0)
+#define wait_for_completion_interruptible_timeout(c, timeout) \
+ linux_wait_for_timeout_common((c), (timeout), 1)
+#define try_wait_for_completion(c) \
+ linux_try_wait_for_completion(c)
+#define completion_done(c) \
+ linux_completion_done(c)
+
+extern void linux_complete_common(struct completion *, int);
+extern int linux_wait_for_common(struct completion *, int);
+extern unsigned long linux_wait_for_timeout_common(struct completion *,
+ unsigned long, int);
+extern int linux_try_wait_for_completion(struct completion *);
+extern int linux_completion_done(struct completion *);
+
+#endif /* _LINUXKPI_LINUX_COMPLETION_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/console.h b/sys/compat/linuxkpi/common/include/linux/console.h
new file mode 100644
index 000000000000..09f486203815
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/console.h
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2022 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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_CONSOLE_H_
+#define _LINUXKPI_LINUX_CONSOLE_H_
+
+#include <linux/types.h>
+
+static inline void
+console_lock(void)
+{
+}
+
+static inline int
+console_trylock(void)
+{
+ return (1);
+}
+
+static inline void
+console_unlock(void)
+{
+}
+
+static inline bool
+vgacon_text_force(void)
+{
+
+ return (false);
+}
+
+#endif /* _LINUXKPI_LINUX_CONSOLE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/container_of.h b/sys/compat/linuxkpi/common/include/linux/container_of.h
new file mode 100644
index 000000000000..7210d531b055
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/container_of.h
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2017 Matt Macy <mmacy@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_CONTAINER_OF_H
+#define _LINUXKPI_LINUX_CONTAINER_OF_H
+
+#include <sys/stdint.h>
+
+#include <linux/build_bug.h>
+#include <linux/stddef.h>
+
+#define container_of(ptr, type, member) \
+({ \
+ const __typeof(((type *)0)->member) *__p = (ptr); \
+ (type *)((uintptr_t)__p - offsetof(type, member)); \
+})
+
+#define container_of_const(ptr, type, member) \
+ _Generic(ptr, \
+ const typeof(*(ptr)) *: \
+ (const type *)container_of(ptr, type, member), \
+ default: \
+ container_of(ptr, type, member) \
+ )
+
+#define typeof_member(type, member) __typeof(((type *)0)->member)
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/cpu.h b/sys/compat/linuxkpi/common/include/linux/cpu.h
new file mode 100644
index 000000000000..43ec3d66a2e3
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/cpu.h
@@ -0,0 +1,78 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020-2021 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb 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_CPU_H
+#define _LINUXKPI_LINUX_CPU_H
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/cpuset.h>
+#include <sys/smp.h>
+#include <linux/compiler.h>
+#include <linux/slab.h>
+
+typedef cpuset_t cpumask_t;
+
+extern cpumask_t cpu_online_mask;
+
+cpumask_t *lkpi_get_static_single_cpu_mask(int);
+
+static __inline int
+cpumask_next(int cpuid, cpumask_t mask)
+{
+
+ /*
+ * -1 can be an input to cpuid according to logic in drivers
+ * but is never a valid cpuid in a set!
+ */
+ KASSERT((cpuid >= -1 && cpuid <= MAXCPU), ("%s: invalid cpuid %d\n",
+ __func__, cpuid));
+ KASSERT(!CPU_EMPTY(&mask), ("%s: empty CPU mask", __func__));
+
+ do {
+ cpuid++;
+#ifdef SMP
+ if (cpuid > mp_maxid)
+#endif
+ cpuid = 0;
+ } while (!CPU_ISSET(cpuid, &mask));
+ return (cpuid);
+}
+
+static __inline void
+cpumask_set_cpu(int cpu, cpumask_t *mask)
+{
+
+ CPU_SET(cpu, mask);
+}
+
+#define cpumask_of(_cpu) (lkpi_get_static_single_cpu_mask(_cpu))
+
+#endif /* _LINUXKPI_LINUX_CPU_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/cpufeature.h b/sys/compat/linuxkpi/common/include/linux/cpufeature.h
new file mode 100644
index 000000000000..746d1a7164a8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/cpufeature.h
@@ -0,0 +1,43 @@
+/*-
+ * 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_CPUFEATURE_H_
+#define _LINUXKPI_LINUX_CPUFEATURE_H_
+
+/*
+ * Linux includes the following header. We don't have it on FreeBSD yet, so
+ * let's comment this include for now. It is still referenced here because
+ * sometimes, consumers of headers rely voluntarily or not on the namespace
+ * pollution.
+ */
+/* #include <linux/init.h> */
+#include <linux/mod_devicetable.h>
+#include <asm/cpufeature.h>
+
+#endif /* _LINUXKPI_LINUX_CPUFEATURE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/crc32.h b/sys/compat/linuxkpi/common/include/linux/crc32.h
new file mode 100644
index 000000000000..e6d39fa7c5ff
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/crc32.h
@@ -0,0 +1,43 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb 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_CRC32_H
+#define _LINUXKPI_LINUX_CRC32_H
+
+#include <sys/gsb_crc32.h>
+
+static __inline uint32_t
+crc32_le(uint32_t crc, const void *data, size_t len)
+{
+
+ return (crc32_raw(data, len, crc));
+}
+
+#endif /* _LINUXKPI_LINUX_CRC32_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/dcache.h b/sys/compat/linuxkpi/common/include/linux/dcache.h
new file mode 100644
index 000000000000..992d6f7c2720
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/dcache.h
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2017 Limelight Networks, Inc.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_DCACHE_H
+#define _LINUXKPI_LINUX_DCACHE_H
+
+#include <sys/vnode.h>
+
+#include <fs/pseudofs/pseudofs.h>
+
+struct dentry {
+ struct vnode *d_inode;
+ struct pfs_node *d_pfs_node; /* FreeBSD specific field */
+};
+
+static inline struct vnode *
+d_inode(const struct dentry *dentry)
+{
+ return (dentry->d_inode);
+}
+
+#endif /* _LINUXKPI_LINUX_DCACHE_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/debugfs.h b/sys/compat/linuxkpi/common/include/linux/debugfs.h
new file mode 100644
index 000000000000..4d146e085a7b
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/debugfs.h
@@ -0,0 +1,124 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2016-2018, Matthew Macy <mmacy@freebsd.org>
+ *
+ * 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_DEBUGFS_H_
+#define _LINUXKPI_LINUX_DEBUGFS_H_
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/types.h>
+
+MALLOC_DECLARE(M_DFSINT);
+
+struct debugfs_reg32 {
+ char *name;
+ unsigned long offset;
+};
+
+struct debugfs_regset32 {
+ const struct debugfs_reg32 *regs;
+ int nregs;
+};
+
+struct debugfs_blob_wrapper {
+ void *data;
+ size_t size;
+};
+
+static inline bool
+debugfs_initialized(void)
+{
+
+ return (true);
+}
+
+struct dentry *debugfs_create_file(const char *name, umode_t mode,
+ struct dentry *parent, void *data,
+ const struct file_operations *fops);
+
+/* TODO: We currently ignore the `file_size` argument. */
+struct dentry *debugfs_create_file_size(const char *name, umode_t mode,
+ struct dentry *parent, void *data,
+ const struct file_operations *fops,
+ loff_t file_size);
+
+struct dentry *debugfs_create_file_unsafe(const char *name, umode_t mode,
+struct dentry *parent, void *data,
+ const struct file_operations *fops);
+
+struct dentry *debugfs_create_mode_unsafe(const char *name, umode_t mode,
+ struct dentry *parent, void *data,
+ const struct file_operations *fops,
+ const struct file_operations *fops_ro,
+ const struct file_operations *fops_wo);
+
+struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
+
+struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
+ const char *dest);
+
+struct dentry *debugfs_lookup(const char *name, struct dentry *parent);
+
+void debugfs_remove(struct dentry *dentry);
+
+void debugfs_remove_recursive(struct dentry *dentry);
+
+#define DEFINE_DEBUGFS_ATTRIBUTE(__fops, __get, __set, __fmt) \
+ DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt)
+#define DEFINE_DEBUGFS_ATTRIBUTE_SIGNED(__fops, __get, __set, __fmt) \
+ DEFINE_SIMPLE_ATTRIBUTE_SIGNED(__fops, __get, __set, __fmt)
+
+void debugfs_create_bool(const char *name, umode_t mode, struct dentry *parent,
+ bool *value);
+void debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent,
+ uint8_t *value);
+void debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent,
+ uint16_t *value);
+void debugfs_create_u32(const char *name, umode_t mode, struct dentry *parent,
+ uint32_t *value);
+void debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent,
+ uint64_t *value);
+void debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent,
+ uint8_t *value);
+void debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent,
+ uint16_t *value);
+void debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent,
+ uint32_t *value);
+void debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent,
+ uint64_t *value);
+void debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent,
+ unsigned long *value);
+void debugfs_create_atomic_t(const char *name, umode_t mode, struct dentry *parent,
+ atomic_t *value);
+void debugfs_create_str(const char *name, umode_t mode, struct dentry *parent,
+ char **value);
+
+struct dentry *debugfs_create_blob(const char *name, umode_t mode,
+ struct dentry *parent, struct debugfs_blob_wrapper *value);
+
+#endif /* _LINUXKPI_LINUX_DEBUGFS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/delay.h b/sys/compat/linuxkpi/common/include/linux/delay.h
new file mode 100644
index 000000000000..f19d1a759c26
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/delay.h
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2021 Mellanox Technologies, Ltd.
+ * Copyright (c) 2014 François Tigeot
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_DELAY_H_
+#define _LINUXKPI_LINUX_DELAY_H_
+
+#include <linux/jiffies.h>
+#include <sys/systm.h>
+
+static inline void
+linux_msleep(unsigned int ms)
+{
+ /* guard against invalid values */
+ if (ms == 0)
+ ms = 1;
+ pause_sbt("lnxsleep", mstosbt(ms), 0, C_HARDCLOCK);
+}
+
+#undef msleep
+#define msleep(ms) linux_msleep(ms)
+
+#undef msleep_interruptible
+#define msleep_interruptible(ms) linux_msleep_interruptible(ms)
+
+#define udelay(t) DELAY(t)
+
+static inline void
+mdelay(unsigned long msecs)
+{
+ while (msecs--)
+ DELAY(1000);
+}
+
+static inline void
+ndelay(unsigned long x)
+{
+ DELAY(howmany(x, 1000));
+}
+
+static inline void
+usleep_range(unsigned long min, unsigned long max)
+{
+ /* guard against invalid values */
+ if (min == 0)
+ min = 1;
+ pause_sbt("lnxsleep", ustosbt(min), 0, C_HARDCLOCK);
+}
+
+extern unsigned int linux_msleep_interruptible(unsigned int ms);
+
+static inline void
+fsleep(unsigned long us)
+{
+
+ if (us < 10)
+ udelay(us);
+ else
+ usleep_range(us, us);
+}
+
+#endif /* _LINUXKPI_LINUX_DELAY_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/devcoredump.h b/sys/compat/linuxkpi/common/include/linux/devcoredump.h
new file mode 100644
index 000000000000..5fa06c6595a8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/devcoredump.h
@@ -0,0 +1,81 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020-2025 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb 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_DEVCOREDUMP_H
+#define _LINUXKPI_LINUX_DEVCOREDUMP_H
+
+#include <linux/slab.h>
+#include <linux/scatterlist.h>
+#include <linux/device.h>
+
+static inline void
+_lkpi_dev_coredumpsg_free(struct scatterlist *table)
+{
+ struct scatterlist *iter;
+ struct page *p;
+ int i;
+
+ iter = table;
+ for_each_sg(table, iter, sg_nents(table), i) {
+ p = sg_page(iter);
+ if (p)
+ __free_page(p);
+ }
+
+ /* XXX what about chained tables? */
+ kfree(table);
+}
+
+static inline void
+dev_coredumpv(struct device *dev __unused, void *data, size_t datalen __unused,
+ gfp_t gfp __unused)
+{
+
+ /* UNIMPLEMENTED */
+ vfree(data);
+}
+
+static inline void
+dev_coredumpsg(struct device *dev __unused, struct scatterlist *table,
+ size_t datalen __unused, gfp_t gfp __unused)
+{
+
+ /* UNIMPLEMENTED */
+ _lkpi_dev_coredumpsg_free(table);
+}
+
+static inline void
+_devcd_free_sgtable(struct scatterlist *table)
+{
+ /* UNIMPLEMENTED */
+ _lkpi_dev_coredumpsg_free(table);
+}
+
+#endif /* _LINUXKPI_LINUX_DEVCOREDUMP_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/device.h b/sys/compat/linuxkpi/common/include/linux/device.h
new file mode 100644
index 000000000000..2556b0c45e49
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/device.h
@@ -0,0 +1,718 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ * Copyright (c) 2021-2022 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * 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 unmodified, 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 ``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 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_DEVICE_H_
+#define _LINUXKPI_LINUX_DEVICE_H_
+
+#include <linux/err.h>
+#include <linux/types.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/compiler.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <linux/kdev_t.h>
+#include <linux/backlight.h>
+#include <linux/pm.h>
+#include <linux/idr.h>
+#include <linux/overflow.h>
+#include <linux/ratelimit.h> /* via linux/dev_printk.h */
+#include <linux/fwnode.h>
+#include <asm/atomic.h>
+
+#include <sys/bus.h>
+#include <sys/backlight.h>
+
+struct device;
+
+struct class {
+ const char *name;
+ struct kobject kobj;
+ devclass_t bsdclass;
+ const struct dev_pm_ops *pm;
+ const struct attribute_group **dev_groups;
+ void (*class_release)(struct class *class);
+ void (*dev_release)(struct device *dev);
+ char * (*devnode)(struct device *dev, umode_t *mode);
+};
+
+struct dev_pm_ops {
+ int (*prepare)(struct device *dev);
+ void (*complete)(struct device *dev);
+ int (*suspend)(struct device *dev);
+ int (*suspend_late)(struct device *dev);
+ int (*resume)(struct device *dev);
+ int (*resume_early)(struct device *dev);
+ int (*freeze)(struct device *dev);
+ int (*freeze_late)(struct device *dev);
+ int (*thaw)(struct device *dev);
+ int (*thaw_early)(struct device *dev);
+ int (*poweroff)(struct device *dev);
+ int (*poweroff_late)(struct device *dev);
+ int (*restore)(struct device *dev);
+ int (*restore_early)(struct device *dev);
+ int (*suspend_noirq)(struct device *dev);
+ int (*runtime_suspend)(struct device *dev);
+ int (*runtime_resume)(struct device *dev);
+ int (*runtime_idle)(struct device *dev);
+};
+
+struct device_driver {
+ const char *name;
+ const struct dev_pm_ops *pm;
+
+ void (*shutdown) (struct device *);
+};
+
+struct device_type {
+ const char *name;
+};
+
+struct device {
+ struct device *parent;
+ struct list_head irqents;
+ device_t bsddev;
+ /*
+ * The following flag is used to determine if the LinuxKPI is
+ * responsible for detaching the BSD device or not. If the
+ * LinuxKPI got the BSD device using devclass_get_device(), it
+ * must not try to detach or delete it, because it's already
+ * done somewhere else.
+ */
+ bool bsddev_attached_here;
+ struct device_driver *driver;
+ struct device_type *type;
+ dev_t devt;
+ struct class *class;
+ void (*release)(struct device *dev);
+ struct kobject kobj;
+ void *dma_priv;
+ void *driver_data;
+ unsigned int irq;
+#define LINUX_IRQ_INVALID 65535
+ unsigned int irq_start;
+ unsigned int irq_end;
+ const struct attribute_group **groups;
+ struct fwnode_handle *fwnode;
+ struct cdev *backlight_dev;
+ struct backlight_device *bd;
+
+ spinlock_t devres_lock;
+ struct list_head devres_head;
+
+ struct dev_pm_info power;
+};
+
+extern struct device linux_root_device;
+extern struct kobject linux_class_root;
+extern const struct kobj_type linux_dev_ktype;
+extern const struct kobj_type linux_class_ktype;
+
+struct class_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct class *, struct class_attribute *, char *);
+ ssize_t (*store)(struct class *, struct class_attribute *, const char *, size_t);
+ const void *(*namespace)(struct class *, const struct class_attribute *);
+};
+
+#define CLASS_ATTR(_name, _mode, _show, _store) \
+ struct class_attribute class_attr_##_name = \
+ { { #_name, NULL, _mode }, _show, _store }
+
+struct device_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct device *,
+ struct device_attribute *, char *);
+ ssize_t (*store)(struct device *,
+ struct device_attribute *, const char *,
+ size_t);
+};
+
+#define DEVICE_ATTR(_name, _mode, _show, _store) \
+ struct device_attribute dev_attr_##_name = \
+ __ATTR(_name, _mode, _show, _store)
+#define DEVICE_ATTR_RO(_name) \
+ struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
+#define DEVICE_ATTR_WO(_name) \
+ struct device_attribute dev_attr_##_name = __ATTR_WO(_name)
+#define DEVICE_ATTR_RW(_name) \
+ struct device_attribute dev_attr_##_name = __ATTR_RW(_name)
+
+/* Simple class attribute that is just a static string */
+struct class_attribute_string {
+ struct class_attribute attr;
+ char *str;
+};
+
+static inline ssize_t
+show_class_attr_string(struct class *class,
+ struct class_attribute *attr, char *buf)
+{
+ struct class_attribute_string *cs;
+ cs = container_of(attr, struct class_attribute_string, attr);
+ return snprintf(buf, PAGE_SIZE, "%s\n", cs->str);
+}
+
+/* Currently read-only only */
+#define _CLASS_ATTR_STRING(_name, _mode, _str) \
+ { __ATTR(_name, _mode, show_class_attr_string, NULL), _str }
+#define CLASS_ATTR_STRING(_name, _mode, _str) \
+ struct class_attribute_string class_attr_##_name = \
+ _CLASS_ATTR_STRING(_name, _mode, _str)
+
+#define dev_printk(lvl, dev, fmt, ...) \
+ device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+
+#define dev_emerg(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+#define dev_alert(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+#define dev_crit(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+#define dev_err(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+#define dev_warn(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+#define dev_notice(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+#define dev_info(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+#define dev_dbg(dev, fmt, ...) do { } while (0)
+
+#define dev_WARN(dev, fmt, ...) \
+ device_printf((dev)->bsddev, "%s:%d: " fmt, __func__, __LINE__, ##__VA_ARGS__)
+
+#define dev_WARN_ONCE(dev, condition, fmt, ...) do { \
+ static bool __dev_WARN_ONCE; \
+ bool __ret_warn_on = (condition); \
+ if (unlikely(__ret_warn_on)) { \
+ if (!__dev_WARN_ONCE) { \
+ __dev_WARN_ONCE = true; \
+ device_printf((dev)->bsddev, "%s:%d: " fmt, __func__, __LINE__, ##__VA_ARGS__); \
+ } \
+ } \
+} while (0)
+
+#define dev_info_once(dev, ...) do { \
+ static bool __dev_info_once; \
+ if (!__dev_info_once) { \
+ __dev_info_once = true; \
+ dev_info(dev, __VA_ARGS__); \
+ } \
+} while (0)
+
+#define dev_warn_once(dev, ...) do { \
+ static bool __dev_warn_once; \
+ if (!__dev_warn_once) { \
+ __dev_warn_once = 1; \
+ dev_warn(dev, __VA_ARGS__); \
+ } \
+} while (0)
+
+#define dev_err_once(dev, ...) do { \
+ static bool __dev_err_once; \
+ if (!__dev_err_once) { \
+ __dev_err_once = 1; \
+ dev_err(dev, __VA_ARGS__); \
+ } \
+} while (0)
+
+#define dev_dbg_once(dev, ...) do { \
+ static bool __dev_dbg_once; \
+ if (!__dev_dbg_once) { \
+ __dev_dbg_once = 1; \
+ dev_dbg(dev, __VA_ARGS__); \
+ } \
+} while (0)
+
+#define dev_err_ratelimited(dev, ...) do { \
+ static linux_ratelimit_t __ratelimited; \
+ if (linux_ratelimited(&__ratelimited)) \
+ dev_err(dev, __VA_ARGS__); \
+} while (0)
+
+#define dev_warn_ratelimited(dev, ...) do { \
+ static linux_ratelimit_t __ratelimited; \
+ if (linux_ratelimited(&__ratelimited)) \
+ dev_warn(dev, __VA_ARGS__); \
+} while (0)
+
+#define dev_dbg_ratelimited(dev, ...) do { \
+ static linux_ratelimit_t __ratelimited; \
+ if (linux_ratelimited(&__ratelimited)) \
+ dev_dbg(dev, __VA_ARGS__); \
+} while (0)
+
+/* 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 *);
+void lkpi_devres_free(void *);
+void *lkpi_devres_find(struct device *, void(*release)(struct device *, void *),
+ int (*match)(struct device *, void *, void *), void *);
+int lkpi_devres_destroy(struct device *, void(*release)(struct device *, void *),
+ int (*match)(struct device *, void *, void *), void *);
+#define devres_alloc(_r, _s, _g) lkpi_devres_alloc(_r, _s, _g)
+#define devres_add(_d, _p) lkpi_devres_add(_d, _p)
+#define devres_free(_p) lkpi_devres_free(_p)
+#define devres_find(_d, _rfn, _mfn, _mp) \
+ lkpi_devres_find(_d, _rfn, _mfn, _mp)
+#define devres_destroy(_d, _rfn, _mfn, _mp) \
+ lkpi_devres_destroy(_d, _rfn, _mfn, _mp)
+void lkpi_devres_release_free_list(struct device *);
+void lkpi_devres_unlink(struct device *, void *);
+void lkpi_devm_kmalloc_release(struct device *, void *);
+#define devm_kfree(_d, _p) lkpi_devm_kmalloc_release(_d, _p)
+
+static inline const char *
+dev_driver_string(const struct device *dev)
+{
+ driver_t *drv;
+ const char *str = "";
+
+ if (dev->bsddev != NULL) {
+ drv = device_get_driver(dev->bsddev);
+ if (drv != NULL)
+ str = drv->name;
+ }
+
+ return (str);
+}
+
+static inline void *
+dev_get_drvdata(const struct device *dev)
+{
+
+ return dev->driver_data;
+}
+
+static inline void
+dev_set_drvdata(struct device *dev, void *data)
+{
+
+ dev->driver_data = data;
+}
+
+static inline struct device *
+get_device(struct device *dev)
+{
+
+ if (dev)
+ kobject_get(&dev->kobj);
+
+ return (dev);
+}
+
+static inline char *
+dev_name(const struct device *dev)
+{
+
+ return kobject_name(&dev->kobj);
+}
+
+static inline bool
+dev_is_removable(struct device *dev)
+{
+
+ return (false);
+}
+
+#define dev_set_name(_dev, _fmt, ...) \
+ kobject_set_name(&(_dev)->kobj, (_fmt), ##__VA_ARGS__)
+
+static inline void
+put_device(struct device *dev)
+{
+
+ if (dev)
+ kobject_put(&dev->kobj);
+}
+
+struct class *lkpi_class_create(const char *name);
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 60400
+#define class_create(name) lkpi_class_create(name)
+#else
+#define class_create(owner, name) lkpi_class_create(name)
+#endif
+
+static inline int
+class_register(struct class *class)
+{
+
+ class->bsdclass = devclass_create(class->name);
+ kobject_init(&class->kobj, &linux_class_ktype);
+ kobject_set_name(&class->kobj, class->name);
+ kobject_add(&class->kobj, &linux_class_root, class->name);
+
+ return (0);
+}
+
+static inline void
+class_unregister(struct class *class)
+{
+
+ kobject_put(&class->kobj);
+}
+
+static inline struct device *kobj_to_dev(struct kobject *kobj)
+{
+ return container_of(kobj, struct device, kobj);
+}
+
+struct device *device_create(struct class *class, struct device *parent,
+ dev_t devt, void *drvdata, const char *fmt, ...);
+struct device *device_create_groups_vargs(struct class *class, struct device *parent,
+ dev_t devt, void *drvdata, const struct attribute_group **groups,
+ const char *fmt, va_list args);
+
+/*
+ * Devices are registered and created for exporting to sysfs. Create
+ * implies register and register assumes the device fields have been
+ * setup appropriately before being called.
+ */
+static inline void
+device_initialize(struct device *dev)
+{
+ device_t bsddev = NULL;
+ int unit = -1;
+
+ if (dev->devt) {
+ unit = MINOR(dev->devt);
+ bsddev = devclass_get_device(dev->class->bsdclass, unit);
+ dev->bsddev_attached_here = false;
+ } else if (dev->parent == NULL) {
+ bsddev = devclass_get_device(dev->class->bsdclass, 0);
+ dev->bsddev_attached_here = false;
+ } else {
+ dev->bsddev_attached_here = true;
+ }
+
+ if (bsddev == NULL && dev->parent != NULL) {
+ bsddev = device_add_child(dev->parent->bsddev,
+ dev->class->kobj.name, unit);
+ }
+
+ if (bsddev != NULL)
+ device_set_softc(bsddev, dev);
+
+ dev->bsddev = bsddev;
+ MPASS(dev->bsddev != NULL);
+ kobject_init(&dev->kobj, &linux_dev_ktype);
+
+ spin_lock_init(&dev->devres_lock);
+ INIT_LIST_HEAD(&dev->devres_head);
+}
+
+static inline int
+device_add(struct device *dev)
+{
+ if (dev->bsddev != NULL) {
+ if (dev->devt == 0)
+ dev->devt = makedev(0, device_get_unit(dev->bsddev));
+ }
+ kobject_add(&dev->kobj, &dev->class->kobj, dev_name(dev));
+
+ if (dev->groups)
+ return (sysfs_create_groups(&dev->kobj, dev->groups));
+
+ return (0);
+}
+
+static inline void
+device_create_release(struct device *dev)
+{
+ kfree(dev);
+}
+
+static inline struct device *
+device_create_with_groups(struct class *class,
+ struct device *parent, dev_t devt, void *drvdata,
+ const struct attribute_group **groups, const char *fmt, ...)
+{
+ va_list vargs;
+ struct device *dev;
+
+ va_start(vargs, fmt);
+ dev = device_create_groups_vargs(class, parent, devt, drvdata,
+ groups, fmt, vargs);
+ va_end(vargs);
+ return dev;
+}
+
+static inline bool
+device_is_registered(struct device *dev)
+{
+
+ return (dev->bsddev != NULL);
+}
+
+static inline int
+device_register(struct device *dev)
+{
+ device_t bsddev = NULL;
+ int unit = -1;
+
+ if (device_is_registered(dev))
+ goto done;
+
+ if (dev->devt) {
+ unit = MINOR(dev->devt);
+ bsddev = devclass_get_device(dev->class->bsdclass, unit);
+ dev->bsddev_attached_here = false;
+ } else if (dev->parent == NULL) {
+ bsddev = devclass_get_device(dev->class->bsdclass, 0);
+ dev->bsddev_attached_here = false;
+ } else {
+ dev->bsddev_attached_here = true;
+ }
+ if (bsddev == NULL && dev->parent != NULL) {
+ bsddev = device_add_child(dev->parent->bsddev,
+ dev->class->kobj.name, unit);
+ }
+ if (bsddev != NULL) {
+ if (dev->devt == 0)
+ dev->devt = makedev(0, device_get_unit(bsddev));
+ device_set_softc(bsddev, dev);
+ }
+ dev->bsddev = bsddev;
+done:
+ kobject_init(&dev->kobj, &linux_dev_ktype);
+ kobject_add(&dev->kobj, &dev->class->kobj, dev_name(dev));
+
+ sysfs_create_groups(&dev->kobj, dev->class->dev_groups);
+
+ return (0);
+}
+
+static inline void
+device_unregister(struct device *dev)
+{
+ device_t bsddev;
+
+ sysfs_remove_groups(&dev->kobj, dev->class->dev_groups);
+
+ bsddev = dev->bsddev;
+ dev->bsddev = NULL;
+
+ if (bsddev != NULL && dev->bsddev_attached_here) {
+ bus_topo_lock();
+ device_delete_child(device_get_parent(bsddev), bsddev);
+ bus_topo_unlock();
+ }
+ put_device(dev);
+}
+
+static inline void
+device_del(struct device *dev)
+{
+ device_t bsddev;
+
+ bsddev = dev->bsddev;
+ dev->bsddev = NULL;
+
+ if (bsddev != NULL && dev->bsddev_attached_here) {
+ bus_topo_lock();
+ device_delete_child(device_get_parent(bsddev), bsddev);
+ bus_topo_unlock();
+ }
+}
+
+static inline void
+device_destroy(struct class *class, dev_t devt)
+{
+ device_t bsddev;
+ int unit;
+
+ unit = MINOR(devt);
+ bsddev = devclass_get_device(class->bsdclass, unit);
+ if (bsddev != NULL)
+ device_unregister(device_get_softc(bsddev));
+}
+
+static inline void
+device_release_driver(struct device *dev)
+{
+
+#if 0
+ /* This leads to panics. Disable temporarily. Keep to rework. */
+
+ /* We also need to cleanup LinuxKPI bits. What else? */
+ lkpi_devres_release_free_list(dev);
+ dev_set_drvdata(dev, NULL);
+ /* Do not call dev->release! */
+
+ bus_topo_lock();
+ if (device_is_attached(dev->bsddev))
+ device_detach(dev->bsddev);
+ bus_topo_unlock();
+#endif
+}
+
+static inline int
+device_reprobe(struct device *dev)
+{
+ int error;
+
+ device_release_driver(dev);
+ bus_topo_lock();
+ error = device_probe_and_attach(dev->bsddev);
+ bus_topo_unlock();
+
+ return (-error);
+}
+
+static inline void
+device_set_wakeup_enable(struct device *dev __unused, bool enable __unused)
+{
+
+ /*
+ * XXX-BZ TODO This is used by wireless drivers supporting WoWLAN which
+ * we currently do not support.
+ */
+}
+
+static inline int
+device_wakeup_enable(struct device *dev)
+{
+
+ device_set_wakeup_enable(dev, true);
+ return (0);
+}
+
+static inline bool
+device_iommu_mapped(struct device *dev __unused)
+{
+ return (false);
+}
+
+#define dev_pm_set_driver_flags(dev, flags) do { \
+} while (0)
+
+static inline void
+linux_class_kfree(struct class *class)
+{
+
+ kfree(class);
+}
+
+static inline void
+class_destroy(struct class *class)
+{
+
+ if (class == NULL)
+ return;
+ class_unregister(class);
+}
+
+static inline int
+device_create_file(struct device *dev, const struct device_attribute *attr)
+{
+
+ if (dev)
+ return sysfs_create_file(&dev->kobj, &attr->attr);
+ return -EINVAL;
+}
+
+static inline void
+device_remove_file(struct device *dev, const struct device_attribute *attr)
+{
+
+ if (dev)
+ sysfs_remove_file(&dev->kobj, &attr->attr);
+}
+
+static inline int
+class_create_file(struct class *class, const struct class_attribute *attr)
+{
+
+ if (class)
+ return sysfs_create_file(&class->kobj, &attr->attr);
+ return -EINVAL;
+}
+
+static inline void
+class_remove_file(struct class *class, const struct class_attribute *attr)
+{
+
+ if (class)
+ sysfs_remove_file(&class->kobj, &attr->attr);
+}
+
+#define dev_to_node(dev) linux_dev_to_node(dev)
+#define of_node_to_nid(node) -1
+int linux_dev_to_node(struct device *);
+
+char *kvasprintf(gfp_t, const char *, va_list);
+char *kasprintf(gfp_t, const char *, ...);
+char *lkpi_devm_kasprintf(struct device *, gfp_t, const char *, ...);
+
+#define devm_kasprintf(_dev, _gfp, _fmt, ...) \
+ lkpi_devm_kasprintf(_dev, _gfp, _fmt, ##__VA_ARGS__)
+
+static __inline void *
+devm_kmalloc(struct device *dev, size_t size, gfp_t gfp)
+{
+ void *p;
+
+ p = lkpi_devres_alloc(lkpi_devm_kmalloc_release, size, gfp);
+ if (p != NULL)
+ lkpi_devres_add(dev, p);
+
+ return (p);
+}
+
+static inline void *
+devm_kmemdup(struct device *dev, const void *src, size_t len, gfp_t gfp)
+{
+ void *dst;
+
+ if (len == 0)
+ return (NULL);
+
+ dst = devm_kmalloc(dev, len, gfp);
+ if (dst != NULL)
+ memcpy(dst, src, len);
+
+ return (dst);
+}
+
+#define devm_kzalloc(_dev, _size, _gfp) \
+ devm_kmalloc((_dev), (_size), (_gfp) | __GFP_ZERO)
+
+#define devm_kcalloc(_dev, _sizen, _size, _gfp) \
+ devm_kmalloc((_dev), ((_sizen) * (_size)), (_gfp) | __GFP_ZERO)
+
+int lkpi_devm_add_action(struct device *dev, void (*action)(void *), void *data);
+#define devm_add_action(dev, action, data) \
+ lkpi_devm_add_action(dev, action, data);
+int lkpi_devm_add_action_or_reset(struct device *dev, void (*action)(void *), void *data);
+#define devm_add_action_or_reset(dev, action, data) \
+ lkpi_devm_add_action_or_reset(dev, action, data)
+
+int lkpi_devm_device_add_group(struct device *dev, const struct attribute_group *group);
+#define devm_device_add_group(dev, group) \
+ lkpi_devm_device_add_group(dev, group)
+
+#endif /* _LINUXKPI_LINUX_DEVICE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/device/driver.h b/sys/compat/linuxkpi/common/include/linux/device/driver.h
new file mode 100644
index 000000000000..03b510c9c8b7
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/device/driver.h
@@ -0,0 +1,33 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Bjoern A. Zeeb
+ * Copyright (c) 2024 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * under sponsorship from the FreeBSD Foundation.
+ */
+
+#ifndef LINUXKPI_LINUX_DEVICE_DRIVER_H
+#define LINUXKPI_LINUX_DEVICE_DRIVER_H
+
+#include <sys/cdefs.h>
+#include <linux/module.h>
+
+#define module_driver(_drv, _regf, _unregf) \
+static inline int \
+__CONCAT(__CONCAT(_, _drv), _init)(void) \
+{ \
+ return (_regf(&(_drv))); \
+} \
+ \
+static inline void \
+__CONCAT(__CONCAT(_, _drv), _exit)(void) \
+{ \
+ _unregf(&(_drv)); \
+} \
+ \
+module_init(__CONCAT(__CONCAT(_, _drv), _init)); \
+module_exit(__CONCAT(__CONCAT(_, _drv), _exit))
+
+#endif /* LINUXKPI_LINUX_DEVICE_DRIVER_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/dma-attrs.h b/sys/compat/linuxkpi/common/include/linux/dma-attrs.h
new file mode 100644
index 000000000000..c9cfa9b621d5
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/dma-attrs.h
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_DMA_ATTR_H_
+#define _LINUXKPI_LINUX_DMA_ATTR_H_
+
+#define DMA_ATTR_WRITE_BARRIER (1 << 0)
+#define DMA_ATTR_WEAK_ORDERING (1 << 1)
+#define DMA_ATTR_WRITE_COMBINE (1 << 2)
+#define DMA_ATTR_NON_CONSISTENT (1 << 3)
+#define DMA_ATTR_NO_KERNEL_MAPPING (1 << 4)
+#define DMA_ATTR_SKIP_CPU_SYNC (1 << 5)
+#define DMA_ATTR_FORCE_CONTIGUOUS (1 << 6)
+#define DMA_ATTR_ALLOC_SINGLE_PAGES (1 << 7)
+#define DMA_ATTR_NO_WARN (1 << 8)
+#define DMA_ATTR_PRIVILEGED (1 << 9)
+
+struct dma_attrs {
+ unsigned long flags;
+};
+#define DEFINE_DMA_ATTRS(x) struct dma_attrs x = { }
+
+static inline void
+init_dma_attrs(struct dma_attrs *attrs)
+{
+ attrs->flags = 0;
+}
+
+#endif /* _LINUXKPI_LINUX_DMA_ATTR_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/dma-buf-map.h b/sys/compat/linuxkpi/common/include/linux/dma-buf-map.h
new file mode 100644
index 000000000000..567ce3b072b3
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/dma-buf-map.h
@@ -0,0 +1,91 @@
+/* Public domain. */
+
+#ifndef _LINUX_DMA_BUF_MAP_H
+#define _LINUX_DMA_BUF_MAP_H
+
+#include <linux/io.h>
+#include <linux/string.h>
+
+struct dma_buf_map {
+ union {
+ void *vaddr_iomem;
+ void *vaddr;
+ };
+ bool is_iomem;
+};
+
+static inline void
+dma_buf_map_incr(struct dma_buf_map *dbm, size_t n)
+{
+ if (dbm->is_iomem)
+ dbm->vaddr_iomem += n;
+ else
+ dbm->vaddr += n;
+}
+
+static inline void
+dma_buf_map_memcpy_to(struct dma_buf_map *dbm, const void *src, size_t len)
+{
+ if (dbm->is_iomem)
+ memcpy_toio(dbm->vaddr_iomem, src, len);
+ else
+ memcpy(dbm->vaddr, src, len);
+}
+
+static inline bool
+dma_buf_map_is_null(const struct dma_buf_map *dbm)
+{
+ if (dbm->is_iomem)
+ return (dbm->vaddr_iomem == NULL);
+ else
+ return (dbm->vaddr == NULL);
+}
+
+static inline bool
+dma_buf_map_is_set(const struct dma_buf_map *dbm)
+{
+ if (dbm->is_iomem)
+ return (dbm->vaddr_iomem != NULL);
+ else
+ return (dbm->vaddr != NULL);
+}
+
+static inline bool
+dma_buf_map_is_equal(
+ const struct dma_buf_map *dbm_a, const struct dma_buf_map *dbm_b)
+{
+ if (dbm_a->is_iomem != dbm_b->is_iomem)
+ return (false);
+
+ if (dbm_a->is_iomem)
+ return (dbm_a->vaddr_iomem == dbm_b->vaddr_iomem);
+ else
+ return (dbm_a->vaddr == dbm_b->vaddr);
+}
+
+static inline void
+dma_buf_map_clear(struct dma_buf_map *dbm)
+{
+ if (dbm->is_iomem) {
+ dbm->vaddr_iomem = NULL;
+ dbm->is_iomem = false;
+ } else {
+ dbm->vaddr = NULL;
+ }
+}
+
+static inline void
+dma_buf_map_set_vaddr_iomem(struct dma_buf_map *dbm, void *addr)
+{
+ dbm->vaddr_iomem = addr;
+ dbm->is_iomem = true;
+}
+
+static inline void
+dma_buf_map_set_vaddr(struct dma_buf_map *dbm, void *addr)
+{
+ dbm->vaddr = addr;
+ dbm->is_iomem = false;
+}
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/dma-mapping.h b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h
new file mode 100644
index 000000000000..2d8e1196d3d3
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h
@@ -0,0 +1,399 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_DMA_MAPPING_H_
+#define _LINUXKPI_LINUX_DMA_MAPPING_H_
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/dma-attrs.h>
+#include <linux/scatterlist.h>
+#include <linux/mm.h>
+#include <linux/page.h>
+#include <linux/sizes.h>
+
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/uma_align_mask.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+
+enum dma_data_direction {
+ DMA_BIDIRECTIONAL = 0,
+ DMA_TO_DEVICE = 1,
+ DMA_FROM_DEVICE = 2,
+ DMA_NONE = 3,
+};
+
+struct dma_map_ops {
+ void* (*alloc_coherent)(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp);
+ void (*free_coherent)(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle);
+ dma_addr_t (*map_page)(struct device *dev, struct page *page,
+ unsigned long offset, size_t size, enum dma_data_direction dir,
+ unsigned long attrs);
+ void (*unmap_page)(struct device *dev, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction dir, unsigned long attrs);
+ int (*map_sg)(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir, unsigned long attrs);
+ void (*unmap_sg)(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction dir, unsigned long attrs);
+ void (*sync_single_for_cpu)(struct device *dev, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction dir);
+ void (*sync_single_for_device)(struct device *dev,
+ dma_addr_t dma_handle, size_t size, enum dma_data_direction dir);
+ void (*sync_single_range_for_cpu)(struct device *dev,
+ dma_addr_t dma_handle, unsigned long offset, size_t size,
+ enum dma_data_direction dir);
+ void (*sync_single_range_for_device)(struct device *dev,
+ dma_addr_t dma_handle, unsigned long offset, size_t size,
+ enum dma_data_direction dir);
+ void (*sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir);
+ void (*sync_sg_for_device)(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir);
+ int (*mapping_error)(struct device *dev, dma_addr_t dma_addr);
+ int (*dma_supported)(struct device *dev, u64 mask);
+ int is_phys;
+};
+
+#define DMA_BIT_MASK(n) ((2ULL << ((n) - 1)) - 1ULL)
+
+int linux_dma_tag_init(struct device *, u64);
+int linux_dma_tag_init_coherent(struct device *, u64);
+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);
+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);
+void linux_dma_unmap(struct device *dev, dma_addr_t dma_addr, size_t size); /* backward compat */
+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);
+void linux_dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg,
+ int nents __unused, enum dma_data_direction direction,
+ unsigned long attrs __unused);
+void linuxkpi_dma_sync(struct device *, dma_addr_t, size_t, bus_dmasync_op_t);
+
+static inline int
+dma_supported(struct device *dev, u64 dma_mask)
+{
+
+ /* XXX busdma takes care of this elsewhere. */
+ return (1);
+}
+
+static inline int
+dma_set_mask(struct device *dev, u64 dma_mask)
+{
+
+ if (!dev->dma_priv || !dma_supported(dev, dma_mask))
+ return -EIO;
+
+ return (linux_dma_tag_init(dev, dma_mask));
+}
+
+static inline int
+dma_set_coherent_mask(struct device *dev, u64 dma_mask)
+{
+
+ if (!dev->dma_priv || !dma_supported(dev, dma_mask))
+ return -EIO;
+
+ return (linux_dma_tag_init_coherent(dev, dma_mask));
+}
+
+static inline int
+dma_set_mask_and_coherent(struct device *dev, u64 dma_mask)
+{
+ int r;
+
+ r = dma_set_mask(dev, dma_mask);
+ if (r == 0)
+ dma_set_coherent_mask(dev, dma_mask);
+ return (r);
+}
+
+static inline void *
+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+ gfp_t flag)
+{
+ return (linux_dma_alloc_coherent(dev, size, dma_handle, flag));
+}
+
+static inline void *
+dma_zalloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+ gfp_t flag)
+{
+
+ return (dma_alloc_coherent(dev, size, dma_handle, flag | __GFP_ZERO));
+}
+
+static inline void *
+dmam_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+ gfp_t flag)
+{
+
+ return (linuxkpi_dmam_alloc_coherent(dev, size, dma_handle, flag));
+}
+
+static inline void
+dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
+ dma_addr_t dma_addr)
+{
+
+ lkpi_dma_unmap(dev, dma_addr, size, DMA_BIDIRECTIONAL, 0);
+ kmem_free(cpu_addr, size);
+}
+
+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)
+{
+
+ return (lkpi_dma_map_phys(dev, page_to_phys(page) + offset, size,
+ direction, attrs));
+}
+
+/* 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)
+
+#define dma_unmap_sg_attrs(dev, sg, nents, dir, attrs) \
+ linux_dma_unmap_sg_attrs(dev, sg, nents, dir, 0)
+
+static inline dma_addr_t
+dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size, enum dma_data_direction direction)
+{
+
+ return (lkpi_dma_map_phys(dev, page_to_phys(page) + offset, size,
+ direction, 0));
+}
+
+static inline void
+dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
+ enum dma_data_direction direction)
+{
+
+ lkpi_dma_unmap(dev, dma_address, size, direction, 0);
+}
+
+static inline dma_addr_t
+dma_map_resource(struct device *dev, phys_addr_t paddr, size_t size,
+ enum dma_data_direction direction, unsigned long attrs)
+{
+ return (lkpi_dma_map_phys(dev, paddr, size, direction, attrs));
+}
+
+static inline void
+dma_unmap_resource(struct device *dev, dma_addr_t dma, size_t size,
+ enum dma_data_direction direction, unsigned long attrs)
+{
+ lkpi_dma_unmap(dev, dma, size, direction, attrs);
+}
+
+static inline void
+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma, size_t size,
+ enum dma_data_direction direction)
+{
+ bus_dmasync_op_t op;
+
+ switch (direction) {
+ case DMA_BIDIRECTIONAL:
+ op = BUS_DMASYNC_POSTREAD;
+ linuxkpi_dma_sync(dev, dma, size, op);
+ op = BUS_DMASYNC_PREREAD;
+ break;
+ case DMA_TO_DEVICE:
+ op = BUS_DMASYNC_POSTWRITE;
+ break;
+ case DMA_FROM_DEVICE:
+ op = BUS_DMASYNC_POSTREAD;
+ break;
+ default:
+ return;
+ }
+
+ linuxkpi_dma_sync(dev, dma, size, op);
+}
+
+static inline void
+dma_sync_single(struct device *dev, dma_addr_t addr, size_t size,
+ enum dma_data_direction dir)
+{
+ dma_sync_single_for_cpu(dev, addr, size, dir);
+}
+
+static inline void
+dma_sync_single_for_device(struct device *dev, dma_addr_t dma,
+ size_t size, enum dma_data_direction direction)
+{
+ bus_dmasync_op_t op;
+
+ switch (direction) {
+ case DMA_BIDIRECTIONAL:
+ op = BUS_DMASYNC_PREWRITE;
+ break;
+ case DMA_TO_DEVICE:
+ op = BUS_DMASYNC_PREREAD;
+ break;
+ case DMA_FROM_DEVICE:
+ op = BUS_DMASYNC_PREWRITE;
+ break;
+ default:
+ return;
+ }
+
+ linuxkpi_dma_sync(dev, dma, size, op);
+}
+
+/* (20250329) These four seem to be unused code. */
+static inline void
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
+ enum dma_data_direction direction)
+{
+ pr_debug("%s:%d: TODO dir %d\n", __func__, __LINE__, direction);
+}
+
+static inline void
+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
+ enum dma_data_direction direction)
+{
+ pr_debug("%s:%d: TODO dir %d\n", __func__, __LINE__, direction);
+}
+
+static inline void
+dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+ unsigned long offset, size_t size, enum dma_data_direction direction)
+{
+ pr_debug("%s:%d: TODO dir %d\n", __func__, __LINE__, direction);
+}
+
+static inline void
+dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
+ unsigned long offset, size_t size, enum dma_data_direction direction)
+{
+ pr_debug("%s:%d: TODO dir %d\n", __func__, __LINE__, direction);
+}
+
+#define DMA_MAPPING_ERROR (~(dma_addr_t)0)
+
+static inline int
+dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+
+ if (dma_addr == 0 || dma_addr == DMA_MAPPING_ERROR)
+ return (-ENOMEM);
+ return (0);
+}
+
+static inline unsigned int dma_set_max_seg_size(struct device *dev,
+ unsigned int size)
+{
+ return (0);
+}
+
+static inline dma_addr_t
+_dma_map_single_attrs(struct device *dev, void *ptr, size_t size,
+ enum dma_data_direction direction, unsigned long attrs)
+{
+ return (lkpi_dma_map_phys(dev, vtophys(ptr), size,
+ direction, attrs));
+}
+
+static inline void
+_dma_unmap_single_attrs(struct device *dev, dma_addr_t dma, size_t size,
+ enum dma_data_direction direction, unsigned long attrs)
+{
+ lkpi_dma_unmap(dev, dma, size, direction, attrs);
+}
+
+static inline size_t
+dma_max_mapping_size(struct device *dev)
+{
+
+ return (SCATTERLIST_MAX_SEGMENT);
+}
+
+#define dma_map_single_attrs(dev, ptr, size, dir, attrs) \
+ _dma_map_single_attrs(dev, ptr, size, dir, 0)
+
+#define dma_unmap_single_attrs(dev, dma_addr, size, dir, attrs) \
+ _dma_unmap_single_attrs(dev, dma_addr, size, dir, 0)
+
+#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)
+#define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, 0)
+#define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, 0)
+
+#define DEFINE_DMA_UNMAP_ADDR(name) dma_addr_t name
+#define DEFINE_DMA_UNMAP_LEN(name) __u32 name
+#define dma_unmap_addr(p, name) ((p)->name)
+#define dma_unmap_addr_set(p, name, v) (((p)->name) = (v))
+#define dma_unmap_len(p, name) ((p)->name)
+#define dma_unmap_len_set(p, name, v) (((p)->name) = (v))
+
+#define dma_get_cache_alignment() (uma_get_cache_align_mask() + 1)
+
+
+static inline int
+dma_map_sgtable(struct device *dev, struct sg_table *sgt,
+ enum dma_data_direction dir,
+ unsigned long attrs)
+{
+ int nents;
+
+ nents = dma_map_sg_attrs(dev, sgt->sgl, sgt->nents, dir, attrs);
+ if (nents < 0)
+ return (nents);
+ sgt->nents = nents;
+ return (0);
+}
+
+static inline void
+dma_unmap_sgtable(struct device *dev, struct sg_table *sgt,
+ enum dma_data_direction dir,
+ unsigned long attrs)
+{
+
+ dma_unmap_sg_attrs(dev, sgt->sgl, sgt->nents, dir, attrs);
+}
+
+
+#endif /* _LINUXKPI_LINUX_DMA_MAPPING_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/dmapool.h b/sys/compat/linuxkpi/common/include/linux/dmapool.h
new file mode 100644
index 000000000000..8501a32e30b7
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/dmapool.h
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_DMAPOOL_H_
+#define _LINUXKPI_LINUX_DMAPOOL_H_
+
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/scatterlist.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+
+struct dma_pool;
+struct dma_pool *linux_dma_pool_create(char *name, struct device *dev,
+ size_t size, size_t align, size_t boundary);
+void linux_dma_pool_destroy(struct dma_pool *pool);
+void lkpi_dmam_pool_destroy(struct device *, void *);
+void *linux_dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags,
+ dma_addr_t *handle);
+void linux_dma_pool_free(struct dma_pool *pool, void *vaddr,
+ dma_addr_t dma_addr);
+
+static inline struct dma_pool *
+dma_pool_create(char *name, struct device *dev, size_t size,
+ size_t align, size_t boundary)
+{
+
+ return (linux_dma_pool_create(name, dev, size, align, boundary));
+}
+
+static inline struct dma_pool *
+dmam_pool_create(/* const */ char *name, struct device *dev, size_t size,
+ size_t align, size_t boundary)
+{
+ struct dma_pool **pp;
+
+ pp = devres_alloc(lkpi_dmam_pool_destroy, sizeof(*pp), GFP_KERNEL);
+ if (pp == NULL)
+ return (NULL);
+ *pp = linux_dma_pool_create(name, dev, size, align, boundary);
+ if (*pp == NULL) {
+ devres_free(pp);
+ return (NULL);
+ }
+
+ devres_add(dev, pp);
+ return (*pp);
+}
+
+static inline void
+dma_pool_destroy(struct dma_pool *pool)
+{
+
+ linux_dma_pool_destroy(pool);
+}
+
+static inline void *
+dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags, dma_addr_t *handle)
+{
+
+ return (linux_dma_pool_alloc(pool, mem_flags, handle));
+}
+
+static inline void *
+dma_pool_zalloc(struct dma_pool *pool, gfp_t mem_flags, dma_addr_t *handle)
+{
+
+ return (dma_pool_alloc(pool, mem_flags | __GFP_ZERO, handle));
+}
+
+static inline void
+dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma_addr)
+{
+
+ linux_dma_pool_free(pool, vaddr, dma_addr);
+}
+
+#endif /* _LINUXKPI_LINUX_DMAPOOL_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/dmi.h b/sys/compat/linuxkpi/common/include/linux/dmi.h
new file mode 100644
index 000000000000..d9760ee0324f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/dmi.h
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot 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_DMI_H__
+#define __LINUXKPI_LINUX_DMI_H__
+
+#include <sys/types.h>
+#include <linux/mod_devicetable.h>
+
+struct dmi_header {
+ uint8_t type;
+ uint8_t length;
+ uint16_t handle;
+};
+
+int linux_dmi_check_system(const struct dmi_system_id *);
+bool linux_dmi_match(enum dmi_field, const char *);
+const struct dmi_system_id *linux_dmi_first_match(const struct dmi_system_id *);
+const char *linux_dmi_get_system_info(int);
+
+#define dmi_check_system(sysid) linux_dmi_check_system(sysid)
+#define dmi_match(f, str) linux_dmi_match(f, str)
+#define dmi_first_match(sysid) linux_dmi_first_match(sysid)
+#define dmi_get_system_info(sysid) linux_dmi_get_system_info(sysid)
+
+static inline int
+dmi_walk(void (*callbackf)(const struct dmi_header *, void *), void *arg)
+{
+
+ return (-ENXIO);
+}
+
+#endif /* __LINUXKPI_LINUX_DMI_H__ */
diff --git a/sys/compat/linuxkpi/common/include/linux/dynamic_debug.h b/sys/compat/linuxkpi/common/include/linux/dynamic_debug.h
new file mode 100644
index 000000000000..12915eec3b68
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/dynamic_debug.h
@@ -0,0 +1,8 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_DYNAMIC_DEBUG_H
+#define _LINUXKPI_LINUX_DYNAMIC_DEBUG_H
+
+#define DECLARE_DYNDBG_CLASSMAP(a, b, c, ...)
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/efi.h b/sys/compat/linuxkpi/common/include/linux/efi.h
new file mode 100644
index 000000000000..aa33371bd0e8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/efi.h
@@ -0,0 +1,68 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
+ *
+ * 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 ``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 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_EFI_H_
+#define _LINUXKPI_LINUX_EFI_H_
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/linker.h>
+#include <sys/systm.h>
+
+#include <machine/md_var.h>
+#include <machine/metadata.h>
+
+#define EFI_BOOT 0
+
+static inline bool
+__efi_enabled(int feature)
+{
+ bool enabled = false;
+
+ switch (feature) {
+ case EFI_BOOT:
+#ifdef __amd64__
+ /* Use cached value on amd64 */
+ enabled = efi_boot;
+#elif defined(MODINFOMD_EFI_MAP)
+ enabled = preload_search_info(preload_kmdp,
+ MODINFO_METADATA | MODINFOMD_EFI_MAP) != NULL;
+#endif
+ break;
+ default:
+ break;
+ }
+
+ return (enabled);
+}
+
+#define efi_enabled(x) ({ \
+ _Static_assert((x) == EFI_BOOT, "unsupported feature"); \
+ __efi_enabled(x); \
+})
+
+#endif /* _LINUXKPI_LINUX_EFI_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/err.h b/sys/compat/linuxkpi/common/include/linux/err.h
new file mode 100644
index 000000000000..3d19949e641e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/err.h
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_ERR_H_
+#define _LINUXKPI_LINUX_ERR_H_
+
+#include <sys/types.h>
+
+#include <linux/compiler.h>
+
+#define MAX_ERRNO 4095
+
+#define IS_ERR_VALUE(x) unlikely((x) >= (uintptr_t)-MAX_ERRNO)
+
+static inline void *
+ERR_PTR(long error)
+{
+ return (void *)(intptr_t)error;
+}
+
+static inline long
+PTR_ERR(const void *ptr)
+{
+ return (intptr_t)ptr;
+}
+
+static inline bool
+IS_ERR(const void *ptr)
+{
+ return IS_ERR_VALUE((uintptr_t)ptr);
+}
+
+static inline bool
+IS_ERR_OR_NULL(const void *ptr)
+{
+ return !ptr || IS_ERR_VALUE((uintptr_t)ptr);
+}
+
+static inline void *
+ERR_CAST(const void *ptr)
+{
+ return __DECONST(void *, ptr);
+}
+
+static inline int
+PTR_ERR_OR_ZERO(const void *ptr)
+{
+ if (IS_ERR(ptr))
+ return PTR_ERR(ptr);
+ else
+ return 0;
+}
+
+#define PTR_RET(p) PTR_ERR_OR_ZERO(p)
+
+#endif /* _LINUXKPI_LINUX_ERR_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/errno.h b/sys/compat/linuxkpi/common/include/linux/errno.h
new file mode 100644
index 000000000000..d634675d43d0
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/errno.h
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_ERRNO_H_
+#define _LINUXKPI_LINUX_ERRNO_H_
+
+#include <sys/errno.h>
+
+#define EBADRQC 56 /* Bad request code */
+#define EBADSLT 57 /* Invalid slot */
+#define ENOKEY 126 /* Required key not available */
+
+#define ECHRNG EDOM
+#define ETIME ETIMEDOUT
+#define ECOMM ESTALE
+#define ENODATA ECONNREFUSED
+#define ENOIOCTLCMD ENOIOCTL
+/* Use same value as Linux, because BSD's ERESTART is negative */
+#define ERESTARTSYS 512
+#define ENOTSUPP EOPNOTSUPP
+#define ENONET EHOSTDOWN
+#define EHWPOISON 133 /* Memory page hardware error */
+
+/*
+ * The error numbers below are arbitrary and do not resemble the numbers
+ * used in Linux. They should not be returned to user space.
+ */
+#define ERESTARTNOINTR 513
+#define ERESTARTNOHAND 514
+#define ERESTART_RESTARTBLOCK 516
+#define EPROBE_DEFER 517
+#define EOPENSTALE 518
+#define EBADHANDLE 521
+#define ENOTSYNC 522
+#define EBADCOOKIE 523
+#define ETOOSMALL 525
+#define ESERVERFAULT 526
+#define EBADTYPE 527
+#define EJUKEBOX 528
+#define EIOCBQUEUED 529
+#define ERFKILL 530
+#define EBADE 531
+#define ENOMEDIUM 532
+#define ENOSR 533
+#define ELNRNG 534
+#define ENAVAIL 535
+
+#endif /* _LINUXKPI_LINUX_ERRNO_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/etherdevice.h b/sys/compat/linuxkpi/common/include/linux/etherdevice.h
new file mode 100644
index 000000000000..1f2d6cf22d7e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/etherdevice.h
@@ -0,0 +1,140 @@
+/*-
+ * Copyright (c) 2015-2016 Mellanox Technologies, Ltd. All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_ETHERDEVICE_H_
+#define _LINUXKPI_LINUX_ETHERDEVICE_H_
+
+#include <linux/types.h>
+#include <linux/device.h>
+
+#include <sys/random.h>
+#include <sys/libkern.h>
+
+#define ETH_MODULE_SFF_8079 1
+#define ETH_MODULE_SFF_8079_LEN 256
+#define ETH_MODULE_SFF_8472 2
+#define ETH_MODULE_SFF_8472_LEN 512
+#define ETH_MODULE_SFF_8636 3
+#define ETH_MODULE_SFF_8636_LEN 256
+#define ETH_MODULE_SFF_8436 4
+#define ETH_MODULE_SFF_8436_LEN 256
+
+struct ethtool_eeprom {
+ u32 offset;
+ u32 len;
+};
+
+struct ethtool_modinfo {
+ u32 type;
+ u32 eeprom_len;
+};
+
+static inline bool
+is_zero_ether_addr(const u8 * addr)
+{
+ return ((addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]) ==
+ 0x00);
+}
+
+static inline bool
+is_unicast_ether_addr(const u8 * addr)
+{
+ return ((addr[0] & 0x01) == 0x00);
+}
+
+static inline bool
+is_multicast_ether_addr(const u8 * addr)
+{
+ return ((addr[0] & 0x01) == 0x01);
+}
+
+static inline bool
+is_broadcast_ether_addr(const u8 * addr)
+{
+ return ((addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) ==
+ 0xff);
+}
+
+static inline bool
+is_valid_ether_addr(const u8 * addr)
+{
+ return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr);
+}
+
+static inline void
+ether_addr_copy(u8 * dst, const u8 * src)
+{
+ memcpy(dst, src, 6);
+}
+
+static inline bool
+ether_addr_equal_unaligned(const u8 *pa, const u8 *pb)
+{
+ return (memcmp(pa, pb, 6) == 0);
+}
+#define ether_addr_equal(_pa, _pb) ether_addr_equal_unaligned(_pa, _pb)
+
+static inline bool
+ether_addr_equal_64bits(const u8 *pa, const u8 *pb)
+{
+ return (memcmp(pa, pb, 6) == 0);
+}
+
+static inline void
+eth_broadcast_addr(u8 *pa)
+{
+ memset(pa, 0xff, 6);
+}
+
+static inline void
+eth_zero_addr(u8 *pa)
+{
+ memset(pa, 0, 6);
+}
+
+static inline void
+random_ether_addr(u8 *dst)
+{
+ arc4random_buf(dst, 6);
+
+ dst[0] &= 0xfe;
+ dst[0] |= 0x02;
+}
+
+static inline void
+eth_random_addr(u8 *dst)
+{
+
+ random_ether_addr(dst);
+}
+
+static inline int
+device_get_mac_address(struct device *dev, char *dst)
+{
+
+ /* XXX get mac address from FDT? */
+ return (-ENOENT);
+}
+
+#endif /* _LINUXKPI_LINUX_ETHERDEVICE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/ethtool.h b/sys/compat/linuxkpi/common/include/linux/ethtool.h
new file mode 100644
index 000000000000..f5567cd7ea40
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/ethtool.h
@@ -0,0 +1,57 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Bjoern A. Zeeb
+ *
+ * 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_ETHTOOL_H_
+#define _LINUXKPI_LINUX_ETHTOOL_H_
+
+#include <linux/types.h>
+
+#define ETH_GSTRING_LEN (2 * IF_NAMESIZE) /* Increase if not large enough */
+
+#define ETHTOOL_FWVERS_LEN 32
+
+struct ethtool_stats {
+ uint8_t __dummy[0];
+};
+
+enum ethtool_ss {
+ ETH_SS_STATS,
+};
+
+struct ethtool_drvinfo {
+ char driver[32];
+ char version[32];
+ char fw_version[ETHTOOL_FWVERS_LEN];
+ char bus_info[32];
+};
+
+struct net_device;
+struct ethtool_ops {
+ void(*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);
+};
+
+#endif /* _LINUXKPI_LINUX_ETHTOOL_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/eventpoll.h b/sys/compat/linuxkpi/common/include/linux/eventpoll.h
new file mode 100644
index 000000000000..e77e6d689f86
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/eventpoll.h
@@ -0,0 +1,45 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022, Jake Freeland <jfree@freebsd.org>
+ *
+ * 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 unmodified, 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 ``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 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_EVENTPOLL_H_
+#define _LINUXKPI_LINUX_EVENTPOLL_H_
+
+#include <sys/poll.h>
+
+#define EPOLLIN POLLIN
+#define EPOLLPRI POLLPRI
+#define EPOLLOUT POLLOUT
+#define EPOLLERR POLLERR
+#define EPOLLHUP POLLHUP
+#define EPOLLNVAL POLLNVAL
+#define EPOLLRDNORM POLLRDNORM
+#define EPOLLRDBAND POLLRDBAND
+#define EPOLLWRNORM POLLWRNORM
+#define EPOLLWRBAND POLLWRBAND
+#define EPOLLRDHUP POLLRDHUP
+
+#endif /* _LINUXKPI_LINUX_EVENTPOLL_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/export.h b/sys/compat/linuxkpi/common/include/linux/export.h
new file mode 100644
index 000000000000..f48bd6af45d3
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/export.h
@@ -0,0 +1,31 @@
+/*-
+ * Copyright (c) 2018 Johannes Lundberg <johalun0@gmail.com>
+ *
+ * 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 unmodified, 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 ``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 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_EXPORT_H
+#define _LINUXKPI_LINUX_EXPORT_H
+
+#define EXPORT_SYMBOL(name)
+#define EXPORT_SYMBOL_GPL(name)
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/file.h b/sys/compat/linuxkpi/common/include/linux/file.h
new file mode 100644
index 000000000000..f6e988c2d88e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/file.h
@@ -0,0 +1,185 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_FILE_H_
+#define _LINUXKPI_LINUX_FILE_H_
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/refcount.h>
+#include <sys/capsicum.h>
+#include <sys/proc.h>
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+
+struct linux_file;
+
+#undef file
+
+extern const struct fileops linuxfileops;
+
+static inline struct linux_file *
+linux_fget(unsigned int fd)
+{
+ struct file *file;
+
+ /* lookup file pointer by file descriptor index */
+ if (fget_unlocked(curthread, fd, &cap_no_rights, &file) != 0)
+ return (NULL);
+
+ /* check if file handle really belongs to us */
+ if (file->f_data == NULL ||
+ file->f_ops != &linuxfileops) {
+ fdrop(file, curthread);
+ return (NULL);
+ }
+ return ((struct linux_file *)file->f_data);
+}
+
+extern void linux_file_free(struct linux_file *filp);
+
+static inline void
+fput(struct linux_file *filp)
+{
+ if (refcount_release(filp->_file == NULL ?
+ &filp->f_count : &filp->_file->f_count)) {
+ linux_file_free(filp);
+ }
+}
+
+static inline unsigned int
+file_count(struct linux_file *filp)
+{
+ return (filp->_file == NULL ?
+ filp->f_count : filp->_file->f_count);
+}
+
+static inline void
+put_unused_fd(unsigned int fd)
+{
+ struct file *file;
+
+ if (fget_unlocked(curthread, fd, &cap_no_rights, &file) != 0) {
+ return;
+ }
+ /*
+ * NOTE: We should only get here when the "fd" has not been
+ * installed, so no need to free the associated Linux file
+ * structure.
+ */
+ fdclose(curthread, file, fd);
+
+ /* drop extra reference */
+ fdrop(file, curthread);
+}
+
+static inline void
+fd_install(unsigned int fd, struct linux_file *filp)
+{
+ struct file *file;
+
+ if (fget_unlocked(curthread, fd, &cap_no_rights, &file) != 0) {
+ filp->_file = NULL;
+ } else {
+ filp->_file = file;
+ finit(file, filp->f_mode, DTYPE_DEV, filp, &linuxfileops);
+
+ /* transfer reference count from "filp" to "file" */
+ while (refcount_release(&filp->f_count) == 0)
+ refcount_acquire(&file->f_count);
+ }
+
+ /* drop the extra reference */
+ fput(filp);
+}
+
+static inline int
+get_unused_fd(void)
+{
+ struct file *file;
+ int error;
+ int fd;
+
+ error = falloc(curthread, &file, &fd, 0);
+ if (error)
+ return -error;
+ /* drop the extra reference */
+ fdrop(file, curthread);
+ return fd;
+}
+
+static inline int
+get_unused_fd_flags(int flags)
+{
+ struct file *file;
+ int error;
+ int fd;
+
+ error = falloc(curthread, &file, &fd, flags);
+ if (error)
+ return -error;
+ /* drop the extra reference */
+ fdrop(file, curthread);
+ return fd;
+}
+
+extern struct linux_file *linux_file_alloc(void);
+
+static inline struct linux_file *
+alloc_file(int mode, const struct file_operations *fops)
+{
+ struct linux_file *filp;
+
+ filp = linux_file_alloc();
+ filp->f_op = fops;
+ filp->f_mode = mode;
+
+ return (filp);
+}
+
+struct fd {
+ struct linux_file *linux_file;
+};
+
+static inline void fdput(struct fd fd)
+{
+ fput(fd.linux_file);
+}
+
+static inline struct fd fdget(unsigned int fd)
+{
+ struct linux_file *f = linux_fget(fd);
+ return (struct fd){f};
+}
+
+#define file linux_file
+#define fget(...) linux_fget(__VA_ARGS__)
+
+#endif /* _LINUXKPI_LINUX_FILE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/firmware.h b/sys/compat/linuxkpi/common/include/linux/firmware.h
new file mode 100644
index 000000000000..a6330ddafb55
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/firmware.h
@@ -0,0 +1,116 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020-2021 The FreeBSD Foundation
+ * Copyright (c) 2022 Bjoern A. Zeeb
+ *
+ * This software was developed by Björn Zeeb 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_FIRMWARE_H
+#define _LINUXKPI_LINUX_FIRMWARE_H
+
+#include <sys/types.h>
+#include <linux/types.h>
+#include <linux/device.h>
+
+struct firmware;
+
+struct linuxkpi_firmware {
+ size_t size;
+ const uint8_t *data;
+ /* XXX Does Linux expose anything else? */
+
+ /* This is LinuxKPI implementation private. */
+ const struct firmware *fbdfw;
+};
+
+int linuxkpi_request_firmware_nowait(struct module *, bool, const char *,
+ struct device *, gfp_t, void *,
+ void(*cont)(const struct linuxkpi_firmware *, void *));
+int linuxkpi_request_firmware(const struct linuxkpi_firmware **,
+ const char *, struct device *);
+int linuxkpi_firmware_request_nowarn(const struct linuxkpi_firmware **,
+ const char *, struct device *);
+void linuxkpi_release_firmware(const struct linuxkpi_firmware *);
+int linuxkpi_request_partial_firmware_into_buf(const struct linuxkpi_firmware **,
+ const char *, struct device *, uint8_t *, size_t, size_t);
+
+
+static __inline int
+request_firmware_nowait(struct module *mod, bool _t,
+ const char *fw_name, struct device *dev, gfp_t gfp, void *drv,
+ void(*cont)(const struct linuxkpi_firmware *, void *))
+{
+
+
+ return (linuxkpi_request_firmware_nowait(mod, _t, fw_name, dev, gfp,
+ drv, cont));
+}
+
+static __inline int
+request_firmware(const struct linuxkpi_firmware **fw,
+ const char *fw_name, struct device *dev)
+{
+
+ return (linuxkpi_request_firmware(fw, fw_name, dev));
+}
+
+static __inline int
+request_firmware_direct(const struct linuxkpi_firmware **fw,
+ const char *fw_name, struct device *dev)
+{
+
+ return (linuxkpi_request_firmware(fw, fw_name, dev));
+}
+
+static __inline int
+firmware_request_nowarn(const struct linuxkpi_firmware **fw,
+ const char *fw_name, struct device *dev)
+{
+
+ return (linuxkpi_firmware_request_nowarn(fw, fw_name, dev));
+}
+
+static __inline void
+release_firmware(const struct linuxkpi_firmware *fw)
+{
+
+ linuxkpi_release_firmware(fw);
+}
+
+static inline int
+request_partial_firmware_into_buf(const struct linuxkpi_firmware **fw,
+ const char *fw_name, struct device *dev, void *buf, size_t buflen,
+ size_t offset)
+{
+
+ return (linuxkpi_request_partial_firmware_into_buf(fw, fw_name,
+ dev, buf, buflen, offset));
+}
+
+#define firmware linuxkpi_firmware
+
+#endif /* _LINUXKPI_LINUX_FIRMWARE_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/fs.h b/sys/compat/linuxkpi/common/include/linux/fs.h
new file mode 100644
index 000000000000..f1568ad6282d
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/fs.h
@@ -0,0 +1,425 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2018 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_FS_H_
+#define _LINUXKPI_LINUX_FS_H_
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/vnode.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/dcache.h>
+#include <linux/capability.h>
+#include <linux/wait_bit.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+
+struct module;
+struct kiocb;
+struct iovec;
+struct dentry;
+struct page;
+struct file_lock;
+struct pipe_inode_info;
+struct vm_area_struct;
+struct poll_table_struct;
+struct files_struct;
+struct pfs_node;
+struct linux_cdev;
+
+#define inode vnode
+#define i_cdev v_rdev
+#define i_private v_data
+
+#define S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH)
+#define S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH)
+
+typedef struct files_struct *fl_owner_t;
+
+struct file_operations;
+
+struct linux_file_wait_queue {
+ struct wait_queue wq;
+ struct wait_queue_head *wqh;
+ atomic_t state;
+#define LINUX_FWQ_STATE_INIT 0
+#define LINUX_FWQ_STATE_NOT_READY 1
+#define LINUX_FWQ_STATE_QUEUED 2
+#define LINUX_FWQ_STATE_READY 3
+#define LINUX_FWQ_STATE_MAX 4
+};
+
+struct linux_file {
+ struct file *_file;
+ const struct file_operations *f_op;
+ void *private_data;
+ int f_flags;
+ int f_mode; /* Just starting mode. */
+ struct dentry *f_dentry;
+ struct dentry f_dentry_store;
+ struct selinfo f_selinfo;
+ struct sigio *f_sigio;
+ struct vnode *f_vnode;
+#define f_inode f_vnode
+ volatile u_int f_count;
+
+ /* anonymous shmem object */
+ vm_object_t f_shmem;
+
+ /* kqfilter support */
+ int f_kqflags;
+#define LINUX_KQ_FLAG_HAS_READ (1 << 0)
+#define LINUX_KQ_FLAG_HAS_WRITE (1 << 1)
+#define LINUX_KQ_FLAG_NEED_READ (1 << 2)
+#define LINUX_KQ_FLAG_NEED_WRITE (1 << 3)
+ /* protects f_selinfo.si_note */
+ spinlock_t f_kqlock;
+ struct linux_file_wait_queue f_wait_queue;
+
+ /* pointer to associated character device, if any */
+ struct linux_cdev *f_cdev;
+
+ struct rcu_head rcu;
+};
+
+#define file linux_file
+#define fasync_struct sigio *
+
+#define fasync_helper(fd, filp, on, queue) \
+({ \
+ if ((on)) \
+ *(queue) = &(filp)->f_sigio; \
+ else \
+ *(queue) = NULL; \
+ 0; \
+})
+
+#define kill_fasync(queue, sig, pollstat) \
+do { \
+ if (*(queue) != NULL) \
+ pgsigio(*(queue), (sig), 0); \
+} while (0)
+
+typedef int (*filldir_t)(void *, const char *, int, off_t, u64, unsigned);
+
+struct file_operations {
+ struct module *owner;
+ 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 *);
+ long (*unlocked_ioctl)(struct linux_file *, unsigned int, unsigned long);
+ long (*compat_ioctl)(struct linux_file *, unsigned int, unsigned long);
+ int (*mmap)(struct linux_file *, struct vm_area_struct *);
+ int (*open)(struct inode *, struct file *);
+ int (*release)(struct inode *, struct linux_file *);
+ int (*fasync)(int, struct linux_file *, int);
+
+/* Although not supported in FreeBSD, to align with Linux code
+ * we are adding llseek() only when it is mapped to no_llseek which returns
+ * an illegal seek error
+ */
+ off_t (*llseek)(struct linux_file *, off_t, int);
+/*
+ * Not supported in FreeBSD. That's ok, we never call it and it allows some
+ * drivers like DRM drivers to compile without changes.
+ */
+ void (*show_fdinfo)(struct seq_file *, struct file *);
+#if 0
+ /* We do not support these methods. Don't permit them to compile. */
+ loff_t (*llseek)(struct file *, loff_t, int);
+ ssize_t (*aio_read)(struct kiocb *, const struct iovec *,
+ unsigned long, loff_t);
+ ssize_t (*aio_write)(struct kiocb *, const struct iovec *,
+ unsigned long, loff_t);
+ int (*readdir)(struct file *, void *, filldir_t);
+ int (*ioctl)(struct inode *, struct file *, unsigned int,
+ unsigned long);
+ int (*flush)(struct file *, fl_owner_t id);
+ int (*fsync)(struct file *, struct dentry *, int datasync);
+ int (*aio_fsync)(struct kiocb *, int datasync);
+ int (*lock)(struct file *, int, struct file_lock *);
+ ssize_t (*sendpage)(struct file *, struct page *, int, size_t,
+ loff_t *, int);
+ unsigned long (*get_unmapped_area)(struct file *, unsigned long,
+ unsigned long, unsigned long, unsigned long);
+ int (*check_flags)(int);
+ int (*flock)(struct file *, int, struct file_lock *);
+ ssize_t (*splice_write)(struct pipe_inode_info *, struct file *,
+ loff_t *, size_t, unsigned int);
+ ssize_t (*splice_read)(struct file *, loff_t *,
+ struct pipe_inode_info *, size_t, unsigned int);
+ int (*setlease)(struct file *, long, struct file_lock **);
+#endif
+};
+#define fops_get(fops) (fops)
+#define replace_fops(f, fops) ((f)->f_op = (fops))
+
+#define FMODE_READ FREAD
+#define FMODE_WRITE FWRITE
+#define FMODE_EXEC FEXEC
+#define FMODE_UNSIGNED_OFFSET 0x2000
+int __register_chrdev(unsigned int major, unsigned int baseminor,
+ unsigned int count, const char *name,
+ const struct file_operations *fops);
+int __register_chrdev_p(unsigned int major, unsigned int baseminor,
+ unsigned int count, const char *name,
+ const struct file_operations *fops, uid_t uid,
+ gid_t gid, int mode);
+void __unregister_chrdev(unsigned int major, unsigned int baseminor,
+ unsigned int count, const char *name);
+
+static inline void
+unregister_chrdev(unsigned int major, const char *name)
+{
+
+ __unregister_chrdev(major, 0, 256, name);
+}
+
+static inline int
+register_chrdev(unsigned int major, const char *name,
+ const struct file_operations *fops)
+{
+
+ return (__register_chrdev(major, 0, 256, name, fops));
+}
+
+static inline int
+register_chrdev_p(unsigned int major, const char *name,
+ const struct file_operations *fops, uid_t uid, gid_t gid, int mode)
+{
+
+ return (__register_chrdev_p(major, 0, 256, name, fops, uid, gid, mode));
+}
+
+static inline int
+register_chrdev_region(dev_t dev, unsigned range, const char *name)
+{
+
+ return 0;
+}
+
+static inline void
+unregister_chrdev_region(dev_t dev, unsigned range)
+{
+
+ return;
+}
+
+static inline int
+alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
+ const char *name)
+{
+
+ return 0;
+}
+
+/* No current support for seek op in FreeBSD */
+static inline int
+nonseekable_open(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+static inline int
+simple_open(struct inode *inode, struct file *filp)
+{
+ filp->private_data = inode->i_private;
+ return 0;
+}
+
+extern unsigned int linux_iminor(struct inode *);
+#define iminor(...) linux_iminor(__VA_ARGS__)
+
+static inline struct linux_file *
+get_file(struct linux_file *f)
+{
+
+ refcount_acquire(f->_file == NULL ? &f->f_count : &f->_file->f_count);
+ return (f);
+}
+
+struct linux_file * linux_get_file_rcu(struct linux_file **f);
+struct linux_file * get_file_active(struct linux_file **f);
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION < 60700
+static inline bool
+get_file_rcu(struct linux_file *f)
+{
+ return (refcount_acquire_if_not_zero(
+ f->_file == NULL ? &f->f_count : &f->_file->f_count));
+}
+#else
+#define get_file_rcu(f) linux_get_file_rcu(f)
+#endif
+
+static inline struct inode *
+igrab(struct inode *inode)
+{
+ int error;
+
+ error = vget(inode, 0);
+ if (error)
+ return (NULL);
+
+ return (inode);
+}
+
+static inline void
+iput(struct inode *inode)
+{
+
+ vrele(inode);
+}
+
+static inline loff_t
+no_llseek(struct file *file, loff_t offset, int whence)
+{
+
+ return (-ESPIPE);
+}
+
+static inline loff_t
+default_llseek(struct file *file, loff_t offset, int whence)
+{
+ return (no_llseek(file, offset, whence));
+}
+
+static inline loff_t
+generic_file_llseek(struct file *file, loff_t offset, int whence)
+{
+ return (no_llseek(file, offset, whence));
+}
+
+static inline loff_t
+noop_llseek(struct linux_file *file, loff_t offset, int whence)
+{
+
+ return (file->_file->f_offset);
+}
+
+static inline struct vnode *
+file_inode(const struct linux_file *file)
+{
+
+ return (file->f_vnode);
+}
+
+static inline int
+call_mmap(struct linux_file *file, struct vm_area_struct *vma)
+{
+
+ return (file->f_op->mmap(file, vma));
+}
+
+static inline void
+i_size_write(struct inode *inode, loff_t i_size)
+{
+}
+
+/*
+ * simple_read_from_buffer: copy data from kernel-space origin
+ * buffer into user-space destination buffer
+ *
+ * @dest: destination buffer
+ * @read_size: number of bytes to be transferred
+ * @ppos: starting transfer position pointer
+ * @orig: origin buffer
+ * @buf_size: size of destination and origin buffers
+ *
+ * Return value:
+ * On success, total bytes copied with *ppos incremented accordingly.
+ * On failure, negative value.
+ */
+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;
+ size_t buf_remain = buf_size - *ppos;
+
+ if (buf_remain < 0 || buf_remain > buf_size)
+ return -EINVAL;
+
+ 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);
+}
+
+MALLOC_DECLARE(M_LSATTR);
+
+#define __DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt, __wrfunc)\
+static inline int \
+__fops ## _open(struct inode *inode, struct file *filp) \
+{ \
+ return (simple_attr_open(inode, filp, __get, __set, __fmt)); \
+} \
+static const struct file_operations __fops = { \
+ .owner = THIS_MODULE, \
+ .open = __fops ## _open, \
+ .release = simple_attr_release, \
+ .read = simple_attr_read, \
+ .write = __wrfunc, \
+ .llseek = no_llseek \
+}
+
+#define DEFINE_SIMPLE_ATTRIBUTE(fops, get, set, fmt) \
+ __DEFINE_SIMPLE_ATTRIBUTE(fops, get, set, fmt, simple_attr_write)
+#define DEFINE_SIMPLE_ATTRIBUTE_SIGNED(fops, get, set, fmt) \
+ __DEFINE_SIMPLE_ATTRIBUTE(fops, get, set, fmt, simple_attr_write_signed)
+
+int simple_attr_open(struct inode *inode, struct file *filp,
+ int (*get)(void *, uint64_t *), int (*set)(void *, uint64_t),
+ const char *fmt);
+
+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_write(struct file *filp, const char *buf, size_t write_size, loff_t *ppos);
+
+ssize_t simple_attr_write_signed(struct file *filp, const char *buf,
+ size_t write_size, loff_t *ppos);
+
+#endif /* _LINUXKPI_LINUX_FS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/fwnode.h b/sys/compat/linuxkpi/common/include/linux/fwnode.h
new file mode 100644
index 000000000000..a1fbc1b6d6a3
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/fwnode.h
@@ -0,0 +1,10 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_FWNODE_H_
+#define _LINUXKPI_LINUX_FWNODE_H_
+
+struct fwnode_handle {
+ struct fwnode_handle *secondary;
+};
+
+#endif /* _LINUXKPI_LINUX_FWNODE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/gcd.h b/sys/compat/linuxkpi/common/include/linux/gcd.h
new file mode 100644
index 000000000000..5ca0540e5102
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/gcd.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Dieter Baron and Thomas Klausner.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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_GCD_H_
+#define _LINUXKPI_LINUX_GCD_H_
+
+static inline unsigned long
+gcd(unsigned long a, unsigned long b)
+{
+ unsigned long c;
+
+ c = a % b;
+ while (c != 0) {
+ a = b;
+ b = c;
+ c = a % b;
+ }
+
+ return (b);
+}
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/gfp.h b/sys/compat/linuxkpi/common/include/linux/gfp.h
new file mode 100644
index 000000000000..4c4caa621789
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/gfp.h
@@ -0,0 +1,214 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_GFP_H_
+#define _LINUXKPI_LINUX_GFP_H_
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+#include <linux/page.h>
+
+#include <vm/vm_param.h>
+#include <vm/vm_object.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+
+#define __GFP_NOWARN 0
+#define __GFP_HIGHMEM 0
+#define __GFP_ZERO M_ZERO
+#define __GFP_NOMEMALLOC 0
+#define __GFP_RECLAIM 0
+#define __GFP_RECLAIMABLE 0
+#define __GFP_RETRY_MAYFAIL 0
+#define __GFP_MOVABLE 0
+#define __GFP_COMP 0
+#define __GFP_KSWAPD_RECLAIM 0
+
+#define __GFP_IO 0
+#define __GFP_NO_KSWAPD 0
+#define __GFP_KSWAPD_RECLAIM 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_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_USER M_WAITOK
+#define GFP_HIGHUSER M_WAITOK
+#define GFP_HIGHUSER_MOVABLE M_WAITOK
+#define GFP_IOFS M_NOWAIT
+#define GFP_NOIO M_NOWAIT
+#define GFP_NOFS M_NOWAIT
+#define GFP_DMA32 __GFP_DMA32
+#define GFP_TEMPORARY M_NOWAIT
+#define GFP_NATIVE_MASK (M_NOWAIT | M_WAITOK | M_USE_RESERVE | M_ZERO)
+#define GFP_TRANSHUGE 0
+#define GFP_TRANSHUGE_LIGHT 0
+
+CTASSERT((__GFP_DMA32 & GFP_NATIVE_MASK) == 0);
+CTASSERT((__GFP_BITS_MASK & GFP_NATIVE_MASK) == GFP_NATIVE_MASK);
+
+struct page_frag_cache {
+ void *va;
+ int pagecnt_bias;
+};
+
+/*
+ * Page management for unmapped pages:
+ */
+struct page *linux_alloc_pages(gfp_t flags, unsigned int order);
+void linux_free_pages(struct page *page, unsigned int order);
+void *linuxkpi_page_frag_alloc(struct page_frag_cache *, size_t, gfp_t);
+void linuxkpi_page_frag_free(void *);
+void linuxkpi__page_frag_cache_drain(struct page *, size_t);
+
+static inline struct page *
+alloc_page(gfp_t flags)
+{
+
+ return (linux_alloc_pages(flags, 0));
+}
+
+static inline struct page *
+alloc_pages(gfp_t flags, unsigned int order)
+{
+
+ return (linux_alloc_pages(flags, order));
+}
+
+static inline struct page *
+alloc_pages_node(int node_id, gfp_t flags, unsigned int order)
+{
+
+ return (linux_alloc_pages(flags, order));
+}
+
+static inline void
+__free_pages(struct page *page, unsigned int order)
+{
+
+ linux_free_pages(page, order);
+}
+
+static inline void
+__free_page(struct page *page)
+{
+
+ linux_free_pages(page, 0);
+}
+
+static inline struct page *
+dev_alloc_pages(unsigned int order)
+{
+ return (linux_alloc_pages(GFP_ATOMIC, order));
+}
+
+struct folio *folio_alloc(gfp_t gfp, unsigned int order);
+
+/*
+ * Page management for mapped pages:
+ */
+vm_offset_t linux_alloc_kmem(gfp_t flags, unsigned int order);
+void linux_free_kmem(vm_offset_t, unsigned int order);
+
+static inline vm_offset_t
+get_zeroed_page(gfp_t flags)
+{
+
+ return (linux_alloc_kmem(flags | __GFP_ZERO, 0));
+}
+
+static inline vm_offset_t
+__get_free_page(gfp_t flags)
+{
+
+ return (linux_alloc_kmem(flags, 0));
+}
+
+static inline vm_offset_t
+__get_free_pages(gfp_t flags, unsigned int order)
+{
+
+ return (linux_alloc_kmem(flags, order));
+}
+
+static inline void
+free_pages(uintptr_t addr, unsigned int order)
+{
+ if (addr == 0)
+ return;
+
+ linux_free_kmem(addr, order);
+}
+
+static inline void
+free_page(uintptr_t addr)
+{
+ if (addr == 0)
+ return;
+
+ linux_free_kmem(addr, 0);
+}
+
+static inline void *
+page_frag_alloc(struct page_frag_cache *pfc, size_t fragsz, gfp_t gfp)
+{
+
+ return (linuxkpi_page_frag_alloc(pfc, fragsz, gfp));
+}
+
+static inline void
+page_frag_free(void *addr)
+{
+
+ linuxkpi_page_frag_free(addr);
+}
+
+static inline void
+__page_frag_cache_drain(struct page *page, size_t count)
+{
+
+ linuxkpi__page_frag_cache_drain(page, count);
+}
+
+static inline bool
+gfpflags_allow_blocking(const gfp_t gfp_flags)
+{
+ return ((gfp_flags & (M_WAITOK | M_NOWAIT)) == M_WAITOK);
+}
+
+#define SetPageReserved(page) do { } while (0) /* NOP */
+#define ClearPageReserved(page) do { } while (0) /* NOP */
+
+#endif /* _LINUXKPI_LINUX_GFP_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/gpf.h b/sys/compat/linuxkpi/common/include/linux/gpf.h
new file mode 100644
index 000000000000..01e883a94728
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/gpf.h
@@ -0,0 +1,33 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Serenity Cyber Security, LLC.
+ *
+ * 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_GPF_H_
+#define _LINUXKPI_LINUX_GPF_H_
+
+#include <linux/mmzone.h>
+
+#endif /* _LINUXKPI_LINUX_GPF_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/hardirq.h b/sys/compat/linuxkpi/common/include/linux/hardirq.h
new file mode 100644
index 000000000000..f79451dd0d35
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/hardirq.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_HARDIRQ_H_
+#define _LINUXKPI_LINUX_HARDIRQ_H_
+
+#include <linux/types.h>
+#include <linux/lockdep.h>
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+
+#define synchronize_irq(irq) _intr_drain((irq))
+
+/*
+ * FIXME: In the i915 driver's `intel_engine_cs.c` file,
+ * `synchronize_hardirq()` was replaced by `synchronize_rcu()` with the
+ * following comment:
+ * "Is it enough to wait that all cpu have context-switched?"
+ *
+ * See commit f6d50b7af554e21c380486d6f41c8537b265c777 in drm-kmod.
+ */
+#define synchronize_hardirq(irq) _intr_drain((irq))
+
+#endif /* _LINUXKPI_LINUX_HARDIRQ_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/hash.h b/sys/compat/linuxkpi/common/include/linux/hash.h
new file mode 100644
index 000000000000..c75814c96724
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/hash.h
@@ -0,0 +1,76 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 NVIDIA corporation & affiliates.
+ * Copyright (c) 2013 François Tigeot
+ *
+ * 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 unmodified, 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 ``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 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_HASH_H_
+#define _LINUXKPI_LINUX_HASH_H_
+
+#include <sys/hash.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <asm/types.h>
+
+#include <linux/bitops.h>
+
+static inline u64
+hash_64(u64 val, u8 bits)
+{
+ u64 ret;
+ u8 x;
+
+ ret = bits;
+
+ for (x = 0; x != sizeof(ret); x++) {
+ u64 chunk = (val >> (8 * x)) & 0xFF;
+ ret = HASHSTEP(ret, chunk);
+ }
+ return (ret >> (64 - bits));
+}
+
+static inline u32
+hash_32(u32 val, u8 bits)
+{
+ u32 ret;
+ u8 x;
+
+ ret = bits;
+
+ for (x = 0; x != sizeof(ret); x++) {
+ u32 chunk = (val >> (8 * x)) & 0xFF;
+ ret = HASHSTEP(ret, chunk);
+ }
+ return (ret >> (32 - bits));
+}
+
+#if BITS_PER_LONG == 64
+#define hash_long(...) hash_64(__VA_ARGS__)
+#else
+#define hash_long(...) hash_32(__VA_ARGS__)
+#endif
+
+#endif /* _LINUXKPI_LINUX_HASH_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/hashtable.h b/sys/compat/linuxkpi/common/include/linux/hashtable.h
new file mode 100644
index 000000000000..55755c354959
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/hashtable.h
@@ -0,0 +1,183 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 NVIDIA corporation & affiliates.
+ *
+ * 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 unmodified, 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 ``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 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_HASHTABLE_H
+#define _LINUXKPI_LINUX_HASHTABLE_H
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <linux/hash.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/log2.h>
+#include <linux/rcupdate.h>
+#include <linux/rculist.h>
+
+#include <ck_queue.h>
+
+struct lkpi_hash_entry {
+ CK_LIST_ENTRY(lkpi_hash_entry) entry;
+};
+
+struct lkpi_hash_head {
+ CK_LIST_HEAD(, lkpi_hash_entry) head;
+};
+
+#define DEFINE_HASHTABLE(name, bits) \
+ struct lkpi_hash_head name[1UL << (bits)]
+
+#define DEFINE_READ_MOSTLY_HASHTABLE(name, bits) \
+ struct lkpi_hash_head name[1UL << (bits)] __read_mostly
+
+#define DECLARE_HASHTABLE(name, bits) \
+ struct lkpi_hash_head name[1UL << (bits)]
+
+#define HASH_SIZE(name) ARRAY_SIZE(name)
+#define HASH_BITS(name) ilog2(HASH_SIZE(name))
+
+#define hash_min(...) \
+ hash_long(__VA_ARGS__)
+
+static inline void
+__hash_init(struct lkpi_hash_head *ht, unsigned long size)
+{
+ unsigned long x;
+
+ for (x = 0; x != size; x++)
+ CK_LIST_INIT(&ht[x].head);
+}
+
+#define hash_init(ht) \
+ __hash_init(ht, HASH_SIZE(ht))
+
+#define hash_add(...) \
+ hash_add_rcu(__VA_ARGS__)
+
+static inline void
+__hash_node_type_assert(struct hlist_node *node)
+{
+ /*
+ * Unfortunately Linux doesn't have an own type for the hash
+ * table node entries. The purpose of this function is simply
+ * to check the type of the passed argument.
+ */
+ CTASSERT(sizeof(struct lkpi_hash_entry) == sizeof(*node));
+}
+
+#define hash_add_rcu(ht, node, key) do { \
+ struct lkpi_hash_head *__head = &(ht)[hash_min(key, HASH_BITS(ht))]; \
+ __hash_node_type_assert(node); \
+ CK_LIST_INSERT_HEAD(&__head->head, \
+ (struct lkpi_hash_entry *)(node), entry); \
+} while (0)
+
+static inline bool
+hash_hashed(struct hlist_node *node)
+{
+ return (((struct lkpi_hash_entry *)node)->entry.cle_prev != NULL);
+}
+
+static inline bool
+__hash_empty(struct lkpi_hash_head *ht, unsigned long size)
+{
+ unsigned long x;
+
+ for (x = 0; x != size; x++) {
+ if (!CK_LIST_EMPTY(&ht[x].head))
+ return (false);
+ }
+ return (true);
+}
+
+#define hash_empty(ht) \
+ __hash_empty(ht, HASH_SIZE(ht))
+
+#define hash_del(...) \
+ hash_del_rcu(__VA_ARGS__)
+
+static inline void
+hash_del_rcu(struct hlist_node *node)
+{
+ CK_LIST_REMOVE((struct lkpi_hash_entry *)node, entry);
+ memset(node, 0, sizeof(*node));
+}
+
+#define __hash_first(ht, type, member) ({ \
+ const struct lkpi_hash_entry *__first = CK_LIST_FIRST(&(ht)->head); \
+ __hash_node_type_assert(&((type *)0)->member); \
+ (__first != NULL ? container_of((const void *)__first, type, member) : NULL); \
+})
+
+#define __hash_next(obj, type, member) ({ \
+ const struct lkpi_hash_entry *__next = \
+ CK_LIST_NEXT((struct lkpi_hash_entry *)&(obj)->member, entry); \
+ __hash_node_type_assert(&(obj)->member); \
+ (__next != NULL ? container_of((const void *)__next, type, member) : NULL); \
+})
+
+#define hash_for_each(...) \
+ hash_for_each_rcu(__VA_ARGS__)
+
+#define hash_for_each_rcu(name, bkt, obj, member) \
+ for ((bkt) = 0, (obj) = NULL; (obj) == NULL && \
+ (bkt) != HASH_SIZE(name); (bkt)++) \
+ for ((obj) = __hash_first(&(name)[bkt], \
+ __typeof(*(obj)), member); \
+ (obj) != NULL; \
+ (obj) = __hash_next(obj, \
+ __typeof(*(obj)), member))
+
+#define hash_for_each_safe(name, bkt, tmp, obj, member) \
+ for ((bkt) = 0, (obj) = NULL; (obj) == NULL && \
+ (bkt) != HASH_SIZE(name); (bkt)++) \
+ for ((obj) = __hash_first(&(name)[bkt], \
+ __typeof(*(obj)), member); \
+ (obj) != NULL && ((tmp) = &__hash_next(obj, \
+ __typeof(*(obj)), member)->member, 1); \
+ (obj) = container_of(tmp, __typeof(*(obj)), member))
+
+#define hash_for_each_possible(...) \
+ hash_for_each_possible_rcu(__VA_ARGS__)
+
+#define hash_for_each_possible_rcu_notrace(...) \
+ hash_for_each_possible_rcu(__VA_ARGS__)
+
+#define hash_for_each_possible_rcu(name, obj, member, key) \
+ for ((obj) = __hash_first(&(name)[hash_min(key, HASH_BITS(name))], \
+ __typeof(*(obj)), member); \
+ (obj) != NULL; \
+ (obj) = __hash_next(obj, __typeof(*(obj)), member))
+
+#define hash_for_each_possible_safe(name, obj, tmp, member, key) \
+ for ((obj) = __hash_first(&(name)[hash_min(key, HASH_BITS(name))], \
+ __typeof(*(obj)), member); \
+ (obj) != NULL && ((tmp) = &__hash_next(obj, \
+ __typeof(*(obj)), member)->member, 1); \
+ (obj) = container_of(tmp, __typeof(*(obj)), member))
+
+#endif /* _LINUXKPI_LINUX_HASHTABLE_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/hdmi.h b/sys/compat/linuxkpi/common/include/linux/hdmi.h
new file mode 100644
index 000000000000..e07578167d69
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/hdmi.h
@@ -0,0 +1,447 @@
+/*
+ * Copyright (C) 2012 Avionic Design GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LINUX_HDMI_H_
+#define __LINUX_HDMI_H_
+
+#include <linux/types.h>
+#include <linux/device.h>
+
+enum hdmi_packet_type {
+ HDMI_PACKET_TYPE_NULL = 0x00,
+ HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
+ HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02,
+ HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03,
+ HDMI_PACKET_TYPE_ACP = 0x04,
+ HDMI_PACKET_TYPE_ISRC1 = 0x05,
+ HDMI_PACKET_TYPE_ISRC2 = 0x06,
+ HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07,
+ HDMI_PACKET_TYPE_DST_AUDIO = 0x08,
+ HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09,
+ HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a,
+ /* + enum hdmi_infoframe_type */
+};
+
+enum hdmi_infoframe_type {
+ HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
+ HDMI_INFOFRAME_TYPE_AVI = 0x82,
+ HDMI_INFOFRAME_TYPE_SPD = 0x83,
+ HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
+ HDMI_INFOFRAME_TYPE_DRM = 0x87,
+};
+
+#define HDMI_IEEE_OUI 0x000c03
+#define HDMI_FORUM_IEEE_OUI 0xc45dd8
+#define HDMI_INFOFRAME_HEADER_SIZE 4
+#define HDMI_AVI_INFOFRAME_SIZE 13
+#define HDMI_SPD_INFOFRAME_SIZE 25
+#define HDMI_AUDIO_INFOFRAME_SIZE 10
+#define HDMI_DRM_INFOFRAME_SIZE 26
+#define HDMI_VENDOR_INFOFRAME_SIZE 4
+
+#define HDMI_INFOFRAME_SIZE(type) \
+ (HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE)
+
+struct hdmi_any_infoframe {
+ enum hdmi_infoframe_type type;
+ unsigned char version;
+ unsigned char length;
+};
+
+enum hdmi_colorspace {
+ HDMI_COLORSPACE_RGB,
+ HDMI_COLORSPACE_YUV422,
+ HDMI_COLORSPACE_YUV444,
+ HDMI_COLORSPACE_YUV420,
+ HDMI_COLORSPACE_RESERVED4,
+ HDMI_COLORSPACE_RESERVED5,
+ HDMI_COLORSPACE_RESERVED6,
+ HDMI_COLORSPACE_IDO_DEFINED,
+};
+
+enum hdmi_scan_mode {
+ HDMI_SCAN_MODE_NONE,
+ HDMI_SCAN_MODE_OVERSCAN,
+ HDMI_SCAN_MODE_UNDERSCAN,
+ HDMI_SCAN_MODE_RESERVED,
+};
+
+enum hdmi_colorimetry {
+ HDMI_COLORIMETRY_NONE,
+ HDMI_COLORIMETRY_ITU_601,
+ HDMI_COLORIMETRY_ITU_709,
+ HDMI_COLORIMETRY_EXTENDED,
+};
+
+enum hdmi_picture_aspect {
+ HDMI_PICTURE_ASPECT_NONE,
+ HDMI_PICTURE_ASPECT_4_3,
+ HDMI_PICTURE_ASPECT_16_9,
+ HDMI_PICTURE_ASPECT_64_27,
+ HDMI_PICTURE_ASPECT_256_135,
+ HDMI_PICTURE_ASPECT_RESERVED,
+};
+
+enum hdmi_active_aspect {
+ HDMI_ACTIVE_ASPECT_16_9_TOP = 2,
+ HDMI_ACTIVE_ASPECT_14_9_TOP = 3,
+ HDMI_ACTIVE_ASPECT_16_9_CENTER = 4,
+ HDMI_ACTIVE_ASPECT_PICTURE = 8,
+ HDMI_ACTIVE_ASPECT_4_3 = 9,
+ HDMI_ACTIVE_ASPECT_16_9 = 10,
+ HDMI_ACTIVE_ASPECT_14_9 = 11,
+ HDMI_ACTIVE_ASPECT_4_3_SP_14_9 = 13,
+ HDMI_ACTIVE_ASPECT_16_9_SP_14_9 = 14,
+ HDMI_ACTIVE_ASPECT_16_9_SP_4_3 = 15,
+};
+
+enum hdmi_extended_colorimetry {
+ HDMI_EXTENDED_COLORIMETRY_XV_YCC_601,
+ HDMI_EXTENDED_COLORIMETRY_XV_YCC_709,
+ HDMI_EXTENDED_COLORIMETRY_S_YCC_601,
+ HDMI_EXTENDED_COLORIMETRY_OPYCC_601,
+ HDMI_EXTENDED_COLORIMETRY_OPRGB,
+
+ /* The following EC values are only defined in CEA-861-F. */
+ HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM,
+ HDMI_EXTENDED_COLORIMETRY_BT2020,
+ HDMI_EXTENDED_COLORIMETRY_RESERVED,
+};
+
+enum hdmi_quantization_range {
+ HDMI_QUANTIZATION_RANGE_DEFAULT,
+ HDMI_QUANTIZATION_RANGE_LIMITED,
+ HDMI_QUANTIZATION_RANGE_FULL,
+ HDMI_QUANTIZATION_RANGE_RESERVED,
+};
+
+/* non-uniform picture scaling */
+enum hdmi_nups {
+ HDMI_NUPS_UNKNOWN,
+ HDMI_NUPS_HORIZONTAL,
+ HDMI_NUPS_VERTICAL,
+ HDMI_NUPS_BOTH,
+};
+
+enum hdmi_ycc_quantization_range {
+ HDMI_YCC_QUANTIZATION_RANGE_LIMITED,
+ HDMI_YCC_QUANTIZATION_RANGE_FULL,
+};
+
+enum hdmi_content_type {
+ HDMI_CONTENT_TYPE_GRAPHICS,
+ HDMI_CONTENT_TYPE_PHOTO,
+ HDMI_CONTENT_TYPE_CINEMA,
+ HDMI_CONTENT_TYPE_GAME,
+};
+
+enum hdmi_metadata_type {
+ HDMI_STATIC_METADATA_TYPE1 = 0,
+};
+
+enum hdmi_eotf {
+ HDMI_EOTF_TRADITIONAL_GAMMA_SDR,
+ HDMI_EOTF_TRADITIONAL_GAMMA_HDR,
+ HDMI_EOTF_SMPTE_ST2084,
+ HDMI_EOTF_BT_2100_HLG,
+};
+
+struct hdmi_avi_infoframe {
+ enum hdmi_infoframe_type type;
+ unsigned char version;
+ unsigned char length;
+ bool itc;
+ unsigned char pixel_repeat;
+ enum hdmi_colorspace colorspace;
+ enum hdmi_scan_mode scan_mode;
+ enum hdmi_colorimetry colorimetry;
+ enum hdmi_picture_aspect picture_aspect;
+ enum hdmi_active_aspect active_aspect;
+ enum hdmi_extended_colorimetry extended_colorimetry;
+ enum hdmi_quantization_range quantization_range;
+ enum hdmi_nups nups;
+ unsigned char video_code;
+ enum hdmi_ycc_quantization_range ycc_quantization_range;
+ enum hdmi_content_type content_type;
+ unsigned short top_bar;
+ unsigned short bottom_bar;
+ unsigned short left_bar;
+ unsigned short right_bar;
+};
+
+/* DRM Infoframe as per CTA 861.G spec */
+struct hdmi_drm_infoframe {
+ enum hdmi_infoframe_type type;
+ unsigned char version;
+ unsigned char length;
+ enum hdmi_eotf eotf;
+ enum hdmi_metadata_type metadata_type;
+ struct {
+ u16 x, y;
+ } display_primaries[3];
+ struct {
+ u16 x, y;
+ } white_point;
+ u16 max_display_mastering_luminance;
+ u16 min_display_mastering_luminance;
+ u16 max_cll;
+ u16 max_fall;
+};
+
+void hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame);
+ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
+ size_t size);
+ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
+ void *buffer, size_t size);
+int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
+int hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *frame);
+ssize_t hdmi_drm_infoframe_pack(struct hdmi_drm_infoframe *frame, void *buffer,
+ size_t size);
+ssize_t hdmi_drm_infoframe_pack_only(const struct hdmi_drm_infoframe *frame,
+ void *buffer, size_t size);
+int hdmi_drm_infoframe_check(struct hdmi_drm_infoframe *frame);
+int hdmi_drm_infoframe_unpack_only(struct hdmi_drm_infoframe *frame,
+ const void *buffer, size_t size);
+
+enum hdmi_spd_sdi {
+ HDMI_SPD_SDI_UNKNOWN,
+ HDMI_SPD_SDI_DSTB,
+ HDMI_SPD_SDI_DVDP,
+ HDMI_SPD_SDI_DVHS,
+ HDMI_SPD_SDI_HDDVR,
+ HDMI_SPD_SDI_DVC,
+ HDMI_SPD_SDI_DSC,
+ HDMI_SPD_SDI_VCD,
+ HDMI_SPD_SDI_GAME,
+ HDMI_SPD_SDI_PC,
+ HDMI_SPD_SDI_BD,
+ HDMI_SPD_SDI_SACD,
+ HDMI_SPD_SDI_HDDVD,
+ HDMI_SPD_SDI_PMP,
+};
+
+struct hdmi_spd_infoframe {
+ enum hdmi_infoframe_type type;
+ unsigned char version;
+ unsigned char length;
+ char vendor[8];
+ char product[16];
+ enum hdmi_spd_sdi sdi;
+};
+
+int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
+ const char *vendor, const char *product);
+ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
+ size_t size);
+ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
+ void *buffer, size_t size);
+int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
+
+enum hdmi_audio_coding_type {
+ HDMI_AUDIO_CODING_TYPE_STREAM,
+ HDMI_AUDIO_CODING_TYPE_PCM,
+ HDMI_AUDIO_CODING_TYPE_AC3,
+ HDMI_AUDIO_CODING_TYPE_MPEG1,
+ HDMI_AUDIO_CODING_TYPE_MP3,
+ HDMI_AUDIO_CODING_TYPE_MPEG2,
+ HDMI_AUDIO_CODING_TYPE_AAC_LC,
+ HDMI_AUDIO_CODING_TYPE_DTS,
+ HDMI_AUDIO_CODING_TYPE_ATRAC,
+ HDMI_AUDIO_CODING_TYPE_DSD,
+ HDMI_AUDIO_CODING_TYPE_EAC3,
+ HDMI_AUDIO_CODING_TYPE_DTS_HD,
+ HDMI_AUDIO_CODING_TYPE_MLP,
+ HDMI_AUDIO_CODING_TYPE_DST,
+ HDMI_AUDIO_CODING_TYPE_WMA_PRO,
+ HDMI_AUDIO_CODING_TYPE_CXT,
+};
+
+enum hdmi_audio_sample_size {
+ HDMI_AUDIO_SAMPLE_SIZE_STREAM,
+ HDMI_AUDIO_SAMPLE_SIZE_16,
+ HDMI_AUDIO_SAMPLE_SIZE_20,
+ HDMI_AUDIO_SAMPLE_SIZE_24,
+};
+
+enum hdmi_audio_sample_frequency {
+ HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM,
+ HDMI_AUDIO_SAMPLE_FREQUENCY_32000,
+ HDMI_AUDIO_SAMPLE_FREQUENCY_44100,
+ HDMI_AUDIO_SAMPLE_FREQUENCY_48000,
+ HDMI_AUDIO_SAMPLE_FREQUENCY_88200,
+ HDMI_AUDIO_SAMPLE_FREQUENCY_96000,
+ HDMI_AUDIO_SAMPLE_FREQUENCY_176400,
+ HDMI_AUDIO_SAMPLE_FREQUENCY_192000,
+};
+
+enum hdmi_audio_coding_type_ext {
+ /* Refer to Audio Coding Type (CT) field in Data Byte 1 */
+ HDMI_AUDIO_CODING_TYPE_EXT_CT,
+
+ /*
+ * The next three CXT values are defined in CEA-861-E only.
+ * They do not exist in older versions, and in CEA-861-F they are
+ * defined as 'Not in use'.
+ */
+ HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC,
+ HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC_V2,
+ HDMI_AUDIO_CODING_TYPE_EXT_MPEG_SURROUND,
+
+ /* The following CXT values are only defined in CEA-861-F. */
+ HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC,
+ HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_V2,
+ HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC,
+ HDMI_AUDIO_CODING_TYPE_EXT_DRA,
+ HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_SURROUND,
+ HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC_SURROUND = 10,
+};
+
+struct hdmi_audio_infoframe {
+ enum hdmi_infoframe_type type;
+ unsigned char version;
+ unsigned char length;
+ unsigned char channels;
+ enum hdmi_audio_coding_type coding_type;
+ enum hdmi_audio_sample_size sample_size;
+ enum hdmi_audio_sample_frequency sample_frequency;
+ enum hdmi_audio_coding_type_ext coding_type_ext;
+ unsigned char channel_allocation;
+ unsigned char level_shift_value;
+ bool downmix_inhibit;
+
+};
+
+int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame);
+ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
+ void *buffer, size_t size);
+ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
+ void *buffer, size_t size);
+int hdmi_audio_infoframe_check(const struct hdmi_audio_infoframe *frame);
+
+#ifdef __linux__
+struct dp_sdp;
+ssize_t
+hdmi_audio_infoframe_pack_for_dp(const struct hdmi_audio_infoframe *frame,
+ struct dp_sdp *sdp, u8 dp_version);
+#endif
+
+enum hdmi_3d_structure {
+ HDMI_3D_STRUCTURE_INVALID = -1,
+ HDMI_3D_STRUCTURE_FRAME_PACKING = 0,
+ HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE,
+ HDMI_3D_STRUCTURE_LINE_ALTERNATIVE,
+ HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL,
+ HDMI_3D_STRUCTURE_L_DEPTH,
+ HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH,
+ HDMI_3D_STRUCTURE_TOP_AND_BOTTOM,
+ HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF = 8,
+};
+
+
+struct hdmi_vendor_infoframe {
+ enum hdmi_infoframe_type type;
+ unsigned char version;
+ unsigned char length;
+ unsigned int oui;
+ u8 vic;
+ enum hdmi_3d_structure s3d_struct;
+ unsigned int s3d_ext_data;
+};
+
+/* HDR Metadata as per 861.G spec */
+struct hdr_static_metadata {
+ __u8 eotf;
+ __u8 metadata_type;
+ __u16 max_cll;
+ __u16 max_fall;
+ __u16 min_cll;
+};
+
+/**
+ * struct hdr_sink_metadata - HDR sink metadata
+ *
+ * Metadata Information read from Sink's EDID
+ */
+struct hdr_sink_metadata {
+ /**
+ * @metadata_type: Static_Metadata_Descriptor_ID.
+ */
+ __u32 metadata_type;
+ /**
+ * @hdmi_type1: HDR Metadata Infoframe.
+ */
+ union {
+ struct hdr_static_metadata hdmi_type1;
+ };
+};
+
+int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
+ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
+ void *buffer, size_t size);
+ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
+ void *buffer, size_t size);
+int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
+
+union hdmi_vendor_any_infoframe {
+ struct {
+ enum hdmi_infoframe_type type;
+ unsigned char version;
+ unsigned char length;
+ unsigned int oui;
+ } any;
+ struct hdmi_vendor_infoframe hdmi;
+};
+
+/**
+ * union hdmi_infoframe - overall union of all abstract infoframe representations
+ * @any: generic infoframe
+ * @avi: avi infoframe
+ * @spd: spd infoframe
+ * @vendor: union of all vendor infoframes
+ * @audio: audio infoframe
+ * @drm: Dynamic Range and Mastering infoframe
+ *
+ * This is used by the generic pack function. This works since all infoframes
+ * have the same header which also indicates which type of infoframe should be
+ * packed.
+ */
+union hdmi_infoframe {
+ struct hdmi_any_infoframe any;
+ struct hdmi_avi_infoframe avi;
+ struct hdmi_spd_infoframe spd;
+ union hdmi_vendor_any_infoframe vendor;
+ struct hdmi_audio_infoframe audio;
+ struct hdmi_drm_infoframe drm;
+};
+
+ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
+ size_t size);
+ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
+ void *buffer, size_t size);
+int hdmi_infoframe_check(union hdmi_infoframe *frame);
+int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
+ const void *buffer, size_t size);
+void hdmi_infoframe_log(const char *level, struct device *dev,
+ const union hdmi_infoframe *frame);
+
+#endif /* _DRM_HDMI_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/highmem.h b/sys/compat/linuxkpi/common/include/linux/highmem.h
new file mode 100644
index 000000000000..58a9cdcdf60f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/highmem.h
@@ -0,0 +1,170 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2016 Matthew Macy (mmacy@mattmacy.io)
+ * Copyright (c) 2017 Mellanox Technologies, Ltd.
+ * Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
+ *
+ * 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_HIGHMEM_H_
+#define _LINUXKPI_LINUX_HIGHMEM_H_
+
+#include <sys/types.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/sched.h>
+#include <sys/sf_buf.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/pmap.h>
+
+#include <linux/mm.h>
+#include <linux/page.h>
+
+#define PageHighMem(p) (0)
+
+static inline struct page *
+kmap_to_page(void *addr)
+{
+
+ return (virt_to_page(addr));
+}
+
+static inline void *
+kmap(struct page *page)
+{
+ struct sf_buf *sf;
+
+ if (PMAP_HAS_DMAP) {
+ return ((void *)PHYS_TO_DMAP(page_to_phys(page)));
+ } else {
+ sched_pin();
+ sf = sf_buf_alloc(page, SFB_NOWAIT | SFB_CPUPRIVATE);
+ if (sf == NULL) {
+ sched_unpin();
+ return (NULL);
+ }
+ return ((void *)sf_buf_kva(sf));
+ }
+}
+
+static inline void *
+kmap_atomic_prot(struct page *page, pgprot_t prot)
+{
+ vm_memattr_t attr = pgprot2cachemode(prot);
+
+ if (attr != VM_MEMATTR_DEFAULT) {
+ page->flags |= PG_FICTITIOUS;
+ pmap_page_set_memattr(page, attr);
+ }
+ return (kmap(page));
+}
+
+static inline void *
+kmap_atomic(struct page *page)
+{
+
+ return (kmap_atomic_prot(page, VM_PROT_ALL));
+}
+
+static inline void *
+kmap_local_page(struct page *page)
+{
+ return (kmap(page));
+}
+
+static inline void *
+kmap_local_page_prot(struct page *page, pgprot_t prot)
+{
+
+ return (kmap_atomic_prot(page, prot));
+}
+
+static inline void
+kunmap(struct page *page)
+{
+ struct sf_buf *sf;
+
+ if (!PMAP_HAS_DMAP) {
+ /* lookup SF buffer in list */
+ sf = sf_buf_alloc(page, SFB_NOWAIT | SFB_CPUPRIVATE);
+
+ /* double-free */
+ sf_buf_free(sf);
+ sf_buf_free(sf);
+
+ sched_unpin();
+ }
+}
+
+static inline void
+kunmap_atomic(void *vaddr)
+{
+
+ if (!PMAP_HAS_DMAP)
+ kunmap(virt_to_page(vaddr));
+}
+
+static inline void
+kunmap_local(void *addr)
+{
+
+ kunmap_atomic(addr);
+}
+
+static inline void
+memcpy_from_page(char *to, struct page *page, size_t offset, size_t len)
+{
+ char *from;
+
+ KASSERT(offset + len <= PAGE_SIZE,
+ ("%s: memcpy from page %p to address %p: "
+ "offset+len (%zu+%zu) would go beyond page end",
+ __func__, page, to, offset, len));
+
+ from = kmap_local_page(page);
+ memcpy(to, from + offset, len);
+ kunmap_local(from);
+}
+
+static inline void
+memcpy_to_page(struct page *page, size_t offset, const char *from, size_t len)
+{
+ char *to;
+
+ KASSERT(offset + len <= PAGE_SIZE,
+ ("%s: memcpy from address %p to page %p: "
+ "offset+len (%zu+%zu) would go beyond page end",
+ __func__, from, page, offset, len));
+
+ to = kmap_local_page(page);
+ memcpy(to + offset, from, len);
+ kunmap_local(to);
+}
+
+#endif /* _LINUXKPI_LINUX_HIGHMEM_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/hrtimer.h b/sys/compat/linuxkpi/common/include/linux/hrtimer.h
new file mode 100644
index 000000000000..88f9487d0b85
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/hrtimer.h
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org>
+ *
+ * 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 unmodified, 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 ``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 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_HRTIMER_H_
+#define _LINUXKPI_LINUX_HRTIMER_H_
+
+#include <sys/_callout.h>
+#include <sys/_mutex.h>
+
+#include <linux/ktime.h>
+#include <linux/rbtree.h>
+#include <linux/timer.h>
+
+enum hrtimer_mode {
+ HRTIMER_MODE_REL,
+ HRTIMER_MODE_REL_PINNED = HRTIMER_MODE_REL,
+};
+
+enum hrtimer_restart {
+ HRTIMER_RESTART,
+ HRTIMER_NORESTART,
+};
+
+struct hrtimer {
+ enum hrtimer_restart (*function)(struct hrtimer *);
+ struct mtx mtx;
+ struct callout callout;
+ s64 expires; /* relative time in nanoseconds */
+ s64 precision; /* in nanoseconds */
+};
+
+#define hrtimer_active(hrtimer) linux_hrtimer_active(hrtimer)
+#define hrtimer_try_to_cancel(hrtimer) linux_hrtimer_try_to_cancel(hrtimer)
+#define hrtimer_cancel(hrtimer) linux_hrtimer_cancel(hrtimer)
+
+#define hrtimer_init(hrtimer, clock, mode) do { \
+ CTASSERT((clock) == CLOCK_MONOTONIC); \
+ CTASSERT((mode) == HRTIMER_MODE_REL); \
+ linux_hrtimer_init(hrtimer); \
+} while (0)
+
+#define hrtimer_set_expires(hrtimer, time) \
+ linux_hrtimer_set_expires(hrtimer, time)
+
+#define hrtimer_start(hrtimer, time, mode) do { \
+ CTASSERT((mode) == HRTIMER_MODE_REL); \
+ linux_hrtimer_start(hrtimer, time); \
+} while (0)
+
+#define hrtimer_start_range_ns(hrtimer, time, prec, mode) do { \
+ CTASSERT((mode) == HRTIMER_MODE_REL); \
+ linux_hrtimer_start_range_ns(hrtimer, time, prec); \
+} while (0)
+
+#define hrtimer_forward_now(hrtimer, interval) do { \
+ linux_hrtimer_forward_now(hrtimer, interval); \
+} while (0)
+
+bool linux_hrtimer_active(struct hrtimer *);
+int linux_hrtimer_try_to_cancel(struct hrtimer *);
+int linux_hrtimer_cancel(struct hrtimer *);
+void linux_hrtimer_init(struct hrtimer *);
+void linux_hrtimer_set_expires(struct hrtimer *, ktime_t);
+void linux_hrtimer_start(struct hrtimer *, ktime_t);
+void linux_hrtimer_start_range_ns(struct hrtimer *, ktime_t, int64_t);
+void linux_hrtimer_forward_now(struct hrtimer *, ktime_t);
+
+#endif /* _LINUXKPI_LINUX_HRTIMER_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/i2c-algo-bit.h b/sys/compat/linuxkpi/common/include/linux/i2c-algo-bit.h
new file mode 100644
index 000000000000..4e8f00f9bebc
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/i2c-algo-bit.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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 _LINUX_I2C_ALGO_BIT_H_
+#define _LINUX_I2C_ALGO_BIT_H_
+
+#include <linux/i2c.h>
+
+struct i2c_algo_bit_data {
+ void *data;
+ void (*setsda) (void *data, int state);
+ void (*setscl) (void *data, int state);
+ int (*getsda) (void *data);
+ int (*getscl) (void *data);
+ int (*pre_xfer) (struct i2c_adapter *);
+ void (*post_xfer) (struct i2c_adapter *);
+
+ int udelay;
+ int timeout;
+};
+
+int lkpi_i2c_bit_add_bus(struct i2c_adapter *adapter);
+
+#define i2c_bit_add_bus(adapter) lkpi_i2c_bit_add_bus(adapter)
+
+#endif /*_LINUX_I2C_ALGO_BIT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/i2c.h b/sys/compat/linuxkpi/common/include/linux/i2c.h
new file mode 100644
index 000000000000..f24d282586f6
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/i2c.h
@@ -0,0 +1,177 @@
+/*-
+ * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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 _LINUX_I2C_H_
+#define _LINUX_I2C_H_
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/systm.h>
+
+#include <linux/device.h>
+
+#define I2C_MAX_ADAPTER_NAME_LENGTH 32
+
+#define I2C_M_RD 0x0001
+#define I2C_M_NOSTART 0x0002
+#define I2C_M_STOP 0x0004
+
+/* No need for us */
+#define I2C_FUNC_I2C 0
+#define I2C_FUNC_SMBUS_EMUL 0
+#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0
+#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0
+#define I2C_FUNC_10BIT_ADDR 0
+
+#define I2C_CLASS_HWMON 0x1
+#define I2C_CLASS_DDC 0x8
+#define I2C_CLASS_SPD 0x80
+
+struct i2c_adapter {
+ struct module *owner;
+ unsigned int class;
+
+ char name[I2C_MAX_ADAPTER_NAME_LENGTH];
+ struct device dev;
+
+ const struct i2c_lock_operations *lock_ops;
+ const struct i2c_algorithm *algo;
+ const struct i2c_adapter_quirks *quirks;
+ void *algo_data;
+
+ int retries;
+ void *data;
+};
+
+struct i2c_msg {
+ uint16_t addr;
+ uint16_t flags;
+ uint16_t len;
+ uint8_t *buf;
+};
+
+struct i2c_algorithm {
+ int (*master_xfer)(struct i2c_adapter *, struct i2c_msg *, int);
+ uint32_t (*functionality)(struct i2c_adapter *);
+};
+
+struct i2c_lock_operations {
+ void (*lock_bus)(struct i2c_adapter *, unsigned int);
+ int (*trylock_bus)(struct i2c_adapter *, unsigned int);
+ void (*unlock_bus)(struct i2c_adapter *, unsigned int);
+};
+
+struct i2c_adapter_quirks {
+ uint64_t flags;
+ int max_num_msgs;
+ uint16_t max_write_len;
+ uint16_t max_read_len;
+ uint16_t max_comb_1st_msg_len;
+ uint16_t max_comb_2nd_msg_len;
+};
+
+#define I2C_AQ_COMB BIT(0)
+#define I2C_AQ_COMB_WRITE_FIRST BIT(1)
+#define I2C_AQ_COMB_READ_SECOND BIT(2)
+#define I2C_AQ_COMB_SAME_ADDR BIT(3)
+#define I2C_AQ_COMB_WRITE_THEN_READ \
+ (I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | \
+ I2C_AQ_COMB_READ_SECOND | I2C_AQ_COMB_SAME_ADDR)
+#define I2C_AQ_NO_CLK_STRETCH BIT(4)
+#define I2C_AQ_NO_ZERO_LEN_READ BIT(5)
+#define I2C_AQ_NO_ZERO_LEN_WRITE BIT(6)
+#define I2C_AQ_NO_ZERO_LEN \
+ (I2C_AQ_NO_ZERO_LEN_READ | I2C_AQ_NO_ZERO_LEN_WRITE)
+#define I2C_AQ_NO_REP_START BIT(7)
+
+int lkpi_i2c_add_adapter(struct i2c_adapter *adapter);
+int lkpi_i2c_del_adapter(struct i2c_adapter *adapter);
+
+int lkpi_i2cbb_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int nmsgs);
+
+#define i2c_add_adapter(adapter) lkpi_i2c_add_adapter(adapter)
+#define i2c_del_adapter(adapter) lkpi_i2c_del_adapter(adapter)
+
+#define i2c_get_adapter(x) NULL
+#define i2c_put_adapter(x)
+
+static inline int
+do_i2c_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int nmsgs)
+{
+ int ret, retries;
+
+ retries = adapter->retries == 0 ? 1 : adapter->retries;
+ for (; retries != 0; retries--) {
+ if (adapter->algo != NULL && adapter->algo->master_xfer != NULL)
+ ret = adapter->algo->master_xfer(adapter, msgs, nmsgs);
+ else
+ ret = lkpi_i2cbb_transfer(adapter, msgs, nmsgs);
+ if (ret != -EAGAIN)
+ break;
+ }
+
+ return (ret);
+}
+
+static inline int
+i2c_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int nmsgs)
+{
+ int ret;
+
+ if (adapter->algo == NULL && adapter->algo_data == NULL)
+ return (-EOPNOTSUPP);
+
+ if (adapter->lock_ops)
+ adapter->lock_ops->lock_bus(adapter, 0);
+
+ ret = do_i2c_transfer(adapter, msgs, nmsgs);
+
+ if (adapter->lock_ops)
+ adapter->lock_ops->unlock_bus(adapter, 0);
+
+ return (ret);
+}
+
+/* Unlocked version of i2c_transfer */
+static inline int
+__i2c_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int nmsgs)
+{
+ return (do_i2c_transfer(adapter, msgs, nmsgs));
+}
+
+static inline void
+i2c_set_adapdata(struct i2c_adapter *adapter, void *data)
+{
+ adapter->data = data;
+}
+
+static inline void *
+i2c_get_adapdata(struct i2c_adapter *adapter)
+{
+ return (adapter->data);
+}
+
+#endif /* _LINUX_I2C_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/idr.h b/sys/compat/linuxkpi/common/include/linux/idr.h
new file mode 100644
index 000000000000..535d8ce07fb4
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/idr.h
@@ -0,0 +1,162 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_IDR_H_
+#define _LINUXKPI_LINUX_IDR_H_
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/limits.h>
+#include <sys/mutex.h>
+
+#include <linux/radix-tree.h>
+#include <linux/gpf.h>
+#include <linux/types.h>
+
+#define IDR_BITS 5
+#define IDR_SIZE (1 << IDR_BITS)
+#define IDR_MASK (IDR_SIZE - 1)
+
+#define MAX_ID_SHIFT ((sizeof(int) * NBBY) - 1)
+#define MAX_ID_BIT (1U << MAX_ID_SHIFT)
+#define MAX_ID_MASK (MAX_ID_BIT - 1)
+#define MAX_LEVEL (MAX_ID_SHIFT + IDR_BITS - 1) / IDR_BITS
+
+#define MAX_IDR_SHIFT (sizeof(int)*8 - 1)
+#define MAX_IDR_BIT (1U << MAX_IDR_SHIFT)
+#define MAX_IDR_MASK (MAX_IDR_BIT - 1)
+
+struct idr_layer {
+ unsigned long bitmap;
+ struct idr_layer *ary[IDR_SIZE];
+};
+
+struct idr {
+ struct mtx lock;
+ struct idr_layer *top;
+ struct idr_layer *free;
+ int layers;
+ int next_cyclic_id;
+};
+
+/* NOTE: It is the applications responsibility to destroy the IDR */
+#define DEFINE_IDR(name) \
+ struct idr name; \
+ SYSINIT(name##_idr_sysinit, SI_SUB_DRIVERS, SI_ORDER_FIRST, \
+ idr_init, &(name))
+
+/* NOTE: It is the applications responsibility to destroy the IDA */
+#define DEFINE_IDA(name) \
+ struct ida name; \
+ SYSINIT(name##_ida_sysinit, SI_SUB_DRIVERS, SI_ORDER_FIRST, \
+ ida_init, &(name))
+
+void idr_preload(gfp_t gfp_mask);
+void idr_preload_end(void);
+void *idr_find(struct idr *idp, int id);
+void *idr_get_next(struct idr *idp, int *nextid);
+bool idr_is_empty(struct idr *idp);
+int idr_pre_get(struct idr *idp, gfp_t gfp_mask);
+int idr_get_new(struct idr *idp, void *ptr, int *id);
+int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id);
+void *idr_replace(struct idr *idp, void *ptr, int id);
+void *idr_remove(struct idr *idp, int id);
+void idr_remove_all(struct idr *idp);
+void idr_destroy(struct idr *idp);
+void idr_init(struct idr *idp);
+int idr_alloc(struct idr *idp, void *ptr, int start, int end, gfp_t);
+int idr_alloc_cyclic(struct idr *idp, void *ptr, int start, int end, gfp_t);
+int idr_for_each(struct idr *idp, int (*fn)(int id, void *p, void *data), void *data);
+
+#define idr_for_each_entry(idp, entry, id) \
+ for ((id) = 0; ((entry) = idr_get_next(idp, &(id))) != NULL; ++(id))
+
+#define IDA_CHUNK_SIZE 128 /* 128 bytes per chunk */
+#define IDA_BITMAP_LONGS (IDA_CHUNK_SIZE / sizeof(long) - 1)
+#define IDA_BITMAP_BITS (IDA_BITMAP_LONGS * sizeof(long) * 8)
+
+struct ida_bitmap {
+ long nr_busy;
+ unsigned long bitmap[IDA_BITMAP_LONGS];
+};
+
+struct ida {
+ struct idr idr;
+ struct ida_bitmap *free_bitmap;
+};
+
+int ida_pre_get(struct ida *ida, gfp_t gfp_mask);
+int ida_get_new_above(struct ida *ida, int starting_id, int *p_id);
+void ida_remove(struct ida *ida, int id);
+void ida_destroy(struct ida *ida);
+void ida_init(struct ida *ida);
+
+int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
+ gfp_t gfp_mask);
+void ida_simple_remove(struct ida *ida, unsigned int id);
+
+static inline void
+ida_free(struct ida *ida, int id)
+{
+
+ ida_remove(ida, id);
+}
+
+static inline int
+ida_get_new(struct ida *ida, int *p_id)
+{
+
+ return (ida_get_new_above(ida, 0, p_id));
+}
+
+static inline int
+ida_alloc_min(struct ida *ida, unsigned int min, gfp_t gfp)
+{
+ return (ida_simple_get(ida, min, UINT_MAX, gfp));
+}
+
+static inline int
+ida_alloc_max(struct ida *ida, unsigned int max, gfp_t gfp)
+{
+
+ return (ida_simple_get(ida, 0, max, gfp));
+}
+
+static inline int ida_alloc(struct ida *ida, gfp_t gfp)
+{
+ return (ida_alloc_max(ida, ~0u, gfp));
+}
+
+static inline bool
+ida_is_empty(struct ida *ida)
+{
+
+ return (idr_is_empty(&ida->idr));
+}
+
+#endif /* _LINUXKPI_LINUX_IDR_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/ieee80211.h b/sys/compat/linuxkpi/common/include/linux/ieee80211.h
new file mode 100644
index 000000000000..3644ef80861b
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/ieee80211.h
@@ -0,0 +1,1245 @@
+/*-
+ * Copyright (c) 2020-2025 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb 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_IEEE80211_H
+#define _LINUXKPI_LINUX_IEEE80211_H
+
+#include <sys/types.h>
+#include <net80211/ieee80211.h>
+
+#include <asm/unaligned.h>
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/if_ether.h>
+
+/* linux_80211.c */
+extern int linuxkpi_debug_80211;
+#ifndef D80211_TODO
+#define D80211_TODO 0x1
+#endif
+#define TODO(fmt, ...) if (linuxkpi_debug_80211 & D80211_TODO) \
+ printf("%s:%d: XXX LKPI80211 TODO " fmt "\n", __func__, __LINE__, ##__VA_ARGS__)
+
+
+/* 9.4.2.55 Management MIC element (CMAC-256, GMAC-128, and GMAC-256). */
+struct ieee80211_mmie_16 {
+ uint8_t element_id;
+ uint8_t length;
+ uint16_t key_id;
+ uint8_t ipn[6];
+ uint8_t mic[16];
+};
+
+#define IEEE80211_CCMP_HDR_LEN 8 /* 802.11i .. net80211 comment */
+#define IEEE80211_CCMP_PN_LEN 6
+#define IEEE80211_CCMP_MIC_LEN 8 /* || 16 */
+#define IEEE80211_CCMP_256_HDR_LEN 8
+#define IEEE80211_CCMP_256_MIC_LEN 16
+#define IEEE80211_GCMP_HDR_LEN 8
+#define IEEE80211_GCMP_MIC_LEN 16
+#define IEEE80211_GCMP_PN_LEN 6
+#define IEEE80211_GMAC_PN_LEN 6
+#define IEEE80211_CMAC_PN_LEN 6
+
+#define IEEE80211_MAX_PN_LEN 16
+
+#define IEEE80211_INVAL_HW_QUEUE ((uint8_t)-1)
+
+#define IEEE80211_MAX_AMPDU_BUF_HT IEEE80211_AGGR_BAWMAX
+#define IEEE80211_MAX_AMPDU_BUF_HE 256
+#define IEEE80211_MAX_AMPDU_BUF_EHT 1024
+
+#define IEEE80211_MAX_FRAME_LEN 2352
+#define IEEE80211_MAX_DATA_LEN (2300 + IEEE80211_CRC_LEN)
+
+#define IEEE80211_MAX_MPDU_LEN_HT_BA 4095 /* 9.3.2.1 Format of Data frames; non-VHT non-DMG STA */
+#define IEEE80211_MAX_MPDU_LEN_HT_3839 3839
+#define IEEE80211_MAX_MPDU_LEN_HT_7935 7935
+#define IEEE80211_MAX_MPDU_LEN_VHT_3895 3895
+#define IEEE80211_MAX_MPDU_LEN_VHT_7991 7991
+#define IEEE80211_MAX_MPDU_LEN_VHT_11454 11454
+
+#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)
+
+/* 802.11-2016, 9.2.4.5.1, Table 9-6 QoS Control Field */
+#define IEEE80211_QOS_CTL_TAG1D_MASK 0x0007
+#define IEEE80211_QOS_CTL_TID_MASK IEEE80211_QOS_TID
+#define IEEE80211_QOS_CTL_EOSP 0x0010
+#define IEEE80211_QOS_CTL_A_MSDU_PRESENT 0x0080
+#define IEEE80211_QOS_CTL_ACK_POLICY_MASK 0x0060
+#define IEEE80211_QOS_CTL_ACK_POLICY_NOACK 0x0020
+#define IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT 0x0100
+
+enum ieee80211_rate_flags {
+ IEEE80211_RATE_SHORT_PREAMBLE = BIT(0),
+};
+
+enum ieee80211_rate_control_changed_flags {
+ IEEE80211_RC_BW_CHANGED = BIT(0),
+ IEEE80211_RC_NSS_CHANGED = BIT(1),
+ IEEE80211_RC_SUPP_RATES_CHANGED = BIT(2),
+ IEEE80211_RC_SMPS_CHANGED = BIT(3),
+};
+
+#define IEEE80211_SCTL_FRAG IEEE80211_SEQ_FRAG_MASK
+#define IEEE80211_SCTL_SEQ IEEE80211_SEQ_SEQ_MASK
+
+#define IEEE80211_TKIP_ICV_LEN 4
+#define IEEE80211_TKIP_IV_LEN 8 /* WEP + KID + EXT */
+
+/* 802.11-2016, 9.4.2.158.3 Supported VHT-MCS and NSS Set field. */
+#define IEEE80211_VHT_EXT_NSS_BW_CAPABLE (1 << 13) /* part of tx_highest */
+
+#define IEEE80211_VHT_MAX_AMPDU_1024K 7 /* 9.4.2.56.3 A-MPDU Parameters field, Table 9-163 */
+
+#define IEEE80211_WEP_IV_LEN 3 /* net80211: IEEE80211_WEP_IVLEN */
+#define IEEE80211_WEP_ICV_LEN 4
+
+#define WLAN_AUTH_OPEN __LINE__ /* TODO FIXME brcmfmac */
+#define WLAN_CAPABILITY_IBSS __LINE__ /* TODO FIXME no longer used? */
+#define WLAN_CAPABILITY_SHORT_PREAMBLE __LINE__ /* TODO FIXME brcmfmac */
+#define WLAN_CAPABILITY_SHORT_SLOT_TIME __LINE__ /* TODO FIXME brcmfmac */
+
+enum wlan_ht_cap_sm_ps {
+ WLAN_HT_CAP_SM_PS_STATIC = 0,
+ WLAN_HT_CAP_SM_PS_DYNAMIC,
+ WLAN_HT_CAP_SM_PS_INVALID,
+ WLAN_HT_CAP_SM_PS_DISABLED,
+};
+
+#define WLAN_MAX_KEY_LEN 32
+#define WLAN_PMKID_LEN 16
+#define WLAN_PMK_LEN_SUITE_B_192 48
+
+enum ieee80211_key_len {
+ WLAN_KEY_LEN_WEP40 = 5,
+ WLAN_KEY_LEN_WEP104 = 13,
+ WLAN_KEY_LEN_TKIP = 32,
+ WLAN_KEY_LEN_CCMP = 16,
+ WLAN_KEY_LEN_CCMP_256 = 32,
+ WLAN_KEY_LEN_GCMP = 16,
+ WLAN_KEY_LEN_AES_CMAC = 16,
+ WLAN_KEY_LEN_GCMP_256 = 32,
+ WLAN_KEY_LEN_BIP_CMAC_256 = 32,
+ WLAN_KEY_LEN_BIP_GMAC_128 = 16,
+ WLAN_KEY_LEN_BIP_GMAC_256 = 32,
+};
+
+/* 802.11-2020, 9.4.2.55.3, Table 9-185 Subfields of the A-MPDU Parameters field */
+enum ieee80211_min_mpdu_start_spacing {
+ IEEE80211_HT_MPDU_DENSITY_NONE = 0,
+#if 0
+ IEEE80211_HT_MPDU_DENSITY_XXX = 1, /* 1/4 us */
+#endif
+ IEEE80211_HT_MPDU_DENSITY_0_5 = 2, /* 1/2 us */
+ IEEE80211_HT_MPDU_DENSITY_1 = 3, /* 1 us */
+ IEEE80211_HT_MPDU_DENSITY_2 = 4, /* 2 us */
+ IEEE80211_HT_MPDU_DENSITY_4 = 5, /* 4us */
+ IEEE80211_HT_MPDU_DENSITY_8 = 6, /* 8us */
+ IEEE80211_HT_MPDU_DENSITY_16 = 7, /* 16us */
+};
+
+/* 9.4.2.57, Table 9-168, HT Operation element fields and subfields */
+#define IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT 0x0080 /* B24.. */
+
+#define IEEE80211_FCTL_FTYPE IEEE80211_FC0_TYPE_MASK
+#define IEEE80211_FCTL_STYPE IEEE80211_FC0_SUBTYPE_MASK
+#define IEEE80211_FCTL_ORDER (IEEE80211_FC1_ORDER << 8)
+#define IEEE80211_FCTL_PROTECTED (IEEE80211_FC1_PROTECTED << 8)
+#define IEEE80211_FCTL_FROMDS (IEEE80211_FC1_DIR_FROMDS << 8)
+#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_FTYPE_MGMT IEEE80211_FC0_TYPE_MGT
+#define IEEE80211_FTYPE_CTL IEEE80211_FC0_TYPE_CTL
+#define IEEE80211_FTYPE_DATA IEEE80211_FC0_TYPE_DATA
+
+#define IEEE80211_STYPE_ASSOC_REQ IEEE80211_FC0_SUBTYPE_ASSOC_REQ
+#define IEEE80211_STYPE_REASSOC_REQ IEEE80211_FC0_SUBTYPE_REASSOC_REQ
+#define IEEE80211_STYPE_PROBE_REQ IEEE80211_FC0_SUBTYPE_PROBE_REQ
+#define IEEE80211_STYPE_DISASSOC IEEE80211_FC0_SUBTYPE_DISASSOC
+#define IEEE80211_STYPE_AUTH IEEE80211_FC0_SUBTYPE_AUTH
+#define IEEE80211_STYPE_DEAUTH IEEE80211_FC0_SUBTYPE_DEAUTH
+#define IEEE80211_STYPE_CTS IEEE80211_FC0_SUBTYPE_CTS
+#define IEEE80211_STYPE_RTS IEEE80211_FC0_SUBTYPE_RTS
+#define IEEE80211_STYPE_ACTION IEEE80211_FC0_SUBTYPE_ACTION
+#define IEEE80211_STYPE_DATA IEEE80211_FC0_SUBTYPE_DATA
+#define IEEE80211_STYPE_QOS_DATA IEEE80211_FC0_SUBTYPE_QOS_DATA
+#define IEEE80211_STYPE_QOS_NULLFUNC IEEE80211_FC0_SUBTYPE_QOS_NULL
+#define IEEE80211_STYPE_QOS_CFACK 0xd0 /* XXX-BZ reserved? */
+
+#define IEEE80211_NUM_ACS 4 /* net8021::WME_NUM_AC */
+
+#define IEEE80211_MAX_SSID_LEN 32 /* 9.4.2.2 SSID element, net80211: IEEE80211_NWID_LEN */
+
+
+/* Figure 9-27, BAR Control field */
+#define IEEE80211_BAR_CTRL_TID_INFO_MASK 0xf000
+#define IEEE80211_BAR_CTRL_TID_INFO_SHIFT 12
+
+#define IEEE80211_PPE_THRES_INFO_PPET_SIZE 1 /* TODO FIXME ax? */
+#define IEEE80211_PPE_THRES_NSS_MASK 2 /* TODO FIXME ax? */
+#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_POS 3 /* TODO FIXME ax? */
+#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK 8 /* TODO FIXME ax? */
+#define IEEE80211_HE_PPE_THRES_INFO_HEADER_SIZE 16 /* TODO FIXME ax? */
+
+/* 802.11-2012, Table 8-130-HT Operation element fields and subfields, HT Protection */
+#define IEEE80211_HT_OP_MODE_PROTECTION IEEE80211_HTINFO_OPMODE /* Mask. */
+#define IEEE80211_HT_OP_MODE_PROTECTION_NONE IEEE80211_HTINFO_OPMODE_PURE /* No protection */
+#define IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER IEEE80211_HTINFO_OPMODE_PROTOPT /* Nonmember protection */
+#define IEEE80211_HT_OP_MODE_PROTECTION_20MHZ IEEE80211_HTINFO_OPMODE_HT20PR /* 20 MHz protection */
+#define IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED IEEE80211_HTINFO_OPMODE_MIXED /* Non-HT mixed */
+
+
+/* 9.6.13.1, Table 9-342 TDLS Action field values. */
+enum ieee80211_tdls_action_code {
+ WLAN_TDLS_SETUP_REQUEST = 0,
+ WLAN_TDLS_SETUP_RESPONSE = 1,
+ WLAN_TDLS_SETUP_CONFIRM = 2,
+ WLAN_TDLS_TEARDOWN = 3,
+ WLAN_TDLS_PEER_TRAFFIC_INDICATION = 4,
+ WLAN_TDLS_CHANNEL_SWITCH_REQUEST = 5,
+ WLAN_TDLS_CHANNEL_SWITCH_RESPONSE = 6,
+ WLAN_TDLS_PEER_PSM_REQUEST = 7,
+ WLAN_TDLS_PEER_PSM_RESPONSE = 8,
+ WLAN_TDLS_PEER_TRAFFIC_RESPONSE = 9,
+ WLAN_TDLS_DISCOVERY_REQUEST = 10,
+ /* 11-255 reserved */
+};
+
+/* 802.11-2020 9.4.2.26, Table 9-153. Extended Capabilities field. */
+/* This is split up into octets CAPA1 = octet 1, ... */
+#define WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING BIT(2 % 8)
+#define WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT BIT(22 % 8)
+#define WLAN_EXT_CAPA3_TIMING_MEASUREMENT_SUPPORT BIT(23 % 8)
+#define WLAN_EXT_CAPA8_OPMODE_NOTIF BIT(62 % 8)
+#define WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB BIT(63 % 8)
+#define WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB BIT(64 % 8)
+#define WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT BIT(77 % 8)
+#define WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT BIT(78 % 8)
+#define WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT BIT(79 % 8)
+
+#define WLAN_EXT_CAPA11_EMA_SUPPORT 0x00 /* XXX TODO FIXME */
+
+
+/* iwlwifi/mvm/utils:: for (ac = IEEE80211_AC_VO; ac <= IEEE80211_AC_VI; ac++) */
+/* Would be so much easier if we'd define constants to the same. */
+enum ieee80211_ac_numbers {
+ IEEE80211_AC_VO = 0, /* net80211::WME_AC_VO */
+ IEEE80211_AC_VI = 1, /* net80211::WME_AC_VI */
+ IEEE80211_AC_BE = 2, /* net80211::WME_AC_BE */
+ IEEE80211_AC_BK = 3, /* net80211::WME_AC_BK */
+};
+
+#define IEEE80211_MAX_QUEUES 16 /* Assume IEEE80211_NUM_TIDS for the moment. */
+
+#define IEEE80211_WMM_IE_STA_QOSINFO_AC_VO 1
+#define IEEE80211_WMM_IE_STA_QOSINFO_AC_VI 2
+#define IEEE80211_WMM_IE_STA_QOSINFO_AC_BK 4
+#define IEEE80211_WMM_IE_STA_QOSINFO_AC_BE 8
+#define IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL 0xf
+
+
+/* Define the LinuxKPI names directly to the net80211 ones. */
+#define IEEE80211_HT_CAP_LDPC_CODING IEEE80211_HTCAP_LDPC
+#define IEEE80211_HT_CAP_SUP_WIDTH_20_40 IEEE80211_HTCAP_CHWIDTH40
+#define IEEE80211_HT_CAP_SM_PS IEEE80211_HTCAP_SMPS
+#define IEEE80211_HT_CAP_SM_PS_SHIFT 2
+#define IEEE80211_HT_CAP_GRN_FLD IEEE80211_HTCAP_GREENFIELD
+#define IEEE80211_HT_CAP_SGI_20 IEEE80211_HTCAP_SHORTGI20
+#define IEEE80211_HT_CAP_SGI_40 IEEE80211_HTCAP_SHORTGI40
+#define IEEE80211_HT_CAP_TX_STBC IEEE80211_HTCAP_TXSTBC
+#define IEEE80211_HT_CAP_RX_STBC IEEE80211_HTCAP_RXSTBC
+#define IEEE80211_HT_CAP_RX_STBC_SHIFT IEEE80211_HTCAP_RXSTBC_S
+#define IEEE80211_HT_CAP_MAX_AMSDU IEEE80211_HTCAP_MAXAMSDU
+#define IEEE80211_HT_CAP_DSSSCCK40 IEEE80211_HTCAP_DSSSCCK40
+#define IEEE80211_HT_CAP_LSIG_TXOP_PROT IEEE80211_HTCAP_LSIGTXOPPROT
+
+#define IEEE80211_HT_MCS_TX_DEFINED 0x0001
+#define IEEE80211_HT_MCS_TX_RX_DIFF 0x0002
+#define IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT 2
+#define IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK 0x0c
+#define IEEE80211_HT_MCS_RX_HIGHEST_MASK 0x3ff
+#define IEEE80211_HT_MCS_MASK_LEN 10
+
+#define IEEE80211_MLD_MAX_NUM_LINKS 15
+#define IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS 0xf
+#define IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP 0x0060
+#define IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP_SAME 1
+
+struct ieee80211_mcs_info {
+ uint8_t rx_mask[IEEE80211_HT_MCS_MASK_LEN];
+ uint16_t rx_highest;
+ uint8_t tx_params;
+ uint8_t __reserved[3];
+} __packed;
+
+/* 802.11-2020, 9.4.2.55.1 HT Capabilities element structure */
+struct ieee80211_ht_cap {
+ uint16_t cap_info;
+ uint8_t ampdu_params_info;
+ struct ieee80211_mcs_info mcs;
+ uint16_t extended_ht_cap_info;
+ uint32_t tx_BF_cap_info;
+ uint8_t antenna_selection_info;
+} __packed;
+
+#define IEEE80211_HT_MAX_AMPDU_FACTOR 13
+#define IEEE80211_HE_HT_MAX_AMPDU_FACTOR 16
+#define IEEE80211_HE_VHT_MAX_AMPDU_FACTOR 20
+#define IEEE80211_HE_6GHZ_MAX_AMPDU_FACTOR 13
+
+enum ieee80211_ht_max_ampdu_len {
+ IEEE80211_HT_MAX_AMPDU_64K
+};
+
+enum ieee80211_ampdu_mlme_action {
+ IEEE80211_AMPDU_RX_START,
+ IEEE80211_AMPDU_RX_STOP,
+ IEEE80211_AMPDU_TX_OPERATIONAL,
+ IEEE80211_AMPDU_TX_START,
+ IEEE80211_AMPDU_TX_STOP_CONT,
+ IEEE80211_AMPDU_TX_STOP_FLUSH,
+ IEEE80211_AMPDU_TX_STOP_FLUSH_CONT
+};
+
+#define IEEE80211_AMPDU_TX_START_IMMEDIATE 1
+#define IEEE80211_AMPDU_TX_START_DELAY_ADDBA 2
+
+enum ieee80211_chanctx_switch_mode {
+ CHANCTX_SWMODE_REASSIGN_VIF,
+ CHANCTX_SWMODE_SWAP_CONTEXTS,
+};
+
+enum ieee80211_chanctx_change_flags {
+ IEEE80211_CHANCTX_CHANGE_MIN_WIDTH = BIT(0),
+ IEEE80211_CHANCTX_CHANGE_RADAR = BIT(1),
+ IEEE80211_CHANCTX_CHANGE_RX_CHAINS = BIT(2),
+ IEEE80211_CHANCTX_CHANGE_WIDTH = BIT(3),
+ IEEE80211_CHANCTX_CHANGE_CHANNEL = BIT(4),
+ IEEE80211_CHANCTX_CHANGE_PUNCTURING = BIT(5),
+ IEEE80211_CHANCTX_CHANGE_MIN_DEF = BIT(6),
+};
+
+enum ieee80211_frame_release_type {
+ IEEE80211_FRAME_RELEASE_PSPOLL = 1,
+ IEEE80211_FRAME_RELEASE_UAPSD = 2,
+};
+
+enum ieee80211_p2p_attr_ids {
+ IEEE80211_P2P_ATTR_DEVICE_ID,
+ IEEE80211_P2P_ATTR_DEVICE_INFO,
+ IEEE80211_P2P_ATTR_GROUP_ID,
+ IEEE80211_P2P_ATTR_LISTEN_CHANNEL,
+ IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
+};
+
+enum ieee80211_reconfig_type {
+ IEEE80211_RECONFIG_TYPE_RESTART,
+ IEEE80211_RECONFIG_TYPE_SUSPEND,
+};
+
+enum ieee80211_roc_type {
+ IEEE80211_ROC_TYPE_MGMT_TX,
+ IEEE80211_ROC_TYPE_NORMAL,
+};
+
+enum ieee80211_smps_mode {
+ IEEE80211_SMPS_OFF,
+ IEEE80211_SMPS_STATIC,
+ IEEE80211_SMPS_DYNAMIC,
+ IEEE80211_SMPS_AUTOMATIC,
+ IEEE80211_SMPS_NUM_MODES,
+};
+
+/* net80211::IEEE80211_S_* different but represents the state machine. */
+/* Note: order here is important! */
+enum ieee80211_sta_state {
+ IEEE80211_STA_NOTEXIST = 0,
+ IEEE80211_STA_NONE = 1,
+ IEEE80211_STA_AUTH = 2,
+ IEEE80211_STA_ASSOC = 3,
+ IEEE80211_STA_AUTHORIZED = 4, /* 802.1x */
+};
+
+enum ieee80211_tx_info_flags {
+ /* XXX TODO .. right shift numbers - not sure where that came from? */
+ IEEE80211_TX_CTL_AMPDU = BIT(0),
+ IEEE80211_TX_CTL_ASSIGN_SEQ = BIT(1),
+ IEEE80211_TX_CTL_NO_ACK = BIT(2),
+ IEEE80211_TX_CTL_SEND_AFTER_DTIM = BIT(3),
+ IEEE80211_TX_CTL_TX_OFFCHAN = BIT(4),
+ IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(5),
+ IEEE80211_TX_STATUS_EOSP = BIT(6),
+ IEEE80211_TX_STAT_ACK = BIT(7),
+ IEEE80211_TX_STAT_AMPDU = BIT(8),
+ IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(9),
+ IEEE80211_TX_STAT_TX_FILTERED = BIT(10),
+ IEEE80211_TX_STAT_NOACK_TRANSMITTED = BIT(11),
+ IEEE80211_TX_CTL_FIRST_FRAGMENT = BIT(12),
+ IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(13),
+ IEEE80211_TX_CTL_NO_CCK_RATE = BIT(14),
+ IEEE80211_TX_CTL_INJECTED = BIT(15),
+ IEEE80211_TX_CTL_HW_80211_ENCAP = BIT(16),
+ IEEE80211_TX_CTL_USE_MINRATE = BIT(17),
+ IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(18),
+ IEEE80211_TX_CTL_LDPC = BIT(19),
+ IEEE80211_TX_CTL_STBC = BIT(20),
+} __packed;
+
+enum ieee80211_tx_status_flags {
+ IEEE80211_TX_STATUS_ACK_SIGNAL_VALID = BIT(0),
+};
+
+enum ieee80211_tx_control_flags {
+ /* XXX TODO .. right shift numbers */
+ IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0),
+ IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1),
+ IEEE80211_TX_CTRL_RATE_INJECT = BIT(2),
+ IEEE80211_TX_CTRL_DONT_USE_RATE_MASK = BIT(3),
+ 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
+
+struct ieee80211_hdr { /* net80211::ieee80211_frame_addr4 */
+ __le16 frame_control;
+ __le16 duration_id;
+ uint8_t addr1[ETH_ALEN];
+ uint8_t addr2[ETH_ALEN];
+ uint8_t addr3[ETH_ALEN];
+ __le16 seq_ctrl;
+ uint8_t addr4[ETH_ALEN];
+};
+
+struct ieee80211_hdr_3addr { /* net80211::ieee80211_frame */
+ __le16 frame_control;
+ __le16 duration_id;
+ uint8_t addr1[ETH_ALEN];
+ uint8_t addr2[ETH_ALEN];
+ uint8_t addr3[ETH_ALEN];
+ __le16 seq_ctrl;
+};
+
+struct ieee80211_qos_hdr { /* net80211:ieee80211_qosframe */
+ __le16 frame_control;
+ __le16 duration_id;
+ uint8_t addr1[ETH_ALEN];
+ uint8_t addr2[ETH_ALEN];
+ uint8_t addr3[ETH_ALEN];
+ __le16 seq_ctrl;
+ __le16 qos_ctrl;
+};
+
+struct ieee80211_vendor_ie {
+};
+
+/* 802.11-2020, Table 9-359-Block Ack Action field values */
+enum ieee80211_back {
+ WLAN_ACTION_ADDBA_REQ = 0,
+};
+
+enum ieee80211_sa_query {
+ WLAN_ACTION_SA_QUERY_RESPONSE = 1,
+};
+
+/* 802.11-2020, Table 9-51-Category values */
+enum ieee80211_category {
+ WLAN_CATEGORY_BACK = 3,
+ WLAN_CATEGORY_SA_QUERY = 8, /* net80211::IEEE80211_ACTION_CAT_SA_QUERY */
+};
+
+/* 80211-2020 9.3.3.2 Format of Management frames */
+struct ieee80211_mgmt {
+ __le16 frame_control;
+ __le16 duration_id;
+ uint8_t da[ETH_ALEN];
+ uint8_t sa[ETH_ALEN];
+ uint8_t bssid[ETH_ALEN];
+ __le16 seq_ctrl;
+ union {
+ /* 9.3.3.3 Beacon frame format */
+ struct {
+ uint64_t timestamp;
+ uint16_t beacon_int;
+ uint16_t capab_info;
+ uint8_t variable[0];
+ } beacon;
+ /* 9.3.3.5 Association Request frame format */
+ struct {
+ uint16_t capab_info;
+ uint16_t listen_interval;
+ uint8_t variable[0];
+ } assoc_req;
+ /* 9.3.3.10 Probe Request frame format */
+ struct {
+ uint8_t variable[0];
+ } probe_req;
+ /* 9.3.3.11 Probe Response frame format */
+ struct {
+ uint64_t timestamp;
+ uint16_t beacon_int;
+ uint16_t capab_info;
+ uint8_t variable[0];
+ } probe_resp;
+ /* 9.3.3.14 Action frame format */
+ struct {
+ /* 9.4.1.11 Action field */
+ uint8_t category;
+ /* 9.6.8 Public Action details */
+ union {
+ /* 9.6.2.5 TPC Report frame format */
+ struct {
+ uint8_t spec_mgmt;
+ uint8_t dialog_token;
+ /* uint32_t tpc_rep_elem:: */
+ uint8_t tpc_elem_id;
+ uint8_t tpc_elem_length;
+ uint8_t tpc_elem_tx_power;
+ uint8_t tpc_elem_link_margin;
+ } tpc_report;
+ /* 9.6.8.33 Fine Timing Measurement frame format */
+ struct {
+ uint8_t dialog_token;
+ uint8_t follow_up;
+ uint8_t tod[6];
+ uint8_t toa[6];
+ uint16_t tod_error;
+ uint16_t toa_error;
+ uint8_t variable[0];
+ } ftm;
+ /* 802.11-2016, 9.6.5.2 ADDBA Request frame format */
+ struct {
+ uint8_t action_code;
+ uint8_t dialog_token;
+ uint16_t capab;
+ uint16_t timeout;
+ uint16_t start_seq_num;
+ /* Optional follows... */
+ uint8_t variable[0];
+ } addba_req;
+ /* XXX */
+ struct {
+ uint8_t dialog_token;
+ } wnm_timing_msr;
+ } u;
+ } action;
+ DECLARE_FLEX_ARRAY(uint8_t, body);
+ } u;
+};
+
+struct ieee80211_cts { /* net80211::ieee80211_frame_cts */
+ __le16 frame_control;
+ __le16 duration;
+ uint8_t ra[ETH_ALEN];
+} __packed;
+
+struct ieee80211_rts { /* net80211::ieee80211_frame_rts */
+ __le16 frame_control;
+ __le16 duration;
+ uint8_t ra[ETH_ALEN];
+ uint8_t ta[ETH_ALEN];
+} __packed;
+
+#define MHZ_TO_KHZ(_f) ((_f) * 1000)
+#define DBI_TO_MBI(_g) ((_g) * 100)
+#define MBI_TO_DBI(_x) ((_x) / 100)
+#define DBM_TO_MBM(_g) ((_g) * 100)
+#define MBM_TO_DBM(_x) ((_x) / 100)
+
+#define IEEE80211_SEQ_TO_SN(_seqn) (((_seqn) & IEEE80211_SEQ_SEQ_MASK) >> \
+ IEEE80211_SEQ_SEQ_SHIFT)
+#define IEEE80211_SN_TO_SEQ(_sn) (((_sn) << IEEE80211_SEQ_SEQ_SHIFT) & \
+ IEEE80211_SEQ_SEQ_MASK)
+
+/* Time unit (TU) to .. See net80211: IEEE80211_DUR_TU */
+#define TU_TO_JIFFIES(_tu) (usecs_to_jiffies(_tu) * 1024)
+#define TU_TO_EXP_TIME(_tu) (jiffies + TU_TO_JIFFIES(_tu))
+
+/* 9.4.2.21.1, Table 9-82. */
+#define IEEE80211_SPCT_MSR_RPRT_TYPE_LCI 8
+#define IEEE80211_SPCT_MSR_RPRT_TYPE_CIVIC 11
+
+/* 9.4.2.1, Table 9-77. Element IDs. */
+enum ieee80211_eid {
+ WLAN_EID_SSID = 0,
+ WLAN_EID_SUPP_RATES = 1,
+ WLAN_EID_DS_PARAMS = 3,
+ WLAN_EID_TIM = 5,
+ WLAN_EID_COUNTRY = 7, /* IEEE80211_ELEMID_COUNTRY */
+ WLAN_EID_REQUEST = 10,
+ WLAN_EID_QBSS_LOAD = 11, /* IEEE80211_ELEMID_BSSLOAD */
+ WLAN_EID_CHANNEL_SWITCH = 37,
+ WLAN_EID_MEASURE_REPORT = 39,
+ WLAN_EID_HT_CAPABILITY = 45, /* IEEE80211_ELEMID_HTCAP */
+ WLAN_EID_RSN = 48, /* IEEE80211_ELEMID_RSN */
+ WLAN_EID_EXT_SUPP_RATES = 50,
+ WLAN_EID_EXT_NON_INHERITANCE = 56,
+ WLAN_EID_EXT_CHANSWITCH_ANN = 60,
+ WLAN_EID_MULTIPLE_BSSID = 71, /* IEEE80211_ELEMID_MULTIBSSID */
+ WLAN_EID_MULTI_BSSID_IDX = 85,
+ WLAN_EID_EXT_CAPABILITY = 127,
+ WLAN_EID_VHT_CAPABILITY = 191, /* IEEE80211_ELEMID_VHT_CAP */
+ WLAN_EID_S1G_TWT = 216,
+ WLAN_EID_VENDOR_SPECIFIC = 221, /* IEEE80211_ELEMID_VENDOR */
+};
+
+enum ieee80211_eid_ext {
+ WLAN_EID_EXT_HE_CAPABILITY = 35,
+};
+
+#define for_each_element(_elem, _data, _len) \
+ for (_elem = (const struct element *)(_data); \
+ (((const uint8_t *)(_data) + (_len) - (const uint8_t *)_elem) >= sizeof(*_elem)) && \
+ (((const uint8_t *)(_data) + (_len) - (const uint8_t *)_elem) >= (sizeof(*_elem) + _elem->datalen)); \
+ _elem = (const struct element *)(_elem->data + _elem->datalen))
+
+#define for_each_element_id(_elem, _eid, _data, _len) \
+ for_each_element(_elem, _data, _len) \
+ if (_elem->id == (_eid))
+
+/* 9.4.1.7, Table 9-45. Reason codes. */
+enum ieee80211_reason_code {
+ /* reserved = 0, */
+ WLAN_REASON_UNSPECIFIED = 1,
+ WLAN_REASON_DEAUTH_LEAVING = 3, /* LEAVING_NETWORK_DEAUTH */
+ WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE = 25,
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED = 26,
+};
+
+/* 9.4.1.9, Table 9-46. Status codes. */
+enum ieee80211_status_code {
+ WLAN_STATUS_SUCCESS = 0,
+ WLAN_STATUS_AUTH_TIMEOUT = 16, /* REJECTED_SEQUENCE_TIMEOUT */
+};
+
+/* 9.3.1.22 Trigger frame format; 80211ax-2021 */
+struct ieee80211_trigger {
+ __le16 frame_control;
+ __le16 duration_id;
+ uint8_t ra[ETH_ALEN];
+ uint8_t ta[ETH_ALEN];
+ __le64 common_info; /* 8+ really */
+ uint8_t variable[];
+};
+
+/* Table 9-29c-Trigger Type subfield encoding */
+enum {
+ IEEE80211_TRIGGER_TYPE_BASIC = 0x0,
+ IEEE80211_TRIGGER_TYPE_MU_BAR = 0x2,
+#if 0
+ /* Not seen yet. */
+ BFRP = 0x1,
+ MU-RTS = 0x3,
+ BSRP = 0x4,
+ GCR MU-BAR = 0x5,
+ BQRP = 0x6,
+ NFRP = 0x7,
+ /* 0x8..0xf reserved */
+#endif
+ IEEE80211_TRIGGER_TYPE_MASK = 0xf
+};
+
+#define IEEE80211_TRIGGER_ULBW_MASK 0xc0000
+#define IEEE80211_TRIGGER_ULBW_20MHZ 0x0
+#define IEEE80211_TRIGGER_ULBW_40MHZ 0x1
+#define IEEE80211_TRIGGER_ULBW_80MHZ 0x2
+#define IEEE80211_TRIGGER_ULBW_160_80P80MHZ 0x3
+
+/* 802.11-2020, Figure 9-687-Control field format; 802.11ax-2021 */
+#define IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST BIT(3)
+#define IEEE80211_TWT_CONTROL_RX_DISABLED BIT(4)
+#define IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT BIT(5)
+
+/* 802.11-2020, Figure 9-688-Request Type field format; 802.11ax-2021 */
+#define IEEE80211_TWT_REQTYPE_SETUP_CMD (BIT(1) | BIT(2) | BIT(3))
+#define IEEE80211_TWT_REQTYPE_TRIGGER BIT(4)
+#define IEEE80211_TWT_REQTYPE_IMPLICIT BIT(5)
+#define IEEE80211_TWT_REQTYPE_FLOWTYPE BIT(6)
+#define IEEE80211_TWT_REQTYPE_FLOWID (BIT(7) | BIT(8) | BIT(9))
+#define IEEE80211_TWT_REQTYPE_WAKE_INT_EXP (BIT(10) | BIT(11) | BIT(12) | BIT(13) | BIT(14))
+#define IEEE80211_TWT_REQTYPE_PROTECTION BIT(15)
+
+struct ieee80211_twt_params {
+ int mantissa, min_twt_dur, twt;
+ uint16_t req_type;
+};
+
+struct ieee80211_twt_setup {
+ int control;
+ struct ieee80211_twt_params *params;
+};
+
+/* 802.11-2020, Table 9-297-TWT Setup Command field values */
+enum ieee80211_twt_setup_cmd {
+ TWT_SETUP_CMD_REQUEST = 0,
+ TWT_SETUP_CMD_SUGGEST = 1,
+ /* DEMAND = 2, */
+ /* GROUPING = 3, */
+ TWT_SETUP_CMD_ACCEPT = 4,
+ /* ALTERNATE = 5 */
+ TWT_SETUP_CMD_DICTATE = 6,
+ TWT_SETUP_CMD_REJECT = 7,
+};
+
+struct ieee80211_bssid_index {
+ int bssid_index;
+};
+
+enum ieee80211_ap_reg_power {
+ IEEE80211_REG_UNSET_AP,
+ IEEE80211_REG_LPI_AP,
+ IEEE80211_REG_SP_AP,
+ IEEE80211_REG_VLP_AP,
+};
+
+/*
+ * 802.11ax-2021, Table 9-277-Meaning of Maximum Transmit Power Count subfield
+ * if Maximum Transmit Power Interpretation subfield is 1 or 3
+ */
+#define IEEE80211_MAX_NUM_PWR_LEVEL 8
+
+/*
+ * 802.11ax-2021, Table 9-275a-Maximum Transmit Power Interpretation subfield
+ * encoding (4) * Table E-12-Regulatory Info subfield encoding in the
+ * United States (2)
+ */
+#define IEEE80211_TPE_MAX_IE_NUM 8
+
+/* 802.11ax-2021, 9.4.2.161 Transmit Power Envelope element */
+struct ieee80211_tx_pwr_env {
+ uint8_t tx_power_info;
+ uint8_t tx_power[IEEE80211_MAX_NUM_PWR_LEVEL];
+};
+
+/* 802.11ax-2021, Figure 9-617-Transmit Power Information field format */
+/* These are field masks (3bit/3bit/2bit). */
+#define IEEE80211_TX_PWR_ENV_INFO_COUNT 0x07
+#define IEEE80211_TX_PWR_ENV_INFO_INTERPRET 0x38
+#define IEEE80211_TX_PWR_ENV_INFO_CATEGORY 0xc0
+
+/*
+ * 802.11ax-2021, Table 9-275a-Maximum Transmit Power Interpretation subfield
+ * encoding
+ */
+enum ieee80211_tx_pwr_interpretation_subfield_enc {
+ IEEE80211_TPE_LOCAL_EIRP,
+ IEEE80211_TPE_LOCAL_EIRP_PSD,
+ IEEE80211_TPE_REG_CLIENT_EIRP,
+ IEEE80211_TPE_REG_CLIENT_EIRP_PSD,
+};
+
+enum ieee80211_tx_pwr_category_6ghz {
+ IEEE80211_TPE_CAT_6GHZ_DEFAULT,
+};
+
+/* 802.11-2020, 9.4.2.27 BSS Load element */
+struct ieee80211_bss_load_elem {
+ uint16_t sta_count;
+ uint8_t channel_util;
+ uint16_t avail_adm_capa;
+};
+
+struct ieee80211_p2p_noa_desc {
+ uint32_t count; /* uint8_t ? */
+ uint32_t duration;
+ uint32_t interval;
+ uint32_t start_time;
+};
+
+struct ieee80211_p2p_noa_attr {
+ uint8_t index;
+ uint8_t oppps_ctwindow;
+ struct ieee80211_p2p_noa_desc desc[4];
+};
+
+
+/* net80211: IEEE80211_IS_CTL() */
+static __inline bool
+ieee80211_is_ctl(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16(IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_TYPE_CTL);
+
+ return (fc == v);
+}
+
+/* net80211: IEEE80211_IS_DATA() */
+static __inline bool
+ieee80211_is_data(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16(IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_TYPE_DATA);
+
+ return (fc == v);
+}
+
+/* net80211: IEEE80211_IS_QOSDATA() */
+static __inline bool
+ieee80211_is_data_qos(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16(IEEE80211_FC0_SUBTYPE_QOS_DATA | IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_SUBTYPE_QOS_DATA | IEEE80211_FC0_TYPE_DATA);
+
+ return (fc == v);
+}
+
+/* net80211: IEEE80211_IS_MGMT() */
+static __inline bool
+ieee80211_is_mgmt(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16(IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_TYPE_MGT);
+
+ return (fc == v);
+}
+
+
+/* Derived from net80211::ieee80211_anyhdrsize. */
+static __inline unsigned int
+ieee80211_hdrlen(__le16 fc)
+{
+ unsigned int size;
+
+ if (ieee80211_is_ctl(fc)) {
+ switch (fc & htole16(IEEE80211_FC0_SUBTYPE_MASK)) {
+ case htole16(IEEE80211_FC0_SUBTYPE_CTS):
+ case htole16(IEEE80211_FC0_SUBTYPE_ACK):
+ return sizeof(struct ieee80211_frame_ack);
+ case htole16(IEEE80211_FC0_SUBTYPE_BAR):
+ return sizeof(struct ieee80211_frame_bar);
+ }
+ return (sizeof(struct ieee80211_frame_min));
+ }
+
+ size = sizeof(struct ieee80211_frame);
+ if (ieee80211_is_data(fc)) {
+ if ((fc & htole16(IEEE80211_FC1_DIR_MASK << 8)) ==
+ htole16(IEEE80211_FC1_DIR_DSTODS << 8))
+ size += IEEE80211_ADDR_LEN;
+ if ((fc & htole16(IEEE80211_FC0_SUBTYPE_QOS_DATA |
+ IEEE80211_FC0_TYPE_MASK)) ==
+ htole16(IEEE80211_FC0_SUBTYPE_QOS_DATA |
+ IEEE80211_FC0_TYPE_DATA))
+ size += sizeof(uint16_t);
+ }
+
+ if (ieee80211_is_mgmt(fc)) {
+#ifdef __notyet__
+ printf("XXX-BZ %s: TODO? fc %#04x size %u\n",
+ __func__, fc, size);
+#endif
+ ;
+ }
+
+ return (size);
+}
+
+static inline bool
+ieee80211_is_trigger(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16(IEEE80211_FC0_SUBTYPE_MASK | IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_SUBTYPE_TRIGGER | IEEE80211_FC0_TYPE_CTL);
+
+ return (fc == v);
+}
+
+static __inline bool
+ieee80211_is_action(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16(IEEE80211_FC0_SUBTYPE_MASK | IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_SUBTYPE_ACTION | IEEE80211_FC0_TYPE_MGT);
+
+ return (fc == v);
+}
+
+static __inline bool
+ieee80211_is_probe_resp(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16(IEEE80211_FC0_SUBTYPE_MASK | IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_SUBTYPE_PROBE_RESP | IEEE80211_FC0_TYPE_MGT);
+
+ return (fc == v);
+}
+
+static __inline bool
+ieee80211_is_auth(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16(IEEE80211_FC0_SUBTYPE_MASK | IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_SUBTYPE_AUTH | IEEE80211_FC0_TYPE_MGT);
+
+ return (fc == v);
+}
+
+static __inline bool
+ieee80211_is_assoc_req(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16(IEEE80211_FC0_SUBTYPE_MASK | IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_SUBTYPE_ASSOC_REQ | IEEE80211_FC0_TYPE_MGT);
+
+ return (fc == v);
+}
+
+static __inline bool
+ieee80211_is_assoc_resp(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16(IEEE80211_FC0_SUBTYPE_MASK | IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_SUBTYPE_ASSOC_RESP | IEEE80211_FC0_TYPE_MGT);
+
+ return (fc == v);
+}
+
+static __inline bool
+ieee80211_is_reassoc_req(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16(IEEE80211_FC0_SUBTYPE_MASK | IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_SUBTYPE_REASSOC_REQ | IEEE80211_FC0_TYPE_MGT);
+
+ return (fc == v);
+}
+
+static __inline bool
+ieee80211_is_reassoc_resp(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16(IEEE80211_FC0_SUBTYPE_MASK | IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_SUBTYPE_REASSOC_RESP | IEEE80211_FC0_TYPE_MGT);
+
+ return (fc == v);
+}
+
+static __inline bool
+ieee80211_is_disassoc(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16(IEEE80211_FC0_SUBTYPE_MASK | IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_SUBTYPE_DISASSOC | IEEE80211_FC0_TYPE_MGT);
+
+ return (fc == v);
+}
+
+static __inline bool
+ieee80211_is_data_present(__le16 fc)
+{
+ __le16 v;
+
+ /* If it is a data frame and NODATA is not present. */
+ fc &= htole16(IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_NODATA);
+ v = htole16(IEEE80211_FC0_TYPE_DATA);
+
+ return (fc == v);
+}
+
+static __inline bool
+ieee80211_is_deauth(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16(IEEE80211_FC0_SUBTYPE_MASK | IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_SUBTYPE_DEAUTH | IEEE80211_FC0_TYPE_MGT);
+
+ return (fc == v);
+}
+
+static __inline bool
+ieee80211_is_beacon(__le16 fc)
+{
+ __le16 v;
+
+ /*
+ * For as much as I get it this comes in LE and unlike FreeBSD
+ * where we get the entire frame header and u8[], here we get the
+ * 9.2.4.1 Frame Control field only. Mask and compare.
+ */
+ fc &= htole16(IEEE80211_FC0_SUBTYPE_MASK | IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_SUBTYPE_BEACON | IEEE80211_FC0_TYPE_MGT);
+
+ return (fc == v);
+}
+
+
+static __inline bool
+ieee80211_is_probe_req(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16(IEEE80211_FC0_SUBTYPE_MASK | IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_SUBTYPE_PROBE_REQ | IEEE80211_FC0_TYPE_MGT);
+
+ return (fc == v);
+}
+
+static __inline bool
+ieee80211_has_protected(__le16 fc)
+{
+
+ return (fc & htole16(IEEE80211_FC1_PROTECTED << 8));
+}
+
+static __inline bool
+ieee80211_is_back_req(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16(IEEE80211_FC0_SUBTYPE_MASK | IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_SUBTYPE_BAR | IEEE80211_FC0_TYPE_CTL);
+
+ return (fc == v);
+}
+
+static __inline bool
+ieee80211_is_bufferable_mmpdu(struct sk_buff *skb)
+{
+ struct ieee80211_mgmt *mgmt;
+ __le16 fc;
+
+ mgmt = (struct ieee80211_mgmt *)skb->data;
+ fc = mgmt->frame_control;
+
+ /* 11.2.2 Bufferable MMPDUs, 80211-2020. */
+ /* XXX we do not care about IBSS yet. */
+
+ if (!ieee80211_is_mgmt(fc))
+ return (false);
+ if (ieee80211_is_action(fc)) /* XXX FTM? */
+ return (true); /* XXX false? */
+ if (ieee80211_is_disassoc(fc))
+ return (true);
+ if (ieee80211_is_deauth(fc))
+ return (true);
+
+ TODO();
+
+ return (false);
+}
+
+static __inline bool
+ieee80211_is_nullfunc(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16(IEEE80211_FC0_SUBTYPE_MASK | IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_SUBTYPE_NODATA | IEEE80211_FC0_TYPE_DATA);
+
+ return (fc == v);
+}
+
+static __inline bool
+ieee80211_is_qos_nullfunc(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16(IEEE80211_FC0_SUBTYPE_MASK | IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_SUBTYPE_QOS_NULL | IEEE80211_FC0_TYPE_DATA);
+
+ return (fc == v);
+}
+
+static __inline bool
+ieee80211_is_any_nullfunc(__le16 fc)
+{
+
+ return (ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc));
+}
+
+static inline bool
+ieee80211_is_pspoll(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16(IEEE80211_FC0_SUBTYPE_MASK | IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_SUBTYPE_PS_POLL | IEEE80211_FC0_TYPE_CTL);
+
+ return (fc == v);
+}
+
+static __inline bool
+ieee80211_has_a4(__le16 fc)
+{
+ __le16 v;
+
+ fc &= htole16((IEEE80211_FC1_DIR_TODS | IEEE80211_FC1_DIR_FROMDS) << 8);
+ v = htole16((IEEE80211_FC1_DIR_TODS | IEEE80211_FC1_DIR_FROMDS) << 8);
+
+ return (fc == v);
+}
+
+static __inline bool
+ieee80211_has_order(__le16 fc)
+{
+
+ return (fc & htole16(IEEE80211_FC1_ORDER << 8));
+}
+
+static __inline bool
+ieee80211_has_retry(__le16 fc)
+{
+
+ return (fc & htole16(IEEE80211_FC1_RETRY << 8));
+}
+
+
+static __inline bool
+ieee80211_has_fromds(__le16 fc)
+{
+
+ return (fc & htole16(IEEE80211_FC1_DIR_FROMDS << 8));
+}
+
+static __inline bool
+ieee80211_has_tods(__le16 fc)
+{
+
+ return (fc & htole16(IEEE80211_FC1_DIR_TODS << 8));
+}
+
+static __inline uint8_t *
+ieee80211_get_SA(struct ieee80211_hdr *hdr)
+{
+
+ if (ieee80211_has_a4(hdr->frame_control))
+ return (hdr->addr4);
+ if (ieee80211_has_fromds(hdr->frame_control))
+ return (hdr->addr3);
+ return (hdr->addr2);
+}
+
+static __inline uint8_t *
+ieee80211_get_DA(struct ieee80211_hdr *hdr)
+{
+
+ if (ieee80211_has_tods(hdr->frame_control))
+ return (hdr->addr3);
+ return (hdr->addr1);
+}
+
+static __inline bool
+ieee80211_is_frag(struct ieee80211_hdr *hdr)
+{
+ TODO();
+ return (false);
+}
+
+static __inline bool
+ieee80211_is_first_frag(__le16 fc)
+{
+ TODO();
+ return (false);
+}
+
+static __inline bool
+ieee80211_is_robust_mgmt_frame(struct sk_buff *skb)
+{
+ TODO();
+ return (false);
+}
+
+static __inline bool
+ieee80211_is_ftm(struct sk_buff *skb)
+{
+ TODO();
+ return (false);
+}
+
+static __inline bool
+ieee80211_is_timing_measurement(struct sk_buff *skb)
+{
+ TODO();
+ return (false);
+}
+
+static __inline bool
+ieee80211_has_pm(__le16 fc)
+{
+ TODO();
+ return (false);
+}
+
+static __inline bool
+ieee80211_has_morefrags(__le16 fc)
+{
+
+ fc &= htole16(IEEE80211_FC1_MORE_FRAG << 8);
+ return (fc != 0);
+}
+
+static __inline u8 *
+ieee80211_get_qos_ctl(struct ieee80211_hdr *hdr)
+{
+ if (ieee80211_has_a4(hdr->frame_control))
+ return (u8 *)hdr + 30;
+ else
+ return (u8 *)hdr + 24;
+}
+
+#endif /* _LINUXKPI_LINUX_IEEE80211_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/if_arp.h b/sys/compat/linuxkpi/common/include/linux/if_arp.h
new file mode 100644
index 000000000000..6201c3a1c284
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/if_arp.h
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_IF_ARP_H_
+#define _LINUXKPI_LINUX_IF_ARP_H_
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if_arp.h>
+#endif /* _LINUXKPI_LINUX_IF_ARP_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/if_ether.h b/sys/compat/linuxkpi/common/include/linux/if_ether.h
new file mode 100644
index 000000000000..6676e8fc142f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/if_ether.h
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ * Copyright (c) 2021-2022 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * 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 unmodified, 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 ``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 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_IF_ETHER_H_
+#define _LINUXKPI_LINUX_IF_ETHER_H_
+
+#include <linux/types.h>
+#include <linux/skbuff.h>
+
+#include <net/ethernet.h>
+
+#define ETH_HLEN ETHER_HDR_LEN /* Total octets in header. */
+#ifndef ETH_ALEN
+#define ETH_ALEN ETHER_ADDR_LEN
+#endif
+#define ETH_FRAME_LEN (ETHER_MAX_LEN - ETHER_CRC_LEN)
+#define ETH_FCS_LEN 4 /* Octets in the FCS */
+#define VLAN_HLEN 4 /* The additional bytes (on top of the Ethernet header)
+ * that VLAN requires. */
+/*
+ * defined Ethernet Protocol ID's.
+ */
+#define ETH_P_ARP ETHERTYPE_ARP
+#define ETH_P_IP ETHERTYPE_IP
+#define ETH_P_IPV6 ETHERTYPE_IPV6
+#define ETH_P_MPLS_UC ETHERTYPE_MPLS
+#define ETH_P_MPLS_MC ETHERTYPE_MPLS_MCAST
+#define ETH_P_8021Q ETHERTYPE_VLAN
+#define ETH_P_8021AD ETHERTYPE_QINQ
+#define ETH_P_PAE ETHERTYPE_PAE
+#define ETH_P_802_2 ETHERTYPE_8023
+#define ETH_P_IPX ETHERTYPE_IPX
+#define ETH_P_AARP ETHERTYPE_AARP
+#define ETH_P_802_3_MIN 0x05DD /* See comment in sys/net/ethernet.h */
+#define ETH_P_LINK_CTL 0x886C /* ITU-T G.989.2 */
+#define ETH_P_TDLS 0x890D /* 802.11z-2010, see wpa. */
+
+struct ethhdr {
+ uint8_t h_dest[ETH_ALEN];
+ uint8_t h_source[ETH_ALEN];
+ uint16_t h_proto;
+} __packed;
+
+static inline struct ethhdr *
+eth_hdr(const struct sk_buff *skb)
+{
+ struct ethhdr *hdr;
+
+ hdr = (struct ethhdr *)skb_mac_header(skb);
+ return (hdr);
+}
+
+#endif /* _LINUXKPI_LINUX_IF_ETHER_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/if_vlan.h b/sys/compat/linuxkpi/common/include/linux/if_vlan.h
new file mode 100644
index 000000000000..3d1c61db1882
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/if_vlan.h
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_IF_VLAN_H_
+#define _LINUXKPI_LINUX_IF_VLAN_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/ethernet.h>
+#include <net/if_var.h>
+#include <net/if_vlan_var.h>
+#include <net/if_types.h>
+
+#define VLAN_N_VID 4096
+
+static inline int
+is_vlan_dev(struct ifnet *ifp)
+{
+ return (if_gettype(ifp) == IFT_L2VLAN);
+}
+
+static inline uint16_t
+vlan_dev_vlan_id(struct ifnet *ifp)
+{
+ uint16_t vtag;
+ if (VLAN_TAG(ifp, &vtag) == 0)
+ return (vtag);
+ return (0);
+}
+
+#endif /* _LINUXKPI_LINUX_IF_VLAN_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/in.h b/sys/compat/linuxkpi/common/include/linux/in.h
new file mode 100644
index 000000000000..5cc92416c7da
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/in.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_IN_H_
+#define _LINUXKPI_LINUX_IN_H_
+
+#include "opt_inet.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <netinet/in.h>
+#include <asm/byteorder.h>
+
+#define ipv4_is_zeronet(be) IN_ZERONET(ntohl(be))
+#define ipv4_is_loopback(be) IN_LOOPBACK(ntohl(be))
+#define ipv4_is_multicast(be) IN_MULTICAST(ntohl(be))
+#define ipv4_is_lbcast(be) ((be) == INADDR_BROADCAST)
+
+#endif /* _LINUXKPI_LINUX_IN_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/in6.h b/sys/compat/linuxkpi/common/include/linux/in6.h
new file mode 100644
index 000000000000..79be45b6819a
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/in6.h
@@ -0,0 +1,34 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_IN6_H_
+#define _LINUXKPI_LINUX_IN6_H_
+
+#include "opt_inet6.h"
+
+#endif /* _LINUXKPI_LINUX_IN6_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/inetdevice.h b/sys/compat/linuxkpi/common/include/linux/inetdevice.h
new file mode 100644
index 000000000000..ea256cd084a8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/inetdevice.h
@@ -0,0 +1,6 @@
+#ifndef _LINUXKPI_LINUX_INETDEVICE_H_
+#define _LINUXKPI_LINUX_INETDEVICE_H_
+
+#include <linux/netdevice.h>
+
+#endif /* _LINUXKPI_LINUX_INETDEVICE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/interrupt.h b/sys/compat/linuxkpi/common/include/linux/interrupt.h
new file mode 100644
index 000000000000..dfd9816da8be
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/interrupt.h
@@ -0,0 +1,195 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2015 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_INTERRUPT_H_
+#define _LINUXKPI_LINUX_INTERRUPT_H_
+
+#include <linux/cpu.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/irqreturn.h>
+#include <linux/hardirq.h>
+
+#include <sys/param.h>
+#include <sys/interrupt.h>
+
+typedef irqreturn_t (*irq_handler_t)(int, void *);
+
+#define IRQF_SHARED 0x0004 /* Historically */
+#define IRQF_NOBALANCING 0
+
+#define IRQ_DISABLE_UNLAZY 0
+
+#define IRQ_NOTCONNECTED (1U << 31)
+
+int lkpi_request_irq(struct device *, unsigned int, irq_handler_t,
+ irq_handler_t, unsigned long, const char *, void *);
+int lkpi_enable_irq(unsigned int);
+void lkpi_disable_irq(unsigned int);
+int lkpi_bind_irq_to_cpu(unsigned int, int);
+void lkpi_free_irq(unsigned int, void *);
+void lkpi_devm_free_irq(struct device *, unsigned int, void *);
+
+static inline int
+request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
+ const char *name, void *arg)
+{
+
+ return (lkpi_request_irq(NULL, irq, handler, NULL, flags, name, arg));
+}
+
+static inline int
+request_threaded_irq(int irq, irq_handler_t handler,
+ irq_handler_t thread_handler, unsigned long flags,
+ const char *name, void *arg)
+{
+
+ return (lkpi_request_irq(NULL, irq, handler, thread_handler,
+ flags, name, arg));
+}
+
+static inline int
+devm_request_irq(struct device *dev, int irq,
+ irq_handler_t handler, unsigned long flags, const char *name, void *arg)
+{
+
+ return (lkpi_request_irq(dev, irq, handler, NULL, flags, name, arg));
+}
+
+static inline int
+devm_request_threaded_irq(struct device *dev, int irq,
+ irq_handler_t handler, irq_handler_t thread_handler,
+ unsigned long flags, const char *name, void *arg)
+{
+
+ return (lkpi_request_irq(dev, irq, handler, thread_handler,
+ flags, name, arg));
+}
+
+static inline int
+enable_irq(unsigned int irq)
+{
+ return (lkpi_enable_irq(irq));
+}
+
+static inline void
+disable_irq(unsigned int irq)
+{
+ lkpi_disable_irq(irq);
+}
+
+static inline void
+disable_irq_nosync(unsigned int irq)
+{
+ lkpi_disable_irq(irq);
+}
+
+static inline int
+bind_irq_to_cpu(unsigned int irq, int cpu_id)
+{
+ return (lkpi_bind_irq_to_cpu(irq, cpu_id));
+}
+
+static inline void
+free_irq(unsigned int irq, void *device)
+{
+ lkpi_free_irq(irq, device);
+}
+
+static inline void
+devm_free_irq(struct device *xdev, unsigned int irq, void *p)
+{
+ lkpi_devm_free_irq(xdev, irq, p);
+}
+
+static inline int
+irq_set_affinity_hint(int vector, const cpumask_t *mask)
+{
+ int error;
+
+ if (mask != NULL)
+ error = intr_setaffinity(vector, CPU_WHICH_IRQ, mask);
+ else
+ error = intr_setaffinity(vector, CPU_WHICH_IRQ, cpuset_root);
+
+ return (-error);
+}
+
+static inline struct msi_desc *
+irq_get_msi_desc(unsigned int irq)
+{
+
+ return (lkpi_pci_msi_desc_alloc(irq));
+}
+
+static inline void
+irq_set_status_flags(unsigned int irq __unused, unsigned long flags __unused)
+{
+}
+
+/*
+ * LinuxKPI tasklet support
+ */
+struct tasklet_struct;
+typedef void tasklet_func_t(unsigned long);
+typedef void tasklet_callback_t(struct tasklet_struct *);
+
+struct tasklet_struct {
+ TAILQ_ENTRY(tasklet_struct) entry;
+ tasklet_func_t *func;
+ /* Our "state" implementation is different. Avoid same name as Linux. */
+ volatile u_int tasklet_state;
+ atomic_t count;
+ unsigned long data;
+ tasklet_callback_t *callback;
+ bool use_callback;
+};
+
+#define DECLARE_TASKLET(_name, _func, _data) \
+struct tasklet_struct _name = { .func = (_func), .data = (_data) }
+
+#define tasklet_hi_schedule(t) tasklet_schedule(t)
+
+/* Some other compat code in the tree has this defined as well. */
+#define from_tasklet(_dev, _t, _field) \
+ container_of(_t, typeof(*(_dev)), _field)
+
+void tasklet_setup(struct tasklet_struct *, tasklet_callback_t *);
+extern void tasklet_schedule(struct tasklet_struct *);
+extern void tasklet_kill(struct tasklet_struct *);
+extern void tasklet_init(struct tasklet_struct *, tasklet_func_t *,
+ unsigned long data);
+extern void tasklet_enable(struct tasklet_struct *);
+extern void tasklet_disable(struct tasklet_struct *);
+extern void tasklet_disable_nosync(struct tasklet_struct *);
+extern int tasklet_trylock(struct tasklet_struct *);
+extern void tasklet_unlock(struct tasklet_struct *);
+extern void tasklet_unlock_wait(struct tasklet_struct *ts);
+#define tasklet_unlock_spin_wait(ts) tasklet_unlock_wait(ts)
+
+#endif /* _LINUXKPI_LINUX_INTERRUPT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/interval_tree.h b/sys/compat/linuxkpi/common/include/linux/interval_tree.h
new file mode 100644
index 000000000000..1eb8a2fb9181
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/interval_tree.h
@@ -0,0 +1,55 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
+ *
+ * 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 unmodified, 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 ``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 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_INTERVAL_TREE_H
+#define _LINUXKPI_LINUX_INTERVAL_TREE_H
+
+#include <linux/rbtree.h>
+
+struct interval_tree_node {
+ struct rb_node rb;
+ unsigned long start;
+ unsigned long last;
+};
+
+#define interval_tree_iter_first(...) \
+ lkpi_interval_tree_iter_first(__VA_ARGS__)
+#define interval_tree_iter_next(...) \
+ lkpi_interval_tree_iter_next(__VA_ARGS__)
+#define interval_tree_insert(...) lkpi_interval_tree_insert(__VA_ARGS__)
+#define interval_tree_remove(...) lkpi_interval_tree_remove(__VA_ARGS__)
+
+struct interval_tree_node *lkpi_interval_tree_iter_first(
+ struct rb_root_cached *, unsigned long, unsigned long);
+struct interval_tree_node *lkpi_interval_tree_iter_next(
+ struct interval_tree_node *, unsigned long, unsigned long);
+void lkpi_interval_tree_insert(struct interval_tree_node *,
+ struct rb_root_cached *);
+void lkpi_interval_tree_remove(struct interval_tree_node *,
+ struct rb_root_cached *);
+
+#endif /* _LINUXKPI_LINUX_INTERVAL_TREE_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/interval_tree_generic.h b/sys/compat/linuxkpi/common/include/linux/interval_tree_generic.h
new file mode 100644
index 000000000000..3ed6e105cbda
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/interval_tree_generic.h
@@ -0,0 +1,99 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2019 Mark Kettenis <kettenis@OpenBSD.org>
+ * Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
+ *
+ * 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 unmodified, 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 ``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 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.
+ */
+
+#include <linux/rbtree.h>
+
+#define INTERVAL_TREE_DEFINE(type, field, valtype, dummy, START, LAST, \
+ attr, name) \
+ __IT_DEFINE_ITER_FROM(type, field, valtype, START, LAST, name) \
+ __IT_DEFINE_ITER_FIRST(type, valtype, attr, name) \
+ __IT_DEFINE_ITER_NEXT(type, field, valtype, attr, name) \
+ __IT_DEFINE_INSERT(type, field, START, attr, name) \
+ __IT_DEFINE_REMOVE(type, field, attr, name)
+
+#define __IT_DEFINE_ITER_FROM(type, field, valtype, START, LAST, name) \
+static inline type * \
+name##_iter_from(struct rb_node *rb, valtype start, valtype last) \
+{ \
+ type *node; \
+ \
+ while (rb != NULL) { \
+ node = rb_entry(rb, type, field); \
+ if (LAST(node) >= start && START(node) <= last) \
+ return (node); \
+ else if (START(node) > last) \
+ break; \
+ rb = rb_next(rb); \
+ } \
+ return (NULL); \
+}
+
+#define __IT_DEFINE_ITER_FIRST(type, valtype, attr, name) \
+attr type * \
+name##_iter_first(struct rb_root_cached *root, valtype start, valtype last) \
+{ \
+ return (name##_iter_from(rb_first_cached(root), start, last)); \
+}
+
+#define __IT_DEFINE_ITER_NEXT(type, field, valtype, attr, name) \
+attr type * \
+name##_iter_next(type *node, valtype start, valtype last) \
+{ \
+ return (name##_iter_from(rb_next(&node->field), start, last)); \
+}
+
+#define __IT_DEFINE_INSERT(type, field, START, attr, name) \
+attr void \
+name##_insert(type *node, struct rb_root_cached *root) \
+{ \
+ struct rb_node **iter = &root->rb_root.rb_node; \
+ struct rb_node *parent = NULL; \
+ type *iter_node; \
+ bool min_entry = true; \
+ \
+ while (*iter != NULL) { \
+ parent = *iter; \
+ iter_node = rb_entry(parent, type, field); \
+ if (START(node) < START(iter_node)) \
+ iter = &parent->rb_left; \
+ else { \
+ iter = &parent->rb_right; \
+ min_entry = false; \
+ } \
+ } \
+ \
+ rb_link_node(&node->field, parent, iter); \
+ rb_insert_color_cached(&node->field, root, min_entry); \
+}
+
+#define __IT_DEFINE_REMOVE(type, field, attr, name) \
+attr void \
+name##_remove(type *node, struct rb_root_cached *root) \
+{ \
+ rb_erase_cached(&node->field, root); \
+}
diff --git a/sys/compat/linuxkpi/common/include/linux/io-64-nonatomic-lo-hi.h b/sys/compat/linuxkpi/common/include/linux/io-64-nonatomic-lo-hi.h
new file mode 100644
index 000000000000..844b3ef171d5
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/io-64-nonatomic-lo-hi.h
@@ -0,0 +1,65 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Felix Palmen
+ *
+ * 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_IO_64_NONATOMIC_LO_HI_H_
+#define _LINUXKPI_LINUX_IO_64_NONATOMIC_LO_HI_H_
+
+#include <linux/io.h>
+
+static inline uint64_t
+lo_hi_readq(const volatile void *addr)
+{
+ const volatile uint32_t *p = addr;
+ uint32_t l, h;
+
+ __io_br();
+ l = le32toh(__raw_readl(p));
+ h = le32toh(__raw_readl(p + 1));
+ __io_ar();
+
+ return (l + ((uint64_t)h << 32));
+}
+
+static inline void
+lo_hi_writeq(uint64_t v, volatile void *addr)
+{
+ volatile uint32_t *p = addr;
+
+ __io_bw();
+ __raw_writel(htole32(v), p);
+ __raw_writel(htole32(v >> 32), p + 1);
+ __io_aw();
+}
+
+#ifndef readq
+#define readq(addr) lo_hi_readq(addr)
+#endif
+
+#ifndef writeq
+#define writeq(v, addr) lo_hi_writeq(v, addr)
+#endif
+
+#endif /* _LINUXKPI_LINUX_IO_64_NONATOMIC_LO_HI_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/io-mapping.h b/sys/compat/linuxkpi/common/include/linux/io-mapping.h
new file mode 100644
index 000000000000..f5f2fbc5c2cb
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/io-mapping.h
@@ -0,0 +1,130 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_IO_MAPPING_H_
+#define _LINUXKPI_LINUX_IO_MAPPING_H_
+
+#include <sys/types.h>
+#include <machine/vm.h>
+
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+struct io_mapping {
+ unsigned long base;
+ unsigned long size;
+ void *mem;
+ vm_memattr_t attr;
+};
+
+struct io_mapping *io_mapping_create_wc(resource_size_t base, unsigned long size);
+
+static inline struct io_mapping *
+io_mapping_init_wc(struct io_mapping *mapping, resource_size_t base,
+ unsigned long size)
+{
+
+ mapping->base = base;
+ mapping->size = size;
+#ifdef VM_MEMATTR_WRITE_COMBINING
+ mapping->mem = ioremap_wc(base, size);
+ mapping->attr = VM_MEMATTR_WRITE_COMBINING;
+#else
+ mapping->mem = ioremap_nocache(base, size);
+ mapping->attr = VM_MEMATTR_UNCACHEABLE;
+#endif
+ return (mapping);
+}
+
+static inline void
+io_mapping_fini(struct io_mapping *mapping)
+{
+
+ iounmap(mapping->mem);
+}
+
+static inline void
+io_mapping_free(struct io_mapping *mapping)
+{
+
+ io_mapping_fini(mapping->mem);
+ kfree(mapping);
+}
+
+static inline void *
+io_mapping_map_atomic_wc(struct io_mapping *mapping, unsigned long offset)
+{
+
+ return ((char *)mapping->mem + offset);
+}
+
+static inline void
+io_mapping_unmap_atomic(void *vaddr)
+{
+}
+
+static inline void *
+io_mapping_map_local_wc(struct io_mapping *mapping, unsigned long offset)
+{
+
+ return (io_mapping_map_atomic_wc(mapping, offset));
+}
+
+static inline void
+io_mapping_unmap_local(void *vaddr __unused)
+{
+}
+
+static inline void *
+io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset,
+ unsigned long size)
+{
+
+ return ((char *)mapping->mem + offset);
+}
+
+int lkpi_io_mapping_map_user(struct io_mapping *iomap,
+ struct vm_area_struct *vma, unsigned long addr, unsigned long pfn,
+ unsigned long size);
+
+static inline int
+io_mapping_map_user(struct io_mapping *iomap, struct vm_area_struct *vma,
+ unsigned long addr, unsigned long pfn, unsigned long size)
+{
+ return (lkpi_io_mapping_map_user(iomap, vma, addr, pfn, size));
+}
+
+static inline void
+io_mapping_unmap(void *vaddr)
+{
+}
+
+#endif /* _LINUXKPI_LINUX_IO_MAPPING_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/io.h b/sys/compat/linuxkpi/common/include/linux/io.h
new file mode 100644
index 000000000000..2d6fef4e7c52
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/io.h
@@ -0,0 +1,566 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2015 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_IO_H_
+#define _LINUXKPI_LINUX_IO_H_
+
+#include <sys/endian.h>
+#include <sys/types.h>
+
+#include <machine/vm.h>
+
+#include <linux/compiler.h>
+#include <linux/err.h>
+#include <asm-generic/io.h>
+#include <linux/types.h>
+#if !defined(__arm__)
+#include <asm/set_memory.h>
+#endif
+
+/*
+ * XXX This is all x86 specific. It should be bus space access.
+ */
+
+/* rmb and wmb are declared in machine/atomic.h, so should be included first. */
+#ifndef __io_br
+#define __io_br() __compiler_membar()
+#endif
+
+#ifndef __io_ar
+#ifdef rmb
+#define __io_ar() rmb()
+#else
+#define __io_ar() __compiler_membar()
+#endif
+#endif
+
+#ifndef __io_bw
+#ifdef wmb
+#define __io_bw() wmb()
+#else
+#define __io_bw() __compiler_membar()
+#endif
+#endif
+
+#ifndef __io_aw
+#define __io_aw() __compiler_membar()
+#endif
+
+/* Access MMIO registers atomically without barriers and byte swapping. */
+
+static inline uint8_t
+__raw_readb(const volatile void *addr)
+{
+ return (*(const volatile uint8_t *)addr);
+}
+#define __raw_readb(addr) __raw_readb(addr)
+
+static inline void
+__raw_writeb(uint8_t v, volatile void *addr)
+{
+ *(volatile uint8_t *)addr = v;
+}
+#define __raw_writeb(v, addr) __raw_writeb(v, addr)
+
+static inline uint16_t
+__raw_readw(const volatile void *addr)
+{
+ return (*(const volatile uint16_t *)addr);
+}
+#define __raw_readw(addr) __raw_readw(addr)
+
+static inline void
+__raw_writew(uint16_t v, volatile void *addr)
+{
+ *(volatile uint16_t *)addr = v;
+}
+#define __raw_writew(v, addr) __raw_writew(v, addr)
+
+static inline uint32_t
+__raw_readl(const volatile void *addr)
+{
+ return (*(const volatile uint32_t *)addr);
+}
+#define __raw_readl(addr) __raw_readl(addr)
+
+static inline void
+__raw_writel(uint32_t v, volatile void *addr)
+{
+ *(volatile uint32_t *)addr = v;
+}
+#define __raw_writel(v, addr) __raw_writel(v, addr)
+
+#ifdef __LP64__
+static inline uint64_t
+__raw_readq(const volatile void *addr)
+{
+ return (*(const volatile uint64_t *)addr);
+}
+#define __raw_readq(addr) __raw_readq(addr)
+
+static inline void
+__raw_writeq(uint64_t v, volatile void *addr)
+{
+ *(volatile uint64_t *)addr = v;
+}
+#define __raw_writeq(v, addr) __raw_writeq(v, addr)
+#endif
+
+#define mmiowb() barrier()
+
+/* Access little-endian MMIO registers atomically with memory barriers. */
+
+#undef readb
+static inline uint8_t
+readb(const volatile void *addr)
+{
+ uint8_t v;
+
+ __io_br();
+ v = *(const volatile uint8_t *)addr;
+ __io_ar();
+ return (v);
+}
+#define readb(addr) readb(addr)
+
+#undef writeb
+static inline void
+writeb(uint8_t v, volatile void *addr)
+{
+ __io_bw();
+ *(volatile uint8_t *)addr = v;
+ __io_aw();
+}
+#define writeb(v, addr) writeb(v, addr)
+
+#undef readw
+static inline uint16_t
+readw(const volatile void *addr)
+{
+ uint16_t v;
+
+ __io_br();
+ v = le16toh(__raw_readw(addr));
+ __io_ar();
+ return (v);
+}
+#define readw(addr) readw(addr)
+
+#undef writew
+static inline void
+writew(uint16_t v, volatile void *addr)
+{
+ __io_bw();
+ __raw_writew(htole16(v), addr);
+ __io_aw();
+}
+#define writew(v, addr) writew(v, addr)
+
+#undef readl
+static inline uint32_t
+readl(const volatile void *addr)
+{
+ uint32_t v;
+
+ __io_br();
+ v = le32toh(__raw_readl(addr));
+ __io_ar();
+ return (v);
+}
+#define readl(addr) readl(addr)
+
+#undef writel
+static inline void
+writel(uint32_t v, volatile void *addr)
+{
+ __io_bw();
+ __raw_writel(htole32(v), addr);
+ __io_aw();
+}
+#define writel(v, addr) writel(v, addr)
+
+#undef readq
+#undef writeq
+#ifdef __LP64__
+static inline uint64_t
+readq(const volatile void *addr)
+{
+ uint64_t v;
+
+ __io_br();
+ v = le64toh(__raw_readq(addr));
+ __io_ar();
+ return (v);
+}
+#define readq(addr) readq(addr)
+
+static inline void
+writeq(uint64_t v, volatile void *addr)
+{
+ __io_bw();
+ __raw_writeq(htole64(v), addr);
+ __io_aw();
+}
+#define writeq(v, addr) writeq(v, addr)
+#endif
+
+/* Access little-endian MMIO registers atomically without memory barriers. */
+
+#undef readb_relaxed
+static inline uint8_t
+readb_relaxed(const volatile void *addr)
+{
+ return (__raw_readb(addr));
+}
+#define readb_relaxed(addr) readb_relaxed(addr)
+
+#undef writeb_relaxed
+static inline void
+writeb_relaxed(uint8_t v, volatile void *addr)
+{
+ __raw_writeb(v, addr);
+}
+#define writeb_relaxed(v, addr) writeb_relaxed(v, addr)
+
+#undef readw_relaxed
+static inline uint16_t
+readw_relaxed(const volatile void *addr)
+{
+ return (le16toh(__raw_readw(addr)));
+}
+#define readw_relaxed(addr) readw_relaxed(addr)
+
+#undef writew_relaxed
+static inline void
+writew_relaxed(uint16_t v, volatile void *addr)
+{
+ __raw_writew(htole16(v), addr);
+}
+#define writew_relaxed(v, addr) writew_relaxed(v, addr)
+
+#undef readl_relaxed
+static inline uint32_t
+readl_relaxed(const volatile void *addr)
+{
+ return (le32toh(__raw_readl(addr)));
+}
+#define readl_relaxed(addr) readl_relaxed(addr)
+
+#undef writel_relaxed
+static inline void
+writel_relaxed(uint32_t v, volatile void *addr)
+{
+ __raw_writel(htole32(v), addr);
+}
+#define writel_relaxed(v, addr) writel_relaxed(v, addr)
+
+#undef readq_relaxed
+#undef writeq_relaxed
+#ifdef __LP64__
+static inline uint64_t
+readq_relaxed(const volatile void *addr)
+{
+ return (le64toh(__raw_readq(addr)));
+}
+#define readq_relaxed(addr) readq_relaxed(addr)
+
+static inline void
+writeq_relaxed(uint64_t v, volatile void *addr)
+{
+ __raw_writeq(htole64(v), addr);
+}
+#define writeq_relaxed(v, addr) writeq_relaxed(v, addr)
+#endif
+
+/* XXX On Linux ioread and iowrite handle both MMIO and port IO. */
+
+#undef ioread8
+static inline uint8_t
+ioread8(const volatile void *addr)
+{
+ return (readb(addr));
+}
+#define ioread8(addr) ioread8(addr)
+
+#undef ioread16
+static inline uint16_t
+ioread16(const volatile void *addr)
+{
+ return (readw(addr));
+}
+#define ioread16(addr) ioread16(addr)
+
+#undef ioread16be
+static inline uint16_t
+ioread16be(const volatile void *addr)
+{
+ uint16_t v;
+
+ __io_br();
+ v = (be16toh(__raw_readw(addr)));
+ __io_ar();
+
+ return (v);
+}
+#define ioread16be(addr) ioread16be(addr)
+
+#undef ioread32
+static inline uint32_t
+ioread32(const volatile void *addr)
+{
+ return (readl(addr));
+}
+#define ioread32(addr) ioread32(addr)
+
+#undef ioread32be
+static inline uint32_t
+ioread32be(const volatile void *addr)
+{
+ uint32_t v;
+
+ __io_br();
+ v = (be32toh(__raw_readl(addr)));
+ __io_ar();
+
+ return (v);
+}
+#define ioread32be(addr) ioread32be(addr)
+
+#ifdef __LP64__
+#undef ioread64
+static inline uint64_t
+ioread64(const volatile void *addr)
+{
+ return (readq(addr));
+}
+#define ioread64(addr) ioread64(addr)
+#endif
+
+#undef iowrite8
+static inline void
+iowrite8(uint8_t v, volatile void *addr)
+{
+ writeb(v, addr);
+}
+#define iowrite8(v, addr) iowrite8(v, addr)
+
+#undef iowrite16
+static inline void
+iowrite16(uint16_t v, volatile void *addr)
+{
+ writew(v, addr);
+}
+#define iowrite16 iowrite16
+
+#undef iowrite32
+static inline void
+iowrite32(uint32_t v, volatile void *addr)
+{
+ writel(v, addr);
+}
+#define iowrite32(v, addr) iowrite32(v, addr)
+
+#undef iowrite32be
+static inline void
+iowrite32be(uint32_t v, volatile void *addr)
+{
+ __io_bw();
+ __raw_writel(htobe32(v), addr);
+ __io_aw();
+}
+#define iowrite32be(v, addr) iowrite32be(v, addr)
+
+#if defined(__i386__) || defined(__amd64__)
+#define _outb(data, port) outb((data), (port))
+#endif
+
+#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__) || defined(__aarch64__) || defined(__riscv)
+void *_ioremap_attr(vm_paddr_t phys_addr, unsigned long size, int attr);
+#else
+static __inline void *
+_ioremap_attr(vm_paddr_t _phys_addr, unsigned long _size, int _attr)
+{
+ return (NULL);
+}
+#endif
+
+struct device;
+static inline void *
+devm_ioremap(struct device *dev, resource_size_t offset, resource_size_t size)
+{
+ return (NULL);
+}
+
+#ifdef VM_MEMATTR_DEVICE
+#define ioremap_nocache(addr, size) \
+ _ioremap_attr((addr), (size), VM_MEMATTR_DEVICE)
+#define ioremap_wt(addr, size) \
+ _ioremap_attr((addr), (size), VM_MEMATTR_DEVICE)
+#define ioremap(addr, size) \
+ _ioremap_attr((addr), (size), VM_MEMATTR_DEVICE)
+#else
+#define ioremap_nocache(addr, size) \
+ _ioremap_attr((addr), (size), VM_MEMATTR_UNCACHEABLE)
+#define ioremap_wt(addr, size) \
+ _ioremap_attr((addr), (size), VM_MEMATTR_WRITE_THROUGH)
+#define ioremap(addr, size) \
+ _ioremap_attr((addr), (size), VM_MEMATTR_UNCACHEABLE)
+#endif
+#ifdef VM_MEMATTR_WRITE_COMBINING
+#define ioremap_wc(addr, size) \
+ _ioremap_attr((addr), (size), VM_MEMATTR_WRITE_COMBINING)
+#else
+#define ioremap_wc(addr, size) ioremap_nocache(addr, size)
+#endif
+#define ioremap_cache(addr, size) \
+ _ioremap_attr((addr), (size), VM_MEMATTR_WRITE_BACK)
+void iounmap(void *addr);
+
+#define memset_io(a, b, c) memset((a), (b), (c))
+#define memcpy_fromio(a, b, c) memcpy((a), (b), (c))
+#define memcpy_toio(a, b, c) memcpy((a), (b), (c))
+
+static inline void
+__iowrite32_copy(void *to, const void *from, size_t count)
+{
+ const uint32_t *src;
+ uint32_t *dst;
+ int i;
+
+ for (i = 0, src = from, dst = to; i < count; i++, src++, dst++)
+ __raw_writel(*src, dst);
+}
+
+static inline void
+__iowrite64_copy(void *to, const void *from, size_t count)
+{
+#ifdef __LP64__
+ const uint64_t *src;
+ uint64_t *dst;
+ int i;
+
+ for (i = 0, src = from, dst = to; i < count; i++, src++, dst++)
+ __raw_writeq(*src, dst);
+#else
+ __iowrite32_copy(to, from, count * 2);
+#endif
+}
+
+static inline void
+__ioread32_copy(void *to, const void *from, size_t count)
+{
+ const uint32_t *src;
+ uint32_t *dst;
+ int i;
+
+ for (i = 0, src = from, dst = to; i < count; i++, src++, dst++)
+ *dst = __raw_readl(src);
+}
+
+static inline void
+__ioread64_copy(void *to, const void *from, size_t count)
+{
+#ifdef __LP64__
+ const uint64_t *src;
+ uint64_t *dst;
+ int i;
+
+ for (i = 0, src = from, dst = to; i < count; i++, src++, dst++)
+ *dst = __raw_readq(src);
+#else
+ __ioread32_copy(to, from, count * 2);
+#endif
+}
+
+enum {
+ MEMREMAP_WB = 1 << 0,
+ MEMREMAP_WT = 1 << 1,
+ MEMREMAP_WC = 1 << 2,
+};
+
+static inline void *
+memremap(resource_size_t offset, size_t size, unsigned long flags)
+{
+ void *addr = NULL;
+
+ if ((flags & MEMREMAP_WB) &&
+ (addr = ioremap_cache(offset, size)) != NULL)
+ goto done;
+ if ((flags & MEMREMAP_WT) &&
+ (addr = ioremap_wt(offset, size)) != NULL)
+ goto done;
+ if ((flags & MEMREMAP_WC) &&
+ (addr = ioremap_wc(offset, size)) != NULL)
+ goto done;
+done:
+ return (addr);
+}
+
+static inline void
+memunmap(void *addr)
+{
+ /* XXX May need to check if this is RAM */
+ iounmap(addr);
+}
+
+#define IOMEM_ERR_PTR(err) (void __iomem *)ERR_PTR(err)
+
+#define __MTRR_ID_BASE 1
+int lkpi_arch_phys_wc_add(unsigned long, unsigned long);
+void lkpi_arch_phys_wc_del(int);
+#define arch_phys_wc_add(...) lkpi_arch_phys_wc_add(__VA_ARGS__)
+#define arch_phys_wc_del(...) lkpi_arch_phys_wc_del(__VA_ARGS__)
+#define arch_phys_wc_index(x) \
+ (((x) < __MTRR_ID_BASE) ? -1 : ((x) - __MTRR_ID_BASE))
+
+static inline int
+arch_io_reserve_memtype_wc(resource_size_t start, resource_size_t size)
+{
+#if defined(__amd64__)
+ vm_offset_t va;
+
+ va = PHYS_TO_DMAP(start);
+ return (-pmap_change_attr(va, size, VM_MEMATTR_WRITE_COMBINING));
+#else
+ return (0);
+#endif
+}
+
+static inline void
+arch_io_free_memtype_wc(resource_size_t start, resource_size_t size)
+{
+#if defined(__amd64__)
+ vm_offset_t va;
+
+ va = PHYS_TO_DMAP(start);
+
+ pmap_change_attr(va, size, VM_MEMATTR_WRITE_BACK);
+#endif
+}
+
+#endif /* _LINUXKPI_LINUX_IO_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/ioctl.h b/sys/compat/linuxkpi/common/include/linux/ioctl.h
new file mode 100644
index 000000000000..77c01224e6a5
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/ioctl.h
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_IOCTL_H_
+#define _LINUXKPI_LINUX_IOCTL_H_
+
+#include <sys/ioccom.h>
+
+#define _IOC_SIZE(cmd) IOCPARM_LEN(cmd)
+#define _IOC_TYPE(cmd) IOCGROUP(cmd)
+#define _IOC_NR(cmd) ((cmd) & 0xff)
+
+#endif /* _LINUXKPI_LINUX_IOCTL_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/iommu.h b/sys/compat/linuxkpi/common/include/linux/iommu.h
new file mode 100644
index 000000000000..391d9778a0c8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/iommu.h
@@ -0,0 +1,29 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_IOMMU_H_
+#define _LINUXKPI_LINUX_IOMMU_H_
+
+#include <linux/device.h>
+
+#define __IOMMU_DOMAIN_PAGING (1U << 0)
+#define __IOMMU_DOMAIN_DMA_API (1U << 1)
+#define __IOMMU_DOMAIN_PT (1U << 2)
+#define __IOMMU_DOMAIN_DMA_FQ (1U << 3)
+
+#define IOMMU_DOMAIN_BLOCKED (0U)
+#define IOMMU_DOMAIN_IDENTITY (__IOMMU_DOMAIN_PT)
+#define IOMMU_DOMAIN_UNMANAGED (__IOMMU_DOMAIN_PAGING)
+#define IOMMU_DOMAIN_DMA (__IOMMU_DOMAIN_PAGING | __IOMMU_DOMAIN_DMA_API)
+#define IOMMU_DOMAIN_DMA_FQ (__IOMMU_DOMAIN_PAGING | __IOMMU_DOMAIN_DMA_API | __IOMMU_DOMAIN_DMA_FQ)
+
+struct iommu_domain {
+ unsigned int type;
+};
+
+static inline struct iommu_domain *
+iommu_get_domain_for_dev(struct device *dev __unused)
+{
+ return (NULL);
+}
+
+#endif /* _LINUXKPI_LINUX_IOMMU_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/iopoll.h b/sys/compat/linuxkpi/common/include/linux/iopoll.h
new file mode 100644
index 000000000000..8d0498a26da1
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/iopoll.h
@@ -0,0 +1,92 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020-2021 Bjoern A. Zeeb
+ *
+ * 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_IOPOLL_H
+#define _LINUXKPI_LINUX_IOPOLL_H
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <linux/delay.h>
+
+#define read_poll_timeout(_pollfp, _var, _cond, _us, _to, _early_sleep, ...) \
+({ \
+ struct timeval __now, __end; \
+ if (_to) { \
+ __end.tv_sec = (_to) / USEC_PER_SEC; \
+ __end.tv_usec = (_to) % USEC_PER_SEC; \
+ microtime(&__now); \
+ timevaladd(&__end, &__now); \
+ } \
+ \
+ if ((_early_sleep) && (_us) > 0) \
+ usleep_range(_us, _us); \
+ do { \
+ (_var) = _pollfp(__VA_ARGS__); \
+ if (_cond) \
+ break; \
+ if (_to) { \
+ microtime(&__now); \
+ if (timevalcmp(&__now, &__end, >)) \
+ break; \
+ } \
+ if ((_us) != 0) \
+ usleep_range(_us, _us); \
+ } while (1); \
+ (_cond) ? 0 : (-ETIMEDOUT); \
+})
+
+#define readx_poll_timeout(_pollfp, _addr, _var, _cond, _us, _to) \
+ read_poll_timeout(_pollfp, _var, _cond, _us, _to, false, _addr)
+
+#define read_poll_timeout_atomic(_pollfp, _var, _cond, _us, _to, _early_sleep, ...) \
+({ \
+ struct timeval __now, __end; \
+ if (_to) { \
+ __end.tv_sec = (_to) / USEC_PER_SEC; \
+ __end.tv_usec = (_to) % USEC_PER_SEC; \
+ microtime(&__now); \
+ timevaladd(&__end, &__now); \
+ } \
+ \
+ if ((_early_sleep) && (_us) > 0) \
+ DELAY(_us); \
+ do { \
+ (_var) = _pollfp(__VA_ARGS__); \
+ if (_cond) \
+ break; \
+ if (_to) { \
+ microtime(&__now); \
+ if (timevalcmp(&__now, &__end, >)) \
+ break; \
+ } \
+ if ((_us) != 0) \
+ DELAY(_us); \
+ } while (1); \
+ (_cond) ? 0 : (-ETIMEDOUT); \
+})
+
+#endif /* _LINUXKPI_LINUX_IOPOLL_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/ioport.h b/sys/compat/linuxkpi/common/include/linux/ioport.h
new file mode 100644
index 000000000000..444f3ad94602
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/ioport.h
@@ -0,0 +1,57 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Serenity Cyber Security, LLC.
+ *
+ * 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_IOPORT_H
+#define _LINUXKPI_LINUX_IOPORT_H
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+#define DEFINE_RES_MEM(_start, _size) \
+ (struct resource) { \
+ .start = (_start), \
+ .end = (_start) + (_size) - 1, \
+ }
+
+struct resource {
+ resource_size_t start;
+ resource_size_t end;
+};
+
+static inline resource_size_t
+resource_size(const struct resource *r)
+{
+ return (r->end - r->start + 1);
+}
+
+static inline bool
+resource_contains(struct resource *a, struct resource *b)
+{
+ return (a->start <= b->start && a->end >= b->end);
+}
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/iosys-map.h b/sys/compat/linuxkpi/common/include/linux/iosys-map.h
new file mode 100644
index 000000000000..66c442b8668f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/iosys-map.h
@@ -0,0 +1,161 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_IOSYS_MAP_H
+#define _LINUXKPI_LINUX_IOSYS_MAP_H
+
+#include <linux/io.h>
+#include <linux/string.h>
+
+struct iosys_map {
+ union {
+ void *vaddr_iomem;
+ void *vaddr;
+ };
+ bool is_iomem;
+#ifdef __OpenBSD__
+ bus_space_handle_t bsh;
+ bus_size_t size;
+#endif
+};
+
+#define IOSYS_MAP_INIT_OFFSET(_ism_src_p, _off) ({ \
+ struct iosys_map ism_dst = *(_ism_src_p); \
+ iosys_map_incr(&ism_dst, _off); \
+ ism_dst; \
+})
+
+static inline void
+iosys_map_incr(struct iosys_map *ism, size_t n)
+{
+ if (ism->is_iomem)
+ ism->vaddr_iomem += n;
+ else
+ ism->vaddr += n;
+}
+
+static inline void
+iosys_map_memcpy_to(struct iosys_map *ism, size_t off, const void *src,
+ size_t len)
+{
+ if (ism->is_iomem)
+ memcpy_toio(ism->vaddr_iomem + off, src, len);
+ else
+ memcpy(ism->vaddr + off, src, len);
+}
+
+static inline bool
+iosys_map_is_null(const struct iosys_map *ism)
+{
+ if (ism->is_iomem)
+ return (ism->vaddr_iomem == NULL);
+ else
+ return (ism->vaddr == NULL);
+}
+
+static inline bool
+iosys_map_is_set(const struct iosys_map *ism)
+{
+ if (ism->is_iomem)
+ return (ism->vaddr_iomem != NULL);
+ else
+ return (ism->vaddr != NULL);
+}
+
+static inline bool
+iosys_map_is_equal(const struct iosys_map *ism_a,
+ const struct iosys_map *ism_b)
+{
+ if (ism_a->is_iomem != ism_b->is_iomem)
+ return (false);
+
+ if (ism_a->is_iomem)
+ return (ism_a->vaddr_iomem == ism_b->vaddr_iomem);
+ else
+ return (ism_a->vaddr == ism_b->vaddr);
+}
+
+static inline void
+iosys_map_clear(struct iosys_map *ism)
+{
+ if (ism->is_iomem) {
+ ism->vaddr_iomem = NULL;
+ ism->is_iomem = false;
+ } else {
+ ism->vaddr = NULL;
+ }
+}
+
+static inline void
+iosys_map_set_vaddr_iomem(struct iosys_map *ism, void *addr)
+{
+ ism->vaddr_iomem = addr;
+ ism->is_iomem = true;
+}
+
+static inline void
+iosys_map_set_vaddr(struct iosys_map *ism, void *addr)
+{
+ ism->vaddr = addr;
+ ism->is_iomem = false;
+}
+
+static inline void
+iosys_map_memset(struct iosys_map *ism, size_t off, int value, size_t len)
+{
+ if (ism->is_iomem)
+ memset_io(ism->vaddr_iomem + off, value, len);
+ else
+ memset(ism->vaddr + off, value, len);
+}
+
+#ifdef __LP64__
+#define _iosys_map_readq(_addr) readq(_addr)
+#define _iosys_map_writeq(_val, _addr) writeq(_val, _addr)
+#else
+#define _iosys_map_readq(_addr) ({ \
+ uint64_t val; \
+ memcpy_fromio(&val, _addr, sizeof(uint64_t)); \
+ val; \
+})
+#define _iosys_map_writeq(_val, _addr) \
+ memcpy_toio(_addr, &(_val), sizeof(uint64_t))
+#endif
+
+#define iosys_map_rd(_ism, _off, _type) ({ \
+ _type val; \
+ if ((_ism)->is_iomem) { \
+ void *addr = (_ism)->vaddr_iomem + (_off); \
+ val = _Generic(val, \
+ uint8_t : readb(addr), \
+ uint16_t: readw(addr), \
+ uint32_t: readl(addr), \
+ uint64_t: _iosys_map_readq(addr)); \
+ } else \
+ val = READ_ONCE(*(_type *)((_ism)->vaddr + (_off))); \
+ val; \
+})
+#define iosys_map_wr(_ism, _off, _type, _val) ({ \
+ _type val = (_val); \
+ if ((_ism)->is_iomem) { \
+ void *addr = (_ism)->vaddr_iomem + (_off); \
+ _Generic(val, \
+ uint8_t : writeb(val, addr), \
+ uint16_t: writew(val, addr), \
+ uint32_t: writel(val, addr), \
+ uint64_t: _iosys_map_writeq(val, addr)); \
+ } else \
+ WRITE_ONCE(*(_type *)((_ism)->vaddr + (_off)), val); \
+})
+
+#define iosys_map_rd_field(_ism, _off, _type, _field) ({ \
+ _type *s; \
+ iosys_map_rd(_ism, (_off) + offsetof(_type, _field), \
+ __typeof(s->_field)); \
+})
+#define iosys_map_wr_field(_ism, _off, _type, _field, _val) ({ \
+ _type *s; \
+ iosys_map_wr(_ism, (_off) + offsetof(_type, _field), \
+ __typeof(s->_field), _val); \
+})
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/ip.h b/sys/compat/linuxkpi/common/include/linux/ip.h
new file mode 100644
index 000000000000..137cf89e7dcb
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/ip.h
@@ -0,0 +1,73 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020-2021 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb 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_IP_H
+#define _LINUXKPI_LINUX_IP_H
+
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <machine/in_cksum.h>
+
+#include <linux/skbuff.h>
+
+/* (u) unconfirmed structure field names; using FreeBSD's meanwhile. */
+struct iphdr {
+ uint8_t ip_hl:4, ip_ver:4; /* (u) */
+ uint8_t ip_tos; /* (u) */
+ uint16_t ip_len; /* (u) */
+ uint16_t id;
+ uint16_t ip_off; /* (u) */
+ uint8_t ip_ttl; /* (u) */
+ uint8_t protocol;
+ uint16_t check;
+ uint32_t saddr;
+ uint32_t daddr;
+};
+
+static __inline struct iphdr *
+ip_hdr(struct sk_buff *skb)
+{
+
+ return (struct iphdr *)skb_network_header(skb);
+}
+
+static __inline void
+ip_send_check(struct iphdr *iph)
+{
+
+ /* Clear the checksum before computing! */
+ iph->check = 0;
+ /* An IPv4 header is the same everywhere even if names differ. */
+ iph->check = in_cksum_hdr((const void *)iph);
+}
+
+#endif /* _LINUXKPI_LINUX_IP_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/irq_work.h b/sys/compat/linuxkpi/common/include/linux/irq_work.h
new file mode 100644
index 000000000000..7c4019bc0242
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/irq_work.h
@@ -0,0 +1,90 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot 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_IRQ_WORK_H_
+#define _LINUXKPI_LINUX_IRQ_WORK_H_
+
+#include <sys/param.h>
+#include <sys/taskqueue.h>
+
+#include <linux/llist.h>
+#include <linux/workqueue.h>
+
+#define LKPI_IRQ_WORK_STD_TQ system_wq->taskqueue
+#define LKPI_IRQ_WORK_FAST_TQ linux_irq_work_tq
+
+#ifdef LKPI_IRQ_WORK_USE_FAST_TQ
+#define LKPI_IRQ_WORK_TQ LKPI_IRQ_WORK_FAST_TQ
+#else
+#define LKPI_IRQ_WORK_TQ LKPI_IRQ_WORK_STD_TQ
+#endif
+
+struct irq_work;
+typedef void (*irq_work_func_t)(struct irq_work *);
+
+struct irq_work {
+ struct task irq_task;
+ union {
+ struct llist_node llnode;
+ struct {
+ struct llist_node llist;
+ } node;
+ };
+ irq_work_func_t func;
+};
+
+extern struct taskqueue *linux_irq_work_tq;
+
+#define DEFINE_IRQ_WORK(name, _func) struct irq_work name = { \
+ .irq_task = TASK_INITIALIZER(0, linux_irq_work_fn, &(name)), \
+ .func = (_func), \
+}
+
+void linux_irq_work_fn(void *, int);
+
+static inline void
+init_irq_work(struct irq_work *irqw, irq_work_func_t func)
+{
+ TASK_INIT(&irqw->irq_task, 0, linux_irq_work_fn, irqw);
+ irqw->func = func;
+}
+
+static inline bool
+irq_work_queue(struct irq_work *irqw)
+{
+ return (taskqueue_enqueue_flags(LKPI_IRQ_WORK_TQ, &irqw->irq_task,
+ TASKQUEUE_FAIL_IF_PENDING) == 0);
+}
+
+static inline void
+irq_work_sync(struct irq_work *irqw)
+{
+ taskqueue_drain(LKPI_IRQ_WORK_TQ, &irqw->irq_task);
+}
+
+#endif /* _LINUXKPI_LINUX_IRQ_WORK_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/irqdomain.h b/sys/compat/linuxkpi/common/include/linux/irqdomain.h
new file mode 100644
index 000000000000..c7788e51cc89
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/irqdomain.h
@@ -0,0 +1,10 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_IRQDOMAIN_H
+#define _LINUXKPI_LINUX_IRQDOMAIN_H
+
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/radix-tree.h>
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/irqreturn.h b/sys/compat/linuxkpi/common/include/linux/irqreturn.h
new file mode 100644
index 000000000000..ff2618449d5e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/irqreturn.h
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2017 Limelight Networks, Inc.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_IRQRETURN_H
+#define _LINUXKPI_LINUX_IRQRETURN_H
+
+typedef enum irqreturn {
+ IRQ_NONE = 0,
+ IRQ_HANDLED = 1,
+ IRQ_WAKE_THREAD = 2
+} irqreturn_t;
+
+#define IRQ_RETVAL(x) ((x) ? IRQ_HANDLED : IRQ_NONE)
+
+#endif /* _LINUXKPI_LINUX_IRQRETURN_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/jhash.h b/sys/compat/linuxkpi/common/include/linux/jhash.h
new file mode 100644
index 000000000000..25e2c04f1965
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/jhash.h
@@ -0,0 +1,144 @@
+#ifndef _LINUXKPI_LINUX_JHASH_H_
+#define _LINUXKPI_LINUX_JHASH_H_
+
+#include <asm/types.h>
+
+/* jhash.h: Jenkins hash support.
+ *
+ * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
+ *
+ * http://burtleburtle.net/bob/hash/
+ *
+ * These are the credits from Bob's sources:
+ *
+ * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
+ * hash(), hash2(), hash3, and mix() are externally useful functions.
+ * Routines to test the hash are included if SELF_TEST is defined.
+ * You can use this free for any purpose. It has no warranty.
+ *
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ *
+ * I've modified Bob's hash to be useful in the Linux kernel, and
+ * any bugs present are surely my fault. -DaveM
+ */
+
+/* NOTE: Arguments are modified. */
+#define __jhash_mix(a, b, c) \
+{ \
+ a -= b; a -= c; a ^= (c>>13); \
+ b -= c; b -= a; b ^= (a<<8); \
+ c -= a; c -= b; c ^= (b>>13); \
+ a -= b; a -= c; a ^= (c>>12); \
+ b -= c; b -= a; b ^= (a<<16); \
+ c -= a; c -= b; c ^= (b>>5); \
+ a -= b; a -= c; a ^= (c>>3); \
+ b -= c; b -= a; b ^= (a<<10); \
+ c -= a; c -= b; c ^= (b>>15); \
+}
+
+/* The golden ration: an arbitrary value */
+#define JHASH_GOLDEN_RATIO 0x9e3779b9
+
+/* The most generic version, hashes an arbitrary sequence
+ * of bytes. No alignment or length assumptions are made about
+ * the input key.
+ */
+static inline u32 jhash(const void *key, u32 length, u32 initval)
+{
+ u32 a, b, c, len;
+ const u8 *k = key;
+
+ len = length;
+ a = b = JHASH_GOLDEN_RATIO;
+ c = initval;
+
+ while (len >= 12) {
+ a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24));
+ b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24));
+ c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24));
+
+ __jhash_mix(a,b,c);
+
+ k += 12;
+ len -= 12;
+ }
+
+ c += length;
+ switch (len) {
+ case 11: c += ((u32)k[10]<<24);
+ case 10: c += ((u32)k[9]<<16);
+ case 9 : c += ((u32)k[8]<<8);
+ case 8 : b += ((u32)k[7]<<24);
+ case 7 : b += ((u32)k[6]<<16);
+ case 6 : b += ((u32)k[5]<<8);
+ case 5 : b += k[4];
+ case 4 : a += ((u32)k[3]<<24);
+ case 3 : a += ((u32)k[2]<<16);
+ case 2 : a += ((u32)k[1]<<8);
+ case 1 : a += k[0];
+ };
+
+ __jhash_mix(a,b,c);
+
+ return c;
+}
+
+/* A special optimized version that handles 1 or more of u32s.
+ * The length parameter here is the number of u32s in the key.
+ */
+static inline u32 jhash2(const u32 *k, u32 length, u32 initval)
+{
+ u32 a, b, c, len;
+
+ a = b = JHASH_GOLDEN_RATIO;
+ c = initval;
+ len = length;
+
+ while (len >= 3) {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ __jhash_mix(a, b, c);
+ k += 3; len -= 3;
+ }
+
+ c += length * 4;
+
+ switch (len) {
+ case 2 : b += k[1];
+ case 1 : a += k[0];
+ };
+
+ __jhash_mix(a,b,c);
+
+ return c;
+}
+
+/* A special ultra-optimized versions that knows they are hashing exactly
+ * 3, 2 or 1 word(s).
+ *
+ * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
+ * done at the end is not done here.
+ */
+static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
+{
+ a += JHASH_GOLDEN_RATIO;
+ b += JHASH_GOLDEN_RATIO;
+ c += initval;
+
+ __jhash_mix(a, b, c);
+
+ return c;
+}
+
+static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
+{
+ return jhash_3words(a, b, 0, initval);
+}
+
+static inline u32 jhash_1word(u32 a, u32 initval)
+{
+ return jhash_3words(a, 0, 0, initval);
+}
+
+#endif /* _LINUXKPI_LINUX_JHASH_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/jiffies.h b/sys/compat/linuxkpi/common/include/linux/jiffies.h
new file mode 100644
index 000000000000..c2409726e874
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/jiffies.h
@@ -0,0 +1,143 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_JIFFIES_H_
+#define _LINUXKPI_LINUX_JIFFIES_H_
+
+#include <linux/types.h>
+#include <linux/time.h>
+
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/time.h>
+
+extern unsigned long jiffies; /* defined in sys/kern/subr_ticks.S */
+#define jiffies_64 jiffies /* XXX-MJ wrong on 32-bit platforms */
+#define jiffies_to_msecs(x) ((unsigned int)(((int64_t)(int)(x)) * 1000 / hz))
+
+#define MAX_JIFFY_OFFSET ((LONG_MAX >> 1) - 1)
+
+#define time_after(a, b) ((long)((b) - (a)) < 0)
+#define time_after32(a, b) ((int32_t)((uint32_t)(b) - (uint32_t)(a)) < 0)
+#define time_before(a, b) time_after(b,a)
+#define time_before32(a, b) time_after32(b, a)
+#define time_after_eq(a, b) ((long)((a) - (b)) >= 0)
+#define time_before_eq(a, b) time_after_eq(b, a)
+#define time_in_range(a,b,c) \
+ (time_after_eq(a,b) && time_before_eq(a,c))
+#define time_is_after_eq_jiffies(a) time_after_eq(a, jiffies)
+#define time_is_after_jiffies(a) time_after(a, jiffies)
+#define time_is_before_jiffies(a) time_before(a, jiffies)
+
+#define HZ hz
+
+extern uint64_t lkpi_nsec2hz_rem;
+extern uint64_t lkpi_nsec2hz_div;
+extern uint64_t lkpi_nsec2hz_max;
+
+extern uint64_t lkpi_usec2hz_rem;
+extern uint64_t lkpi_usec2hz_div;
+extern uint64_t lkpi_usec2hz_max;
+
+extern uint64_t lkpi_msec2hz_rem;
+extern uint64_t lkpi_msec2hz_div;
+extern uint64_t lkpi_msec2hz_max;
+
+static inline unsigned long
+msecs_to_jiffies(uint64_t msec)
+{
+ uint64_t result;
+
+ if (msec > lkpi_msec2hz_max)
+ msec = lkpi_msec2hz_max;
+ result = howmany(msec * lkpi_msec2hz_rem, lkpi_msec2hz_div);
+ if (result > MAX_JIFFY_OFFSET)
+ result = MAX_JIFFY_OFFSET;
+
+ return ((unsigned long)result);
+}
+
+static inline unsigned long
+usecs_to_jiffies(uint64_t usec)
+{
+ uint64_t result;
+
+ if (usec > lkpi_usec2hz_max)
+ usec = lkpi_usec2hz_max;
+ result = howmany(usec * lkpi_usec2hz_rem, lkpi_usec2hz_div);
+ if (result > MAX_JIFFY_OFFSET)
+ result = MAX_JIFFY_OFFSET;
+
+ return ((unsigned long)result);
+}
+
+static inline uint64_t
+nsecs_to_jiffies64(uint64_t nsec)
+{
+
+ if (nsec > lkpi_nsec2hz_max)
+ nsec = lkpi_nsec2hz_max;
+ return (howmany(nsec * lkpi_nsec2hz_rem, lkpi_nsec2hz_div));
+}
+
+static inline unsigned long
+nsecs_to_jiffies(uint64_t nsec)
+{
+
+ if (sizeof(unsigned long) >= sizeof(uint64_t)) {
+ if (nsec > lkpi_nsec2hz_max)
+ nsec = lkpi_nsec2hz_max;
+ } else {
+ if (nsec > (lkpi_nsec2hz_max >> 32))
+ nsec = (lkpi_nsec2hz_max >> 32);
+ }
+ return (howmany(nsec * lkpi_nsec2hz_rem, lkpi_nsec2hz_div));
+}
+
+static inline uint64_t
+jiffies_to_nsecs(unsigned long j)
+{
+
+ return ((1000000000ULL / hz) * (uint64_t)j);
+}
+
+static inline uint64_t
+jiffies_to_usecs(unsigned long j)
+{
+
+ return ((1000000ULL / hz) * (uint64_t)j);
+}
+
+static inline uint64_t
+get_jiffies_64(void)
+{
+
+ return ((uint64_t)jiffies);
+}
+
+#endif /* _LINUXKPI_LINUX_JIFFIES_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/jump_label.h b/sys/compat/linuxkpi/common/include/linux/jump_label.h
new file mode 100644
index 000000000000..444754a0ff82
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/jump_label.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016-2020 François Tigeot <ftigeot@wolfpond.org>
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_JUMP_LABEL_H_
+#define _LINUXKPI_LINUX_JUMP_LABEL_H_
+
+#include <linux/types.h>
+#include <linux/compiler.h>
+#include <linux/bug.h>
+
+#define DEFINE_STATIC_KEY_FALSE(key) bool key = false
+
+static inline void
+static_branch_enable(bool *flag)
+{
+ *flag = true;
+}
+
+static inline bool
+static_branch_likely(bool *flag)
+{
+ return *flag;
+}
+
+#endif /* _LINUXKPI_LINUX_JUMP_LABEL_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kconfig.h b/sys/compat/linuxkpi/common/include/linux/kconfig.h
new file mode 100644
index 000000000000..c1d186b56e1f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/kconfig.h
@@ -0,0 +1,76 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb 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_KCONFIG_H_
+#define _LINUXKPI_LINUX_KCONFIG_H_
+
+/*
+ * Checking if an option is defined would be easy if we could do CPP inside CPP.
+ * The defined case whether -Dxxx or -Dxxx=1 are easy to deal with. In either
+ * case the defined value is "1". A more general -Dxxx=<c> case will require
+ * more effort to deal with all possible "true" values. Hope we do not have
+ * to do this as well.
+ * The real problem is the undefined case. To avoid this problem we do the
+ * concat/varargs trick: "yyy" ## xxx can make two arguments if xxx is "1"
+ * by having a #define for yyy_1 which is "ignore,".
+ * Otherwise we will just get "yyy".
+ * Need to be careful about variable substitutions in macros though.
+ * This way we make a (true, false) problem a (don't care, true, false) or a
+ * (don't care true, false). Then we can use a variadic macro to only select
+ * the always well known and defined argument #2. And that seems to be
+ * exactly what we need. Use 1 for true and 0 for false to also allow
+ * #if IS_*() checks pre-compiler checks which do not like #if true.
+ */
+#define ___XAB_1 dontcare,
+#define ___IS_XAB(_ignore, _x, ...) (_x)
+#define __IS_XAB(_x) ___IS_XAB(_x 1, 0)
+#define _IS_XAB(_x) __IS_XAB(__CONCAT(___XAB_, _x))
+
+/* This is if CONFIG_ccc=y. */
+#define IS_BUILTIN(_x) _IS_XAB(_x)
+/* This is if CONFIG_ccc=m. */
+#define IS_MODULE(_x) _IS_XAB(_x ## _MODULE)
+/* This is if CONFIG_ccc is compiled in(=y) or a module(=m). */
+#define IS_ENABLED(_x) (IS_BUILTIN(_x) || IS_MODULE(_x))
+/*
+ * This is weird case. If the CONFIG_ccc is builtin (=y) this returns true;
+ * or if the CONFIG_ccc is a module (=m) and the caller is built as a module
+ * (-DMODULE defined) this returns true, but if the callers is not a module
+ * (-DMODULE not defined, which means caller is BUILTIN) then it returns
+ * false. In other words, a module can reach the kernel, a module can reach
+ * a module, but the kernel cannot reach a module, and code never compiled
+ * cannot be reached either.
+ * XXX -- I'd hope the module-to-module case would be handled by a proper
+ * module dependency definition (MODULE_DEPEND() in FreeBSD).
+ */
+#define IS_REACHABLE(_x) (IS_BUILTIN(_x) || \
+ (IS_MODULE(_x) && IS_BUILTIN(MODULE)))
+
+#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
new file mode 100644
index 000000000000..988dd771254a
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/kdev_t.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_KDEV_T_H_
+#define _LINUXKPI_LINUX_KDEV_T_H_
+
+#include <sys/types.h>
+
+#define MAJOR(dev) major(dev)
+#define MINOR(dev) minor(dev)
+#define MKDEV(ma, mi) makedev(ma, mi)
+
+static inline uint16_t
+old_encode_dev(dev_t dev)
+{
+ return ((MAJOR(dev) << 8) | MINOR(dev));
+}
+
+#endif /* _LINUXKPI_LINUX_KDEV_T_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kernel.h b/sys/compat/linuxkpi/common/include/linux/kernel.h
new file mode 100644
index 000000000000..11a13cbd49b4
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/kernel.h
@@ -0,0 +1,385 @@
+/*-
+ * 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) 2014-2015 François Tigeot
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_KERNEL_H_
+#define _LINUXKPI_LINUX_KERNEL_H_
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/param.h>
+#include <sys/libkern.h>
+#include <sys/stat.h>
+#include <sys/smp.h>
+#include <sys/stddef.h>
+#include <sys/syslog.h>
+#include <sys/time.h>
+
+#include <linux/bitops.h>
+#include <linux/build_bug.h>
+#include <linux/compiler.h>
+#include <linux/container_of.h>
+#include <linux/kstrtox.h>
+#include <linux/limits.h>
+#include <linux/math.h>
+#include <linux/minmax.h>
+#include <linux/stringify.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/typecheck.h>
+#include <linux/jiffies.h>
+#include <linux/log2.h>
+#include <linux/kconfig.h>
+
+#include <asm/byteorder.h>
+#include <asm/cpufeature.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+
+#include <linux/stdarg.h>
+
+#define KERN_CONT ""
+#define KERN_EMERG "<0>"
+#define KERN_ALERT "<1>"
+#define KERN_CRIT "<2>"
+#define KERN_ERR "<3>"
+#define KERN_WARNING "<4>"
+#define KERN_NOTICE "<5>"
+#define KERN_INFO "<6>"
+#define KERN_DEBUG "<7>"
+
+#define S8_C(x) x
+#define U8_C(x) x ## U
+#define S16_C(x) x
+#define U16_C(x) x ## U
+#define S32_C(x) x
+#define U32_C(x) x ## U
+#define S64_C(x) x ## LL
+#define U64_C(x) x ## ULL
+
+#define BUG() panic("BUG at %s:%d", __FILE__, __LINE__)
+#define BUG_ON(cond) do { \
+ if (cond) { \
+ panic("BUG ON %s failed at %s:%d", \
+ __stringify(cond), __FILE__, __LINE__); \
+ } \
+} while (0)
+
+extern int linuxkpi_warn_dump_stack;
+#define WARN_ON(cond) ({ \
+ bool __ret = (cond); \
+ if (__ret) { \
+ printf("WARNING %s failed at %s:%d\n", \
+ __stringify(cond), __FILE__, __LINE__); \
+ if (linuxkpi_warn_dump_stack) \
+ linux_dump_stack(); \
+ } \
+ unlikely(__ret); \
+})
+
+#define WARN_ON_SMP(cond) WARN_ON(cond)
+
+#define WARN_ON_ONCE(cond) ({ \
+ static bool __warn_on_once; \
+ bool __ret = (cond); \
+ if (__ret && !__warn_on_once) { \
+ __warn_on_once = 1; \
+ printf("WARNING %s failed at %s:%d\n", \
+ __stringify(cond), __FILE__, __LINE__); \
+ if (linuxkpi_warn_dump_stack) \
+ linux_dump_stack(); \
+ } \
+ unlikely(__ret); \
+})
+
+#define oops_in_progress SCHEDULER_STOPPED()
+
+#undef ALIGN
+#define ALIGN(x, y) roundup2((x), (y))
+#define ALIGN_DOWN(x, y) rounddown2(x, y)
+#undef PTR_ALIGN
+#define PTR_ALIGN(p, a) ((__typeof(p))ALIGN((uintptr_t)(p), (a)))
+#define IS_ALIGNED(x, a) (((x) & ((__typeof(x))(a) - 1)) == 0)
+#define __KERNEL_DIV_ROUND_UP(x, n) howmany(x, n)
+#define FIELD_SIZEOF(t, f) sizeof(((t *)0)->f)
+
+#define printk(...) printf(__VA_ARGS__)
+#define vprintk(f, a) vprintf(f, a)
+
+#define PTR_IF(x, p) ((x) ? (p) : NULL)
+
+#define asm __asm
+
+extern void linux_dump_stack(void);
+#define dump_stack() linux_dump_stack()
+
+struct va_format {
+ const char *fmt;
+ va_list *va;
+};
+
+static inline int
+vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
+{
+ ssize_t ssize = size;
+ int i;
+
+ i = vsnprintf(buf, size, fmt, args);
+
+ return ((i >= ssize) ? (ssize - 1) : i);
+}
+
+static inline int
+scnprintf(char *buf, size_t size, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i = vscnprintf(buf, size, fmt, args);
+ va_end(args);
+
+ return (i);
+}
+
+/*
+ * The "pr_debug()" and "pr_devel()" macros should produce zero code
+ * unless DEBUG is defined:
+ */
+#ifdef DEBUG
+extern int linuxkpi_debug;
+#define pr_debug(fmt, ...) \
+ do { \
+ if (linuxkpi_debug) \
+ log(LOG_DEBUG, fmt, ##__VA_ARGS__); \
+ } while (0)
+#define pr_devel(fmt, ...) \
+ log(LOG_DEBUG, pr_fmt(fmt), ##__VA_ARGS__)
+#else
+#define pr_debug(fmt, ...) \
+ ({ if (0) log(LOG_DEBUG, fmt, ##__VA_ARGS__); 0; })
+#define pr_devel(fmt, ...) \
+ ({ if (0) log(LOG_DEBUG, pr_fmt(fmt), ##__VA_ARGS__); 0; })
+#endif
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) fmt
+#endif
+
+/*
+ * Print a one-time message (analogous to WARN_ONCE() et al):
+ */
+#define printk_once(...) do { \
+ static bool __print_once; \
+ \
+ if (!__print_once) { \
+ __print_once = true; \
+ printk(__VA_ARGS__); \
+ } \
+} while (0)
+
+/*
+ * Log a one-time message (analogous to WARN_ONCE() et al):
+ */
+#define log_once(level,...) do { \
+ static bool __log_once; \
+ \
+ if (unlikely(!__log_once)) { \
+ __log_once = true; \
+ log(level, __VA_ARGS__); \
+ } \
+} while (0)
+
+#define pr_emerg(fmt, ...) \
+ log(LOG_EMERG, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_alert(fmt, ...) \
+ log(LOG_ALERT, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_crit(fmt, ...) \
+ log(LOG_CRIT, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_err(fmt, ...) \
+ log(LOG_ERR, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_err_once(fmt, ...) \
+ log_once(LOG_ERR, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_warning(fmt, ...) \
+ log(LOG_WARNING, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_warn(...) \
+ pr_warning(__VA_ARGS__)
+#define pr_warn_once(fmt, ...) \
+ log_once(LOG_WARNING, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_notice(fmt, ...) \
+ log(LOG_NOTICE, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_info(fmt, ...) \
+ log(LOG_INFO, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_info_once(fmt, ...) \
+ log_once(LOG_INFO, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_cont(fmt, ...) \
+ printk(KERN_CONT fmt, ##__VA_ARGS__)
+#define pr_warn_ratelimited(...) do { \
+ static linux_ratelimit_t __ratelimited; \
+ if (linux_ratelimited(&__ratelimited)) \
+ pr_warning(__VA_ARGS__); \
+} while (0)
+
+#ifndef WARN
+#define WARN(condition, ...) ({ \
+ bool __ret_warn_on = (condition); \
+ if (unlikely(__ret_warn_on)) \
+ pr_warning(__VA_ARGS__); \
+ unlikely(__ret_warn_on); \
+})
+#endif
+
+#ifndef WARN_ONCE
+#define WARN_ONCE(condition, ...) ({ \
+ bool __ret_warn_on = (condition); \
+ if (unlikely(__ret_warn_on)) \
+ pr_warn_once(__VA_ARGS__); \
+ unlikely(__ret_warn_on); \
+})
+#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)))
+
+#define smp_processor_id() PCPU_GET(cpuid)
+#define num_possible_cpus() mp_ncpus
+#define num_online_cpus() mp_ncpus
+
+#if defined(__i386__) || defined(__amd64__)
+extern bool linux_cpu_has_clflush;
+#define cpu_has_clflush linux_cpu_has_clflush
+#endif
+
+typedef struct linux_ratelimit {
+ struct timeval lasttime;
+ int counter;
+} linux_ratelimit_t;
+
+static inline bool
+linux_ratelimited(linux_ratelimit_t *rl)
+{
+ return (ppsratecheck(&rl->lasttime, &rl->counter, 1));
+}
+
+#define __is_constexpr(x) \
+ __builtin_constant_p(x)
+
+/*
+ * The is_signed() macro below returns true if the passed data type is
+ * signed. Else false is returned.
+ */
+#define is_signed(datatype) (((datatype)-1 / (datatype)2) == (datatype)0)
+
+#define TAINT_WARN 0
+#define test_taint(x) (0)
+#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)
+{
+ const char *s, *d;
+ uint8_t mac[6], hx, lx;
+ int i;
+
+ if (strlen(macin) < (3 * 6 - 1))
+ return (false);
+
+ i = 0;
+ s = macin;
+ do {
+ /* Should we also support '-'-delimiters? */
+ d = strchrnul(s, ':');
+ hx = lx = 0;
+ while (s < d) {
+ /* Fail on abc:123:xxx:... */
+ if ((d - s) > 2)
+ return (false);
+ /* We do support non-well-formed strings: 3:45:6:... */
+ if ((d - s) > 1) {
+ hx = _h2b(*s);
+ if (hx < 0)
+ return (false);
+ s++;
+ }
+ lx = _h2b(*s);
+ if (lx < 0)
+ return (false);
+ s++;
+ }
+ mac[i] = (hx << 4) | lx;
+ i++;
+ if (i >= 6)
+ return (false);
+ } while (d != NULL && *d != '\0');
+
+ memcpy(macout, mac, 6);
+ return (true);
+}
+
+#define DECLARE_FLEX_ARRAY(_t, _n) \
+ struct { struct { } __dummy_ ## _n; _t _n[0]; }
+
+#endif /* _LINUXKPI_LINUX_KERNEL_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kernel_stat.h b/sys/compat/linuxkpi/common/include/linux/kernel_stat.h
new file mode 100644
index 000000000000..c960b4ad2cff
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/kernel_stat.h
@@ -0,0 +1,34 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
+ *
+ * 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_KERNEL_STAT_H_
+#define _LINUXKPI_LINUX_KERNEL_STAT_H_
+
+#include <linux/interrupt.h>
+
+#endif /* _LINUXKPI_LINUX_KERNEL_STAT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kfifo.h b/sys/compat/linuxkpi/common/include/linux/kfifo.h
new file mode 100644
index 000000000000..d2f570781661
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/kfifo.h
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
+ * Copyright (c) 2022 Bjoern A. Zeeb
+ *
+ * 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_KFIFO_H_
+#define _LINUXKPI_LINUX_KFIFO_H_
+
+#include <sys/types.h>
+
+#include <linux/slab.h>
+#include <linux/gfp.h>
+
+#define INIT_KFIFO(x) 0
+#define DECLARE_KFIFO(x, y, z)
+
+#define DECLARE_KFIFO_PTR(_name, _type) \
+ struct kfifo_ ## _name { \
+ size_t total; \
+ size_t count; \
+ size_t first; \
+ size_t last; \
+ _type *head; \
+ } _name
+
+#define kfifo_len(_kf) \
+({ \
+ (_kf)->count; \
+})
+
+#define kfifo_is_empty(_kf) \
+({ \
+ ((_kf)->count == 0) ? true : false; \
+})
+
+#define kfifo_is_full(_kf) \
+({ \
+ ((_kf)->count == (_kf)->total) ? true : false; \
+})
+
+#define kfifo_put(_kf, _e) \
+({ \
+ bool _rc; \
+ \
+ /* Would overflow. */ \
+ if (kfifo_is_full(_kf)) { \
+ _rc = false; \
+ } else { \
+ (_kf)->head[(_kf)->last] = (_e); \
+ (_kf)->count++; \
+ (_kf)->last++; \
+ if ((_kf)->last > (_kf)->total) \
+ (_kf)->last = 0; \
+ _rc = true; \
+ } \
+ \
+ _rc; \
+})
+
+#define kfifo_get(_kf, _e) \
+({ \
+ bool _rc; \
+ \
+ if (kfifo_is_empty(_kf)) { \
+ _rc = false; \
+ } else { \
+ *(_e) = (_kf)->head[(_kf)->first]; \
+ (_kf)->count--; \
+ (_kf)->first++; \
+ if ((_kf)->first > (_kf)->total) \
+ (_kf)->first = 0; \
+ _rc = true; \
+ } \
+ \
+ _rc; \
+})
+
+#define kfifo_alloc(_kf, _s, _gfp) \
+({ \
+ int _error; \
+ \
+ (_kf)->head = kmalloc(sizeof(__typeof(*(_kf)->head)) * (_s), _gfp); \
+ if ((_kf)->head == NULL) \
+ _error = ENOMEM; \
+ else { \
+ (_kf)->total = (_s); \
+ _error = 0; \
+ } \
+ \
+ _error; \
+})
+
+#define kfifo_free(_kf) \
+({ \
+ kfree((_kf)->head); \
+ (_kf)->head = NULL; \
+ (_kf)->total = (_kf)->count = (_kf)->first = (_kf)->last = 0; \
+})
+
+#endif /* _LINUXKPI_LINUX_KFIFO_H_*/
diff --git a/sys/compat/linuxkpi/common/include/linux/kmemleak.h b/sys/compat/linuxkpi/common/include/linux/kmemleak.h
new file mode 100644
index 000000000000..7007e72718c7
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/kmemleak.h
@@ -0,0 +1,8 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_KMEMLEAK_H_
+#define _LINUXKPI_LINUX_KMEMLEAK_H_
+
+#define kmemleak_update_trace(x)
+
+#endif /* _LINUXKPI_LINUX_KMEMLEAK_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kmod.h b/sys/compat/linuxkpi/common/include/linux/kmod.h
new file mode 100644
index 000000000000..8f9f034aabd8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/kmod.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_KMOD_H_
+#define _LINUXKPI_LINUX_KMOD_H_
+
+#include <sys/types.h>
+#include <sys/syscallsubr.h>
+#include <sys/refcount.h>
+#include <sys/sbuf.h>
+#include <sys/stdarg.h>
+#include <sys/proc.h>
+
+#define request_module(...) \
+({\
+ char modname[128]; \
+ snprintf(modname, sizeof(modname), __VA_ARGS__); \
+ kern_kldload(curthread, modname, NULL); \
+})
+
+#define request_module_nowait request_module
+
+#endif /* _LINUXKPI_LINUX_KMOD_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kobject.h b/sys/compat/linuxkpi/common/include/linux/kobject.h
new file mode 100644
index 000000000000..98f55d1234c4
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/kobject.h
@@ -0,0 +1,210 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_KOBJECT_H_
+#define _LINUXKPI_LINUX_KOBJECT_H_
+
+#include <sys/stdarg.h>
+
+#include <linux/kernel.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+struct kobject;
+struct kset;
+struct sysctl_oid;
+
+#define KOBJ_CHANGE 0x01
+
+struct kobj_type {
+ void (*release)(struct kobject *kobj);
+ const struct sysfs_ops *sysfs_ops;
+ struct attribute **default_attrs;
+ const struct attribute_group **default_groups;
+};
+
+extern const struct kobj_type linux_kfree_type;
+
+struct kobject {
+ struct kobject *parent;
+ char *name;
+ struct kref kref;
+ const struct kobj_type *ktype;
+ struct list_head entry;
+ struct sysctl_oid *oidp;
+ struct kset *kset;
+};
+
+extern struct kobject *mm_kobj;
+
+struct attribute {
+ const char *name;
+ struct module *owner;
+ mode_t mode;
+};
+
+extern const struct sysfs_ops kobj_sysfs_ops;
+
+struct kobj_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf);
+ ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count);
+};
+
+struct kset_uevent_ops {
+ /* TODO */
+};
+
+struct kset {
+ struct list_head list;
+ spinlock_t list_lock;
+ struct kobject kobj;
+ const struct kset_uevent_ops *uevent_ops;
+};
+
+static inline void
+kobject_init(struct kobject *kobj, const struct kobj_type *ktype)
+{
+
+ kref_init(&kobj->kref);
+ INIT_LIST_HEAD(&kobj->entry);
+ kobj->ktype = ktype;
+ kobj->oidp = NULL;
+}
+
+void linux_kobject_release(struct kref *kref);
+
+static inline void
+kobject_put(struct kobject *kobj)
+{
+
+ if (kobj)
+ kref_put(&kobj->kref, linux_kobject_release);
+}
+
+static inline struct kobject *
+kobject_get(struct kobject *kobj)
+{
+
+ if (kobj)
+ kref_get(&kobj->kref);
+ return kobj;
+}
+
+struct kobject *kobject_create(void);
+int kobject_set_name_vargs(struct kobject *kobj, const char *fmt, va_list);
+int kobject_add(struct kobject *kobj, struct kobject *parent,
+ const char *fmt, ...);
+
+static inline struct kobject *
+kobject_create_and_add(const char *name, struct kobject *parent)
+{
+ struct kobject *kobj;
+
+ kobj = kobject_create();
+ if (kobj == NULL)
+ return (NULL);
+ if (kobject_add(kobj, parent, "%s", name) == 0)
+ return (kobj);
+ kobject_put(kobj);
+
+ return (NULL);
+}
+
+static inline void
+kobject_del(struct kobject *kobj __unused)
+{
+}
+
+static inline char *
+kobject_name(const struct kobject *kobj)
+{
+
+ return kobj->name;
+}
+
+int kobject_set_name(struct kobject *kobj, const char *fmt, ...);
+int kobject_init_and_add(struct kobject *kobj, const struct kobj_type *ktype,
+ struct kobject *parent, const char *fmt, ...);
+
+static __inline void
+kobject_uevent_env(struct kobject *kobj, int action, char *envp[])
+{
+
+ /*
+ * iwlwifi(4) sends an INACCESSIBLE event when it detects that the card
+ * (pice endpoint) is gone and it attempts a removal cleanup.
+ * Not sure if we do anything related to udev/sysfs at the moment or
+ * need a shortcut or simply ignore it (for now).
+ */
+}
+
+void kset_init(struct kset *kset);
+int kset_register(struct kset *kset);
+void kset_unregister(struct kset *kset);
+struct kset * kset_create_and_add(const char *name,
+ const struct kset_uevent_ops *u, struct kobject *parent_kobj);
+
+static inline struct kset *
+to_kset(struct kobject *kobj)
+{
+ if (kobj != NULL)
+ return container_of(kobj, struct kset, kobj);
+ else
+ return NULL;
+}
+
+static inline struct kset *
+kset_get(struct kset *kset)
+{
+ if (kset != NULL) {
+ struct kobject *kobj;
+
+ kobj = kobject_get(&kset->kobj);
+ return to_kset(kobj);
+ } else {
+ return NULL;
+ }
+}
+
+static inline void
+kset_put(struct kset *kset)
+{
+ if (kset != NULL)
+ kobject_put(&kset->kobj);
+}
+
+void linux_kobject_kfree_name(struct kobject *kobj);
+
+#endif /* _LINUXKPI_LINUX_KOBJECT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kref.h b/sys/compat/linuxkpi/common/include/linux/kref.h
new file mode 100644
index 000000000000..b2fba468f7df
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/kref.h
@@ -0,0 +1,129 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2015 Mellanox Technologies, Ltd.
+ * Copyright (c) 2013 François Tigeot
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_KREF_H_
+#define _LINUXKPI_LINUX_KREF_H_
+
+#include <sys/types.h>
+#include <sys/refcount.h>
+
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/refcount.h>
+
+#include <asm/atomic.h>
+
+struct kref {
+ refcount_t refcount;
+};
+
+static inline void
+kref_init(struct kref *kref)
+{
+
+ refcount_init((uint32_t *)&kref->refcount, 1);
+}
+
+static inline unsigned int
+kref_read(const struct kref *kref)
+{
+
+ return (refcount_load(__DECONST(u_int32_t *, &kref->refcount)));
+}
+
+static inline void
+kref_get(struct kref *kref)
+{
+
+ refcount_acquire((uint32_t *)&kref->refcount);
+}
+
+static inline int
+kref_put(struct kref *kref, void (*rel)(struct kref *kref))
+{
+
+ if (refcount_release((uint32_t *)&kref->refcount)) {
+ rel(kref);
+ return 1;
+ }
+ return 0;
+}
+
+static inline int
+kref_put_lock(struct kref *kref, void (*rel)(struct kref *kref),
+ spinlock_t *lock)
+{
+
+ if (refcount_release((uint32_t *)&kref->refcount)) {
+ spin_lock(lock);
+ rel(kref);
+ return (1);
+ }
+ return (0);
+}
+
+static inline int
+kref_sub(struct kref *kref, unsigned int count,
+ void (*rel)(struct kref *kref))
+{
+
+ while (count--) {
+ if (refcount_release((uint32_t *)&kref->refcount)) {
+ rel(kref);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static inline int __must_check
+kref_get_unless_zero(struct kref *kref)
+{
+
+ return refcount_acquire_if_not_zero((uint32_t *)&kref->refcount);
+}
+
+static inline int kref_put_mutex(struct kref *kref,
+ void (*release)(struct kref *kref), struct mutex *lock)
+{
+ WARN_ON(release == NULL);
+ if (unlikely(!refcount_release_if_not_last((uint32_t *)&kref->refcount))) {
+ mutex_lock(lock);
+ if (unlikely(!refcount_release((uint32_t *)&kref->refcount))) {
+ mutex_unlock(lock);
+ return 0;
+ }
+ release(kref);
+ return 1;
+ }
+ return 0;
+}
+
+#endif /* _LINUXKPI_LINUX_KREF_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kstrtox.h b/sys/compat/linuxkpi/common/include/linux/kstrtox.h
new file mode 100644
index 000000000000..5da99de24197
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/kstrtox.h
@@ -0,0 +1,324 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2017-2018 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ * Copyright (c) 2018 Johannes Lundberg <johalun0@gmail.com>
+ * Copyright (c) 2020-2022 The FreeBSD Foundation
+ * Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
+ * Copyright (c) 2023 Serenity Cyber Security, LLC
+ *
+ * Portions of this software were developed by Bjoern A. Zeeb and
+ * Emmanuel Vadot 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 unmodified, 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 ``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 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_KSTRTOX_H_
+#define _LINUXKPI_LINUX_KSTRTOX_H_
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/libkern.h>
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+#include <asm/uaccess.h>
+
+static inline unsigned long long
+simple_strtoull(const char *cp, char **endp, unsigned int base)
+{
+ return (strtouq(cp, endp, base));
+}
+
+static inline long long
+simple_strtoll(const char *cp, char **endp, unsigned int base)
+{
+ return (strtoq(cp, endp, base));
+}
+
+static inline unsigned long
+simple_strtoul(const char *cp, char **endp, unsigned int base)
+{
+ return (strtoul(cp, endp, base));
+}
+
+static inline long
+simple_strtol(const char *cp, char **endp, unsigned int base)
+{
+ return (strtol(cp, endp, base));
+}
+
+static inline int
+kstrtoul(const char *cp, unsigned int base, unsigned long *res)
+{
+ char *end;
+
+ *res = strtoul(cp, &end, base);
+
+ /* skip newline character, if any */
+ if (*end == '\n')
+ end++;
+ if (*cp == 0 || *end != 0)
+ return (-EINVAL);
+ return (0);
+}
+
+static inline int
+kstrtol(const char *cp, unsigned int base, long *res)
+{
+ char *end;
+
+ *res = strtol(cp, &end, base);
+
+ /* skip newline character, if any */
+ if (*end == '\n')
+ end++;
+ if (*cp == 0 || *end != 0)
+ return (-EINVAL);
+ return (0);
+}
+
+static inline int
+kstrtoint(const char *cp, unsigned int base, int *res)
+{
+ char *end;
+ long temp;
+
+ *res = temp = strtol(cp, &end, base);
+
+ /* skip newline character, if any */
+ if (*end == '\n')
+ end++;
+ if (*cp == 0 || *end != 0)
+ return (-EINVAL);
+ if (temp != (int)temp)
+ return (-ERANGE);
+ return (0);
+}
+
+static inline int
+kstrtouint(const char *cp, unsigned int base, unsigned int *res)
+{
+ char *end;
+ unsigned long temp;
+
+ *res = temp = strtoul(cp, &end, base);
+
+ /* skip newline character, if any */
+ if (*end == '\n')
+ end++;
+ if (*cp == 0 || *end != 0)
+ return (-EINVAL);
+ if (temp != (unsigned int)temp)
+ return (-ERANGE);
+ return (0);
+}
+
+static inline int
+kstrtou8(const char *cp, unsigned int base, uint8_t *res)
+{
+ char *end;
+ unsigned long temp;
+
+ *res = temp = strtoul(cp, &end, base);
+
+ /* skip newline character, if any */
+ if (*end == '\n')
+ end++;
+ if (*cp == 0 || *end != 0)
+ return (-EINVAL);
+ if (temp != (uint8_t)temp)
+ return (-ERANGE);
+ return (0);
+}
+
+static inline int
+kstrtou16(const char *cp, unsigned int base, uint16_t *res)
+{
+ char *end;
+ unsigned long temp;
+
+ *res = temp = strtoul(cp, &end, base);
+
+ /* skip newline character, if any */
+ if (*end == '\n')
+ end++;
+ if (*cp == 0 || *end != 0)
+ return (-EINVAL);
+ if (temp != (uint16_t)temp)
+ return (-ERANGE);
+ 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));
+}
+
+static inline int
+kstrtos64(const char *cp, unsigned int base, int64_t *res)
+{
+ char *end;
+
+ *res = strtoq(cp, &end, base);
+
+ /* skip newline character, if any */
+ if (*end == '\n')
+ end++;
+ if (*cp == 0 || *end != 0)
+ return (-EINVAL);
+ return (0);
+}
+
+static inline int
+kstrtoll(const char *cp, unsigned int base, long long *res)
+{
+ return (kstrtos64(cp, base, (int64_t *)res));
+}
+
+static inline int
+kstrtou64(const char *cp, unsigned int base, u64 *res)
+{
+ char *end;
+
+ *res = strtouq(cp, &end, base);
+
+ /* skip newline character, if any */
+ if (*end == '\n')
+ end++;
+ if (*cp == 0 || *end != 0)
+ return (-EINVAL);
+ return (0);
+}
+
+static inline int
+kstrtoull(const char *cp, unsigned int base, unsigned long long *res)
+{
+ return (kstrtou64(cp, base, (uint64_t *)res));
+}
+
+static inline int
+kstrtobool(const char *s, bool *res)
+{
+ int len;
+
+ if (s == NULL || (len = strlen(s)) == 0 || res == NULL)
+ return (-EINVAL);
+
+ /* skip newline character, if any */
+ if (s[len - 1] == '\n')
+ len--;
+
+ if (len == 1 && strchr("yY1", s[0]) != NULL)
+ *res = true;
+ else if (len == 1 && strchr("nN0", s[0]) != NULL)
+ *res = false;
+ else if (strncasecmp("on", s, len) == 0)
+ *res = true;
+ else if (strncasecmp("off", s, len) == 0)
+ *res = false;
+ else
+ return (-EINVAL);
+
+ return (0);
+}
+
+static inline int
+kstrtobool_from_user(const char __user *s, size_t count, bool *res)
+{
+ char buf[8] = {};
+
+ if (count > (sizeof(buf) - 1))
+ count = (sizeof(buf) - 1);
+
+ if (copy_from_user(buf, s, count))
+ return (-EFAULT);
+
+ return (kstrtobool(buf, res));
+}
+
+static inline int
+kstrtoint_from_user(const char __user *s, size_t count, unsigned int base,
+ int *p)
+{
+ char buf[36] = {};
+
+ if (count > (sizeof(buf) - 1))
+ count = (sizeof(buf) - 1);
+
+ if (copy_from_user(buf, s, count))
+ return (-EFAULT);
+
+ return (kstrtoint(buf, base, p));
+}
+
+static inline int
+kstrtouint_from_user(const char __user *s, size_t count, unsigned int base,
+ unsigned int *p)
+{
+ char buf[36] = {};
+
+ if (count > (sizeof(buf) - 1))
+ count = (sizeof(buf) - 1);
+
+ if (copy_from_user(buf, s, count))
+ return (-EFAULT);
+
+ return (kstrtouint(buf, base, p));
+}
+
+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));
+}
+
+static inline int
+kstrtou8_from_user(const char __user *s, size_t count, unsigned int base,
+ uint8_t *p)
+{
+ char buf[8] = {};
+
+ if (count > (sizeof(buf) - 1))
+ count = (sizeof(buf) - 1);
+
+ if (copy_from_user(buf, s, count))
+ return (-EFAULT);
+
+ return (kstrtou8(buf, base, p));
+}
+
+#endif /* _LINUXKPI_LINUX_KSTRTOX_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kthread.h b/sys/compat/linuxkpi/common/include/linux/kthread.h
new file mode 100644
index 000000000000..1fde734fd767
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/kthread.h
@@ -0,0 +1,166 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_KTHREAD_H_
+#define _LINUXKPI_LINUX_KTHREAD_H_
+
+#include <linux/sched.h>
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/unistd.h>
+
+struct task_struct;
+struct kthread_work;
+
+typedef void (*kthread_work_func_t)(struct kthread_work *work);
+
+struct kthread_worker {
+ struct task_struct *task;
+ struct taskqueue *tq;
+};
+
+struct kthread_work {
+ struct taskqueue *tq;
+ struct task task;
+ kthread_work_func_t func;
+};
+
+#define kthread_run(fn, data, fmt, ...) ({ \
+ struct task_struct *__task; \
+ struct thread *__td; \
+ \
+ if (kthread_add(linux_kthread_fn, NULL, NULL, &__td, \
+ RFSTOPPED, 0, fmt, ## __VA_ARGS__)) \
+ __task = NULL; \
+ else \
+ __task = linux_kthread_setup_and_run(__td, fn, data); \
+ __task; \
+})
+
+int linux_kthread_stop(struct task_struct *);
+bool linux_kthread_should_stop_task(struct task_struct *);
+bool linux_kthread_should_stop(void);
+int linux_kthread_park(struct task_struct *);
+void linux_kthread_parkme(void);
+bool linux_kthread_should_park(void);
+void linux_kthread_unpark(struct task_struct *);
+void linux_kthread_fn(void *);
+struct task_struct *linux_kthread_setup_and_run(struct thread *,
+ linux_task_fn_t *, void *arg);
+int linux_in_atomic(void);
+
+#define kthread_stop(task) linux_kthread_stop(task)
+#define kthread_should_stop() linux_kthread_should_stop()
+#define kthread_should_stop_task(task) linux_kthread_should_stop_task(task)
+#define kthread_park(task) linux_kthread_park(task)
+#define kthread_parkme() linux_kthread_parkme()
+#define kthread_should_park() linux_kthread_should_park()
+#define kthread_unpark(task) linux_kthread_unpark(task)
+
+#define in_atomic() linux_in_atomic()
+
+/* Only kthread_(create|destroy)_worker interface is allowed */
+#define kthread_init_worker(worker) \
+ _Static_assert(false, "pre-4.9 worker interface is not supported");
+
+task_fn_t lkpi_kthread_work_fn;
+task_fn_t lkpi_kthread_worker_init_fn;
+
+#define kthread_create_worker(flags, fmt, ...) ({ \
+ struct kthread_worker *__w; \
+ struct task __task; \
+ \
+ __w = malloc(sizeof(*__w), M_KMALLOC, M_WAITOK | M_ZERO); \
+ __w->tq = taskqueue_create("lkpi kthread taskq", M_WAITOK, \
+ taskqueue_thread_enqueue, &__w->tq); \
+ taskqueue_start_threads(&__w->tq, 1, PWAIT, fmt, ##__VA_ARGS__);\
+ TASK_INIT(&__task, 0, lkpi_kthread_worker_init_fn, __w); \
+ taskqueue_enqueue(__w->tq, &__task); \
+ taskqueue_drain(__w->tq, &__task); \
+ __w; \
+})
+
+static inline void
+kthread_destroy_worker(struct kthread_worker *worker)
+{
+ taskqueue_drain_all(worker->tq);
+ taskqueue_free(worker->tq);
+ free(worker, M_KMALLOC);
+}
+
+static inline void
+kthread_init_work(struct kthread_work *work, kthread_work_func_t func)
+{
+ work->tq = NULL;
+ work->func = func;
+ TASK_INIT(&work->task, 0, lkpi_kthread_work_fn, work);
+}
+
+static inline bool
+kthread_queue_work(struct kthread_worker *worker, struct kthread_work *work)
+{
+ int error;
+
+ error = taskqueue_enqueue_flags(worker->tq, &work->task,
+ TASKQUEUE_FAIL_IF_CANCELING | TASKQUEUE_FAIL_IF_PENDING);
+ if (error == 0)
+ work->tq = worker->tq;
+ return (error == 0);
+}
+
+static inline bool
+kthread_cancel_work_sync(struct kthread_work *work)
+{
+ u_int pending = 0;
+
+ if (work->tq != NULL &&
+ taskqueue_cancel(work->tq, &work->task, &pending) != 0)
+ taskqueue_drain(work->tq, &work->task);
+
+ return (pending != 0);
+}
+
+static inline void
+kthread_flush_work(struct kthread_work *work)
+{
+ if (work->tq != NULL)
+ taskqueue_drain(work->tq, &work->task);
+}
+
+static inline void
+kthread_flush_worker(struct kthread_worker *worker)
+{
+ taskqueue_drain_all(worker->tq);
+}
+
+#endif /* _LINUXKPI_LINUX_KTHREAD_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/ktime.h b/sys/compat/linuxkpi/common/include/linux/ktime.h
new file mode 100644
index 000000000000..6a2f04f3d789
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/ktime.h
@@ -0,0 +1,287 @@
+/*-
+ * Copyright (c) 2018 Limelight Networks, Inc.
+ * Copyright (c) 2014-2018 Mellanox Technologies, Ltd.
+ * Copyright (c) 2015 François Tigeot
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_KTIME_H
+#define _LINUXKPI_LINUX_KTIME_H
+
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/jiffies.h>
+
+/* time values in nanoseconds */
+typedef s64 ktime_t;
+
+#define KTIME_MAX ((s64)~((u64)1 << 63))
+#define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC)
+
+static inline int64_t
+ktime_to_ns(ktime_t kt)
+{
+ return (kt);
+}
+
+static inline ktime_t
+ns_to_ktime(uint64_t nsec)
+{
+ return (nsec);
+}
+
+static inline int64_t
+ktime_divns(const ktime_t kt, int64_t div)
+{
+ return (kt / div);
+}
+
+static inline int64_t
+ktime_to_us(ktime_t kt)
+{
+ return (ktime_divns(kt, NSEC_PER_USEC));
+}
+
+static inline int64_t
+ktime_to_ms(ktime_t kt)
+{
+ return (ktime_divns(kt, NSEC_PER_MSEC));
+}
+
+static inline ktime_t
+ms_to_ktime(uint64_t ms)
+{
+ return (ms * NSEC_PER_MSEC);
+}
+
+static inline struct timeval
+ktime_to_timeval(ktime_t kt)
+{
+ return (ns_to_timeval(kt));
+}
+
+static inline ktime_t
+ktime_add_ns(ktime_t kt, int64_t ns)
+{
+ return (kt + ns);
+}
+
+static inline ktime_t
+ktime_add_ms(ktime_t kt, int64_t ms)
+{
+
+ return (ktime_add_ns(kt, ms * NSEC_PER_MSEC));
+}
+
+static inline ktime_t
+ktime_add_us(ktime_t kt, int64_t us)
+{
+
+ return (ktime_add_ns(kt, us * NSEC_PER_USEC));
+}
+
+static inline ktime_t
+ktime_sub_ns(ktime_t kt, int64_t ns)
+{
+ return (kt - ns);
+}
+
+static inline ktime_t
+ktime_set(const long secs, const unsigned long nsecs)
+{
+ ktime_t retval = {(s64) secs * NSEC_PER_SEC + (s64) nsecs};
+
+ return (retval);
+}
+
+static inline ktime_t
+ktime_sub(ktime_t lhs, ktime_t rhs)
+{
+ return (lhs - rhs);
+}
+
+static inline int64_t
+ktime_us_delta(ktime_t later, ktime_t earlier)
+{
+ ktime_t diff = ktime_sub(later, earlier);
+
+ return (ktime_to_us(diff));
+}
+
+static inline int64_t
+ktime_ms_delta(ktime_t later, ktime_t earlier)
+{
+ ktime_t diff = ktime_sub(later, earlier);
+
+ return (ktime_to_ms(diff));
+}
+
+static inline ktime_t
+ktime_add(ktime_t lhs, ktime_t rhs)
+{
+ return (lhs + rhs);
+}
+
+static inline int
+ktime_compare(const ktime_t cmp1, const ktime_t cmp2)
+{
+
+ if (cmp1 > cmp2)
+ return (1);
+ else if (cmp1 < cmp2)
+ return (-1);
+ else
+ return (0);
+}
+
+static inline bool
+ktime_after(const ktime_t cmp1, const ktime_t cmp2)
+{
+
+ return (ktime_compare(cmp1, cmp2) > 0);
+}
+
+static inline bool
+ktime_before(const ktime_t cmp1, const ktime_t cmp2)
+{
+
+ return (ktime_compare(cmp1, cmp2) < 0);
+}
+
+static inline ktime_t
+timespec_to_ktime(struct timespec ts)
+{
+ return (ktime_set(ts.tv_sec, ts.tv_nsec));
+}
+
+static inline ktime_t
+timeval_to_ktime(struct timeval tv)
+{
+ return (ktime_set(tv.tv_sec, tv.tv_usec * NSEC_PER_USEC));
+}
+
+static inline int64_t
+timespec64_to_ns(struct timespec64 *ts)
+{
+ return (timespec_to_ns(ts));
+}
+
+#define ktime_to_timespec(kt) ns_to_timespec(kt)
+#define ktime_to_timespec64(kt) ns_to_timespec(kt)
+#define ktime_to_timeval(kt) ns_to_timeval(kt)
+#define ktime_to_ns(kt) (kt)
+#define ktime_get_ts(ts) getnanouptime(ts)
+#define ktime_get_ts64(ts) getnanouptime(ts)
+#define ktime_get_raw_ts64(ts) getnanouptime(ts)
+#define ktime_get_real_ts64(ts) getnanotime(ts)
+#define getrawmonotonic64(ts) getnanouptime(ts)
+
+static inline int64_t
+ktime_get_ns(void)
+{
+ struct timespec ts;
+
+ ktime_get_ts(&ts);
+
+ return (ktime_to_ns(timespec_to_ktime(ts)));
+}
+
+static inline ktime_t
+ktime_get(void)
+{
+ struct timespec ts;
+
+ ktime_get_ts(&ts);
+ return (timespec_to_ktime(ts));
+}
+
+static inline ktime_t
+ktime_get_boottime(void)
+{
+ struct timespec ts;
+
+ nanouptime(&ts);
+ return (timespec_to_ktime(ts));
+}
+
+static inline uint64_t
+ktime_get_boottime_ns(void)
+{
+
+ return (ktime_to_ns(ktime_get_boottime()));
+}
+
+static inline uint64_t
+ktime_get_boottime_seconds(void)
+{
+
+ return (ktime_divns(ktime_get_boottime(), NSEC_PER_SEC));
+}
+
+static inline ktime_t
+ktime_get_real(void)
+{
+ struct timespec ts;
+
+ nanotime(&ts);
+ return (timespec_to_ktime(ts));
+}
+
+static inline ktime_t
+ktime_get_real_seconds(void)
+{
+ struct timespec ts;
+
+ nanotime(&ts);
+ return (ts.tv_sec);
+}
+
+static inline ktime_t
+ktime_get_raw(void)
+{
+ struct timespec ts;
+
+ nanouptime(&ts);
+ return (timespec_to_ktime(ts));
+}
+
+static inline u64
+ktime_get_raw_ns(void)
+{
+ struct timespec ts;
+
+ nanouptime(&ts);
+ return (ktime_to_ns(timespec_to_ktime(ts)));
+}
+
+static inline uint64_t
+ktime_get_raw_fast_ns(void)
+{
+ struct timespec ts;
+
+ getnanouptime(&ts);
+ return (ktime_to_ns(timespec_to_ktime(ts)));
+}
+
+#endif /* _LINUXKPI_LINUX_KTIME_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/leds.h b/sys/compat/linuxkpi/common/include/linux/leds.h
new file mode 100644
index 000000000000..89f7286f6800
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/leds.h
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2022 Bjoern A. Zeeb
+ *
+ * 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_LEDS_H
+#define _LINUXKPI_LINUX_LEDS_H
+
+enum led_brightness {
+ LED_OFF,
+};
+
+struct led_classdev {
+ const char *name;
+ const char *default_trigger;
+ int (*blink_set)(struct led_classdev *, unsigned long *, unsigned long *);
+ void (*brightness_set)(struct led_classdev *, enum led_brightness);
+ void (*led_set)(struct led_classdev *, enum led_brightness);
+};
+
+#endif /* _LINUXKPI_LINUX_LEDS_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/limits.h b/sys/compat/linuxkpi/common/include/linux/limits.h
new file mode 100644
index 000000000000..716366033bb3
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/limits.h
@@ -0,0 +1,47 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Serenity Cyber Security, LLC.
+ *
+ * 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_LIMITS_H
+#define _LINUXKPI_LINUX_LIMITS_H
+
+#include <sys/types.h>
+#include <sys/stdint.h>
+
+#define U8_MAX UINT8_MAX
+#define S8_MAX INT8_MAX
+#define S8_MIN INT8_MIN
+#define U16_MAX UINT16_MAX
+#define S16_MAX INT16_MAX
+#define S16_MIN INT16_MIN
+#define U32_MAX UINT32_MAX
+#define S32_MAX INT32_MAX
+#define S32_MIN INT32_MIN
+#define U64_MAX UINT64_MAX
+#define S64_MAX INT64_MAX
+#define S64_MIN INT64_MIN
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/list.h b/sys/compat/linuxkpi/common/include/linux/list.h
new file mode 100644
index 000000000000..a6c74a324dac
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/list.h
@@ -0,0 +1,529 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_LIST_H_
+#define _LINUXKPI_LINUX_LIST_H_
+
+#ifndef _STANDALONE
+/*
+ * Since LIST_HEAD conflicts with the Linux definition we must include any
+ * FreeBSD header which requires it here so it is resolved with the correct
+ * definition prior to the undef.
+ */
+#include <linux/types.h>
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/queue.h>
+#include <sys/cpuset.h>
+#include <sys/jail.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/conf.h>
+#include <sys/socket.h>
+#include <sys/mbuf.h>
+
+#include <net/bpf.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_types.h>
+#include <net/if_media.h>
+#include <net/vnet.h>
+
+#include <netinet/in.h>
+#include <netinet/in_pcb.h>
+#include <netinet/in_var.h>
+#include <netinet/tcp_lro.h>
+
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+
+#include <net80211/ieee80211.h>
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_node.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/pmap.h>
+#endif
+
+#ifndef prefetch
+#define prefetch(x)
+#endif
+
+#define LINUX_LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LINUX_LIST_HEAD(name) \
+ struct list_head name = LINUX_LIST_HEAD_INIT(name)
+
+static inline void
+INIT_LIST_HEAD(struct list_head *list)
+{
+
+ list->next = list->prev = list;
+}
+
+static inline int
+list_empty(const struct list_head *head)
+{
+
+ return (head->next == head);
+}
+
+static inline int
+list_empty_careful(const struct list_head *head)
+{
+ struct list_head *next = head->next;
+
+ return ((next == head) && (next == head->prev));
+}
+
+static inline void
+__list_del(struct list_head *prev, struct list_head *next)
+{
+ next->prev = prev;
+ WRITE_ONCE(prev->next, next);
+}
+
+static inline void
+__list_del_entry(struct list_head *entry)
+{
+
+ __list_del(entry->prev, entry->next);
+}
+
+static inline void
+list_del(struct list_head *entry)
+{
+
+ __list_del(entry->prev, entry->next);
+}
+
+static inline void
+list_replace(struct list_head *old, struct list_head *new)
+{
+ new->next = old->next;
+ new->next->prev = new;
+ new->prev = old->prev;
+ new->prev->next = new;
+}
+
+static inline void
+list_replace_init(struct list_head *old, struct list_head *new)
+{
+ list_replace(old, new);
+ INIT_LIST_HEAD(old);
+}
+
+static inline void
+__list_add(struct list_head *new, struct list_head *prev,
+ struct list_head *next)
+{
+
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+static inline void
+list_del_init(struct list_head *entry)
+{
+
+ list_del(entry);
+ INIT_LIST_HEAD(entry);
+}
+
+#define list_entry(ptr, type, field) container_of(ptr, type, field)
+
+#define list_first_entry(ptr, type, member) \
+ list_entry((ptr)->next, type, member)
+
+#define list_last_entry(ptr, type, member) \
+ list_entry((ptr)->prev, type, member)
+
+#define list_first_entry_or_null(ptr, type, member) \
+ (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)
+
+#define list_next_entry(ptr, member) \
+ list_entry(((ptr)->member.next), typeof(*(ptr)), member)
+
+#define list_safe_reset_next(ptr, n, member) \
+ (n) = list_next_entry(ptr, member)
+
+#define list_prev_entry(ptr, member) \
+ list_entry(((ptr)->member.prev), typeof(*(ptr)), member)
+
+#define list_for_each(p, head) \
+ for (p = (head)->next; p != (head); p = (p)->next)
+
+#define list_for_each_safe(p, n, head) \
+ for (p = (head)->next, n = (p)->next; p != (head); p = n, n = (p)->next)
+
+#define list_for_each_entry(p, h, field) \
+ for (p = list_entry((h)->next, typeof(*p), field); &(p)->field != (h); \
+ p = list_entry((p)->field.next, typeof(*p), field))
+
+#define list_for_each_entry_safe(p, n, h, field) \
+ for (p = list_entry((h)->next, typeof(*p), field), \
+ n = list_entry((p)->field.next, typeof(*p), field); &(p)->field != (h);\
+ p = n, n = list_entry(n->field.next, typeof(*n), field))
+
+#define list_for_each_entry_from(p, h, field) \
+ for ( ; &(p)->field != (h); \
+ p = list_entry((p)->field.next, typeof(*p), field))
+
+#define list_for_each_entry_continue(p, h, field) \
+ for (p = list_next_entry((p), field); &(p)->field != (h); \
+ p = list_next_entry((p), field))
+
+#define list_for_each_entry_safe_from(pos, n, head, member) \
+ for (n = list_entry((pos)->member.next, typeof(*pos), member); \
+ &(pos)->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+#define list_for_each_entry_reverse(p, h, field) \
+ for (p = list_entry((h)->prev, typeof(*p), field); &(p)->field != (h); \
+ p = list_entry((p)->field.prev, typeof(*p), field))
+
+#define list_for_each_entry_safe_reverse(p, n, h, field) \
+ for (p = list_entry((h)->prev, typeof(*p), field), \
+ n = list_entry((p)->field.prev, typeof(*p), field); &(p)->field != (h); \
+ p = n, n = list_entry(n->field.prev, typeof(*n), field))
+
+#define list_for_each_entry_continue_reverse(p, h, field) \
+ for (p = list_entry((p)->field.prev, typeof(*p), field); &(p)->field != (h); \
+ p = list_entry((p)->field.prev, typeof(*p), field))
+
+#define list_for_each_prev(p, h) for (p = (h)->prev; p != (h); p = (p)->prev)
+
+#define list_for_each_prev_safe(p, n, h) \
+ for (p = (h)->prev, n = (p)->prev; \
+ p != (h); \
+ p = n, n = (p)->prev)
+
+#define list_for_each_entry_from_reverse(p, h, field) \
+ for (; &p->field != (h); \
+ p = list_prev_entry(p, field))
+
+#define list_for_each_rcu(p, head) \
+ for (p = rcu_dereference((head)->next); \
+ p != (head); \
+ p = rcu_dereference((p)->next))
+
+static inline void
+list_add(struct list_head *new, struct list_head *head)
+{
+
+ __list_add(new, head, head->next);
+}
+
+static inline void
+list_add_tail(struct list_head *new, struct list_head *head)
+{
+
+ __list_add(new, head->prev, head);
+}
+
+static inline void
+list_move(struct list_head *list, struct list_head *head)
+{
+
+ list_del(list);
+ list_add(list, head);
+}
+
+static inline void
+list_move_tail(struct list_head *entry, struct list_head *head)
+{
+
+ list_del(entry);
+ list_add_tail(entry, head);
+}
+
+static inline void
+list_rotate_to_front(struct list_head *entry, struct list_head *head)
+{
+
+ list_move_tail(entry, head);
+}
+
+static inline void
+list_bulk_move_tail(struct list_head *head, struct list_head *first,
+ struct list_head *last)
+{
+ first->prev->next = last->next;
+ last->next->prev = first->prev;
+ head->prev->next = first;
+ first->prev = head->prev;
+ last->next = head;
+ head->prev = last;
+}
+
+static inline void
+linux_list_splice(const struct list_head *list, struct list_head *prev,
+ struct list_head *next)
+{
+ struct list_head *first;
+ struct list_head *last;
+
+ if (list_empty(list))
+ return;
+ first = list->next;
+ last = list->prev;
+ first->prev = prev;
+ prev->next = first;
+ last->next = next;
+ next->prev = last;
+}
+
+static inline void
+list_splice(const struct list_head *list, struct list_head *head)
+{
+
+ linux_list_splice(list, head, head->next);
+}
+
+static inline void
+list_splice_tail(struct list_head *list, struct list_head *head)
+{
+
+ linux_list_splice(list, head->prev, head);
+}
+
+static inline void
+list_splice_init(struct list_head *list, struct list_head *head)
+{
+
+ linux_list_splice(list, head, head->next);
+ INIT_LIST_HEAD(list);
+}
+
+static inline void
+list_splice_tail_init(struct list_head *list, struct list_head *head)
+{
+
+ linux_list_splice(list, head->prev, head);
+ INIT_LIST_HEAD(list);
+}
+
+#undef LIST_HEAD
+#define LIST_HEAD(name) struct list_head name = { &(name), &(name) }
+
+struct hlist_head {
+ struct hlist_node *first;
+};
+
+struct hlist_node {
+ struct hlist_node *next, **pprev;
+};
+#define HLIST_HEAD_INIT { }
+#define HLIST_HEAD(name) struct hlist_head name = HLIST_HEAD_INIT
+#define INIT_HLIST_HEAD(head) (head)->first = NULL
+#define INIT_HLIST_NODE(node) \
+do { \
+ (node)->next = NULL; \
+ (node)->pprev = NULL; \
+} while (0)
+
+static inline int
+hlist_unhashed(const struct hlist_node *h)
+{
+
+ return !h->pprev;
+}
+
+static inline int
+hlist_empty(const struct hlist_head *h)
+{
+
+ return !READ_ONCE(h->first);
+}
+
+static inline void
+hlist_del(struct hlist_node *n)
+{
+
+ WRITE_ONCE(*(n->pprev), n->next);
+ if (n->next != NULL)
+ n->next->pprev = n->pprev;
+}
+
+static inline void
+hlist_del_init(struct hlist_node *n)
+{
+
+ if (hlist_unhashed(n))
+ return;
+ hlist_del(n);
+ INIT_HLIST_NODE(n);
+}
+
+static inline void
+hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+
+ n->next = h->first;
+ if (h->first != NULL)
+ h->first->pprev = &n->next;
+ WRITE_ONCE(h->first, n);
+ n->pprev = &h->first;
+}
+
+static inline void
+hlist_add_before(struct hlist_node *n, struct hlist_node *next)
+{
+
+ n->pprev = next->pprev;
+ n->next = next;
+ next->pprev = &n->next;
+ WRITE_ONCE(*(n->pprev), n);
+}
+
+static inline void
+hlist_add_behind(struct hlist_node *n, struct hlist_node *prev)
+{
+
+ n->next = prev->next;
+ WRITE_ONCE(prev->next, n);
+ n->pprev = &prev->next;
+
+ if (n->next != NULL)
+ n->next->pprev = &n->next;
+}
+
+static inline void
+hlist_move_list(struct hlist_head *old, struct hlist_head *new)
+{
+
+ new->first = old->first;
+ if (new->first)
+ new->first->pprev = &new->first;
+ old->first = NULL;
+}
+
+static inline int list_is_singular(const struct list_head *head)
+{
+ return !list_empty(head) && (head->next == head->prev);
+}
+
+static inline void __list_cut_position(struct list_head *list,
+ struct list_head *head, struct list_head *entry)
+{
+ struct list_head *new_first = entry->next;
+ list->next = head->next;
+ list->next->prev = list;
+ list->prev = entry;
+ entry->next = list;
+ head->next = new_first;
+ new_first->prev = head;
+}
+
+static inline void list_cut_position(struct list_head *list,
+ struct list_head *head, struct list_head *entry)
+{
+ if (list_empty(head))
+ return;
+ if (list_is_singular(head) &&
+ (head->next != entry && head != entry))
+ return;
+ if (entry == head)
+ INIT_LIST_HEAD(list);
+ else
+ __list_cut_position(list, head, entry);
+}
+
+static inline int list_is_first(const struct list_head *list,
+ const struct list_head *head)
+{
+
+ return (list->prev == head);
+}
+
+static inline int list_is_last(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->next == head;
+}
+
+static inline size_t
+list_count_nodes(const struct list_head *list)
+{
+ const struct list_head *lh;
+ size_t count;
+
+ count = 0;
+ list_for_each(lh, list) {
+ count++;
+ }
+
+ return (count);
+}
+
+#define hlist_entry(ptr, type, field) container_of(ptr, type, field)
+
+#define hlist_for_each(p, head) \
+ for (p = (head)->first; p; p = (p)->next)
+
+#define hlist_for_each_safe(p, n, head) \
+ for (p = (head)->first; p && ({ n = (p)->next; 1; }); p = n)
+
+#define hlist_entry_safe(ptr, type, member) \
+ ((ptr) ? hlist_entry(ptr, type, member) : NULL)
+
+#define hlist_for_each_entry(pos, head, member) \
+ for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
+ pos; \
+ pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+#define hlist_for_each_entry_continue(pos, member) \
+ for (pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member); \
+ (pos); \
+ pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+#define hlist_for_each_entry_from(pos, member) \
+ for (; (pos); \
+ pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+#define hlist_for_each_entry_safe(pos, n, head, member) \
+ for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member); \
+ (pos) && ({ n = (pos)->member.next; 1; }); \
+ pos = hlist_entry_safe(n, typeof(*(pos)), member))
+
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
+extern void list_sort(void *priv, struct list_head *head, int (*cmp)(void *priv,
+ const struct list_head *a, const struct list_head *b));
+#else
+extern void list_sort(void *priv, struct list_head *head, int (*cmp)(void *priv,
+ struct list_head *a, struct list_head *b));
+#endif
+
+#endif /* _LINUXKPI_LINUX_LIST_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/llist.h b/sys/compat/linuxkpi/common/include/linux/llist.h
new file mode 100644
index 000000000000..fd842f05e9eb
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/llist.h
@@ -0,0 +1,101 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_LLIST_H
+#define _LINUXKPI_LINUX_LLIST_H
+
+#include <sys/types.h>
+#include <machine/atomic.h>
+
+struct llist_node {
+ struct llist_node *next;
+};
+
+struct llist_head {
+ struct llist_node *first;
+};
+
+#define LLIST_HEAD_INIT(name) { NULL }
+#define LLIST_HEAD(name) struct llist_head name = LLIST_HEAD_INIT(name)
+
+#define llist_entry(ptr, type, member) \
+ ((ptr) ? container_of(ptr, type, member) : NULL)
+
+static inline struct llist_node *
+llist_del_all(struct llist_head *head)
+{
+ return ((void *)atomic_readandclear_ptr((uintptr_t *)&head->first));
+}
+
+static inline struct llist_node *
+llist_del_first(struct llist_head *head)
+{
+ struct llist_node *first, *next;
+
+ do {
+ first = head->first;
+ if (first == NULL)
+ return NULL;
+ next = first->next;
+ } while (atomic_cmpset_ptr((uintptr_t *)&head->first,
+ (uintptr_t)first, (uintptr_t)next) == 0);
+
+ return (first);
+}
+
+static inline bool
+llist_add(struct llist_node *new, struct llist_head *head)
+{
+ struct llist_node *first;
+
+ do {
+ new->next = first = head->first;
+ } while (atomic_cmpset_ptr((uintptr_t *)&head->first,
+ (uintptr_t)first, (uintptr_t)new) == 0);
+
+ return (first == NULL);
+}
+
+static inline bool
+llist_add_batch(struct llist_node *new_first, struct llist_node *new_last,
+ struct llist_head *head)
+{
+ struct llist_node *first;
+
+ do {
+ new_last->next = first = head->first;
+ } while (atomic_cmpset_ptr((uintptr_t *)&head->first,
+ (uintptr_t)first, (uintptr_t)new_first) == 0);
+
+ return (first == NULL);
+}
+
+static inline void
+init_llist_head(struct llist_head *head)
+{
+ head->first = NULL;
+}
+
+static inline bool
+llist_empty(struct llist_head *head)
+{
+ return (head->first == NULL);
+}
+
+#define llist_for_each_safe(pos, n, node) \
+ for ((pos) = (node); \
+ (pos) != NULL && \
+ ((n) = (pos)->next, pos); \
+ (pos) = (n))
+
+#define llist_for_each_entry_safe(pos, n, node, member) \
+ for (pos = llist_entry((node), __typeof(*pos), member); \
+ pos != NULL && \
+ (n = llist_entry(pos->member.next, __typeof(*pos), member), pos); \
+ pos = n)
+
+#define llist_for_each_entry(pos, node, member) \
+ for ((pos) = llist_entry((node), __typeof(*(pos)), member); \
+ (pos) != NULL; \
+ (pos) = llist_entry((pos)->member.next, __typeof(*(pos)), member))
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/lockdep.h b/sys/compat/linuxkpi/common/include/linux/lockdep.h
new file mode 100644
index 000000000000..93fe445f7057
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/lockdep.h
@@ -0,0 +1,120 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_LOCKDEP_H_
+#define _LINUXKPI_LINUX_LOCKDEP_H_
+
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/lock.h>
+
+struct lock_class_key {
+};
+struct lockdep_map {
+};
+struct pin_cookie {
+};
+
+#define lockdep_set_class(lock, key)
+#define lockdep_set_subclass(lock, sub)
+#define lockdep_set_class_and_name(lock, key, name)
+#define lockdep_set_current_reclaim_state(g) do { } while (0)
+#define lockdep_clear_current_reclaim_state() do { } while (0)
+#define lockdep_init_map(_map, _name, _key, _x) do { } while(0)
+#define lockdep_register_key(key) do { } while(0)
+#define lockdep_unregister_key(key) do { } while(0)
+
+#ifdef INVARIANTS
+#define lockdep_assert(cond) do { WARN_ON(!(cond)); } while (0)
+#define lockdep_assert_once(cond) do { WARN_ON_ONCE(!(cond)); } while (0)
+
+#define lockdep_assert_not_held(m) do { \
+ struct lock_object *__lock = (struct lock_object *)(m); \
+ LOCK_CLASS(__lock)->lc_assert(__lock, LA_UNLOCKED); \
+} while (0)
+
+#define lockdep_assert_held(m) do { \
+ struct lock_object *__lock = (struct lock_object *)(m); \
+ LOCK_CLASS(__lock)->lc_assert(__lock, LA_LOCKED); \
+} while (0)
+
+#define lockdep_assert_held_once(m) do { \
+ struct lock_object *__lock = (struct lock_object *)(m); \
+ LOCK_CLASS(__lock)->lc_assert(__lock, LA_LOCKED | LA_NOTRECURSED); \
+} while (0)
+
+#define lockdep_assert_none_held_once() do { } while (0)
+
+#else
+#define lockdep_assert(cond) do { } while (0)
+#define lockdep_assert_once(cond) do { } while (0)
+
+#define lockdep_assert_not_held(m) do { (void)(m); } while (0)
+#define lockdep_assert_held(m) do { (void)(m); } while (0)
+#define lockdep_assert_none_held_once() do { } while (0)
+
+#define lockdep_assert_held_once(m) do { (void)(m); } while (0)
+
+#endif
+
+static __inline bool
+lockdep_is_held(void *__m __diagused)
+{
+#ifdef INVARIANTS
+ struct lock_object *__lock;
+ struct thread *__td;
+
+ __lock = __m;
+ return (LOCK_CLASS(__lock)->lc_owner(__lock, &__td) != 0);
+#else
+ return (true);
+#endif
+}
+#define lockdep_is_held_type(_m, _t) lockdep_is_held(_m)
+
+#define might_lock(m) do { } while (0)
+#define might_lock_read(m) do { } while (0)
+#define might_lock_nested(m, n) do { } while (0)
+
+#define lock_acquire(...) do { } while (0)
+#define lock_release(...) do { } while (0)
+#define lock_acquire_shared_recursive(...) do { } while (0)
+
+#define mutex_acquire(...) do { } while (0)
+#define mutex_release(...) do { } while (0)
+
+#define lock_map_acquire(_map) do { } while (0)
+#define lock_map_acquire_read(_map) do { } while (0)
+#define lock_map_release(_map) do { } while (0)
+
+#define lockdep_pin_lock(l) ({ struct pin_cookie __pc = { }; __pc; })
+#define lockdep_repin_lock(l,c) do { (void)(l); (void)(c); } while (0)
+#define lockdep_unpin_lock(l,c) do { (void)(l); (void)(c); } while (0)
+
+#endif /* _LINUXKPI_LINUX_LOCKDEP_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/log2.h b/sys/compat/linuxkpi/common/include/linux/log2.h
new file mode 100644
index 000000000000..660e9adb6fa9
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/log2.h
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2015 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_LOG2_H_
+#define _LINUXKPI_LINUX_LOG2_H_
+
+#include <linux/types.h>
+
+#include <sys/libkern.h>
+
+#define is_power_of_2(n) ({ \
+ __typeof(n) _n = (n); \
+ _n != 0 && (_n & (_n - 1)) == 0; \
+})
+
+#endif /* _LINUXKPI_LINUX_LOG2_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/math.h b/sys/compat/linuxkpi/common/include/linux/math.h
new file mode 100644
index 000000000000..5a348a57747b
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/math.h
@@ -0,0 +1,76 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2013-2015 Mellanox Technologies, Ltd.
+ * Copyright (c) 2014-2015 François Tigeot
+ * Copyright (c) 2016 Matt Macy <mmacy@FreeBSD.org>
+ * Copyright (c) 2019 Johannes Lundberg <johalun@FreeBSD.org>
+ * Copyright (c) 2023 Serenity Cyber Security, LLC.
+ *
+ * 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_MATH_H_
+#define _LINUXKPI_LINUX_MATH_H_
+
+#include <linux/types.h>
+
+/*
+ * This looks more complex than it should be. But we need to
+ * get the type for the ~ right in round_down (it needs to be
+ * as wide as the result!), and we want to evaluate the macro
+ * arguments just once each.
+ */
+#define __round_mask(x, y) ((__typeof__(x))((y)-1))
+#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
+#define round_down(x, y) ((x) & ~__round_mask(x, y))
+
+#define DIV_ROUND_UP(x, n) howmany(x, n)
+#define DIV_ROUND_UP_ULL(x, n) DIV_ROUND_UP((unsigned long long)(x), (n))
+#define DIV_ROUND_DOWN_ULL(x, n) ((unsigned long long)(x) / (n))
+
+#define DIV_ROUND_CLOSEST(x, divisor) (((x) + ((divisor) / 2)) / (divisor))
+#define DIV_ROUND_CLOSEST_ULL(x, divisor) ({ \
+ __typeof(divisor) __d = (divisor); \
+ unsigned long long __ret = (x) + (__d) / 2; \
+ __ret /= __d; \
+ __ret; \
+})
+
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 60600
+#define abs_diff(x, y) ({ \
+ __typeof(x) _x = (x); \
+ __typeof(y) _y = (y); \
+ _x > _y ? _x - _y : _y - _x; \
+})
+#endif
+
+static inline uintmax_t
+mult_frac(uintmax_t x, uintmax_t multiplier, uintmax_t divisor)
+{
+ uintmax_t q = (x / divisor);
+ uintmax_t r = (x % divisor);
+
+ return ((q * multiplier) + ((r * multiplier) / divisor));
+}
+
+#endif /* _LINUXKPI_LINUX_MATH_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/math64.h b/sys/compat/linuxkpi/common/include/linux/math64.h
new file mode 100644
index 000000000000..a216d350570f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/math64.h
@@ -0,0 +1,171 @@
+/*-
+ * Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2014-2015 Mellanox Technologies, Ltd. All rights reserved.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_MATH64_H
+#define _LINUXKPI_LINUX_MATH64_H
+
+#include <sys/stdint.h>
+#include <sys/systm.h>
+
+#define do_div(n, base) ({ \
+ uint32_t __base = (base); \
+ uint32_t __rem; \
+ __rem = ((uint64_t)(n)) % __base; \
+ (n) = ((uint64_t)(n)) / __base; \
+ __rem; \
+})
+
+static inline uint64_t
+div64_u64_rem(uint64_t dividend, uint64_t divisor, uint64_t *remainder)
+{
+
+ *remainder = dividend % divisor;
+ return (dividend / divisor);
+}
+
+static inline int64_t
+div64_s64(int64_t dividend, int64_t divisor)
+{
+
+ return (dividend / divisor);
+}
+
+static inline uint64_t
+div64_u64(uint64_t dividend, uint64_t divisor)
+{
+
+ return (dividend / divisor);
+}
+
+#define div64_ul(x, y) div64_u64((x), (y))
+
+static inline uint64_t
+div_u64_rem(uint64_t dividend, uint32_t divisor, uint32_t *remainder)
+{
+
+ *remainder = dividend % divisor;
+ return (dividend / divisor);
+}
+
+static inline int64_t
+div_s64(int64_t dividend, int32_t divisor)
+{
+
+ return (dividend / divisor);
+}
+
+static inline uint64_t
+div_u64(uint64_t dividend, uint32_t divisor)
+{
+
+ return (dividend / divisor);
+}
+
+static inline uint64_t
+mul_u32_u32(uint32_t a, uint32_t b)
+{
+
+ return ((uint64_t)a * b);
+}
+
+static inline uint64_t
+div64_u64_round_up(uint64_t dividend, uint64_t divisor)
+{
+ return ((dividend + divisor - 1) / divisor);
+}
+
+#define DIV64_U64_ROUND_UP(...) \
+ div64_u64_round_up(__VA_ARGS__)
+
+static inline uint64_t
+mul_u64_u32_div(uint64_t x, uint32_t y, uint32_t div)
+{
+ const uint64_t rem = x % div;
+
+ return ((x / div) * y + (rem * y) / div);
+}
+
+static inline uint64_t
+mul_u64_u64_div_u64(uint64_t x, uint64_t y, uint64_t z)
+{
+ uint64_t res, rem;
+ uint64_t x1, y1, y1z;
+
+ res = rem = 0;
+ x1 = x;
+ y1z = y / z;
+ y1 = y - y1z * z;
+
+ /*
+ * INVARIANT: x * y = res * z + rem + (y1 + y1z * z) * x1
+ * INVARIANT: y1 < z
+ * INVARIANT: rem < z
+ */
+ while (x1 > 0) {
+ /* Handle low bit. */
+ if (x1 & 1) {
+ x1 &= ~1;
+ res += y1z;
+ rem += y1;
+ if ((rem < y1) || (rem >= z)) {
+ res += 1;
+ rem -= z;
+ }
+ }
+
+ /* Shift x1 right and (y1 + y1z * z) left */
+ x1 >>= 1;
+ if ((y1 * 2 < y1) || (y1 * 2 >= z)) {
+ y1z = y1z * 2 + 1;
+ y1 = y1 * 2 - z;
+ } else {
+ y1z *= 2;
+ y1 *= 2;
+ }
+ }
+
+ KASSERT(res * z + rem == x * y, ("%s: res %ju * z %ju + rem %ju != "
+ "x %ju * y %ju", __func__, (uintmax_t)res, (uintmax_t)z,
+ (uintmax_t)rem, (uintmax_t)x, (uintmax_t)y));
+ KASSERT(rem < z, ("%s: rem %ju >= z %ju\n", __func__,
+ (uintmax_t)rem, (uintmax_t)z));
+
+ return (res);
+}
+
+static inline uint64_t
+mul_u64_u32_shr(uint64_t x, uint32_t y, unsigned int shift)
+{
+ uint32_t hi, lo;
+ hi = x >> 32;
+ lo = x & 0xffffffff;
+
+ return (mul_u32_u32(lo, y) >> shift) +
+ (mul_u32_u32(hi, y) << (32 - shift));
+}
+
+#endif /* _LINUXKPI_LINUX_MATH64_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/media-bus-format.h b/sys/compat/linuxkpi/common/include/linux/media-bus-format.h
new file mode 100644
index 000000000000..1e1954d45409
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/media-bus-format.h
@@ -0,0 +1,8 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_MEDIA_BUS_FORMAT_H_
+#define _LINUXKPI_LINUX_MEDIA_BUS_FORMAT_H_
+
+#define MEDIA_BUS_FMT_FIXED 1
+
+#endif /* _LINUXKPI_LINUX_MEDIA_BUS_FORMAT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/mhi.h b/sys/compat/linuxkpi/common/include/linux/mhi.h
new file mode 100644
index 000000000000..24b3205d6f5a
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/mhi.h
@@ -0,0 +1,222 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022-2023 Bjoern A. Zeeb
+ *
+ * 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_MHI_H
+#define _LINUXKPI_LINUX_MHI_H
+
+#include <linux/types.h>
+
+/* Modem Host Interface (MHI) */
+
+/* XXX FIXME */
+#define MHI_DB_BRST_DISABLE 0
+#define MHI_ER_CTRL 0
+
+enum mhi_callback {
+ MHI_CB_SYS_ERROR,
+ MHI_CB_BW_REQ,
+ MHI_CB_EE_MISSION_MODE,
+ MHI_CB_EE_RDDM,
+ MHI_CB_FATAL_ERROR,
+ MHI_CB_IDLE,
+ MHI_CB_LPM_ENTER,
+ MHI_CB_LPM_EXIT,
+ MHI_CB_PENDING_DATA,
+};
+
+struct mhi_channel_config {
+ const char *name;
+ int auto_queue, dir, doorbell, doorbell_mode_switch, ee_mask, event_ring, lpm_notify, num, num_elements, offload_channel, pollcfg;
+};
+
+struct mhi_event_config {
+ int client_managed, data_type, hardware_event, irq, irq_moderation_ms, mode, num_elements, offload_channel, priority;
+};
+
+struct mhi_device {
+};
+
+struct mhi_controller_config {
+ const struct mhi_channel_config *ch_cfg;
+ struct mhi_event_config *event_cfg;
+
+ int buf_len, max_channels, num_channels, num_events, use_bounce_buf;
+
+ uint32_t timeout_ms;
+};
+
+struct mhi_controller {
+ struct device *cntrl_dev;
+ struct mhi_device *mhi_dev;
+ void *regs;
+ int *irq;
+ const char *fw_image;
+ const u8 *fw_data;
+ size_t fw_sz;
+
+ bool fbc_download;
+ size_t rddm_size;
+ size_t sbl_size;
+ size_t seg_len;
+ size_t reg_len;
+ int nr_irqs;
+ unsigned long irq_flags;
+ uint32_t timeout_ms;
+
+ dma_addr_t iova_start;
+ dma_addr_t iova_stop;
+
+ int (*runtime_get)(struct mhi_controller *);
+ void (*runtime_put)(struct mhi_controller *);
+ void (*status_cb)(struct mhi_controller *, enum mhi_callback);
+ int (*read_reg)(struct mhi_controller *, void __iomem *, uint32_t *);
+ void (*write_reg)(struct mhi_controller *, void __iomem *, uint32_t);
+};
+
+/* -------------------------------------------------------------------------- */
+
+struct mhi_controller *linuxkpi_mhi_alloc_controller(void);
+void linuxkpi_mhi_free_controller(struct mhi_controller *);
+int linuxkpi_mhi_register_controller(struct mhi_controller *,
+ const struct mhi_controller_config *);
+void linuxkpi_mhi_unregister_controller(struct mhi_controller *);
+
+/* -------------------------------------------------------------------------- */
+
+static inline struct mhi_controller *
+mhi_alloc_controller(void)
+{
+
+ /* Keep allocations internal to our implementation. */
+ return (linuxkpi_mhi_alloc_controller());
+}
+
+static inline void
+mhi_free_controller(struct mhi_controller *mhi_ctrl)
+{
+
+ linuxkpi_mhi_free_controller(mhi_ctrl);
+}
+
+static inline int
+mhi_register_controller(struct mhi_controller *mhi_ctrl,
+ const struct mhi_controller_config *cfg)
+{
+
+ return (linuxkpi_mhi_register_controller(mhi_ctrl, cfg));
+}
+
+static inline void
+mhi_unregister_controller(struct mhi_controller *mhi_ctrl)
+{
+
+ linuxkpi_mhi_unregister_controller(mhi_ctrl);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static __inline int
+mhi_device_get_sync(struct mhi_device *mhi_dev)
+{
+ /* XXX TODO */
+ return (-1);
+}
+
+static __inline void
+mhi_device_put(struct mhi_device *mhi_dev)
+{
+ /* XXX TODO */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static __inline int
+mhi_prepare_for_power_up(struct mhi_controller *mhi_ctrl)
+{
+ /* XXX TODO */
+ return (0);
+}
+
+static __inline int
+mhi_sync_power_up(struct mhi_controller *mhi_ctrl)
+{
+ /* XXX TODO */
+ return (0);
+}
+
+static __inline int
+mhi_async_power_up(struct mhi_controller *mhi_ctrl)
+{
+ /* XXX TODO */
+ return (0);
+}
+
+static __inline void
+mhi_power_down(struct mhi_controller *mhi_ctrl, bool x)
+{
+ /* XXX TODO */
+}
+
+static __inline void
+mhi_unprepare_after_power_down(struct mhi_controller *mhi_ctrl)
+{
+ /* XXX TODO */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static __inline int
+mhi_pm_suspend(struct mhi_controller *mhi_ctrl)
+{
+ /* XXX TODO */
+ return (0);
+}
+
+static __inline int
+mhi_pm_resume(struct mhi_controller *mhi_ctrl)
+{
+ /* XXX TODO */
+ return (0);
+}
+
+static __inline int
+mhi_pm_resume_force(struct mhi_controller *mhi_ctrl)
+{
+ /* XXX TODO */
+ return (0);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static __inline int
+mhi_force_rddm_mode(struct mhi_controller *mhi_ctrl)
+{
+ /* XXX TODO */
+ return (0);
+}
+
+#endif /* _LINUXKPI_LINUX_MHI_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/minmax.h b/sys/compat/linuxkpi/common/include/linux/minmax.h
new file mode 100644
index 000000000000..d48958f0899f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/minmax.h
@@ -0,0 +1,74 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2015 Mellanox Technologies, Ltd.
+ * Copyright (c) 2014-2015 François Tigeot
+ * Copyright (c) 2015 Hans Petter Selasky <hselasky@FreeBSD.org>
+ * Copyright (c) 2016 Matt Macy <mmacy@FreeBSD.org>
+ * Copyright (c) 2023 Serenity Cyber Security, LLC.
+ *
+ * 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_MINMAX_H_
+#define _LINUXKPI_LINUX_MINMAX_H_
+
+#include <linux/build_bug.h>
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+#define min(x, y) ((x) < (y) ? (x) : (y))
+#define max(x, y) ((x) > (y) ? (x) : (y))
+
+#define min3(a, b, c) min(a, min(b, c))
+#define max3(a, b, c) max(a, max(b, c))
+
+#define min_not_zero(x, y) ({ \
+ __typeof(x) __min1 = (x); \
+ __typeof(y) __min2 = (y); \
+ __min1 == 0 ? __min2 : ((__min2 == 0) ? __min1 : min(__min1, __min2));\
+})
+
+#define min_t(type, x, y) ({ \
+ type __min1 = (x); \
+ type __min2 = (y); \
+ __min1 < __min2 ? __min1 : __min2; })
+
+#define max_t(type, x, y) ({ \
+ type __max1 = (x); \
+ type __max2 = (y); \
+ __max1 > __max2 ? __max1 : __max2; })
+
+#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)
+
+/* Swap values of a and b */
+#define swap(a, b) do { \
+ __typeof(a) _swap_tmp = a; \
+ a = b; \
+ b = _swap_tmp; \
+} while (0)
+
+#endif /* _LINUXKPI_LINUX_MINMAX_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/miscdevice.h b/sys/compat/linuxkpi/common/include/linux/miscdevice.h
new file mode 100644
index 000000000000..c66006a6b78e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/miscdevice.h
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_MISCDEVICE_H_
+#define _LINUXKPI_LINUX_MISCDEVICE_H_
+
+#define MISC_DYNAMIC_MINOR -1
+
+#include <linux/device.h>
+#include <linux/cdev.h>
+
+struct miscdevice {
+ const char *name;
+ struct device *this_device;
+ const struct file_operations *fops;
+ struct cdev *cdev;
+ int minor;
+ const char *nodename;
+ umode_t mode;
+};
+
+extern struct class linux_class_misc;
+
+static inline int
+misc_register(struct miscdevice *misc)
+{
+ misc->this_device = device_create(&linux_class_misc,
+ &linux_root_device, 0, misc, misc->name);
+ misc->cdev = cdev_alloc();
+ if (misc->cdev == NULL)
+ return -ENOMEM;
+ misc->cdev->owner = THIS_MODULE;
+ misc->cdev->ops = misc->fops;
+ kobject_set_name(&misc->cdev->kobj, misc->name);
+ if (cdev_add(misc->cdev, misc->this_device->devt, 1))
+ return -EINVAL;
+ return (0);
+}
+
+static inline int
+misc_deregister(struct miscdevice *misc)
+{
+ device_destroy(&linux_class_misc, misc->this_device->devt);
+ cdev_del(misc->cdev);
+
+ return (0);
+}
+
+#endif /* _LINUXKPI_LINUX_MISCDEVICE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/mm.h b/sys/compat/linuxkpi/common/include/linux/mm.h
new file mode 100644
index 000000000000..156b00a0c0f0
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/mm.h
@@ -0,0 +1,479 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * Copyright (c) 2015 François Tigeot
+ * Copyright (c) 2015 Matthew Dillon <dillon@backplane.com>
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_MM_H_
+#define _LINUXKPI_LINUX_MM_H_
+
+#include <linux/spinlock.h>
+#include <linux/gfp.h>
+#include <linux/kernel.h>
+#include <linux/mm_types.h>
+#include <linux/mmzone.h>
+#include <linux/pfn.h>
+#include <linux/list.h>
+#include <linux/mmap_lock.h>
+#include <linux/overflow.h>
+#include <linux/shrinker.h>
+#include <linux/page.h>
+
+#include <asm/pgtable.h>
+
+#define PAGE_ALIGN(x) ALIGN(x, PAGE_SIZE)
+
+/*
+ * Make sure our LinuxKPI defined virtual memory flags don't conflict
+ * with the ones defined by FreeBSD:
+ */
+CTASSERT((VM_PROT_ALL & -(1 << 8)) == 0);
+
+#define VM_READ VM_PROT_READ
+#define VM_WRITE VM_PROT_WRITE
+#define VM_EXEC VM_PROT_EXECUTE
+
+#define VM_ACCESS_FLAGS (VM_READ | VM_WRITE | VM_EXEC)
+
+#define VM_PFNINTERNAL (1 << 8) /* FreeBSD private flag to vm_insert_pfn() */
+#define VM_MIXEDMAP (1 << 9)
+#define VM_NORESERVE (1 << 10)
+#define VM_PFNMAP (1 << 11)
+#define VM_IO (1 << 12)
+#define VM_MAYWRITE (1 << 13)
+#define VM_DONTCOPY (1 << 14)
+#define VM_DONTEXPAND (1 << 15)
+#define VM_DONTDUMP (1 << 16)
+#define VM_SHARED (1 << 17)
+
+#define VMA_MAX_PREFAULT_RECORD 1
+
+#define FOLL_WRITE (1 << 0)
+#define FOLL_FORCE (1 << 1)
+
+#define VM_FAULT_OOM (1 << 0)
+#define VM_FAULT_SIGBUS (1 << 1)
+#define VM_FAULT_MAJOR (1 << 2)
+#define VM_FAULT_WRITE (1 << 3)
+#define VM_FAULT_HWPOISON (1 << 4)
+#define VM_FAULT_HWPOISON_LARGE (1 << 5)
+#define VM_FAULT_SIGSEGV (1 << 6)
+#define VM_FAULT_NOPAGE (1 << 7)
+#define VM_FAULT_LOCKED (1 << 8)
+#define VM_FAULT_RETRY (1 << 9)
+#define VM_FAULT_FALLBACK (1 << 10)
+
+#define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | \
+ VM_FAULT_HWPOISON |VM_FAULT_HWPOISON_LARGE | VM_FAULT_FALLBACK)
+
+#define FAULT_FLAG_WRITE (1 << 0)
+#define FAULT_FLAG_MKWRITE (1 << 1)
+#define FAULT_FLAG_ALLOW_RETRY (1 << 2)
+#define FAULT_FLAG_RETRY_NOWAIT (1 << 3)
+#define FAULT_FLAG_KILLABLE (1 << 4)
+#define FAULT_FLAG_TRIED (1 << 5)
+#define FAULT_FLAG_USER (1 << 6)
+#define FAULT_FLAG_REMOTE (1 << 7)
+#define FAULT_FLAG_INSTRUCTION (1 << 8)
+
+#define fault_flag_allow_retry_first(flags) \
+ (((flags) & (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_TRIED)) == FAULT_FLAG_ALLOW_RETRY)
+
+typedef int (*pte_fn_t)(linux_pte_t *, unsigned long addr, void *data);
+
+struct vm_area_struct {
+ vm_offset_t vm_start;
+ vm_offset_t vm_end;
+ vm_offset_t vm_pgoff;
+ pgprot_t vm_page_prot;
+ unsigned long vm_flags;
+ struct mm_struct *vm_mm;
+ void *vm_private_data;
+ const struct vm_operations_struct *vm_ops;
+ struct linux_file *vm_file;
+
+ /* internal operation */
+ vm_paddr_t vm_pfn; /* PFN for memory map */
+ vm_size_t vm_len; /* length for memory map */
+ vm_pindex_t vm_pfn_first;
+ int vm_pfn_count;
+ int *vm_pfn_pcount;
+ vm_object_t vm_obj;
+ vm_map_t vm_cached_map;
+ TAILQ_ENTRY(vm_area_struct) vm_entry;
+};
+
+struct vm_fault {
+ unsigned int flags;
+ pgoff_t pgoff;
+ union {
+ /* user-space address */
+ void *virtual_address; /* < 4.11 */
+ unsigned long address; /* >= 4.11 */
+ };
+ struct page *page;
+ struct vm_area_struct *vma;
+};
+
+struct vm_operations_struct {
+ void (*open) (struct vm_area_struct *);
+ void (*close) (struct vm_area_struct *);
+ int (*fault) (struct vm_fault *);
+ int (*access) (struct vm_area_struct *, unsigned long, void *, int, int);
+};
+
+struct sysinfo {
+ uint64_t totalram; /* Total usable main memory size */
+ uint64_t freeram; /* Available memory size */
+ uint64_t totalhigh; /* Total high memory size */
+ uint64_t freehigh; /* Available high memory size */
+ uint32_t mem_unit; /* Memory unit size in bytes */
+};
+
+static inline struct page *
+virt_to_head_page(const void *p)
+{
+
+ return (virt_to_page(p));
+}
+
+static inline struct folio *
+virt_to_folio(const void *p)
+{
+ struct page *page = virt_to_page(p);
+
+ return (page_folio(page));
+}
+
+/*
+ * Compute log2 of the power of two rounded up count of pages
+ * needed for size bytes.
+ */
+static inline int
+get_order(unsigned long size)
+{
+ int order;
+
+ size = (size - 1) >> PAGE_SHIFT;
+ order = 0;
+ while (size) {
+ order++;
+ size >>= 1;
+ }
+ return (order);
+}
+
+/*
+ * Resolve a page into a virtual address:
+ *
+ * NOTE: This function only works for pages allocated by the kernel.
+ */
+void *linux_page_address(const struct page *);
+#define page_address(page) linux_page_address(page)
+
+static inline void *
+lowmem_page_address(struct page *page)
+{
+ return (page_address(page));
+}
+
+/*
+ * This only works via memory map operations.
+ */
+static inline int
+io_remap_pfn_range(struct vm_area_struct *vma,
+ unsigned long addr, unsigned long pfn, unsigned long size,
+ vm_memattr_t prot)
+{
+ vma->vm_page_prot = prot;
+ vma->vm_pfn = pfn;
+ vma->vm_len = size;
+
+ return (0);
+}
+
+vm_fault_t
+lkpi_vmf_insert_pfn_prot_locked(struct vm_area_struct *vma, unsigned long addr,
+ unsigned long pfn, pgprot_t prot);
+
+static inline vm_fault_t
+vmf_insert_pfn_prot(struct vm_area_struct *vma, unsigned long addr,
+ unsigned long pfn, pgprot_t prot)
+{
+ vm_fault_t ret;
+
+ VM_OBJECT_WLOCK(vma->vm_obj);
+ ret = lkpi_vmf_insert_pfn_prot_locked(vma, addr, pfn, prot);
+ VM_OBJECT_WUNLOCK(vma->vm_obj);
+
+ return (ret);
+}
+#define vmf_insert_pfn_prot(...) \
+ _Static_assert(false, \
+"This function is always called in a loop. Consider using the locked version")
+
+static inline int
+apply_to_page_range(struct mm_struct *mm, unsigned long address,
+ unsigned long size, pte_fn_t fn, void *data)
+{
+ return (-ENOTSUP);
+}
+
+int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address,
+ unsigned long size);
+
+int lkpi_remap_pfn_range(struct vm_area_struct *vma,
+ unsigned long start_addr, unsigned long start_pfn, unsigned long size,
+ pgprot_t prot);
+
+static inline int
+remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
+ unsigned long pfn, unsigned long size, pgprot_t prot)
+{
+ return (lkpi_remap_pfn_range(vma, addr, pfn, size, prot));
+}
+
+static inline unsigned long
+vma_pages(struct vm_area_struct *vma)
+{
+ return ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT);
+}
+
+#define offset_in_page(off) ((unsigned long)(off) & (PAGE_SIZE - 1))
+
+static inline void
+set_page_dirty(struct page *page)
+{
+ vm_page_dirty(page);
+}
+
+static inline void
+mark_page_accessed(struct page *page)
+{
+ vm_page_reference(page);
+}
+
+static inline void
+get_page(struct page *page)
+{
+ vm_page_wire(page);
+}
+
+static inline void
+put_page(struct page *page)
+{
+ /* `__free_page()` takes care of the refcounting (unwire). */
+ __free_page(page);
+}
+
+static inline void
+folio_get(struct folio *folio)
+{
+ get_page(&folio->page);
+}
+
+static inline void
+folio_put(struct folio *folio)
+{
+ put_page(&folio->page);
+}
+
+/*
+ * Linux uses the following "transparent" union so that `release_pages()`
+ * accepts both a list of `struct page` or a list of `struct folio`. This
+ * relies on the fact that a `struct folio` can be cast to a `struct page`.
+ */
+typedef union {
+ struct page **pages;
+ struct folio **folios;
+} release_pages_arg __attribute__ ((__transparent_union__));
+
+void linux_release_pages(release_pages_arg arg, int nr);
+#define release_pages(arg, nr) linux_release_pages((arg), (nr))
+
+extern long
+lkpi_get_user_pages(unsigned long start, unsigned long nr_pages,
+ unsigned int gup_flags, struct page **);
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 60500
+#define get_user_pages(start, nr_pages, gup_flags, pages) \
+ lkpi_get_user_pages(start, nr_pages, gup_flags, pages)
+#else
+#define get_user_pages(start, nr_pages, gup_flags, pages, vmas) \
+ lkpi_get_user_pages(start, nr_pages, gup_flags, pages)
+#endif
+
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 60500
+static inline long
+pin_user_pages(unsigned long start, unsigned long nr_pages,
+ unsigned int gup_flags, struct page **pages)
+{
+ return (get_user_pages(start, nr_pages, gup_flags, pages));
+}
+#else
+static inline long
+pin_user_pages(unsigned long start, unsigned long nr_pages,
+ unsigned int gup_flags, struct page **pages,
+ struct vm_area_struct **vmas)
+{
+ return (get_user_pages(start, nr_pages, gup_flags, pages, vmas));
+}
+#endif
+
+extern int
+__get_user_pages_fast(unsigned long start, int nr_pages, int write,
+ struct page **);
+
+static inline int
+pin_user_pages_fast(unsigned long start, int nr_pages,
+ unsigned int gup_flags, struct page **pages)
+{
+ return __get_user_pages_fast(
+ start, nr_pages, !!(gup_flags & FOLL_WRITE), pages);
+}
+
+extern long
+get_user_pages_remote(struct task_struct *, struct mm_struct *,
+ unsigned long start, unsigned long nr_pages,
+ unsigned int gup_flags, struct page **,
+ struct vm_area_struct **);
+
+static inline long
+pin_user_pages_remote(struct task_struct *task, struct mm_struct *mm,
+ unsigned long start, unsigned long nr_pages,
+ unsigned int gup_flags, struct page **pages,
+ struct vm_area_struct **vmas)
+{
+ return get_user_pages_remote(
+ task, mm, start, nr_pages, gup_flags, pages, vmas);
+}
+
+#define unpin_user_page(page) put_page(page)
+#define unpin_user_pages(pages, npages) release_pages(pages, npages)
+
+#define copy_highpage(to, from) pmap_copy_page(from, to)
+
+static inline pgprot_t
+vm_get_page_prot(unsigned long vm_flags)
+{
+ return (vm_flags & VM_PROT_ALL);
+}
+
+static inline void
+vm_flags_set(struct vm_area_struct *vma, unsigned long flags)
+{
+ vma->vm_flags |= flags;
+}
+
+static inline void
+vm_flags_clear(struct vm_area_struct *vma, unsigned long flags)
+{
+ vma->vm_flags &= ~flags;
+}
+
+static inline struct page *
+vmalloc_to_page(const void *addr)
+{
+ vm_paddr_t paddr;
+
+ paddr = pmap_kextract((vm_offset_t)addr);
+ return (PHYS_TO_VM_PAGE(paddr));
+}
+
+static inline int
+trylock_page(struct page *page)
+{
+ return (vm_page_tryxbusy(page));
+}
+
+static inline void
+unlock_page(struct page *page)
+{
+
+ vm_page_xunbusy(page);
+}
+
+extern int is_vmalloc_addr(const void *addr);
+void si_meminfo(struct sysinfo *si);
+
+static inline unsigned long
+totalram_pages(void)
+{
+ return ((unsigned long)physmem);
+}
+
+#define unmap_mapping_range(...) lkpi_unmap_mapping_range(__VA_ARGS__)
+void lkpi_unmap_mapping_range(void *obj, loff_t const holebegin __unused,
+ loff_t const holelen, int even_cows __unused);
+
+#define PAGE_ALIGNED(p) __is_aligned(p, PAGE_SIZE)
+
+void vma_set_file(struct vm_area_struct *vma, struct linux_file *file);
+
+static inline void
+might_alloc(gfp_t gfp_mask __unused)
+{
+}
+
+#define is_cow_mapping(flags) (false)
+
+static inline bool
+want_init_on_free(void)
+{
+ return (false);
+}
+
+static inline unsigned long
+folio_pfn(struct folio *folio)
+{
+ return (page_to_pfn(&folio->page));
+}
+
+static inline long
+folio_nr_pages(struct folio *folio)
+{
+ return (1);
+}
+
+static inline size_t
+folio_size(struct folio *folio)
+{
+ return (PAGE_SIZE);
+}
+
+static inline void
+folio_mark_dirty(struct folio *folio)
+{
+ set_page_dirty(&folio->page);
+}
+
+static inline void *
+folio_address(const struct folio *folio)
+{
+ return (page_address(&folio->page));
+}
+
+#endif /* _LINUXKPI_LINUX_MM_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/mm_types.h b/sys/compat/linuxkpi/common/include/linux/mm_types.h
new file mode 100644
index 000000000000..3ea68e97004c
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/mm_types.h
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_MM_TYPES_H_
+#define _LINUXKPI_LINUX_MM_TYPES_H_
+
+#include <linux/types.h>
+#include <linux/page.h>
+#include <linux/rbtree.h>
+#include <linux/rwsem.h>
+
+#include <asm/atomic.h>
+
+typedef int vm_fault_t;
+
+struct vm_area_struct;
+struct task_struct;
+
+struct mm_struct {
+ struct vm_area_struct *mmap;
+ atomic_t mm_count;
+ atomic_t mm_users;
+ size_t pinned_vm;
+ /* Renamed to mmap_lock in v5.8 */
+ struct rw_semaphore mmap_sem;
+};
+
+extern void linux_mm_dtor(struct mm_struct *mm);
+
+static inline void
+mmdrop(struct mm_struct *mm)
+{
+ if (__predict_false(atomic_dec_and_test(&mm->mm_count)))
+ linux_mm_dtor(mm);
+}
+
+static inline bool
+mmget_not_zero(struct mm_struct *mm)
+{
+ return (atomic_inc_not_zero(&mm->mm_users));
+}
+
+static inline void
+mmput(struct mm_struct *mm)
+{
+ if (__predict_false(atomic_dec_and_test(&mm->mm_users)))
+ mmdrop(mm);
+}
+
+static inline void
+mmgrab(struct mm_struct *mm)
+{
+ atomic_inc(&mm->mm_count);
+}
+
+extern struct mm_struct *linux_get_task_mm(struct task_struct *);
+#define get_task_mm(task) linux_get_task_mm(task)
+
+struct folio {
+ /*
+ * The page member must be at the beginning because `page_folio(p)`
+ * casts from a `struct page` to a `struct folio`.
+ *
+ * `release_pages()` also relies on this to be able to accept either a
+ * list of `struct page` or a list of `struct folio`.
+ */
+ struct page page;
+};
+
+#endif /* _LINUXKPI_LINUX_MM_TYPES_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/mman.h b/sys/compat/linuxkpi/common/include/linux/mman.h
new file mode 100644
index 000000000000..eff80759b4cd
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/mman.h
@@ -0,0 +1,38 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
+ *
+ * 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 _LINUX_MMAN_H
+#define _LINUX_MMAN_H
+
+/*
+ * In Linux, <linux/mman.h> includes <linux/percpu_counter.h>, which includes
+ * <linux/smp.h>.
+ */
+#include <linux/smp.h>
+
+#endif /* _LINUX_MMAN_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/mmap_lock.h b/sys/compat/linuxkpi/common/include/linux/mmap_lock.h
new file mode 100644
index 000000000000..de6b2a029b1f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/mmap_lock.h
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2022 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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_MMAP_LOCK_H_
+#define _LINUXKPI_LINUX_MMAP_LOCK_H_
+
+#include <linux/mm_types.h>
+#include <linux/rwsem.h>
+
+static inline void
+mmap_read_lock(struct mm_struct *mm)
+{
+
+ down_read(&mm->mmap_sem);
+}
+
+static inline void
+mmap_read_unlock(struct mm_struct *mm)
+{
+
+ up_read(&mm->mmap_sem);
+}
+
+static inline void
+mmap_write_lock_killable(struct mm_struct *mm)
+{
+
+ down_write_killable(&mm->mmap_sem);
+}
+
+#endif /* _LINUXKPI_LINUX_MMAP_LOCK_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/mmu_context.h b/sys/compat/linuxkpi/common/include/linux/mmu_context.h
new file mode 100644
index 000000000000..4c1bc61b3edb
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/mmu_context.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2018 Johannes Lundberg <johalun0@gmail.com>
+ *
+ * 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 unmodified, 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 ``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 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_MMU_CONTEXT_H_
+#define _LINUXKPI_LINUX_MMU_CONTEXT_H_
+
+struct mm_struct;
+
+static inline void
+use_mm(struct mm_struct *mm)
+{
+ /* NOP is deliberate */
+}
+
+static inline void
+unuse_mm(struct mm_struct *mm)
+{
+ /* NOP is deliberate */
+}
+
+#endif /* _LINUXKPI_LINUX_MMU_CONTEXT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/mmu_notifier.h b/sys/compat/linuxkpi/common/include/linux/mmu_notifier.h
new file mode 100644
index 000000000000..2492a6a3bd4f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/mmu_notifier.h
@@ -0,0 +1,33 @@
+/*-
+ * Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_MMU_NOTIFIER_H_
+#define _LINUXKPI_LINUX_MMU_NOTIFIER_H_
+
+struct mmu_notifier {
+};
+
+#endif /* _LINUXKPI_LINUX_MMU_NOTIFIER_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/mmzone.h b/sys/compat/linuxkpi/common/include/linux/mmzone.h
new file mode 100644
index 000000000000..57d3dcac9597
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/mmzone.h
@@ -0,0 +1,15 @@
+/* Public domain. */
+
+#ifndef _LINUX_MMZONE_H
+#define _LINUX_MMZONE_H
+
+#include <linux/mm_types.h>
+#include <linux/numa.h>
+#include <linux/page-flags.h>
+
+#define MAX_ORDER 11
+
+#define MAX_PAGE_ORDER 10
+#define NR_PAGE_ORDERS (MAX_PAGE_ORDER + 1)
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/mod_devicetable.h b/sys/compat/linuxkpi/common/include/linux/mod_devicetable.h
new file mode 100644
index 000000000000..87bd6ec24bce
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/mod_devicetable.h
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot 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_MOD_DEVICETABLE_H__
+#define __LINUXKPI_LINUX_MOD_DEVICETABLE_H__
+
+#include <linux/types.h>
+
+enum dmi_field {
+ DMI_NONE,
+ DMI_BIOS_VENDOR,
+ DMI_BIOS_VERSION,
+ DMI_BIOS_DATE,
+ DMI_BIOS_RELEASE,
+ DMI_EC_FIRMWARE_RELEASE,
+ DMI_SYS_VENDOR,
+ DMI_PRODUCT_NAME,
+ DMI_PRODUCT_VERSION,
+ DMI_PRODUCT_SERIAL,
+ DMI_PRODUCT_UUID,
+ DMI_PRODUCT_SKU,
+ DMI_PRODUCT_FAMILY,
+ DMI_BOARD_VENDOR,
+ DMI_BOARD_NAME,
+ DMI_BOARD_VERSION,
+ DMI_BOARD_SERIAL,
+ DMI_BOARD_ASSET_TAG,
+ DMI_CHASSIS_VENDOR,
+ DMI_CHASSIS_TYPE,
+ DMI_CHASSIS_VERSION,
+ DMI_CHASSIS_SERIAL,
+ DMI_CHASSIS_ASSET_TAG,
+ DMI_STRING_MAX,
+ DMI_OEM_STRING,
+};
+
+struct dmi_strmatch {
+ unsigned char slot : 7;
+ unsigned char exact_match : 1;
+ char substr[79];
+};
+
+struct dmi_system_id {
+ int (*callback)(const struct dmi_system_id *);
+ const char *ident;
+ struct dmi_strmatch matches[4];
+ void *driver_data;
+};
+
+#define DMI_MATCH(a, b) { .slot = a, .substr = b }
+#define DMI_EXACT_MATCH(a, b) { .slot = a, .substr = b, .exact_match = 1 }
+
+#define I2C_NAME_SIZE 20
+#define I2C_MODULE_PREFIX "i2c:"
+
+#define ACPI_ID_LEN 16
+
+#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
new file mode 100644
index 000000000000..079dacf8df6c
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/module.h
@@ -0,0 +1,127 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_MODULE_H_
+#define _LINUXKPI_LINUX_MODULE_H_
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/queue.h>
+#include <sys/linker.h>
+
+#include <linux/list.h>
+#include <linux/compiler.h>
+#include <linux/stringify.h>
+#include <linux/kmod.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+
+#define MODULE_AUTHOR(name)
+#define MODULE_DESCRIPTION(name)
+#define MODULE_LICENSE(name)
+#define MODULE_INFO(tag, info)
+#define MODULE_FIRMWARE(firmware)
+#define MODULE_SUPPORTED_DEVICE(name)
+#define MODULE_IMPORT_NS(_name)
+
+/*
+ * THIS_MODULE is used to differentiate modules on Linux. We currently
+ * completely stub out any Linux struct module usage, but THIS_MODULE is still
+ * used to populate the "owner" fields of various drivers. Even though we
+ * don't actually dereference these "owner" fields they are still used by
+ * drivers to check if devices/dmabufs/etc come from different modules. For
+ * example, during DRM GEM import some drivers check if the dmabuf's owner
+ * matches the dev's owner. If they match because they are both NULL drivers
+ * may incorrectly think two resources come from the same module.
+ *
+ * To handle this we specify an undefined symbol __this_linker_file, which
+ * will get special treatment from the linker when resolving. This will
+ * populate the usages of __this_linker_file with the linker_file_t of the
+ * module.
+ */
+#ifdef KLD_MODULE
+#define THIS_MODULE ((struct module *)&__this_linker_file)
+#else
+#define THIS_MODULE ((struct module *)0)
+#endif
+
+#define __MODULE_STRING(x) __stringify(x)
+
+/* OFED pre-module initialization */
+#define SI_SUB_OFED_PREINIT (SI_SUB_ROOT_CONF - 2)
+/* OFED default module initialization */
+#define SI_SUB_OFED_MODINIT (SI_SUB_ROOT_CONF - 1)
+
+#include <sys/linker.h>
+
+static inline void
+_module_run(void *arg)
+{
+ void (*fn)(void);
+#ifdef OFED_DEBUG_INIT
+ char name[1024];
+ caddr_t pc;
+ long offset;
+
+ pc = (caddr_t)arg;
+ if (linker_search_symbol_name(pc, name, sizeof(name), &offset) != 0)
+ printf("Running ??? (%p)\n", pc);
+ else
+ printf("Running %s (%p)\n", name, pc);
+#endif
+ fn = arg;
+ fn();
+}
+
+#define module_init(fn) \
+ SYSINIT(fn, SI_SUB_OFED_MODINIT, SI_ORDER_FIRST, _module_run, (fn))
+
+#define module_exit(fn) \
+ SYSUNINIT(fn, SI_SUB_OFED_MODINIT, SI_ORDER_SECOND, _module_run, (fn))
+
+/*
+ * The following two macros are a workaround for not having a module
+ * load and unload order resolver:
+ */
+#define module_init_order(fn, order) \
+ SYSINIT(fn, SI_SUB_OFED_MODINIT, (order), _module_run, (fn))
+
+#define module_exit_order(fn, order) \
+ SYSUNINIT(fn, SI_SUB_OFED_MODINIT, (order), _module_run, (fn))
+
+#define module_get(module)
+#define module_put(module)
+#define try_module_get(module) 1
+
+#define postcore_initcall(fn) module_init(fn)
+
+#endif /* _LINUXKPI_LINUX_MODULE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/moduleparam.h b/sys/compat/linuxkpi/common/include/linux/moduleparam.h
new file mode 100644
index 000000000000..b61bbce495ea
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/moduleparam.h
@@ -0,0 +1,146 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_MODULEPARAM_H_
+#define _LINUXKPI_LINUX_MODULEPARAM_H_
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <linux/types.h>
+
+#ifndef LINUXKPI_PARAM_PARENT
+#define LINUXKPI_PARAM_PARENT _compat_linuxkpi
+#endif
+
+#ifndef LINUXKPI_PARAM_PREFIX
+#define LINUXKPI_PARAM_PREFIX /* empty prefix is the default */
+#endif
+
+#ifndef LINUXKPI_PARAM_PERM
+#define LINUXKPI_PARAM_PERM(perm) (((perm) & 0222) ? CTLFLAG_RWTUN : CTLFLAG_RDTUN)
+#endif
+
+#define LINUXKPI_PARAM_CONCAT_SUB(a,b,c,d) a##b##c##d
+#define LINUXKPI_PARAM_CONCAT(...) LINUXKPI_PARAM_CONCAT_SUB(__VA_ARGS__)
+#define LINUXKPI_PARAM_PASS(...) __VA_ARGS__
+#define LINUXKPI_PARAM_DESC(name) LINUXKPI_PARAM_CONCAT(linuxkpi_,LINUXKPI_PARAM_PREFIX,name,_desc)
+#define LINUXKPI_PARAM_NAME(name) LINUXKPI_PARAM_CONCAT(LINUXKPI_PARAM_PREFIX,name,,)
+
+#define LINUXKPI_PARAM_bool(name, var, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_BOOL(LINUXKPI_PARAM_PARENT, OID_AUTO,\
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
+ LINUXKPI_PARAM_DESC(name)))
+
+#define LINUXKPI_PARAM_byte(name, var, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_U8(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
+ LINUXKPI_PARAM_DESC(name)))
+
+#define LINUXKPI_PARAM_short(name, var, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_S16(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
+ LINUXKPI_PARAM_DESC(name)))
+
+#define LINUXKPI_PARAM_ushort(name, var, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_U16(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
+ LINUXKPI_PARAM_DESC(name)))
+
+#define LINUXKPI_PARAM_int(name, var, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_INT(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0,\
+ LINUXKPI_PARAM_DESC(name)))
+
+#define LINUXKPI_PARAM_uint(name, var, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_UINT(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
+ LINUXKPI_PARAM_DESC(name)))
+
+#define LINUXKPI_PARAM_bint(name, var, perm) \
+ LINUXKPI_PARAM_int(name, var, perm)
+
+#define LINUXKPI_PARAM_hexint(name, var, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_UINT(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
+ LINUXKPI_PARAM_DESC(name)))
+
+#define LINUXKPI_PARAM_long(name, var, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_LONG(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
+ LINUXKPI_PARAM_DESC(name)))
+
+#define LINUXKPI_PARAM_ulong(name, var, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_ULONG(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
+ LINUXKPI_PARAM_DESC(name)))
+
+#define LINUXKPI_PARAM_charp(name, var, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_STRING(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
+ LINUXKPI_PARAM_DESC(name)))
+
+#define module_param_string(name, str, len, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_STRING(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), (str), (len), \
+ LINUXKPI_PARAM_DESC(name)))
+
+#define module_param_named(name, var, type, mode) \
+ LINUXKPI_PARAM_##type(name, var, mode)
+
+#define module_param(var, type, mode) \
+ LINUXKPI_PARAM_##type(var, var, mode)
+
+#define module_param_named_unsafe(name, var, type, mode) \
+ LINUXKPI_PARAM_##type(name, var, mode)
+
+#define module_param_unsafe(var, type, mode) \
+ LINUXKPI_PARAM_##type(var, var, mode)
+
+#define module_param_array(var, type, addr_argc, mode)
+
+#define MODULE_PARM_DESC(name, desc) \
+ const char LINUXKPI_PARAM_DESC(name)[] = { desc }
+
+#define kernel_param_lock(...) do {} while (0)
+#define kernel_param_unlock(...) do {} while (0)
+
+SYSCTL_DECL(_compat_linuxkpi);
+
+#endif /* _LINUXKPI_LINUX_MODULEPARAM_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/mutex.h b/sys/compat/linuxkpi/common/include/linux/mutex.h
new file mode 100644
index 000000000000..6fb6a7744a89
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/mutex.h
@@ -0,0 +1,177 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_MUTEX_H_
+#define _LINUXKPI_LINUX_MUTEX_H_
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/sx.h>
+
+#include <linux/kernel.h>
+#include <linux/cleanup.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+
+typedef struct mutex {
+ struct sx sx;
+} mutex_t;
+
+/*
+ * By defining CONFIG_NO_MUTEX_SKIP LinuxKPI mutexes and asserts will
+ * not be skipped during panic().
+ */
+#ifdef CONFIG_NO_MUTEX_SKIP
+#define MUTEX_SKIP(void) 0
+#else
+#define MUTEX_SKIP(void) unlikely(SCHEDULER_STOPPED() || kdb_active)
+#endif
+
+#define mutex_lock(_m) do { \
+ if (MUTEX_SKIP()) \
+ break; \
+ sx_xlock(&(_m)->sx); \
+} while (0)
+
+#define mutex_lock_nested(_m, _s) mutex_lock(_m)
+#define mutex_lock_nest_lock(_m, _s) mutex_lock(_m)
+
+#define mutex_lock_interruptible(_m) ({ \
+ MUTEX_SKIP() ? 0 : \
+ linux_mutex_lock_interruptible(_m); \
+})
+
+#define mutex_lock_interruptible_nested(m, c) mutex_lock_interruptible(m)
+
+/*
+ * Reuse the interruptable method since the SX
+ * lock handles both signals and interrupts:
+ */
+#define mutex_lock_killable(_m) ({ \
+ MUTEX_SKIP() ? 0 : \
+ linux_mutex_lock_interruptible(_m); \
+})
+
+#define mutex_lock_killable_nested(_m, _sub) \
+ mutex_lock_killable(_m)
+
+#define mutex_unlock(_m) do { \
+ if (MUTEX_SKIP()) \
+ break; \
+ sx_xunlock(&(_m)->sx); \
+} while (0)
+
+#define mutex_trylock(_m) ({ \
+ MUTEX_SKIP() ? 1 : \
+ !!sx_try_xlock(&(_m)->sx); \
+})
+
+enum mutex_trylock_recursive_enum {
+ MUTEX_TRYLOCK_FAILED = 0,
+ MUTEX_TRYLOCK_SUCCESS = 1,
+ MUTEX_TRYLOCK_RECURSIVE = 2,
+};
+
+static inline __must_check enum mutex_trylock_recursive_enum
+mutex_trylock_recursive(struct mutex *lock)
+{
+ if (unlikely(sx_xholder(&lock->sx) == curthread))
+ return (MUTEX_TRYLOCK_RECURSIVE);
+
+ return (mutex_trylock(lock));
+}
+
+#define mutex_init(_m) \
+ linux_mutex_init(_m, mutex_name(#_m), SX_NOWITNESS)
+
+#define __mutex_init(_m, _n, _l) \
+ linux_mutex_init(_m, _n, SX_NOWITNESS)
+
+#define mutex_init_witness(_m) \
+ linux_mutex_init(_m, mutex_name(#_m), SX_DUPOK)
+
+#define mutex_destroy(_m) \
+ linux_mutex_destroy(_m)
+
+static inline bool
+mutex_is_locked(mutex_t *m)
+{
+ return ((struct thread *)SX_OWNER(m->sx.sx_lock) != NULL);
+}
+
+static inline bool
+mutex_is_owned(mutex_t *m)
+{
+ return (sx_xlocked(&m->sx));
+}
+
+static inline int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *m)
+{
+ if (atomic_dec_and_test(cnt)) {
+ mutex_lock(m);
+ return (1);
+ }
+
+ return (0);
+}
+
+#ifdef WITNESS_ALL
+/* NOTE: the maximum WITNESS name is 64 chars */
+#define __mutex_name(name, file, line) \
+ (((const char *){file ":" #line "-" name}) + \
+ (sizeof(file) > 16 ? sizeof(file) - 16 : 0))
+#else
+#define __mutex_name(name, file, line) name
+#endif
+#define _mutex_name(...) __mutex_name(__VA_ARGS__)
+#define mutex_name(name) _mutex_name(name, __FILE__, __LINE__)
+
+#define DEFINE_MUTEX(lock) \
+ mutex_t lock; \
+ SX_SYSINIT_FLAGS(lock, &(lock).sx, mutex_name(#lock), SX_DUPOK)
+
+static inline void
+linux_mutex_init(mutex_t *m, const char *name, int flags)
+{
+ memset(m, 0, sizeof(*m));
+ sx_init_flags(&m->sx, name, flags);
+}
+
+static inline void
+linux_mutex_destroy(mutex_t *m)
+{
+ if (mutex_is_owned(m))
+ mutex_unlock(m);
+ sx_destroy(&m->sx);
+}
+
+extern int linux_mutex_lock_interruptible(mutex_t *m);
+
+#endif /* _LINUXKPI_LINUX_MUTEX_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/net.h b/sys/compat/linuxkpi/common/include/linux/net.h
new file mode 100644
index 000000000000..a5172f3f31eb
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/net.h
@@ -0,0 +1,88 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_NET_H_
+#define _LINUXKPI_LINUX_NET_H_
+
+#include <sys/types.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/errno.h>
+
+static inline int
+sock_create_kern(int family, int type, int proto, struct socket **res)
+{
+ return -socreate(family, res, type, proto, curthread->td_ucred,
+ curthread);
+}
+
+static inline int
+sock_getname(struct socket *so, struct sockaddr *sa, int *sockaddr_len,
+ int peer)
+{
+ int error;
+
+ /*
+ * XXXGL: we can't use sopeeraddr()/sosockaddr() here since with
+ * INVARIANTS they would check if supplied sockaddr has enough
+ * length. Such notion doesn't even exist in Linux KPI.
+ */
+ if (peer) {
+ if ((so->so_state & SS_ISCONNECTED) == 0)
+ return (-ENOTCONN);
+
+ error = so->so_proto->pr_peeraddr(so, sa);
+ } else
+ error = so->so_proto->pr_sockaddr(so, sa);
+ if (error)
+ return (-error);
+ *sockaddr_len = sa->sa_len;
+
+ return (0);
+}
+
+static inline void
+sock_release(struct socket *so)
+{
+ soclose(so);
+}
+
+
+int linuxkpi_net_ratelimit(void);
+
+static inline int
+net_ratelimit(void)
+{
+
+ return (linuxkpi_net_ratelimit());
+}
+
+#endif /* _LINUXKPI_LINUX_NET_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/net_dim.h b/sys/compat/linuxkpi/common/include/linux/net_dim.h
new file mode 100644
index 000000000000..4fe3e39210e7
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/net_dim.h
@@ -0,0 +1,408 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0
+ *
+ * Copyright (c) 2016, Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2017-2018, Broadcom Limited. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* This file implements Dynamic Interrupt Moderation, DIM */
+
+#ifndef _LINUXKPI_LINUX_NET_DIM_H
+#define _LINUXKPI_LINUX_NET_DIM_H
+
+#include <asm/types.h>
+
+#include <linux/workqueue.h>
+#include <linux/ktime.h>
+
+struct net_dim_cq_moder {
+ u16 usec;
+ u16 pkts;
+ u8 cq_period_mode;
+};
+
+struct net_dim_sample {
+ ktime_t time;
+ u32 pkt_ctr;
+ u32 byte_ctr;
+ u16 event_ctr;
+};
+
+struct net_dim_stats {
+ int ppms; /* packets per msec */
+ int bpms; /* bytes per msec */
+ int epms; /* events per msec */
+};
+
+struct net_dim { /* Adaptive Moderation */
+ u8 state;
+ struct net_dim_stats prev_stats;
+ struct net_dim_sample start_sample;
+ struct work_struct work;
+ u16 event_ctr;
+ u8 profile_ix;
+ u8 mode;
+ u8 tune_state;
+ u8 steps_right;
+ u8 steps_left;
+ u8 tired;
+};
+
+enum {
+ NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE = 0x0,
+ NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE = 0x1,
+ NET_DIM_CQ_PERIOD_NUM_MODES = 0x2,
+ NET_DIM_CQ_PERIOD_MODE_DISABLED = 0xFF,
+};
+
+/* Adaptive moderation logic */
+enum {
+ NET_DIM_START_MEASURE,
+ NET_DIM_MEASURE_IN_PROGRESS,
+ NET_DIM_APPLY_NEW_PROFILE,
+};
+
+enum {
+ NET_DIM_PARKING_ON_TOP,
+ NET_DIM_PARKING_TIRED,
+ NET_DIM_GOING_RIGHT,
+ NET_DIM_GOING_LEFT,
+};
+
+enum {
+ NET_DIM_STATS_WORSE,
+ NET_DIM_STATS_SAME,
+ NET_DIM_STATS_BETTER,
+};
+
+enum {
+ NET_DIM_STEPPED,
+ NET_DIM_TOO_TIRED,
+ NET_DIM_ON_EDGE,
+};
+
+#define NET_DIM_PARAMS_NUM_PROFILES 5
+/* Adaptive moderation profiles */
+#define NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE 256
+#define NET_DIM_DEF_PROFILE_CQE 1
+#define NET_DIM_DEF_PROFILE_EQE 1
+
+/* All profiles sizes must be NET_PARAMS_DIM_NUM_PROFILES */
+#define NET_DIM_EQE_PROFILES { \
+ {1, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+ {8, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+ {64, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+ {128, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+ {256, NET_DIM_DEFAULT_RX_CQ_MODERATION_PKTS_FROM_EQE}, \
+}
+
+#define NET_DIM_CQE_PROFILES { \
+ {2, 256}, \
+ {8, 128}, \
+ {16, 64}, \
+ {32, 64}, \
+ {64, 64} \
+}
+
+static const struct net_dim_cq_moder
+ net_dim_profile[NET_DIM_CQ_PERIOD_NUM_MODES][NET_DIM_PARAMS_NUM_PROFILES] = {
+ NET_DIM_EQE_PROFILES,
+ NET_DIM_CQE_PROFILES,
+};
+
+static inline struct net_dim_cq_moder
+net_dim_get_profile(u8 cq_period_mode,
+ int ix)
+{
+ struct net_dim_cq_moder cq_moder;
+
+ cq_moder = net_dim_profile[cq_period_mode][ix];
+ cq_moder.cq_period_mode = cq_period_mode;
+ return cq_moder;
+}
+
+static inline struct net_dim_cq_moder
+net_dim_get_def_profile(u8 rx_cq_period_mode)
+{
+ int default_profile_ix;
+
+ if (rx_cq_period_mode == NET_DIM_CQ_PERIOD_MODE_START_FROM_CQE)
+ default_profile_ix = NET_DIM_DEF_PROFILE_CQE;
+ else /* NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE */
+ default_profile_ix = NET_DIM_DEF_PROFILE_EQE;
+
+ return net_dim_get_profile(rx_cq_period_mode, default_profile_ix);
+}
+
+static inline bool
+net_dim_on_top(struct net_dim *dim)
+{
+ switch (dim->tune_state) {
+ case NET_DIM_PARKING_ON_TOP:
+ case NET_DIM_PARKING_TIRED:
+ return true;
+ case NET_DIM_GOING_RIGHT:
+ return (dim->steps_left > 1) && (dim->steps_right == 1);
+ default: /* NET_DIM_GOING_LEFT */
+ return (dim->steps_right > 1) && (dim->steps_left == 1);
+ }
+}
+
+static inline void
+net_dim_turn(struct net_dim *dim)
+{
+ switch (dim->tune_state) {
+ case NET_DIM_PARKING_ON_TOP:
+ case NET_DIM_PARKING_TIRED:
+ break;
+ case NET_DIM_GOING_RIGHT:
+ dim->tune_state = NET_DIM_GOING_LEFT;
+ dim->steps_left = 0;
+ break;
+ case NET_DIM_GOING_LEFT:
+ dim->tune_state = NET_DIM_GOING_RIGHT;
+ dim->steps_right = 0;
+ break;
+ }
+}
+
+static inline int
+net_dim_step(struct net_dim *dim)
+{
+ if (dim->tired == (NET_DIM_PARAMS_NUM_PROFILES * 2))
+ return NET_DIM_TOO_TIRED;
+
+ switch (dim->tune_state) {
+ case NET_DIM_PARKING_ON_TOP:
+ case NET_DIM_PARKING_TIRED:
+ break;
+ case NET_DIM_GOING_RIGHT:
+ if (dim->profile_ix == (NET_DIM_PARAMS_NUM_PROFILES - 1))
+ return NET_DIM_ON_EDGE;
+ dim->profile_ix++;
+ dim->steps_right++;
+ break;
+ case NET_DIM_GOING_LEFT:
+ if (dim->profile_ix == 0)
+ return NET_DIM_ON_EDGE;
+ dim->profile_ix--;
+ dim->steps_left++;
+ break;
+ }
+
+ dim->tired++;
+ return NET_DIM_STEPPED;
+}
+
+static inline void
+net_dim_park_on_top(struct net_dim *dim)
+{
+ dim->steps_right = 0;
+ dim->steps_left = 0;
+ dim->tired = 0;
+ dim->tune_state = NET_DIM_PARKING_ON_TOP;
+}
+
+static inline void
+net_dim_park_tired(struct net_dim *dim)
+{
+ dim->steps_right = 0;
+ dim->steps_left = 0;
+ dim->tune_state = NET_DIM_PARKING_TIRED;
+}
+
+static inline void
+net_dim_exit_parking(struct net_dim *dim)
+{
+ dim->tune_state = dim->profile_ix ? NET_DIM_GOING_LEFT :
+ NET_DIM_GOING_RIGHT;
+ net_dim_step(dim);
+}
+
+#define IS_SIGNIFICANT_DIFF(val, ref) \
+ (((100UL * abs((val) - (ref))) / (ref)) > 10) /* more than 10%
+ * difference */
+
+static inline int
+net_dim_stats_compare(struct net_dim_stats *curr,
+ struct net_dim_stats *prev)
+{
+ if (!prev->bpms)
+ return curr->bpms ? NET_DIM_STATS_BETTER :
+ NET_DIM_STATS_SAME;
+
+ if (IS_SIGNIFICANT_DIFF(curr->bpms, prev->bpms))
+ return (curr->bpms > prev->bpms) ? NET_DIM_STATS_BETTER :
+ NET_DIM_STATS_WORSE;
+
+ if (!prev->ppms)
+ return curr->ppms ? NET_DIM_STATS_BETTER :
+ NET_DIM_STATS_SAME;
+
+ if (IS_SIGNIFICANT_DIFF(curr->ppms, prev->ppms))
+ return (curr->ppms > prev->ppms) ? NET_DIM_STATS_BETTER :
+ NET_DIM_STATS_WORSE;
+
+ if (!prev->epms)
+ return NET_DIM_STATS_SAME;
+
+ if (IS_SIGNIFICANT_DIFF(curr->epms, prev->epms))
+ return (curr->epms < prev->epms) ? NET_DIM_STATS_BETTER :
+ NET_DIM_STATS_WORSE;
+
+ return NET_DIM_STATS_SAME;
+}
+
+static inline bool
+net_dim_decision(struct net_dim_stats *curr_stats,
+ struct net_dim *dim)
+{
+ int prev_state = dim->tune_state;
+ int prev_ix = dim->profile_ix;
+ int stats_res;
+ int step_res;
+
+ switch (dim->tune_state) {
+ case NET_DIM_PARKING_ON_TOP:
+ stats_res = net_dim_stats_compare(curr_stats, &dim->prev_stats);
+ if (stats_res != NET_DIM_STATS_SAME)
+ net_dim_exit_parking(dim);
+ break;
+
+ case NET_DIM_PARKING_TIRED:
+ dim->tired--;
+ if (!dim->tired)
+ net_dim_exit_parking(dim);
+ break;
+
+ case NET_DIM_GOING_RIGHT:
+ case NET_DIM_GOING_LEFT:
+ stats_res = net_dim_stats_compare(curr_stats, &dim->prev_stats);
+ if (stats_res != NET_DIM_STATS_BETTER)
+ net_dim_turn(dim);
+
+ if (net_dim_on_top(dim)) {
+ net_dim_park_on_top(dim);
+ break;
+ }
+ step_res = net_dim_step(dim);
+ switch (step_res) {
+ case NET_DIM_ON_EDGE:
+ net_dim_park_on_top(dim);
+ break;
+ case NET_DIM_TOO_TIRED:
+ net_dim_park_tired(dim);
+ break;
+ }
+
+ break;
+ }
+
+ if ((prev_state != NET_DIM_PARKING_ON_TOP) ||
+ (dim->tune_state != NET_DIM_PARKING_ON_TOP))
+ dim->prev_stats = *curr_stats;
+
+ return dim->profile_ix != prev_ix;
+}
+
+static inline void
+net_dim_sample(u16 event_ctr,
+ u64 packets,
+ u64 bytes,
+ struct net_dim_sample *s)
+{
+ s->time = ktime_get();
+ s->pkt_ctr = packets;
+ s->byte_ctr = bytes;
+ s->event_ctr = event_ctr;
+}
+
+#define NET_DIM_NEVENTS 64
+#define BIT_GAP(bits, end, start) ((((end) - (start)) + BIT_ULL(bits)) & (BIT_ULL(bits) - 1))
+
+static inline void
+net_dim_calc_stats(struct net_dim_sample *start,
+ struct net_dim_sample *end,
+ struct net_dim_stats *curr_stats)
+{
+ /* u32 holds up to 71 minutes, should be enough */
+ u32 delta_us = ktime_us_delta(end->time, start->time);
+ u32 npkts = BIT_GAP(BITS_PER_TYPE(u32), end->pkt_ctr, start->pkt_ctr);
+ u32 nbytes = BIT_GAP(BITS_PER_TYPE(u32), end->byte_ctr,
+ start->byte_ctr);
+
+ if (!delta_us)
+ return;
+
+ curr_stats->ppms = DIV_ROUND_UP(npkts * USEC_PER_MSEC, delta_us);
+ curr_stats->bpms = DIV_ROUND_UP(nbytes * USEC_PER_MSEC, delta_us);
+ curr_stats->epms = DIV_ROUND_UP(NET_DIM_NEVENTS * USEC_PER_MSEC,
+ delta_us);
+}
+
+static inline void
+net_dim(struct net_dim *dim,
+ u64 packets, u64 bytes)
+{
+ struct net_dim_stats curr_stats;
+ struct net_dim_sample end_sample;
+ u16 nevents;
+
+ dim->event_ctr++;
+
+ switch (dim->state) {
+ case NET_DIM_MEASURE_IN_PROGRESS:
+ nevents = BIT_GAP(BITS_PER_TYPE(u16),
+ dim->event_ctr,
+ dim->start_sample.event_ctr);
+ if (nevents < NET_DIM_NEVENTS)
+ break;
+ net_dim_sample(dim->event_ctr, packets, bytes, &end_sample);
+ net_dim_calc_stats(&dim->start_sample, &end_sample,
+ &curr_stats);
+ if (net_dim_decision(&curr_stats, dim)) {
+ dim->state = NET_DIM_APPLY_NEW_PROFILE;
+ schedule_work(&dim->work);
+ break;
+ }
+ /* FALLTHROUGH */
+ case NET_DIM_START_MEASURE:
+ net_dim_sample(dim->event_ctr, packets, bytes, &dim->start_sample);
+ dim->state = NET_DIM_MEASURE_IN_PROGRESS;
+ break;
+ case NET_DIM_APPLY_NEW_PROFILE:
+ break;
+ default:
+ break;
+ }
+}
+
+#endif /* _LINUXKPI_LINUX_NET_DIM_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/netdev_features.h b/sys/compat/linuxkpi/common/include/linux/netdev_features.h
new file mode 100644
index 000000000000..fae82776b071
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/netdev_features.h
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2020-2025 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * 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 unmodified, 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 ``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 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_NETDEV_FEATURES_H_
+#define _LINUXKPI_LINUX_NETDEV_FEATURES_H_
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+
+typedef uint32_t netdev_features_t;
+
+#define NETIF_F_HIGHDMA BIT(0) /* Can DMA to high memory. */
+#define NETIF_F_SG BIT(1) /* Can do scatter/gather I/O. */
+#define NETIF_F_IP_CSUM BIT(2) /* Can csum TCP/UDP on IPv4. */
+#define NETIF_F_IPV6_CSUM BIT(3) /* Can csum TCP/UDP on IPv6. */
+#define NETIF_F_TSO BIT(4) /* Can do TCP over IPv4 segmentation. */
+#define NETIF_F_TSO6 BIT(5) /* Can do TCP over IPv6 segmentation. */
+#define NETIF_F_RXCSUM BIT(6) /* Can do receive csum offload. */
+#define NETIF_F_HW_CSUM BIT(7) /* Can csum packets (which?). */
+#define NETIF_F_HW_TC BIT(8) /* Can offload TC. */
+
+#define NETIF_F_CSUM_MASK (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)
+
+#define NETIF_F_BITS \
+ "\20\1HIGHDMA\2SG\3IP_CSUM\4IPV6_CSUM\5TSO\6TSO6\7RXCSUM" \
+ "\10HW_CSUM\11HW_TC"
+
+#endif /* _LINUXKPI_LINUX_NETDEV_FEATURES_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/netdevice.h b/sys/compat/linuxkpi/common/include/linux/netdevice.h
new file mode 100644
index 000000000000..cd7d23077a62
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/netdevice.h
@@ -0,0 +1,488 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2019 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ * Copyright (c) 2020-2021 The FreeBSD Foundation
+ * Copyright (c) 2020-2022 Bjoern A. Zeeb
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * 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 unmodified, 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 ``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 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_NETDEVICE_H
+#define _LINUXKPI_LINUX_NETDEVICE_H
+
+#include <linux/types.h>
+#include <linux/netdev_features.h>
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/taskqueue.h>
+
+#include <net/if_types.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/net.h>
+#include <linux/if_ether.h>
+#include <linux/notifier.h>
+#include <linux/random.h>
+#include <linux/rcupdate.h>
+
+#ifdef VIMAGE
+#define init_net *vnet0
+#else
+#define init_net *((struct vnet *)0)
+#endif
+
+struct sk_buff;
+struct net_device;
+struct wireless_dev; /* net/cfg80211.h */
+
+#define MAX_ADDR_LEN 20
+
+#define NET_NAME_UNKNOWN 0
+
+enum net_addr_assign_type {
+ NET_ADDR_RANDOM,
+};
+
+enum netdev_tx {
+ NETDEV_TX_OK = 0,
+};
+typedef enum netdev_tx netdev_tx_t;
+
+struct netdev_hw_addr {
+ struct list_head addr_list;
+ uint8_t addr[MAX_ADDR_LEN];
+};
+
+struct netdev_hw_addr_list {
+ struct list_head addr_list;
+ int count;
+};
+
+enum net_device_reg_state {
+ NETREG_DUMMY = 1,
+ NETREG_REGISTERED,
+};
+
+enum tc_setup_type {
+ TC_SETUP_MAX_DUMMY,
+};
+
+struct net_device_ops {
+ int (*ndo_open)(struct net_device *);
+ int (*ndo_stop)(struct net_device *);
+ int (*ndo_set_mac_address)(struct net_device *, void *);
+ netdev_tx_t (*ndo_start_xmit)(struct sk_buff *, struct net_device *);
+ void (*ndo_set_rx_mode)(struct net_device *);
+};
+
+struct net_device {
+ /* net_device fields seen publicly. */
+ /* XXX can we later make some aliases to ifnet? */
+ char name[IFNAMSIZ];
+ struct wireless_dev *ieee80211_ptr;
+ uint8_t dev_addr[ETH_ALEN];
+ struct netdev_hw_addr_list mc;
+ netdev_features_t features;
+ struct {
+ unsigned long multicast;
+
+ unsigned long rx_bytes;
+ unsigned long rx_errors;
+ unsigned long rx_packets;
+ unsigned long tx_bytes;
+ unsigned long tx_dropped;
+ unsigned long tx_errors;
+ unsigned long tx_packets;
+ } stats;
+ enum net_addr_assign_type addr_assign_type;
+ enum net_device_reg_state reg_state;
+ const struct ethtool_ops *ethtool_ops;
+ const struct net_device_ops *netdev_ops;
+
+ bool needs_free_netdev;
+ /* Not properly typed as-of now. */
+ int flags, type;
+ int name_assign_type, needed_headroom;
+ int threaded;
+
+ void (*priv_destructor)(struct net_device *);
+
+ /* net_device internal. */
+ struct device dev;
+
+ /*
+ * In case we delete the net_device we need to be able to clear all
+ * NAPI consumers.
+ */
+ struct mtx napi_mtx;
+ TAILQ_HEAD(, napi_struct) napi_head;
+ struct taskqueue *napi_tq;
+
+ /* Must stay last. */
+ uint8_t drv_priv[0] __aligned(CACHE_LINE_SIZE);
+};
+
+#define SET_NETDEV_DEV(_ndev, _dev) (_ndev)->dev.parent = _dev;
+
+/* -------------------------------------------------------------------------- */
+/* According to linux::ipoib_main.c. */
+struct netdev_notifier_info {
+ struct net_device *dev;
+ struct ifnet *ifp;
+};
+
+static inline struct net_device *
+netdev_notifier_info_to_dev(struct netdev_notifier_info *ni)
+{
+ return (ni->dev);
+}
+
+static inline struct ifnet *
+netdev_notifier_info_to_ifp(struct netdev_notifier_info *ni)
+{
+ return (ni->ifp);
+}
+
+int register_netdevice_notifier(struct notifier_block *);
+int register_inetaddr_notifier(struct notifier_block *);
+int unregister_netdevice_notifier(struct notifier_block *);
+int unregister_inetaddr_notifier(struct notifier_block *);
+
+/* -------------------------------------------------------------------------- */
+
+#define NAPI_POLL_WEIGHT 64 /* budget */
+
+/*
+ * There are drivers directly testing napi state bits, so we need to publicly
+ * expose them. If you ask me, those accesses should be hid behind an
+ * inline function and the bit flags not be directly exposed.
+ */
+enum napi_state_bits {
+ /*
+ * Official Linux flags encountered.
+ */
+ NAPI_STATE_SCHED = 1,
+
+ /*
+ * Our internal versions (for now).
+ */
+ /* Do not schedule new things while we are waiting to clear things. */
+ LKPI_NAPI_FLAG_DISABLE_PENDING = 0,
+ /* To synchronise that only one poll is ever running. */
+ LKPI_NAPI_FLAG_IS_SCHEDULED = 1,
+ /* If trying to schedule while poll is running. Need to re-schedule. */
+ LKPI_NAPI_FLAG_LOST_RACE_TRY_AGAIN = 2,
+ /* When shutting down forcefully prevent anything from running task/poll. */
+ LKPI_NAPI_FLAG_SHUTDOWN = 3,
+};
+
+struct napi_struct {
+ TAILQ_ENTRY(napi_struct) entry;
+
+ struct list_head rx_list;
+ struct net_device *dev;
+ int (*poll)(struct napi_struct *, int);
+ int budget;
+ int rx_count;
+
+
+ /*
+ * These flags mostly need to be checked/changed atomically
+ * (multiple together in some cases).
+ */
+ volatile unsigned long state;
+
+ /* FreeBSD internal. */
+ /* Use task for now, so we can easily switch between direct and task. */
+ struct task napi_task;
+};
+
+void linuxkpi_init_dummy_netdev(struct net_device *);
+void linuxkpi_netif_napi_add(struct net_device *, struct napi_struct *,
+ int(*napi_poll)(struct napi_struct *, int));
+void linuxkpi_netif_napi_del(struct napi_struct *);
+bool linuxkpi_napi_schedule_prep(struct napi_struct *);
+void linuxkpi___napi_schedule(struct napi_struct *);
+bool linuxkpi_napi_schedule(struct napi_struct *);
+void linuxkpi_napi_reschedule(struct napi_struct *);
+bool linuxkpi_napi_complete_done(struct napi_struct *, int);
+bool linuxkpi_napi_complete(struct napi_struct *);
+void linuxkpi_napi_disable(struct napi_struct *);
+void linuxkpi_napi_enable(struct napi_struct *);
+void linuxkpi_napi_synchronize(struct napi_struct *);
+
+#define init_dummy_netdev(_n) \
+ linuxkpi_init_dummy_netdev(_n)
+#define netif_napi_add(_nd, _ns, _p) \
+ linuxkpi_netif_napi_add(_nd, _ns, _p)
+#define netif_napi_del(_n) \
+ linuxkpi_netif_napi_del(_n)
+#define napi_schedule_prep(_n) \
+ linuxkpi_napi_schedule_prep(_n)
+#define __napi_schedule(_n) \
+ linuxkpi___napi_schedule(_n)
+#define napi_schedule(_n) \
+ linuxkpi_napi_schedule(_n)
+#define napi_reschedule(_n) \
+ linuxkpi_napi_reschedule(_n)
+#define napi_complete_done(_n, _r) \
+ linuxkpi_napi_complete_done(_n, _r)
+#define napi_complete(_n) \
+ linuxkpi_napi_complete(_n)
+#define napi_disable(_n) \
+ linuxkpi_napi_disable(_n)
+#define napi_enable(_n) \
+ linuxkpi_napi_enable(_n)
+#define napi_synchronize(_n) \
+ linuxkpi_napi_synchronize(_n)
+
+
+static inline void
+netif_napi_add_tx(struct net_device *dev, struct napi_struct *napi,
+ int(*napi_poll)(struct napi_struct *, int))
+{
+
+ netif_napi_add(dev, napi, napi_poll);
+}
+
+static inline bool
+napi_is_scheduled(struct napi_struct *napi)
+{
+
+ return (test_bit(LKPI_NAPI_FLAG_IS_SCHEDULED, &napi->state));
+}
+
+/* -------------------------------------------------------------------------- */
+
+static inline void
+netdev_rss_key_fill(uint32_t *buf, size_t len)
+{
+
+ /*
+ * Remembering from a previous life there was discussions on what is
+ * a good RSS hash key. See end of rss_init() in net/rss_config.c.
+ * iwlwifi is looking for a 10byte "secret" so stay with random for now.
+ */
+ get_random_bytes(buf, len);
+}
+
+static inline int
+netdev_hw_addr_list_count(struct netdev_hw_addr_list *list)
+{
+
+ return (list->count);
+}
+
+static inline int
+netdev_mc_count(struct net_device *ndev)
+{
+
+ return (netdev_hw_addr_list_count(&ndev->mc));
+}
+
+#define netdev_hw_addr_list_for_each(_addr, _list) \
+ list_for_each_entry((_addr), &(_list)->addr_list, addr_list)
+
+#define netdev_for_each_mc_addr(na, ndev) \
+ netdev_hw_addr_list_for_each(na, &(ndev)->mc)
+
+static __inline void
+synchronize_net(void)
+{
+
+ /* We probably cannot do that unconditionally at some point anymore. */
+ synchronize_rcu();
+}
+
+static __inline void
+netif_receive_skb_list(struct list_head *head)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static __inline int
+napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (-1);
+}
+
+static __inline void
+ether_setup(struct net_device *ndev)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static __inline void
+dev_net_set(struct net_device *ndev, void *p)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static __inline int
+dev_set_threaded(struct net_device *ndev, bool threaded)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (-ENODEV);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static __inline bool
+netif_carrier_ok(struct net_device *ndev)
+{
+ pr_debug("%s: TODO\n", __func__);
+ return (false);
+}
+
+static __inline void
+netif_carrier_off(struct net_device *ndev)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static __inline void
+netif_carrier_on(struct net_device *ndev)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static __inline bool
+netif_queue_stopped(struct net_device *ndev)
+{
+ pr_debug("%s: TODO\n", __func__);
+ return (false);
+}
+
+static __inline void
+netif_stop_queue(struct net_device *ndev)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static __inline void
+netif_wake_queue(struct net_device *ndev)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static __inline int
+register_netdevice(struct net_device *ndev)
+{
+
+ /* assert rtnl_locked? */
+ pr_debug("%s: TODO\n", __func__);
+ return (0);
+}
+
+static __inline int
+register_netdev(struct net_device *ndev)
+{
+ int error;
+
+ /* lock */
+ error = register_netdevice(ndev);
+ /* unlock */
+ pr_debug("%s: TODO\n", __func__);
+ return (error);
+}
+
+static __inline void
+unregister_netdev(struct net_device *ndev)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static __inline void
+unregister_netdevice(struct net_device *ndev)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static __inline void
+netif_rx(struct sk_buff *skb)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static __inline void
+netif_rx_ni(struct sk_buff *skb)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+/* -------------------------------------------------------------------------- */
+
+struct net_device *linuxkpi_alloc_netdev(size_t, const char *, uint32_t,
+ void(*)(struct net_device *));
+void linuxkpi_free_netdev(struct net_device *);
+
+#define alloc_netdev(_l, _n, _f, _func) \
+ linuxkpi_alloc_netdev(_l, _n, _f, _func)
+#define alloc_netdev_dummy(_l) \
+ linuxkpi_alloc_netdev(_l, "dummy", NET_NAME_UNKNOWN, NULL)
+#define free_netdev(_n) \
+ linuxkpi_free_netdev(_n)
+
+static inline void *
+netdev_priv(const struct net_device *ndev)
+{
+
+ return (__DECONST(void *, ndev->drv_priv));
+}
+
+/* -------------------------------------------------------------------------- */
+/* This is really rtnetlink and probably belongs elsewhere. */
+
+#define rtnl_lock() do { } while(0)
+#define rtnl_unlock() do { } while(0)
+#define rcu_dereference_rtnl(x) READ_ONCE(x)
+
+#endif /* _LINUXKPI_LINUX_NETDEVICE_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/nl80211.h b/sys/compat/linuxkpi/common/include/linux/nl80211.h
new file mode 100644
index 000000000000..f3979d3a2abc
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/nl80211.h
@@ -0,0 +1,445 @@
+/*-
+ * Copyright (c) 2020-2024 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb 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_NL80211_H
+#define _LINUXKPI_LINUX_NL80211_H
+
+#include <linux/bitops.h>
+
+enum nl80211_feature_flags {
+ NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE = BIT(0),
+ NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES = BIT(1),
+ NL80211_FEATURE_HT_IBSS = BIT(2),
+ NL80211_FEATURE_LOW_PRIORITY_SCAN = BIT(3),
+ NL80211_FEATURE_ND_RANDOM_MAC_ADDR = BIT(4),
+ NL80211_FEATURE_P2P_GO_CTWIN = BIT(5),
+ NL80211_FEATURE_P2P_GO_OPPPS = BIT(6),
+ NL80211_FEATURE_QUIET = BIT(7),
+ NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR = BIT(8),
+ NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR = BIT(9),
+ NL80211_FEATURE_DYNAMIC_SMPS = BIT(10),
+ NL80211_FEATURE_STATIC_SMPS = BIT(11),
+ NL80211_FEATURE_SUPPORTS_WMM_ADMISSION = BIT(12),
+ NL80211_FEATURE_TDLS_CHANNEL_SWITCH = BIT(13),
+ NL80211_FEATURE_TX_POWER_INSERTION = BIT(14),
+ NL80211_FEATURE_WFA_TPC_IE_IN_PROBES = BIT(15),
+ NL80211_FEATURE_AP_SCAN = BIT(16),
+ NL80211_FEATURE_ACTIVE_MONITOR = BIT(17),
+};
+
+enum nl80211_pmsr_ftm_failure_flags {
+ NL80211_PMSR_FTM_FAILURE_NO_RESPONSE = BIT(0),
+ NL80211_PMSR_FTM_FAILURE_PEER_BUSY = BIT(1),
+ NL80211_PMSR_FTM_FAILURE_UNSPECIFIED = BIT(2),
+};
+
+enum nl80211_pmsr_status_flags {
+ NL80211_PMSR_STATUS_FAILURE = BIT(0),
+ NL80211_PMSR_STATUS_SUCCESS = BIT(1),
+ NL80211_PMSR_STATUS_TIMEOUT = BIT(2),
+};
+
+#define NL80211_PMSR_TYPE_FTM 1
+
+enum nl80211_reg_rule_flags {
+ NL80211_RRF_AUTO_BW = BIT(0),
+ NL80211_RRF_DFS = BIT(1),
+ NL80211_RRF_GO_CONCURRENT = BIT(2),
+ NL80211_RRF_NO_IR = BIT(3),
+ NL80211_RRF_NO_OUTDOOR = BIT(4),
+ NL80211_RRF_NO_HT40MINUS = BIT(5),
+ NL80211_RRF_NO_HT40PLUS = BIT(6),
+ NL80211_RRF_NO_80MHZ = BIT(7),
+ NL80211_RRF_NO_160MHZ = BIT(8),
+ NL80211_RRF_NO_HE = BIT(9),
+ NL80211_RRF_NO_OFDM = BIT(10),
+ NL80211_RRF_NO_320MHZ = BIT(11),
+ NL80211_RRF_NO_EHT = BIT(12),
+ NL80211_RRF_DFS_CONCURRENT = BIT(13),
+ NL80211_RRF_NO_6GHZ_VLP_CLIENT = BIT(14),
+ NL80211_RRF_NO_6GHZ_AFC_CLIENT = BIT(15),
+ NL80211_RRF_PSD = BIT(16),
+ NL80211_RRF_ALLOW_6GHZ_VLP_AP = BIT(17),
+};
+#define NL80211_RRF_NO_HT40 (NL80211_RRF_NO_HT40MINUS|NL80211_RRF_NO_HT40PLUS)
+
+enum nl80211_scan_flags {
+ NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME = BIT(0),
+ NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION = BIT(1),
+ NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE = BIT(2),
+ NL80211_SCAN_FLAG_RANDOM_ADDR = BIT(3),
+ NL80211_SCAN_FLAG_COLOCATED_6GHZ = BIT(4),
+ NL80211_SCAN_FLAG_RANDOM_SN = BIT(5),
+ NL80211_SCAN_FLAG_ACCEPT_BCAST_PROBE_RESP = BIT(6),
+};
+
+#define NL80211_MAX_SUPP_REG_RULES 512 /* TODO FIXME, random */
+
+#define NL80211_BSS_CHAN_WIDTH_20 __LINE__ /* TODO FIXME, brcmfmac */
+
+enum nl80211_wpa_versions {
+ NL80211_WPA_VERSION_1 = 1,
+ NL80211_WPA_VERSION_2,
+ NL80211_WPA_VERSION_3,
+};
+
+enum nl80211_bss_select_attr {
+ __NL80211_BSS_SELECT_ATTR_INVALID = 0,
+ NL80211_BSS_SELECT_ATTR_BAND_PREF,
+ NL80211_BSS_SELECT_ATTR_RSSI,
+ NL80211_BSS_SELECT_ATTR_RSSI_ADJUST,
+};
+
+enum nl80211_sta_flag {
+ /* XXX TODO */
+ NL80211_STA_FLAG_ASSOCIATED,
+ NL80211_STA_FLAG_AUTHENTICATED,
+ NL80211_STA_FLAG_AUTHORIZED,
+ NL80211_STA_FLAG_TDLS_PEER,
+ NL80211_STA_FLAG_WME,
+};
+
+enum nl80211_band {
+ /* XXX TODO */
+ NL80211_BAND_2GHZ = 0,
+ NL80211_BAND_5GHZ,
+ NL80211_BAND_60GHZ,
+ NL80211_BAND_6GHZ,
+
+ /* Keep this last. */
+ NUM_NL80211_BANDS
+} __packed;
+
+enum nl80211_channel_type {
+ NL80211_CHAN_NO_HT,
+ NL80211_CHAN_HT20,
+ NL80211_CHAN_HT40PLUS,
+ NL80211_CHAN_HT40MINUS,
+};
+
+enum nl80211_chan_width {
+ /* XXX TODO */
+ NL80211_CHAN_WIDTH_20_NOHT,
+ NL80211_CHAN_WIDTH_20,
+ NL80211_CHAN_WIDTH_40,
+ NL80211_CHAN_WIDTH_80,
+ NL80211_CHAN_WIDTH_80P80,
+ NL80211_CHAN_WIDTH_160,
+ NL80211_CHAN_WIDTH_5,
+ NL80211_CHAN_WIDTH_10,
+ NL80211_CHAN_WIDTH_320,
+};
+
+enum nl80211_iftype {
+ /* XXX TODO */
+ NL80211_IFTYPE_UNSPECIFIED,
+ NL80211_IFTYPE_ADHOC,
+ NL80211_IFTYPE_STATION,
+ NL80211_IFTYPE_AP,
+ NL80211_IFTYPE_AP_VLAN,
+ NL80211_IFTYPE_MONITOR,
+ NL80211_IFTYPE_P2P_CLIENT,
+ NL80211_IFTYPE_P2P_DEVICE,
+ NL80211_IFTYPE_P2P_GO,
+ NL80211_IFTYPE_MESH_POINT,
+ NL80211_IFTYPE_WDS,
+ NL80211_IFTYPE_OCB,
+ NL80211_IFTYPE_NAN,
+
+ /* Keep this last. */
+ NUM_NL80211_IFTYPES
+};
+
+enum nl80211_preamble {
+ /* XXX TODO */
+ NL80211_PREAMBLE_LEGACY,
+ NL80211_PREAMBLE_HT,
+ NL80211_PREAMBLE_VHT,
+ NL80211_PREAMBLE_HE,
+};
+
+enum nl80211_tdls_operation {
+ /* XXX TODO */
+ NL80211_TDLS_SETUP,
+ NL80211_TDLS_TEARDOWN,
+ NL80211_TDLS_ENABLE_LINK,
+ NL80211_TDLS_DISABLE_LINK,
+ NL80211_TDLS_DISCOVERY_REQ,
+};
+
+enum nl80211_cqm_rssi_threshold_event {
+ /* XXX TODO */
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
+ NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,
+};
+
+enum nl80211_ext_feature {
+ /* XXX TODO */
+ NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP,
+ NL80211_EXT_FEATURE_BSS_PARENT_TSF,
+ NL80211_EXT_FEATURE_CAN_REPLACE_PTK0,
+ NL80211_EXT_FEATURE_DFS_OFFLOAD,
+ NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER,
+ NL80211_EXT_FEATURE_EXT_KEY_ID,
+ NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME,
+ NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER,
+ NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION,
+ NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE,
+ NL80211_EXT_FEATURE_PROTECTED_TWT,
+ NL80211_EXT_FEATURE_SAE_OFFLOAD,
+ NL80211_EXT_FEATURE_SCAN_START_TIME,
+ NL80211_EXT_FEATURE_SET_SCAN_DWELL,
+ NL80211_EXT_FEATURE_VHT_IBSS,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK,
+ NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT,
+ NL80211_EXT_FEATURE_SCAN_RANDOM_SN,
+ NL80211_EXT_FEATURE_STA_TX_PWR,
+ NL80211_EXT_FEATURE_CQM_RSSI_LIST,
+ NL80211_EXT_FEATURE_AQL,
+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS,
+ NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT,
+ NL80211_EXT_FEATURE_BEACON_RATE_LEGACY,
+ NL80211_EXT_FEATURE_BEACON_RATE_HT,
+ NL80211_EXT_FEATURE_BEACON_RATE_VHT,
+ NL80211_EXT_FEATURE_BEACON_RATE_HE,
+ NL80211_EXT_FEATURE_BSS_COLOR,
+ NL80211_EXT_FEATURE_FILS_DISCOVERY,
+ NL80211_EXT_FEATURE_RADAR_BACKGROUND,
+ NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP,
+ NL80211_EXT_FEATURE_BEACON_PROTECTION,
+ NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT,
+ NL80211_EXT_FEATURE_PUNCT,
+ NL80211_EXT_FEATURE_DFS_CONCURRENT,
+ NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS,
+ NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT,
+ NL80211_EXT_FEATURE_SECURE_LTF,
+ NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
+ NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK,
+ NL80211_EXT_FEATURE_SAE_OFFLOAD_AP,
+
+ /* Keep this last. */
+ NUM_NL80211_EXT_FEATURES
+};
+
+/* Keep in order with lkpi_nl80211_sta_info_to_str() */
+enum nl80211_sta_info {
+ /* XXX TODO */
+ NL80211_STA_INFO_BEACON_RX,
+ NL80211_STA_INFO_BEACON_SIGNAL_AVG,
+ NL80211_STA_INFO_BSS_PARAM,
+ NL80211_STA_INFO_CHAIN_SIGNAL,
+ NL80211_STA_INFO_CHAIN_SIGNAL_AVG,
+ NL80211_STA_INFO_CONNECTED_TIME,
+ NL80211_STA_INFO_INACTIVE_TIME,
+ NL80211_STA_INFO_SIGNAL,
+ NL80211_STA_INFO_SIGNAL_AVG,
+ NL80211_STA_INFO_STA_FLAGS,
+ NL80211_STA_INFO_RX_BITRATE,
+ NL80211_STA_INFO_RX_PACKETS,
+ NL80211_STA_INFO_RX_BYTES,
+ NL80211_STA_INFO_RX_DROP_MISC,
+ NL80211_STA_INFO_TX_BITRATE,
+ NL80211_STA_INFO_TX_PACKETS,
+ NL80211_STA_INFO_TX_BYTES,
+ NL80211_STA_INFO_TX_BYTES64,
+ NL80211_STA_INFO_RX_BYTES64,
+ NL80211_STA_INFO_TX_FAILED,
+ NL80211_STA_INFO_TX_RETRIES,
+ NL80211_STA_INFO_RX_DURATION,
+ NL80211_STA_INFO_TX_DURATION,
+ NL80211_STA_INFO_ACK_SIGNAL,
+ NL80211_STA_INFO_ACK_SIGNAL_AVG,
+};
+
+enum nl80211_ftm_stats {
+ /* XXX TODO */
+ NL80211_FTM_STATS_ASAP_NUM,
+ NL80211_FTM_STATS_FAILED_NUM,
+ NL80211_FTM_STATS_NON_ASAP_NUM,
+ NL80211_FTM_STATS_OUT_OF_WINDOW_TRIGGERS_NUM,
+ NL80211_FTM_STATS_PARTIAL_NUM,
+ NL80211_FTM_STATS_RESCHEDULE_REQUESTS_NUM,
+ NL80211_FTM_STATS_SUCCESS_NUM,
+ NL80211_FTM_STATS_TOTAL_DURATION_MSEC,
+ NL80211_FTM_STATS_UNKNOWN_TRIGGERS_NUM,
+};
+
+enum nl80211_reg_initiator {
+ /* XXX TODO */
+ NL80211_REGDOM_SET_BY_USER,
+ NL80211_REGDOM_SET_BY_DRIVER,
+ NL80211_REGDOM_SET_BY_CORE,
+ NL80211_REGDOM_SET_BY_COUNTRY_IE,
+};
+
+struct nl80211_sta_flag_update {
+ /* XXX TODO */
+ int mask, set;
+
+};
+
+enum nl80211_tx_power_setting {
+ /* XXX TODO */
+ NL80211_TX_POWER_AUTOMATIC,
+ NL80211_TX_POWER_FIXED,
+ NL80211_TX_POWER_LIMITED,
+};
+
+enum nl80211_crit_proto_id {
+ /* XXX TODO */
+ NL80211_CRIT_PROTO_DHCP,
+};
+
+enum nl80211_auth_type {
+ NL80211_AUTHTYPE_AUTOMATIC,
+ NL80211_AUTHTYPE_OPEN_SYSTEM,
+ NL80211_AUTHTYPE_SHARED_KEY,
+ NL80211_AUTHTYPE_SAE,
+};
+
+enum nl80211_key_type {
+ NL80211_KEYTYPE_GROUP,
+ NL80211_KEYTYPE_PAIRWISE,
+};
+
+enum nl80211_he_ru_alloc {
+ NL80211_RATE_INFO_HE_RU_ALLOC_26,
+ NL80211_RATE_INFO_HE_RU_ALLOC_52,
+ NL80211_RATE_INFO_HE_RU_ALLOC_106,
+ NL80211_RATE_INFO_HE_RU_ALLOC_242,
+ NL80211_RATE_INFO_HE_RU_ALLOC_484,
+ NL80211_RATE_INFO_HE_RU_ALLOC_996,
+ NL80211_RATE_INFO_HE_RU_ALLOC_2x996,
+};
+
+enum nl80211_he_gi {
+ NL80211_RATE_INFO_HE_GI_0_8,
+ NL80211_RATE_INFO_HE_GI_1_6,
+ NL80211_RATE_INFO_HE_GI_3_2,
+};
+
+enum nl80211_he_ltf {
+ NL80211_RATE_INFO_HE_1XLTF,
+ NL80211_RATE_INFO_HE_2XLTF,
+ NL80211_RATE_INFO_HE_4XLTF,
+};
+
+enum nl80211_eht_gi {
+ NL80211_RATE_INFO_EHT_GI_0_8,
+ NL80211_RATE_INFO_EHT_GI_1_6,
+ NL80211_RATE_INFO_EHT_GI_3_2,
+};
+
+enum nl80211_eht_ru_alloc {
+ NL80211_RATE_INFO_EHT_RU_ALLOC_26,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_52,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_52P26,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_106,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_106P26,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_242,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_484P242,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_996,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_996P484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_2x996,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_2x996P484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_3x996,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_3x996P484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_4x996,
+};
+
+enum nl80211_dfs_regions {
+ NL80211_DFS_UNSET,
+ NL80211_DFS_FCC,
+ NL80211_DFS_ETSI,
+ NL80211_DFS_JP,
+};
+
+enum nl80211_dfs_state {
+ NL80211_DFS_USABLE,
+};
+
+enum nl80211_sar_type {
+ NL80211_SAR_TYPE_POWER,
+};
+
+#define NL80211_VHT_NSS_MAX 8
+#define NL80211_HE_NSS_MAX 8
+
+enum nl80211_tid_cfg_attr {
+ NL80211_TID_CONFIG_ATTR_NOACK,
+ NL80211_TID_CONFIG_ATTR_RETRY_SHORT,
+ NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE,
+ NL80211_TID_CONFIG_ATTR_TX_RATE,
+ NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL,
+ NL80211_TID_CONFIG_ATTR_RETRY_LONG,
+ NL80211_TID_CONFIG_ATTR_AMPDU_CTRL,
+ NL80211_TID_CONFIG_ATTR_AMSDU_CTRL,
+};
+
+enum nl80211_tid_config {
+ NL80211_TID_CONFIG_ENABLE,
+};
+
+enum nl80211_tx_rate_setting {
+ NL80211_TX_RATE_AUTOMATIC,
+ NL80211_TX_RATE_FIXED,
+ NL80211_TX_RATE_LIMITED,
+};
+
+enum nl80211_txrate_gi {
+ NL80211_TXRATE_DEFAULT_GI,
+ NL80211_TXRATE_FORCE_SGI,
+ NL80211_TXRATE_FORCE_LGI,
+};
+
+enum nl80211_probe_resp_offload_support {
+ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2,
+ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS,
+ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P,
+};
+
+enum nl80211_user_reg_hint_type {
+ NL80211_USER_REG_HINT_USER,
+};
+
+enum nl80211_hidden_ssid {
+ NL80211_HIDDEN_SSID_NOT_IN_USE,
+};
+
+#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16
+#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
+
+#define NL80211_KCK_LEN 16
+#define NL80211_KCK_EXT_LEN 24
+#define NL80211_KEK_LEN 16
+#define NL80211_KEK_EXT_LEN 32
+#define NL80211_REPLAY_CTR_LEN 8
+#endif /* _LINUXKPI_LINUX_NL80211_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/nodemask.h b/sys/compat/linuxkpi/common/include/linux/nodemask.h
new file mode 100644
index 000000000000..7a245cc6f256
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/nodemask.h
@@ -0,0 +1,46 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Serenity Cyber Security, LLC.
+ *
+ * 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_NODEMASK_H_
+#define _LINUXKPI_LINUX_NODEMASK_H_
+
+#include <linux/kernel.h> /* pr_debug */
+
+static inline int
+num_online_nodes(void)
+{
+ return (1);
+}
+
+static inline int
+num_possible_nodes(void)
+{
+ pr_debug("%s: TODO\n", __func__);
+ return (1);
+}
+
+#endif /* _LINUXKPI_LINUX_NODEMASK_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/nospec.h b/sys/compat/linuxkpi/common/include/linux/nospec.h
new file mode 100644
index 000000000000..e8458ae8b371
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/nospec.h
@@ -0,0 +1,8 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_NOSPEC_H_
+#define _LINUXKPI_LINUX_NOSPEC_H_
+
+#define array_index_nospec(a, b) (a)
+
+#endif /* _LINUXKPILINUX_NOSPEC_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/notifier.h b/sys/compat/linuxkpi/common/include/linux/notifier.h
new file mode 100644
index 000000000000..9302a1ce4606
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/notifier.h
@@ -0,0 +1,58 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_NOTIFIER_H_
+#define _LINUXKPI_LINUX_NOTIFIER_H_
+
+#include <sys/types.h>
+#include <sys/eventhandler.h>
+
+#define NOTIFY_DONE 0
+#define NOTIFY_OK 0x0001
+#define NOTIFY_STOP_MASK 0x8000
+#define NOTIFY_BAD (NOTIFY_STOP_MASK | 0x0002)
+
+enum {
+ NETDEV_CHANGE,
+ NETDEV_UP,
+ NETDEV_DOWN,
+ NETDEV_REGISTER,
+ NETDEV_UNREGISTER,
+ NETDEV_CHANGEADDR,
+ NETDEV_CHANGEIFADDR,
+ LINUX_NOTIFY_TAGS /* must be last */
+};
+
+struct notifier_block {
+ int (*notifier_call) (struct notifier_block *, unsigned long, void *);
+ struct notifier_block *next;
+ int priority;
+ eventhandler_tag tags[LINUX_NOTIFY_TAGS];
+};
+
+#endif /* _LINUXKPI_LINUX_NOTIFIER_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/numa.h b/sys/compat/linuxkpi/common/include/linux/numa.h
new file mode 100644
index 000000000000..6b227e177a64
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/numa.h
@@ -0,0 +1,34 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot 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_NUMA_H_
+#define _LINUXKPI_LINUX_NUMA_H_
+
+#define NUMA_NO_NODE -1
+
+#endif /* _LINUXKPI_LINUX_NUMA_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/of.h b/sys/compat/linuxkpi/common/include/linux/of.h
new file mode 100644
index 000000000000..fb4554a8ddbc
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/of.h
@@ -0,0 +1,33 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Serenity Cyber Security, LLC.
+ *
+ * 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_OF_H
+#define _LINUXKPI_LINUX_OF_H
+
+#include <linux/kobject.h>
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/overflow.h b/sys/compat/linuxkpi/common/include/linux/overflow.h
new file mode 100644
index 000000000000..9ba9b9500f11
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/overflow.h
@@ -0,0 +1,349 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+#ifndef _LINUXKPI_LINUX_OVERFLOW_H
+#define _LINUXKPI_LINUX_OVERFLOW_H
+
+#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
+ * type. These macros may also be useful elsewhere. It would seem more obvious
+ * to do something like:
+ *
+ * #define type_min(T) (T)(is_signed_type(T) ? (T)1 << (8*sizeof(T)-1) : 0)
+ * #define type_max(T) (T)(is_signed_type(T) ? ((T)1 << (8*sizeof(T)-1)) - 1 : ~(T)0)
+ *
+ * Unfortunately, the middle expressions, strictly speaking, have
+ * undefined behaviour, and at least some versions of gcc warn about
+ * the type_max expression (but not if -fsanitize=undefined is in
+ * effect; in that case, the warning is deferred to runtime...).
+ *
+ * The slightly excessive casting in type_min is to make sure the
+ * macros also produce sensible values for the exotic type _Bool. [The
+ * overflow checkers only almost work for _Bool, but that's
+ * a-feature-not-a-bug, since people shouldn't be doing arithmetic on
+ * _Bools. Besides, the gcc builtins don't allow _Bool* as third
+ * argument.]
+ *
+ * Idea stolen from
+ * https://mail-index.netbsd.org/tech-misc/2007/02/05/0000.html -
+ * credit to Christian Biere.
+ */
+#define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type)))
+#define type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T)))
+#define type_min(T) ((T)((T)-type_max(T)-(T)1))
+
+/*
+ * 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)
+{
+ return unlikely(overflow);
+}
+
+/**
+ * check_add_overflow() - Calculate addition with overflow checking
+ * @a: first addend
+ * @b: second addend
+ * @d: pointer to store sum
+ *
+ * Returns 0 on success.
+ *
+ * *@d holds the results of the attempted addition, but is not considered
+ * "safe for use" on a non-zero return value, which indicates that the
+ * sum has overflowed or been truncated.
+ */
+#define check_add_overflow(a, b, d) \
+ __must_check_overflow(__builtin_add_overflow(a, b, d))
+
+/**
+ * check_sub_overflow() - Calculate subtraction with overflow checking
+ * @a: minuend; value to subtract from
+ * @b: subtrahend; value to subtract from @a
+ * @d: pointer to store difference
+ *
+ * Returns 0 on success.
+ *
+ * *@d holds the results of the attempted subtraction, but is not considered
+ * "safe for use" on a non-zero return value, which indicates that the
+ * difference has underflowed or been truncated.
+ */
+#define check_sub_overflow(a, b, d) \
+ __must_check_overflow(__builtin_sub_overflow(a, b, d))
+
+/**
+ * check_mul_overflow() - Calculate multiplication with overflow checking
+ * @a: first factor
+ * @b: second factor
+ * @d: pointer to store product
+ *
+ * Returns 0 on success.
+ *
+ * *@d holds the results of the attempted multiplication, but is not
+ * considered "safe for use" on a non-zero return value, which indicates
+ * that the product has overflowed or been truncated.
+ */
+#define check_mul_overflow(a, b, d) \
+ __must_check_overflow(__builtin_mul_overflow(a, b, d))
+
+/**
+ * check_shl_overflow() - Calculate a left-shifted value and check overflow
+ * @a: Value to be shifted
+ * @s: How many bits left to shift
+ * @d: Pointer to where to store the result
+ *
+ * Computes *@d = (@a << @s)
+ *
+ * Returns true if '*@d' cannot hold the result or when '@a << @s' doesn't
+ * make sense. Example conditions:
+ *
+ * - '@a << @s' causes bits to be lost when stored in *@d.
+ * - '@s' is garbage (e.g. negative) or so large that the result of
+ * '@a << @s' is guaranteed to be 0.
+ * - '@a' is negative.
+ * - '@a << @s' sets the sign bit, if any, in '*@d'.
+ *
+ * '*@d' will hold the results of the attempted shift, but is not
+ * considered "safe for use" if true is returned.
+ */
+#define check_shl_overflow(a, s, d) __must_check_overflow(({ \
+ typeof(a) _a = a; \
+ typeof(s) _s = s; \
+ typeof(d) _d = d; \
+ u64 _a_full = _a; \
+ unsigned int _to_shift = \
+ is_non_negative(_s) && _s < 8 * sizeof(*d) ? _s : 0; \
+ *_d = (_a_full << _to_shift); \
+ (_to_shift != _s || is_negative(*_d) || is_negative(_a) || \
+ (*_d >> _to_shift) != _a); \
+}))
+
+#define __overflows_type_constexpr(x, T) ( \
+ is_unsigned_type(typeof(x)) ? \
+ (x) > type_max(typeof(T)) : \
+ is_unsigned_type(typeof(T)) ? \
+ (x) < 0 || (x) > type_max(typeof(T)) : \
+ (x) < type_min(typeof(T)) || (x) > type_max(typeof(T)))
+
+#define __overflows_type(x, T) ({ \
+ typeof(T) v = 0; \
+ check_add_overflow((x), v, &v); \
+})
+
+/**
+ * overflows_type - helper for checking the overflows between value, variables,
+ * or data type
+ *
+ * @n: source constant value or variable to be checked
+ * @T: destination variable or data type proposed to store @x
+ *
+ * Compares the @x expression for whether or not it can safely fit in
+ * the storage of the type in @T. @x and @T can have different types.
+ * If @x is a constant expression, this will also resolve to a constant
+ * expression.
+ *
+ * Returns: true if overflow can occur, false otherwise.
+ */
+#define overflows_type(n, T) \
+ __builtin_choose_expr(__is_constexpr(n), \
+ __overflows_type_constexpr(n, T), \
+ __overflows_type(n, T))
+
+/**
+ * castable_to_type - like __same_type(), but also allows for casted literals
+ *
+ * @n: variable or constant value
+ * @T: variable or data type
+ *
+ * Unlike the __same_type() macro, this allows a constant value as the
+ * first argument. If this value would not overflow into an assignment
+ * of the second argument's type, it returns true. Otherwise, this falls
+ * back to __same_type().
+ */
+#define castable_to_type(n, T) \
+ __builtin_choose_expr(__is_constexpr(n), \
+ !__overflows_type_constexpr(n, T), \
+ __same_type(n, T))
+
+/**
+ * size_mul() - Calculate size_t multiplication with saturation at SIZE_MAX
+ * @factor1: first factor
+ * @factor2: second factor
+ *
+ * Returns: calculate @factor1 * @factor2, both promoted to size_t,
+ * 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)
+{
+ size_t bytes;
+
+ if (check_mul_overflow(factor1, factor2, &bytes))
+ return SIZE_MAX;
+
+ return bytes;
+}
+
+/**
+ * size_add() - Calculate size_t addition with saturation at SIZE_MAX
+ * @addend1: first addend
+ * @addend2: second addend
+ *
+ * Returns: calculate @addend1 + @addend2, both promoted to size_t,
+ * 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)
+{
+ size_t bytes;
+
+ if (check_add_overflow(addend1, addend2, &bytes))
+ return SIZE_MAX;
+
+ return bytes;
+}
+
+/**
+ * size_sub() - Calculate size_t subtraction with saturation at SIZE_MAX
+ * @minuend: value to subtract from
+ * @subtrahend: value to subtract from @minuend
+ *
+ * Returns: calculate @minuend - @subtrahend, both promoted to size_t,
+ * with any overflow causing the return value to be SIZE_MAX. For
+ * composition with the size_add() and size_mul() helpers, neither
+ * 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)
+{
+ size_t bytes;
+
+ if (minuend == SIZE_MAX || subtrahend == SIZE_MAX ||
+ check_sub_overflow(minuend, subtrahend, &bytes))
+ return SIZE_MAX;
+
+ return bytes;
+}
+
+/**
+ * array_size() - Calculate size of 2-dimensional array.
+ * @a: dimension one
+ * @b: dimension two
+ *
+ * Calculates size of 2-dimensional array: @a * @b.
+ *
+ * Returns: number of bytes needed to represent the array or SIZE_MAX on
+ * overflow.
+ */
+#define array_size(a, b) size_mul(a, b)
+
+/**
+ * array3_size() - Calculate size of 3-dimensional array.
+ * @a: dimension one
+ * @b: dimension two
+ * @c: dimension three
+ *
+ * Calculates size of 3-dimensional array: @a * @b * @c.
+ *
+ * Returns: number of bytes needed to represent the array or SIZE_MAX on
+ * overflow.
+ */
+#define array3_size(a, b, c) size_mul(size_mul(a, b), c)
+
+/**
+ * flex_array_size() - Calculate size of a flexible array member
+ * within an enclosing structure.
+ * @p: Pointer to the structure.
+ * @member: Name of the flexible array member.
+ * @count: Number of elements in the array.
+ *
+ * Calculates size of a flexible array of @count number of @member
+ * elements, at the end of structure @p.
+ *
+ * Return: number of bytes needed or SIZE_MAX on overflow.
+ */
+#define flex_array_size(p, member, count) \
+ __builtin_choose_expr(__is_constexpr(count), \
+ (count) * sizeof(*(p)->member) + __must_be_array((p)->member), \
+ size_mul(count, sizeof(*(p)->member) + __must_be_array((p)->member)))
+
+/**
+ * struct_size() - Calculate size of structure with trailing flexible array.
+ * @p: Pointer to the structure.
+ * @member: Name of the array member.
+ * @count: Number of elements in the array.
+ *
+ * Calculates size of memory needed for structure of @p followed by an
+ * array of @count number of @member elements.
+ *
+ * Return: number of bytes needed or SIZE_MAX on overflow.
+ */
+#define struct_size(p, member, count) \
+ __builtin_choose_expr(__is_constexpr(count), \
+ sizeof(*(p)) + flex_array_size(p, member, count), \
+ size_add(sizeof(*(p)), flex_array_size(p, member, count)))
+
+/**
+ * struct_size_t() - Calculate size of structure with trailing flexible array
+ * @type: structure type name.
+ * @member: Name of the array member.
+ * @count: Number of elements in the array.
+ *
+ * Calculates size of memory needed for structure @type followed by an
+ * array of @count number of @member elements. Prefer using struct_size()
+ * when possible instead, to keep calculations associated with a specific
+ * instance variable of type @type.
+ *
+ * Return: number of bytes needed or SIZE_MAX on overflow.
+ */
+#define struct_size_t(type, member, count) \
+ struct_size((type *)NULL, member, count)
+
+/**
+ * _DEFINE_FLEX() - helper macro for DEFINE_FLEX() family.
+ * Enables caller macro to pass (different) initializer.
+ *
+ * @type: structure type name, including "struct" keyword.
+ * @name: Name for a variable to define.
+ * @member: Name of the array member.
+ * @count: Number of elements in the array; must be compile-time const.
+ * @initializer: initializer expression (could be empty for no init).
+ */
+#define _DEFINE_FLEX(type, name, member, count, initializer) \
+ _Static_assert(__builtin_constant_p(count), \
+ "onstack flex array members require compile-time const count"); \
+ union { \
+ u8 bytes[struct_size_t(type, member, count)]; \
+ type obj; \
+ } name##_u initializer; \
+ type *name = (type *)&name##_u
+
+/**
+ * DEFINE_FLEX() - Define an on-stack instance of structure with a trailing
+ * flexible array member.
+ *
+ * @type: structure type name, including "struct" keyword.
+ * @name: Name for a variable to define.
+ * @member: Name of the array member.
+ * @count: Number of elements in the array; must be compile-time const.
+ *
+ * Define a zeroed, on-stack, instance of @type structure with a trailing
+ * flexible array member.
+ * Use __struct_size(@name) to get compile-time size of it afterwards.
+ */
+#define DEFINE_FLEX(type, name, member, count) \
+ _DEFINE_FLEX(type, name, member, count, = {})
+
+#endif /* _LINUXKPI_LINUX_OVERFLOW_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/page-flags.h b/sys/compat/linuxkpi/common/include/linux/page-flags.h
new file mode 100644
index 000000000000..a22b3a24c330
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/page-flags.h
@@ -0,0 +1,41 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
+ *
+ * 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_PAGEFLAGS_H_
+#define _LINUXKPI_LINUX_PAGEFLAGS_H_
+
+#include <linux/mm_types.h>
+
+#define PageHighMem(p) (0)
+
+#define page_folio(p) \
+ (_Generic((p), \
+ const struct page *: (const struct folio *)(p), \
+ struct page *: (struct folio *)(p)))
+
+#endif /* _LINUXKPI_LINUX_PAGEFLAGS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/page.h b/sys/compat/linuxkpi/common/include/linux/page.h
new file mode 100644
index 000000000000..37ab593a64e9
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/page.h
@@ -0,0 +1,130 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_PAGE_H_
+#define _LINUXKPI_LINUX_PAGE_H_
+
+#include <linux/types.h>
+
+#include <sys/param.h>
+#include <sys/vmmeter.h>
+
+#include <machine/atomic.h>
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/pmap.h>
+
+#if defined(__i386__) || defined(__amd64__)
+#include <machine/md_var.h>
+#endif
+
+typedef unsigned long linux_pte_t;
+typedef unsigned long linux_pmd_t;
+typedef unsigned long linux_pgd_t;
+typedef unsigned long pgprot_t;
+
+#define page vm_page
+
+#define LINUXKPI_PROT_VALID (1 << 3)
+#define LINUXKPI_CACHE_MODE_SHIFT 4
+
+CTASSERT((VM_PROT_ALL & -LINUXKPI_PROT_VALID) == 0);
+
+#define PAGE_KERNEL_IO 0x0000
+
+static inline pgprot_t
+cachemode2protval(vm_memattr_t attr)
+{
+ return ((attr << LINUXKPI_CACHE_MODE_SHIFT) | LINUXKPI_PROT_VALID);
+}
+
+static inline vm_memattr_t
+pgprot2cachemode(pgprot_t prot)
+{
+ if (prot & LINUXKPI_PROT_VALID)
+ return (prot >> LINUXKPI_CACHE_MODE_SHIFT);
+ else
+ return (VM_MEMATTR_DEFAULT);
+}
+
+#define page_to_virt(page) linux_page_address(page)
+#define virt_to_page(x) PHYS_TO_VM_PAGE(vtophys(x))
+#define page_to_pfn(pp) (VM_PAGE_TO_PHYS(pp) >> PAGE_SHIFT)
+#define pfn_to_page(pfn) (PHYS_TO_VM_PAGE((pfn) << PAGE_SHIFT))
+#define nth_page(page,n) pfn_to_page(page_to_pfn(page) + (n))
+#define page_to_phys(page) VM_PAGE_TO_PHYS(page)
+
+#define clear_page(page) memset(page, 0, PAGE_SIZE)
+#define pgprot_noncached(prot) \
+ (((prot) & VM_PROT_ALL) | cachemode2protval(VM_MEMATTR_UNCACHEABLE))
+#ifdef VM_MEMATTR_WRITE_COMBINING
+#define pgprot_writecombine(prot) \
+ (((prot) & VM_PROT_ALL) | cachemode2protval(VM_MEMATTR_WRITE_COMBINING))
+#else
+#define pgprot_writecombine(prot) pgprot_noncached(prot)
+#endif
+
+#undef PAGE_MASK
+#define PAGE_MASK (~(PAGE_SIZE-1))
+/*
+ * Modifying PAGE_MASK in the above way breaks trunc_page, round_page,
+ * and btoc macros. Therefore, redefine them in a way that makes sense
+ * so the LinuxKPI consumers don't get totally broken behavior.
+ */
+#undef btoc
+#define btoc(x) (((vm_offset_t)(x) + PAGE_SIZE - 1) >> PAGE_SHIFT)
+#undef round_page
+#define round_page(x) ((((uintptr_t)(x)) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
+#undef trunc_page
+#define trunc_page(x) ((uintptr_t)(x) & ~(PAGE_SIZE - 1))
+
+#if defined(__i386__) || defined(__amd64__)
+#undef clflush
+#undef clflushopt
+static inline void
+lkpi_clflushopt(unsigned long addr)
+{
+ if (cpu_stdext_feature & CPUID_STDEXT_CLFLUSHOPT)
+ clflushopt(addr);
+ else if (cpu_feature & CPUID_CLFSH)
+ clflush(addr);
+ else
+ pmap_invalidate_cache();
+}
+#define clflush(x) clflush((unsigned long)(x))
+#define clflushopt(x) lkpi_clflushopt((unsigned long)(x))
+
+static inline void
+clflush_cache_range(void *addr, unsigned int size)
+{
+ pmap_force_invalidate_cache_range((vm_offset_t)addr,
+ (vm_offset_t)addr + size);
+}
+#endif
+
+#endif /* _LINUXKPI_LINUX_PAGE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/pagemap.h b/sys/compat/linuxkpi/common/include/linux/pagemap.h
new file mode 100644
index 000000000000..cb6a1820ea8b
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/pagemap.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot 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_PAGEMAP_H_
+#define _LINUXKPI_LINUX_PAGEMAP_H_
+
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/vmalloc.h>
+
+struct folio_batch;
+
+#define invalidate_mapping_pages(...) \
+ linux_invalidate_mapping_pages(__VA_ARGS__)
+
+unsigned long linux_invalidate_mapping_pages(vm_object_t obj, pgoff_t start,
+ pgoff_t end);
+
+static inline void
+mapping_clear_unevictable(vm_object_t mapping)
+{
+}
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/pagevec.h b/sys/compat/linuxkpi/common/include/linux/pagevec.h
new file mode 100644
index 000000000000..0a952e965b5a
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/pagevec.h
@@ -0,0 +1,137 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_PAGEVEC_H_
+#define _LINUXKPI_LINUX_PAGEVEC_H_
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+
+#include <linux/pagemap.h>
+
+#define PAGEVEC_SIZE 15
+
+struct pagevec {
+ uint8_t nr;
+ struct page *pages[PAGEVEC_SIZE];
+};
+
+static inline unsigned int
+pagevec_space(struct pagevec *pvec)
+{
+ return PAGEVEC_SIZE - pvec->nr;
+}
+
+static inline void
+pagevec_init(struct pagevec *pvec)
+{
+ pvec->nr = 0;
+}
+
+static inline void
+pagevec_reinit(struct pagevec *pvec)
+{
+ pvec->nr = 0;
+}
+
+static inline unsigned int
+pagevec_count(struct pagevec *pvec)
+{
+ return pvec->nr;
+}
+
+static inline unsigned int
+pagevec_add(struct pagevec *pvec, struct page *page)
+{
+ pvec->pages[pvec->nr++] = page;
+ return PAGEVEC_SIZE - pvec->nr;
+}
+
+static inline void
+__pagevec_release(struct pagevec *pvec)
+{
+ release_pages(pvec->pages, pagevec_count(pvec));
+ pagevec_reinit(pvec);
+}
+
+static inline void
+pagevec_release(struct pagevec *pvec)
+{
+ if (pagevec_count(pvec))
+ __pagevec_release(pvec);
+}
+
+static inline void
+check_move_unevictable_pages(struct pagevec *pvec)
+{
+}
+
+/*
+ * struct folio
+ *
+ * On Linux, `struct folio` replaces `struct page`. To manage a list of folios,
+ * there is `struct folio_batch` on top of this, which replaces `struct
+ * pagevec` above.
+ *
+ * Here is the original description when `struct folio` was added to the Linux
+ * kernel:
+ * "A struct folio is a new abstraction to replace the venerable struct page.
+ * A function which takes a struct folio argument declares that it will
+ * operate on the entire (possibly compound) page, not just PAGE_SIZE bytes.
+ * In return, the caller guarantees that the pointer it is passing does not
+ * point to a tail page. No change to generated code."
+ */
+
+struct folio;
+
+struct folio_batch {
+ uint8_t nr;
+ struct folio *folios[PAGEVEC_SIZE];
+};
+
+static inline void
+folio_batch_init(struct folio_batch *fbatch)
+{
+ fbatch->nr = 0;
+}
+
+static inline void
+folio_batch_reinit(struct folio_batch *fbatch)
+{
+ fbatch->nr = 0;
+}
+
+static inline unsigned int
+folio_batch_count(struct folio_batch *fbatch)
+{
+ return (fbatch->nr);
+}
+
+static inline unsigned int
+folio_batch_space(struct folio_batch *fbatch)
+{
+ return (PAGEVEC_SIZE - fbatch->nr);
+}
+
+static inline unsigned int
+folio_batch_add(struct folio_batch *fbatch, struct folio *folio)
+{
+ KASSERT(
+ fbatch->nr < PAGEVEC_SIZE,
+ ("struct folio_batch %p is full", fbatch));
+
+ fbatch->folios[fbatch->nr++] = folio;
+
+ return (folio_batch_space(fbatch));
+}
+
+void __folio_batch_release(struct folio_batch *fbatch);
+
+static inline void
+folio_batch_release(struct folio_batch *fbatch)
+{
+ if (folio_batch_count(fbatch))
+ __folio_batch_release(fbatch);
+}
+
+#endif /* _LINUXKPI_LINUX_PAGEVEC_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/pci.h b/sys/compat/linuxkpi/common/include/linux/pci.h
new file mode 100644
index 000000000000..af19829f1cbb
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/pci.h
@@ -0,0 +1,1537 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ * Copyright (c) 2020-2022 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * 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 unmodified, 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 ``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 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_PCI_H_
+#define _LINUXKPI_LINUX_PCI_H_
+
+#define CONFIG_PCI_MSI
+
+#include <linux/types.h>
+#include <linux/device/driver.h>
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/nv.h>
+#include <sys/pciio.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pci_private.h>
+
+#include <machine/resource.h>
+
+#include <linux/list.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <asm/atomic.h>
+#include <asm/memtype.h>
+#include <linux/device.h>
+#include <linux/pci_ids.h>
+#include <linux/pm.h>
+
+#include <linux/kernel.h> /* pr_debug */
+
+struct pci_device_id {
+ uint32_t vendor;
+ uint32_t device;
+ uint32_t subvendor;
+ uint32_t subdevice;
+ uint32_t class;
+ uint32_t class_mask;
+ uintptr_t driver_data;
+};
+
+#define MODULE_DEVICE_TABLE_BUS_pci(_bus, _table) \
+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))
+#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
+#define PCI_FUNC(devfn) ((devfn) & 0x07)
+#define PCI_BUS_NUM(devfn) (((devfn) >> 8) & 0xff)
+#define PCI_DEVID(bus, devfn) ((((uint16_t)(bus)) << 8) | (devfn))
+
+#define PCI_VDEVICE(_vendor, _device) \
+ .vendor = PCI_VENDOR_ID_##_vendor, .device = (_device), \
+ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
+#define PCI_DEVICE(_vendor, _device) \
+ .vendor = (_vendor), .device = (_device), \
+ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
+
+#define to_pci_dev(n) container_of(n, struct pci_dev, dev)
+
+#define PCI_STD_NUM_BARS 6
+#define PCI_BASE_ADDRESS_0 PCIR_BARS
+#define PCI_BASE_ADDRESS_MEM_TYPE_64 PCIM_BAR_MEM_64
+#define PCI_VENDOR_ID PCIR_VENDOR
+#define PCI_DEVICE_ID PCIR_DEVICE
+#define PCI_COMMAND PCIR_COMMAND
+#define PCI_COMMAND_INTX_DISABLE PCIM_CMD_INTxDIS
+#define PCI_COMMAND_MEMORY PCIM_CMD_MEMEN
+#define PCI_PRIMARY_BUS PCIR_PRIBUS_1
+#define PCI_SECONDARY_BUS PCIR_SECBUS_1
+#define PCI_SUBORDINATE_BUS PCIR_SUBBUS_1
+#define PCI_SEC_LATENCY_TIMER PCIR_SECLAT_1
+#define PCI_EXP_DEVCTL PCIER_DEVICE_CTL /* Device Control */
+#define PCI_EXP_LNKCTL PCIER_LINK_CTL /* Link Control */
+#define PCI_EXP_LNKCTL_ASPM_L0S PCIEM_LINK_CTL_ASPMC_L0S
+#define PCI_EXP_LNKCTL_ASPM_L1 PCIEM_LINK_CTL_ASPMC_L1
+#define PCI_EXP_LNKCTL_ASPMC PCIEM_LINK_CTL_ASPMC
+#define PCI_EXP_LNKCTL_CLKREQ_EN PCIEM_LINK_CTL_ECPM /* Enable clock PM */
+#define PCI_EXP_LNKCTL_HAWD PCIEM_LINK_CTL_HAWD
+#define PCI_EXP_FLAGS_TYPE PCIEM_FLAGS_TYPE /* Device/Port type */
+#define PCI_EXP_DEVCAP PCIER_DEVICE_CAP /* Device capabilities */
+#define PCI_EXP_DEVSTA PCIER_DEVICE_STA /* Device Status */
+#define PCI_EXP_LNKCAP PCIER_LINK_CAP /* Link Capabilities */
+#define PCI_EXP_LNKSTA PCIER_LINK_STA /* Link Status */
+#define PCI_EXP_SLTCAP PCIER_SLOT_CAP /* Slot Capabilities */
+#define PCI_EXP_SLTCTL PCIER_SLOT_CTL /* Slot Control */
+#define PCI_EXP_SLTSTA PCIER_SLOT_STA /* Slot Status */
+#define PCI_EXP_RTCTL PCIER_ROOT_CTL /* Root Control */
+#define PCI_EXP_RTCAP PCIER_ROOT_CAP /* Root Capabilities */
+#define PCI_EXP_RTSTA PCIER_ROOT_STA /* Root Status */
+#define PCI_EXP_DEVCAP2 PCIER_DEVICE_CAP2 /* Device Capabilities 2 */
+#define PCI_EXP_DEVCTL2 PCIER_DEVICE_CTL2 /* Device Control 2 */
+#define PCI_EXP_DEVCTL2_LTR_EN PCIEM_CTL2_LTR_ENABLE
+#define PCI_EXP_DEVCTL2_COMP_TMOUT_DIS PCIEM_CTL2_COMP_TIMO_DISABLE
+#define PCI_EXP_LNKCAP2 PCIER_LINK_CAP2 /* Link Capabilities 2 */
+#define PCI_EXP_LNKCTL2 PCIER_LINK_CTL2 /* Link Control 2 */
+#define PCI_EXP_LNKSTA2 PCIER_LINK_STA2 /* Link Status 2 */
+#define PCI_EXP_FLAGS PCIER_FLAGS /* Capabilities register */
+#define PCI_EXP_FLAGS_VERS PCIEM_FLAGS_VERSION /* Capability version */
+#define PCI_EXP_TYPE_ROOT_PORT PCIEM_TYPE_ROOT_PORT /* Root Port */
+#define PCI_EXP_TYPE_ENDPOINT PCIEM_TYPE_ENDPOINT /* Express Endpoint */
+#define PCI_EXP_TYPE_LEG_END PCIEM_TYPE_LEGACY_ENDPOINT /* Legacy Endpoint */
+#define PCI_EXP_TYPE_DOWNSTREAM PCIEM_TYPE_DOWNSTREAM_PORT /* Downstream Port */
+#define PCI_EXP_FLAGS_SLOT PCIEM_FLAGS_SLOT /* Slot implemented */
+#define PCI_EXP_TYPE_RC_EC PCIEM_TYPE_ROOT_EC /* Root Complex Event Collector */
+#define PCI_EXP_LNKSTA_CLS PCIEM_LINK_STA_SPEED
+#define PCI_EXP_LNKSTA_CLS_8_0GB 0x0003 /* Current Link Speed 8.0GT/s */
+#define PCI_EXP_LNKCAP_SLS_2_5GB 0x01 /* Supported Link Speed 2.5GT/s */
+#define PCI_EXP_LNKCAP_SLS_5_0GB 0x02 /* Supported Link Speed 5.0GT/s */
+#define PCI_EXP_LNKCAP_SLS_8_0GB 0x03 /* Supported Link Speed 8.0GT/s */
+#define PCI_EXP_LNKCAP_SLS_16_0GB 0x04 /* Supported Link Speed 16.0GT/s */
+#define PCI_EXP_LNKCAP_SLS_32_0GB 0x05 /* Supported Link Speed 32.0GT/s */
+#define PCI_EXP_LNKCAP_SLS_64_0GB 0x06 /* Supported Link Speed 64.0GT/s */
+#define PCI_EXP_LNKCAP_MLW 0x03f0 /* Maximum Link Width */
+#define PCI_EXP_LNKCAP2_SLS_2_5GB 0x02 /* Supported Link Speed 2.5GT/s */
+#define PCI_EXP_LNKCAP2_SLS_5_0GB 0x04 /* Supported Link Speed 5.0GT/s */
+#define PCI_EXP_LNKCAP2_SLS_8_0GB 0x08 /* Supported Link Speed 8.0GT/s */
+#define PCI_EXP_LNKCAP2_SLS_16_0GB 0x10 /* Supported Link Speed 16.0GT/s */
+#define PCI_EXP_LNKCAP2_SLS_32_0GB 0x20 /* Supported Link Speed 32.0GT/s */
+#define PCI_EXP_LNKCAP2_SLS_64_0GB 0x40 /* Supported Link Speed 64.0GT/s */
+#define PCI_EXP_LNKCTL2_TLS 0x000f
+#define PCI_EXP_LNKCTL2_TLS_2_5GT 0x0001 /* Supported Speed 2.5GT/s */
+#define PCI_EXP_LNKCTL2_TLS_5_0GT 0x0002 /* Supported Speed 5GT/s */
+#define PCI_EXP_LNKCTL2_TLS_8_0GT 0x0003 /* Supported Speed 8GT/s */
+#define PCI_EXP_LNKCTL2_TLS_16_0GT 0x0004 /* Supported Speed 16GT/s */
+#define PCI_EXP_LNKCTL2_TLS_32_0GT 0x0005 /* Supported Speed 32GT/s */
+#define PCI_EXP_LNKCTL2_TLS_64_0GT 0x0006 /* Supported Speed 64GT/s */
+#define PCI_EXP_LNKCTL2_ENTER_COMP 0x0010 /* Enter Compliance */
+#define PCI_EXP_LNKCTL2_TX_MARGIN 0x0380 /* Transmit Margin */
+
+#define PCI_MSI_ADDRESS_LO PCIR_MSI_ADDR
+#define PCI_MSI_ADDRESS_HI PCIR_MSI_ADDR_HIGH
+#define PCI_MSI_FLAGS PCIR_MSI_CTRL
+#define PCI_MSI_FLAGS_ENABLE PCIM_MSICTRL_MSI_ENABLE
+#define PCI_MSIX_FLAGS PCIR_MSIX_CTRL
+#define PCI_MSIX_FLAGS_ENABLE PCIM_MSIXCTRL_MSIX_ENABLE
+
+#define PCI_EXP_LNKCAP_CLKPM 0x00040000
+#define PCI_EXP_DEVSTA_TRPND 0x0020
+
+#define IORESOURCE_MEM (1 << SYS_RES_MEMORY)
+#define IORESOURCE_IO (1 << SYS_RES_IOPORT)
+#define IORESOURCE_IRQ (1 << SYS_RES_IRQ)
+
+enum pci_bus_speed {
+ PCI_SPEED_UNKNOWN = -1,
+ PCIE_SPEED_2_5GT,
+ PCIE_SPEED_5_0GT,
+ PCIE_SPEED_8_0GT,
+ PCIE_SPEED_16_0GT,
+ PCIE_SPEED_32_0GT,
+ PCIE_SPEED_64_0GT,
+};
+
+enum pcie_link_width {
+ PCIE_LNK_WIDTH_RESRV = 0x00,
+ PCIE_LNK_X1 = 0x01,
+ PCIE_LNK_X2 = 0x02,
+ PCIE_LNK_X4 = 0x04,
+ PCIE_LNK_X8 = 0x08,
+ PCIE_LNK_X12 = 0x0c,
+ PCIE_LNK_X16 = 0x10,
+ PCIE_LNK_X32 = 0x20,
+ PCIE_LNK_WIDTH_UNKNOWN = 0xff,
+};
+
+#define PCIE_LINK_STATE_L0S 0x00000001
+#define PCIE_LINK_STATE_L1 0x00000002
+#define PCIE_LINK_STATE_CLKPM 0x00000004
+
+typedef int pci_power_t;
+
+#define PCI_D0 PCI_POWERSTATE_D0
+#define PCI_D1 PCI_POWERSTATE_D1
+#define PCI_D2 PCI_POWERSTATE_D2
+#define PCI_D3hot PCI_POWERSTATE_D3
+#define PCI_D3cold 4
+
+#define PCI_POWER_ERROR PCI_POWERSTATE_UNKNOWN
+
+extern const char *pci_power_names[6];
+
+#define PCI_ERR_UNCOR_STATUS PCIR_AER_UC_STATUS
+#define PCI_ERR_COR_STATUS PCIR_AER_COR_STATUS
+#define PCI_ERR_ROOT_COMMAND PCIR_AER_ROOTERR_CMD
+#define PCI_ERR_ROOT_ERR_SRC PCIR_AER_COR_SOURCE_ID
+
+#define PCI_EXT_CAP_ID_ERR PCIZ_AER
+#define PCI_EXT_CAP_ID_L1SS PCIZ_L1PM
+
+#define PCI_L1SS_CTL1 0x8
+#define PCI_L1SS_CTL1_L1SS_MASK 0xf
+
+#define PCI_IRQ_INTX 0x01
+#define PCI_IRQ_MSI 0x02
+#define PCI_IRQ_MSIX 0x04
+#define PCI_IRQ_ALL_TYPES (PCI_IRQ_MSIX|PCI_IRQ_MSI|PCI_IRQ_INTX)
+
+#if defined(LINUXKPI_VERSION) && (LINUXKPI_VERSION <= 61000)
+#define PCI_IRQ_LEGACY PCI_IRQ_INTX
+#endif
+
+struct pci_dev;
+
+struct pci_driver {
+ struct list_head node;
+ char *name;
+ const struct pci_device_id *id_table;
+ int (*probe)(struct pci_dev *dev, const struct pci_device_id *id);
+ void (*remove)(struct pci_dev *dev);
+ int (*suspend) (struct pci_dev *dev, pm_message_t state); /* Device suspended */
+ int (*resume) (struct pci_dev *dev); /* Device woken up */
+ void (*shutdown) (struct pci_dev *dev); /* Device shutdown */
+ driver_t bsddriver;
+ devclass_t bsdclass;
+ struct device_driver driver;
+ const struct pci_error_handlers *err_handler;
+ bool isdrm;
+ int bsd_probe_return;
+ int (*bsd_iov_init)(device_t dev, uint16_t num_vfs,
+ const nvlist_t *pf_config);
+ void (*bsd_iov_uninit)(device_t dev);
+ int (*bsd_iov_add_vf)(device_t dev, uint16_t vfnum,
+ const nvlist_t *vf_config);
+};
+
+struct pci_bus {
+ struct pci_dev *self;
+ /* struct pci_bus *parent */
+ int domain;
+ int number;
+};
+
+extern struct list_head pci_drivers;
+extern struct list_head pci_devices;
+extern spinlock_t pci_lock;
+
+#define __devexit_p(x) x
+
+#define module_pci_driver(_drv) \
+ module_driver(_drv, linux_pci_register_driver, linux_pci_unregister_driver)
+
+struct msi_msg {
+ uint32_t data;
+};
+
+struct pci_msi_desc {
+ struct {
+ bool is_64;
+ } msi_attrib;
+};
+
+struct msi_desc {
+ struct msi_msg msg;
+ struct pci_msi_desc pci;
+};
+
+struct msix_entry {
+ int entry;
+ int vector;
+};
+
+/*
+ * If we find drivers accessing this from multiple KPIs we may have to
+ * refcount objects of this structure.
+ */
+struct resource;
+struct pci_mmio_region {
+ TAILQ_ENTRY(pci_mmio_region) next;
+ struct resource *res;
+ int rid;
+ int type;
+};
+
+struct pci_dev {
+ struct device dev;
+ struct list_head links;
+ struct pci_driver *pdrv;
+ struct pci_bus *bus;
+ struct pci_dev *root;
+ pci_power_t current_state;
+ uint16_t device;
+ uint16_t vendor;
+ uint16_t subsystem_vendor;
+ uint16_t subsystem_device;
+ unsigned int irq;
+ unsigned int devfn;
+ uint32_t class;
+ uint8_t revision;
+ uint8_t msi_cap;
+ uint8_t msix_cap;
+ bool managed; /* devres "pcim_*(). */
+ bool want_iomap_res;
+ bool msi_enabled;
+ bool msix_enabled;
+ phys_addr_t rom;
+ size_t romlen;
+ struct msi_desc **msi_desc;
+ char *path_name;
+ spinlock_t pcie_cap_lock;
+
+ TAILQ_HEAD(, pci_mmio_region) mmio;
+};
+
+int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name);
+int pci_alloc_irq_vectors(struct pci_dev *pdev, int minv, int maxv,
+ unsigned int flags);
+bool pci_device_is_present(struct pci_dev *pdev);
+
+int linuxkpi_pcim_enable_device(struct pci_dev *pdev);
+void __iomem **linuxkpi_pcim_iomap_table(struct pci_dev *pdev);
+void *linuxkpi_pci_iomap_range(struct pci_dev *pdev, int mmio_bar,
+ unsigned long mmio_off, unsigned long mmio_size);
+void *linuxkpi_pci_iomap(struct pci_dev *pdev, int mmio_bar, int mmio_size);
+void linuxkpi_pci_iounmap(struct pci_dev *pdev, void *res);
+int linuxkpi_pcim_iomap_regions(struct pci_dev *pdev, uint32_t mask,
+ const char *name);
+int linuxkpi_pci_request_regions(struct pci_dev *pdev, const char *res_name);
+void linuxkpi_pci_release_region(struct pci_dev *pdev, int bar);
+void linuxkpi_pci_release_regions(struct pci_dev *pdev);
+int linuxkpi_pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries,
+ int nreq);
+
+/* Internal helper function(s). */
+struct pci_dev *lkpinew_pci_dev(device_t);
+void lkpi_pci_devres_release(struct device *, void *);
+struct pci_dev *lkpi_pci_get_device(uint16_t, uint16_t, struct pci_dev *);
+struct msi_desc *lkpi_pci_msi_desc_alloc(int);
+struct device *lkpi_pci_find_irq_dev(unsigned int irq);
+int _lkpi_pci_enable_msi_range(struct pci_dev *pdev, int minvec, int maxvec);
+
+#define pci_err(pdev, fmt, ...) \
+ dev_err(&(pdev)->dev, fmt, ##__VA_ARGS__)
+#define pci_info(pdev, fmt, ...) \
+ dev_info(&(pdev)->dev, fmt, ##__VA_ARGS__)
+
+static inline bool
+dev_is_pci(struct device *dev)
+{
+
+ return (device_get_devclass(dev->bsddev) == devclass_find("pci"));
+}
+
+static inline uint16_t
+pci_dev_id(struct pci_dev *pdev)
+{
+ return (PCI_DEVID(pdev->bus->number, pdev->devfn));
+}
+
+static inline int
+pci_resource_type(struct pci_dev *pdev, int bar)
+{
+ struct pci_map *pm;
+
+ pm = pci_find_bar(pdev->dev.bsddev, PCIR_BAR(bar));
+ if (!pm)
+ return (-1);
+
+ if (PCI_BAR_IO(pm->pm_value))
+ return (SYS_RES_IOPORT);
+ else
+ return (SYS_RES_MEMORY);
+}
+
+/*
+ * All drivers just seem to want to inspect the type not flags.
+ */
+static inline int
+pci_resource_flags(struct pci_dev *pdev, int bar)
+{
+ int type;
+
+ type = pci_resource_type(pdev, bar);
+ if (type < 0)
+ return (0);
+ return (1 << type);
+}
+
+static inline const char *
+pci_name(struct pci_dev *d)
+{
+ return d->path_name;
+}
+
+static inline void *
+pci_get_drvdata(struct pci_dev *pdev)
+{
+
+ return dev_get_drvdata(&pdev->dev);
+}
+
+static inline void
+pci_set_drvdata(struct pci_dev *pdev, void *data)
+{
+
+ dev_set_drvdata(&pdev->dev, data);
+}
+
+static inline struct pci_dev *
+pci_dev_get(struct pci_dev *pdev)
+{
+
+ if (pdev != NULL)
+ get_device(&pdev->dev);
+ return (pdev);
+}
+
+static __inline void
+pci_dev_put(struct pci_dev *pdev)
+{
+
+ if (pdev != NULL)
+ put_device(&pdev->dev);
+}
+
+static inline int
+pci_enable_device(struct pci_dev *pdev)
+{
+
+ pci_enable_io(pdev->dev.bsddev, SYS_RES_IOPORT);
+ pci_enable_io(pdev->dev.bsddev, SYS_RES_MEMORY);
+ return (0);
+}
+
+static inline void
+pci_disable_device(struct pci_dev *pdev)
+{
+
+ pci_disable_busmaster(pdev->dev.bsddev);
+}
+
+static inline int
+pci_set_master(struct pci_dev *pdev)
+{
+
+ pci_enable_busmaster(pdev->dev.bsddev);
+ return (0);
+}
+
+static inline int
+pci_set_power_state(struct pci_dev *pdev, int state)
+{
+
+ pci_set_powerstate(pdev->dev.bsddev, state);
+ return (0);
+}
+
+static inline int
+pci_clear_master(struct pci_dev *pdev)
+{
+
+ pci_disable_busmaster(pdev->dev.bsddev);
+ return (0);
+}
+
+static inline bool
+pci_is_root_bus(struct pci_bus *pbus)
+{
+
+ return (pbus->self == NULL);
+}
+
+static inline struct pci_dev *
+pci_upstream_bridge(struct pci_dev *pdev)
+{
+
+ if (pci_is_root_bus(pdev->bus))
+ return (NULL);
+
+ /*
+ * If we do not have a (proper) "upstream bridge" set, e.g., we point
+ * to ourselves, try to handle this case on the fly like we do
+ * for pcie_find_root_port().
+ */
+ if (pdev == pdev->bus->self) {
+ device_t bridge;
+
+ /*
+ * In the case of DRM drivers, the passed device is a child of
+ * `vgapci`. We want to start the lookup from `vgapci`, so the
+ * parent of the passed `drmn`.
+ *
+ * We can use the `isdrm` flag to determine this.
+ */
+ bridge = pdev->dev.bsddev;
+ if (pdev->pdrv != NULL && pdev->pdrv->isdrm)
+ bridge = device_get_parent(bridge);
+ if (bridge == NULL)
+ goto done;
+
+ bridge = device_get_parent(bridge);
+ if (bridge == NULL)
+ goto done;
+ bridge = device_get_parent(bridge);
+ if (bridge == NULL)
+ goto done;
+ if (device_get_devclass(device_get_parent(bridge)) !=
+ devclass_find("pci"))
+ goto done;
+
+ /*
+ * "bridge" is a PCI-to-PCI bridge. Create a Linux pci_dev
+ * for it so it can be returned.
+ */
+ pdev->bus->self = lkpinew_pci_dev(bridge);
+ }
+done:
+ return (pdev->bus->self);
+}
+
+#define pci_release_region(pdev, bar) linuxkpi_pci_release_region(pdev, bar)
+#define pci_release_regions(pdev) linuxkpi_pci_release_regions(pdev)
+#define pci_request_regions(pdev, res_name) \
+ linuxkpi_pci_request_regions(pdev, res_name)
+
+static inline void
+lkpi_pci_disable_msix(struct pci_dev *pdev)
+{
+
+ pci_release_msi(pdev->dev.bsddev);
+
+ /*
+ * The MSIX IRQ numbers associated with this PCI device are no
+ * longer valid and might be re-assigned. Make sure
+ * lkpi_pci_find_irq_dev() does no longer see them by
+ * resetting their references to zero:
+ */
+ pdev->dev.irq_start = 0;
+ pdev->dev.irq_end = 0;
+ pdev->msix_enabled = false;
+}
+/* Only for consistency. No conflict on that one. */
+#define pci_disable_msix(pdev) lkpi_pci_disable_msix(pdev)
+
+static inline void
+lkpi_pci_disable_msi(struct pci_dev *pdev)
+{
+
+ pci_release_msi(pdev->dev.bsddev);
+
+ pdev->dev.irq_start = 0;
+ pdev->dev.irq_end = 0;
+ pdev->irq = pdev->dev.irq;
+ pdev->msi_enabled = false;
+}
+#define pci_disable_msi(pdev) lkpi_pci_disable_msi(pdev)
+#define pci_free_irq_vectors(pdev) lkpi_pci_disable_msi(pdev)
+
+unsigned long pci_resource_start(struct pci_dev *pdev, int bar);
+unsigned long pci_resource_len(struct pci_dev *pdev, int bar);
+
+static inline bus_addr_t
+pci_bus_address(struct pci_dev *pdev, int bar)
+{
+
+ return (pci_resource_start(pdev, bar));
+}
+
+#define PCI_CAP_ID_EXP PCIY_EXPRESS
+#define PCI_CAP_ID_PCIX PCIY_PCIX
+#define PCI_CAP_ID_AGP PCIY_AGP
+#define PCI_CAP_ID_PM PCIY_PMG
+
+#define PCI_EXP_DEVCTL PCIER_DEVICE_CTL
+#define PCI_EXP_DEVCTL_PAYLOAD PCIEM_CTL_MAX_PAYLOAD
+#define PCI_EXP_DEVCTL_READRQ PCIEM_CTL_MAX_READ_REQUEST
+#define PCI_EXP_LNKCTL PCIER_LINK_CTL
+#define PCI_EXP_LNKSTA PCIER_LINK_STA
+
+static inline int
+pci_find_capability(struct pci_dev *pdev, int capid)
+{
+ int reg;
+
+ if (pci_find_cap(pdev->dev.bsddev, capid, &reg))
+ return (0);
+ return (reg);
+}
+
+static inline int pci_pcie_cap(struct pci_dev *dev)
+{
+ return pci_find_capability(dev, PCI_CAP_ID_EXP);
+}
+
+static inline int
+pci_find_ext_capability(struct pci_dev *pdev, int capid)
+{
+ int reg;
+
+ if (pci_find_extcap(pdev->dev.bsddev, capid, &reg))
+ return (0);
+ return (reg);
+}
+
+#define PCIM_PCAP_PME_SHIFT 11
+static __inline bool
+pci_pme_capable(struct pci_dev *pdev, uint32_t flag)
+{
+ struct pci_devinfo *dinfo;
+ pcicfgregs *cfg;
+
+ if (flag > (PCIM_PCAP_D3PME_COLD >> PCIM_PCAP_PME_SHIFT))
+ return (false);
+
+ dinfo = device_get_ivars(pdev->dev.bsddev);
+ cfg = &dinfo->cfg;
+
+ if (cfg->pp.pp_cap == 0)
+ return (false);
+
+ if ((cfg->pp.pp_cap & (1 << (PCIM_PCAP_PME_SHIFT + flag))) != 0)
+ return (true);
+
+ return (false);
+}
+
+static inline int
+pci_disable_link_state(struct pci_dev *pdev, uint32_t flags)
+{
+
+ if (!pci_enable_aspm)
+ return (-EPERM);
+
+ return (-ENXIO);
+}
+
+static inline int
+pci_read_config_byte(const struct pci_dev *pdev, int where, u8 *val)
+{
+
+ *val = (u8)pci_read_config(pdev->dev.bsddev, where, 1);
+ return (0);
+}
+
+static inline int
+pci_read_config_word(const struct pci_dev *pdev, int where, u16 *val)
+{
+
+ *val = (u16)pci_read_config(pdev->dev.bsddev, where, 2);
+ return (0);
+}
+
+static inline int
+pci_read_config_dword(const struct pci_dev *pdev, int where, u32 *val)
+{
+
+ *val = (u32)pci_read_config(pdev->dev.bsddev, where, 4);
+ return (0);
+}
+
+static inline int
+pci_write_config_byte(const struct pci_dev *pdev, int where, u8 val)
+{
+
+ pci_write_config(pdev->dev.bsddev, where, val, 1);
+ return (0);
+}
+
+static inline int
+pci_write_config_word(const struct pci_dev *pdev, int where, u16 val)
+{
+
+ pci_write_config(pdev->dev.bsddev, where, val, 2);
+ return (0);
+}
+
+static inline int
+pci_write_config_dword(const struct pci_dev *pdev, int where, u32 val)
+{
+
+ pci_write_config(pdev->dev.bsddev, where, val, 4);
+ return (0);
+}
+
+int linux_pci_register_driver(struct pci_driver *pdrv);
+int linux_pci_register_drm_driver(struct pci_driver *pdrv);
+void linux_pci_unregister_driver(struct pci_driver *pdrv);
+void linux_pci_unregister_drm_driver(struct pci_driver *pdrv);
+
+#define pci_register_driver(pdrv) linux_pci_register_driver(pdrv)
+#define pci_unregister_driver(pdrv) linux_pci_unregister_driver(pdrv)
+
+/*
+ * Enable msix, positive errors indicate actual number of available
+ * vectors. Negative errors are failures.
+ *
+ * NB: define added to prevent this definition of pci_enable_msix from
+ * clashing with the native FreeBSD version.
+ */
+#define pci_enable_msix(...) linuxkpi_pci_enable_msix(__VA_ARGS__)
+
+#define pci_enable_msix_range(...) \
+ linux_pci_enable_msix_range(__VA_ARGS__)
+
+static inline int
+pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
+ int minvec, int maxvec)
+{
+ int nvec = maxvec;
+ int rc;
+
+ if (maxvec < minvec)
+ return (-ERANGE);
+
+ do {
+ rc = pci_enable_msix(dev, entries, nvec);
+ if (rc < 0) {
+ return (rc);
+ } else if (rc > 0) {
+ if (rc < minvec)
+ return (-ENOSPC);
+ nvec = rc;
+ }
+ } while (rc);
+ return (nvec);
+}
+
+#define pci_enable_msi(pdev) \
+ linux_pci_enable_msi(pdev)
+
+static inline int
+pci_enable_msi(struct pci_dev *pdev)
+{
+
+ return (_lkpi_pci_enable_msi_range(pdev, 1, 1));
+}
+
+static inline int
+pci_channel_offline(struct pci_dev *pdev)
+{
+
+ return (pci_read_config(pdev->dev.bsddev, PCIR_VENDOR, 2) == PCIV_INVALID);
+}
+
+static inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
+{
+ return -ENODEV;
+}
+
+static inline void pci_disable_sriov(struct pci_dev *dev)
+{
+}
+
+#define pci_iomap_range(pdev, mmio_bar, mmio_off, mmio_size) \
+ linuxkpi_pci_iomap_range(pdev, mmio_bar, mmio_off, mmio_size)
+#define pci_iomap(pdev, mmio_bar, mmio_size) \
+ linuxkpi_pci_iomap(pdev, mmio_bar, mmio_size)
+#define pci_iounmap(pdev, res) linuxkpi_pci_iounmap(pdev, res)
+
+static inline void
+lkpi_pci_save_state(struct pci_dev *pdev)
+{
+
+ pci_save_state(pdev->dev.bsddev);
+}
+
+static inline void
+lkpi_pci_restore_state(struct pci_dev *pdev)
+{
+
+ pci_restore_state(pdev->dev.bsddev);
+}
+
+#define pci_save_state(dev) lkpi_pci_save_state(dev)
+#define pci_restore_state(dev) lkpi_pci_restore_state(dev)
+
+static inline int
+pci_reset_function(struct pci_dev *pdev)
+{
+
+ return (-ENOSYS);
+}
+
+#define DEFINE_PCI_DEVICE_TABLE(_table) \
+ const struct pci_device_id _table[] __devinitdata
+
+/* XXX This should not be necessary. */
+#define pcix_set_mmrbc(d, v) 0
+#define pcix_get_max_mmrbc(d) 0
+#define pcie_set_readrq(d, v) pci_set_max_read_req((d)->dev.bsddev, (v))
+
+#define PCI_DMA_BIDIRECTIONAL 0
+#define PCI_DMA_TODEVICE 1
+#define PCI_DMA_FROMDEVICE 2
+#define PCI_DMA_NONE 3
+
+#define pci_pool dma_pool
+#define pci_pool_destroy(...) dma_pool_destroy(__VA_ARGS__)
+#define pci_pool_alloc(...) dma_pool_alloc(__VA_ARGS__)
+#define pci_pool_free(...) dma_pool_free(__VA_ARGS__)
+#define pci_pool_create(_name, _pdev, _size, _align, _alloc) \
+ dma_pool_create(_name, &(_pdev)->dev, _size, _align, _alloc)
+#define pci_free_consistent(_hwdev, _size, _vaddr, _dma_handle) \
+ dma_free_coherent((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \
+ _size, _vaddr, _dma_handle)
+#define pci_map_sg(_hwdev, _sg, _nents, _dir) \
+ dma_map_sg((_hwdev) == NULL ? NULL : &(_hwdev->dev), \
+ _sg, _nents, (enum dma_data_direction)_dir)
+#define pci_map_single(_hwdev, _ptr, _size, _dir) \
+ dma_map_single((_hwdev) == NULL ? NULL : &(_hwdev->dev), \
+ (_ptr), (_size), (enum dma_data_direction)_dir)
+#define pci_unmap_single(_hwdev, _addr, _size, _dir) \
+ dma_unmap_single((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \
+ _addr, _size, (enum dma_data_direction)_dir)
+#define pci_unmap_sg(_hwdev, _sg, _nents, _dir) \
+ dma_unmap_sg((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \
+ _sg, _nents, (enum dma_data_direction)_dir)
+#define pci_map_page(_hwdev, _page, _offset, _size, _dir) \
+ dma_map_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev, _page,\
+ _offset, _size, (enum dma_data_direction)_dir)
+#define pci_unmap_page(_hwdev, _dma_address, _size, _dir) \
+ dma_unmap_page((_hwdev) == NULL ? NULL : &(_hwdev)->dev, \
+ _dma_address, _size, (enum dma_data_direction)_dir)
+#define pci_set_dma_mask(_pdev, mask) dma_set_mask(&(_pdev)->dev, (mask))
+#define pci_dma_mapping_error(_pdev, _dma_addr) \
+ dma_mapping_error(&(_pdev)->dev, _dma_addr)
+#define pci_set_consistent_dma_mask(_pdev, _mask) \
+ dma_set_coherent_mask(&(_pdev)->dev, (_mask))
+#define DECLARE_PCI_UNMAP_ADDR(x) DEFINE_DMA_UNMAP_ADDR(x);
+#define DECLARE_PCI_UNMAP_LEN(x) DEFINE_DMA_UNMAP_LEN(x);
+#define pci_unmap_addr dma_unmap_addr
+#define pci_unmap_addr_set dma_unmap_addr_set
+#define pci_unmap_len dma_unmap_len
+#define pci_unmap_len_set dma_unmap_len_set
+
+typedef unsigned int __bitwise pci_channel_state_t;
+typedef unsigned int __bitwise pci_ers_result_t;
+
+enum pci_channel_state {
+ pci_channel_io_normal = 1,
+ pci_channel_io_frozen = 2,
+ pci_channel_io_perm_failure = 3,
+};
+
+enum pci_ers_result {
+ PCI_ERS_RESULT_NONE = 1,
+ PCI_ERS_RESULT_CAN_RECOVER = 2,
+ PCI_ERS_RESULT_NEED_RESET = 3,
+ PCI_ERS_RESULT_DISCONNECT = 4,
+ PCI_ERS_RESULT_RECOVERED = 5,
+};
+
+/* PCI bus error event callbacks */
+struct pci_error_handlers {
+ pci_ers_result_t (*error_detected)(struct pci_dev *dev,
+ enum pci_channel_state error);
+ pci_ers_result_t (*mmio_enabled)(struct pci_dev *dev);
+ pci_ers_result_t (*link_reset)(struct pci_dev *dev);
+ pci_ers_result_t (*slot_reset)(struct pci_dev *dev);
+ void (*resume)(struct pci_dev *dev);
+};
+
+/* FreeBSD does not support SRIOV - yet */
+static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
+{
+ return dev;
+}
+
+static inline bool pci_is_pcie(struct pci_dev *dev)
+{
+ return !!pci_pcie_cap(dev);
+}
+
+static inline u16 pcie_flags_reg(struct pci_dev *dev)
+{
+ int pos;
+ u16 reg16;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (!pos)
+ return 0;
+
+ pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &reg16);
+
+ return reg16;
+}
+
+static inline int pci_pcie_type(struct pci_dev *dev)
+{
+ return (pcie_flags_reg(dev) & PCI_EXP_FLAGS_TYPE) >> 4;
+}
+
+static inline int pcie_cap_version(struct pci_dev *dev)
+{
+ return pcie_flags_reg(dev) & PCI_EXP_FLAGS_VERS;
+}
+
+static inline bool pcie_cap_has_lnkctl(struct pci_dev *dev)
+{
+ int type = pci_pcie_type(dev);
+
+ return pcie_cap_version(dev) > 1 ||
+ type == PCI_EXP_TYPE_ROOT_PORT ||
+ type == PCI_EXP_TYPE_ENDPOINT ||
+ type == PCI_EXP_TYPE_LEG_END;
+}
+
+static inline bool pcie_cap_has_devctl(const struct pci_dev *dev)
+{
+ return true;
+}
+
+static inline bool pcie_cap_has_sltctl(struct pci_dev *dev)
+{
+ int type = pci_pcie_type(dev);
+
+ return pcie_cap_version(dev) > 1 || type == PCI_EXP_TYPE_ROOT_PORT ||
+ (type == PCI_EXP_TYPE_DOWNSTREAM &&
+ pcie_flags_reg(dev) & PCI_EXP_FLAGS_SLOT);
+}
+
+static inline bool pcie_cap_has_rtctl(struct pci_dev *dev)
+{
+ int type = pci_pcie_type(dev);
+
+ return pcie_cap_version(dev) > 1 || type == PCI_EXP_TYPE_ROOT_PORT ||
+ type == PCI_EXP_TYPE_RC_EC;
+}
+
+static bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos)
+{
+ if (!pci_is_pcie(dev))
+ return false;
+
+ switch (pos) {
+ case PCI_EXP_FLAGS_TYPE:
+ return true;
+ case PCI_EXP_DEVCAP:
+ case PCI_EXP_DEVCTL:
+ case PCI_EXP_DEVSTA:
+ return pcie_cap_has_devctl(dev);
+ case PCI_EXP_LNKCAP:
+ case PCI_EXP_LNKCTL:
+ case PCI_EXP_LNKSTA:
+ return pcie_cap_has_lnkctl(dev);
+ case PCI_EXP_SLTCAP:
+ case PCI_EXP_SLTCTL:
+ case PCI_EXP_SLTSTA:
+ return pcie_cap_has_sltctl(dev);
+ case PCI_EXP_RTCTL:
+ case PCI_EXP_RTCAP:
+ case PCI_EXP_RTSTA:
+ return pcie_cap_has_rtctl(dev);
+ case PCI_EXP_DEVCAP2:
+ case PCI_EXP_DEVCTL2:
+ case PCI_EXP_LNKCAP2:
+ case PCI_EXP_LNKCTL2:
+ case PCI_EXP_LNKSTA2:
+ return pcie_cap_version(dev) > 1;
+ default:
+ return false;
+ }
+}
+
+static inline int
+pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *dst)
+{
+ *dst = 0;
+ if (pos & 3)
+ return -EINVAL;
+
+ if (!pcie_capability_reg_implemented(dev, pos))
+ return -EINVAL;
+
+ return pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, dst);
+}
+
+static inline int
+pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *dst)
+{
+ *dst = 0;
+ if (pos & 3)
+ return -EINVAL;
+
+ if (!pcie_capability_reg_implemented(dev, pos))
+ return -EINVAL;
+
+ return pci_read_config_word(dev, pci_pcie_cap(dev) + pos, dst);
+}
+
+static inline int
+pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val)
+{
+ if (pos & 1)
+ return -EINVAL;
+
+ if (!pcie_capability_reg_implemented(dev, pos))
+ return 0;
+
+ return pci_write_config_word(dev, pci_pcie_cap(dev) + pos, val);
+}
+
+static inline int
+pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos,
+ uint16_t clear, uint16_t set)
+{
+ int error;
+ uint16_t v;
+
+ if (pos == PCI_EXP_LNKCTL || pos == PCI_EXP_RTCTL)
+ spin_lock(&dev->pcie_cap_lock);
+
+ error = pcie_capability_read_word(dev, pos, &v);
+ if (error == 0) {
+ v &= ~clear;
+ v |= set;
+ error = pcie_capability_write_word(dev, pos, v);
+ }
+
+ if (pos == PCI_EXP_LNKCTL || pos == PCI_EXP_RTCTL)
+ spin_unlock(&dev->pcie_cap_lock);
+
+ return (error);
+}
+
+static inline int
+pcie_capability_set_word(struct pci_dev *dev, int pos, uint16_t val)
+{
+ return (pcie_capability_clear_and_set_word(dev, pos, 0, val));
+}
+
+static inline int
+pcie_capability_clear_word(struct pci_dev *dev, int pos, uint16_t val)
+{
+ return (pcie_capability_clear_and_set_word(dev, pos, val, 0));
+}
+
+static inline int pcie_get_minimum_link(struct pci_dev *dev,
+ enum pci_bus_speed *speed, enum pcie_link_width *width)
+{
+ *speed = PCI_SPEED_UNKNOWN;
+ *width = PCIE_LNK_WIDTH_UNKNOWN;
+ return (0);
+}
+
+static inline int
+pci_num_vf(struct pci_dev *dev)
+{
+ return (0);
+}
+
+static inline enum pci_bus_speed
+pcie_get_speed_cap(struct pci_dev *dev)
+{
+ 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);
+
+ if (pci_get_vendor(root) == PCI_VENDOR_ID_VIA ||
+ pci_get_vendor(root) == PCI_VENDOR_ID_SERVERWORKS)
+ return (PCI_SPEED_UNKNOWN);
+
+ if ((error = pci_find_cap(root, PCIY_EXPRESS, &pos)) != 0)
+ return (PCI_SPEED_UNKNOWN);
+
+ lnkcap2 = pci_read_config(root, pos + PCIER_LINK_CAP2, 4);
+
+ if (lnkcap2) { /* PCIe r3.0-compliant */
+ if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_2_5GB)
+ return (PCIE_SPEED_2_5GT);
+ if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_5_0GB)
+ return (PCIE_SPEED_5_0GT);
+ if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB)
+ return (PCIE_SPEED_8_0GT);
+ if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_16_0GB)
+ return (PCIE_SPEED_16_0GT);
+ if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_32_0GB)
+ return (PCIE_SPEED_32_0GT);
+ if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_64_0GB)
+ return (PCIE_SPEED_64_0GT);
+ } else { /* pre-r3.0 */
+ lnkcap = pci_read_config(root, pos + PCIER_LINK_CAP, 4);
+ if (lnkcap & PCI_EXP_LNKCAP_SLS_2_5GB)
+ return (PCIE_SPEED_2_5GT);
+ if (lnkcap & PCI_EXP_LNKCAP_SLS_5_0GB)
+ return (PCIE_SPEED_5_0GT);
+ if (lnkcap & PCI_EXP_LNKCAP_SLS_8_0GB)
+ return (PCIE_SPEED_8_0GT);
+ if (lnkcap & PCI_EXP_LNKCAP_SLS_16_0GB)
+ return (PCIE_SPEED_16_0GT);
+ if (lnkcap & PCI_EXP_LNKCAP_SLS_32_0GB)
+ return (PCIE_SPEED_32_0GT);
+ if (lnkcap & PCI_EXP_LNKCAP_SLS_64_0GB)
+ return (PCIE_SPEED_64_0GT);
+ }
+ return (PCI_SPEED_UNKNOWN);
+}
+
+static inline enum pcie_link_width
+pcie_get_width_cap(struct pci_dev *dev)
+{
+ uint32_t lnkcap;
+
+ pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
+ if (lnkcap)
+ return ((lnkcap & PCI_EXP_LNKCAP_MLW) >> 4);
+
+ return (PCIE_LNK_WIDTH_UNKNOWN);
+}
+
+static inline int
+pcie_get_mps(struct pci_dev *dev)
+{
+ return (pci_get_max_payload(dev->dev.bsddev));
+}
+
+static inline uint32_t
+PCIE_SPEED2MBS_ENC(enum pci_bus_speed spd)
+{
+
+ switch(spd) {
+ case PCIE_SPEED_64_0GT:
+ return (64000 * 128 / 130);
+ case PCIE_SPEED_32_0GT:
+ return (32000 * 128 / 130);
+ case PCIE_SPEED_16_0GT:
+ return (16000 * 128 / 130);
+ case PCIE_SPEED_8_0GT:
+ return (8000 * 128 / 130);
+ case PCIE_SPEED_5_0GT:
+ return (5000 * 8 / 10);
+ case PCIE_SPEED_2_5GT:
+ return (2500 * 8 / 10);
+ default:
+ return (0);
+ }
+}
+
+static inline uint32_t
+pcie_bandwidth_available(struct pci_dev *pdev,
+ struct pci_dev **limiting,
+ enum pci_bus_speed *speed,
+ enum pcie_link_width *width)
+{
+ enum pci_bus_speed nspeed = pcie_get_speed_cap(pdev);
+ enum pcie_link_width nwidth = pcie_get_width_cap(pdev);
+
+ if (speed)
+ *speed = nspeed;
+ if (width)
+ *width = nwidth;
+
+ return (nwidth * PCIE_SPEED2MBS_ENC(nspeed));
+}
+
+static inline bool
+pcie_aspm_enabled(struct pci_dev *pdev)
+{
+ return (false);
+}
+
+static inline struct pci_dev *
+pcie_find_root_port(struct pci_dev *pdev)
+{
+ device_t root;
+
+ if (pdev->root != NULL)
+ return (pdev->root);
+
+ root = pci_find_pcie_root_port(pdev->dev.bsddev);
+ if (root == NULL)
+ return (NULL);
+
+ pdev->root = lkpinew_pci_dev(root);
+ return (pdev->root);
+}
+
+/* This is needed when people rip out the device "HotPlug". */
+static inline void
+pci_lock_rescan_remove(void)
+{
+}
+
+static inline void
+pci_unlock_rescan_remove(void)
+{
+}
+
+static __inline void
+pci_stop_and_remove_bus_device(struct pci_dev *pdev)
+{
+}
+
+static inline int
+pci_rescan_bus(struct pci_bus *pbus)
+{
+ device_t *devlist, parent;
+ int devcount, error;
+
+ if (!device_is_attached(pbus->self->dev.bsddev))
+ return (0);
+ /* pci_rescan_method() will work on the pcib (parent). */
+ error = BUS_RESCAN(pbus->self->dev.bsddev);
+ if (error != 0)
+ return (0);
+
+ parent = device_get_parent(pbus->self->dev.bsddev);
+ error = device_get_children(parent, &devlist, &devcount);
+ if (error != 0)
+ return (0);
+ if (devcount != 0)
+ free(devlist, M_TEMP);
+
+ return (devcount);
+}
+
+/*
+ * The following functions can be used to attach/detach the LinuxKPI's
+ * PCI device runtime. The pci_driver and pci_device_id pointer is
+ * allowed to be NULL. Other pointers must be all valid.
+ * The pci_dev structure should be zero-initialized before passed
+ * to the linux_pci_attach_device function.
+ */
+extern int linux_pci_attach_device(device_t, struct pci_driver *,
+ const struct pci_device_id *, struct pci_dev *);
+extern int linux_pci_detach_device(struct pci_dev *);
+
+static inline int
+pci_dev_present(const struct pci_device_id *cur)
+{
+ while (cur != NULL && (cur->vendor || cur->device)) {
+ if (pci_find_device(cur->vendor, cur->device) != NULL) {
+ return (1);
+ }
+ cur++;
+ }
+ return (0);
+}
+
+static inline const struct pci_device_id *
+pci_match_id(const struct pci_device_id *ids, struct pci_dev *pdev)
+{
+ if (ids == NULL)
+ return (NULL);
+
+ for (;
+ ids->vendor != 0 || ids->subvendor != 0 || ids->class_mask != 0;
+ ids++)
+ if ((ids->vendor == PCI_ANY_ID ||
+ ids->vendor == pdev->vendor) &&
+ (ids->device == PCI_ANY_ID ||
+ ids->device == pdev->device) &&
+ (ids->subvendor == PCI_ANY_ID ||
+ ids->subvendor == pdev->subsystem_vendor) &&
+ (ids->subdevice == PCI_ANY_ID ||
+ ids->subdevice == pdev->subsystem_device) &&
+ ((ids->class ^ pdev->class) & ids->class_mask) == 0)
+ return (ids);
+
+ return (NULL);
+}
+
+struct pci_dev *lkpi_pci_get_domain_bus_and_slot(int domain,
+ unsigned int bus, unsigned int devfn);
+#define pci_get_domain_bus_and_slot(domain, bus, devfn) \
+ lkpi_pci_get_domain_bus_and_slot(domain, bus, devfn)
+
+static inline int
+pci_domain_nr(struct pci_bus *pbus)
+{
+
+ return (pbus->domain);
+}
+
+static inline int
+pci_bus_read_config(struct pci_bus *bus, unsigned int devfn,
+ int pos, uint32_t *val, int len)
+{
+
+ *val = pci_read_config(bus->self->dev.bsddev, pos, len);
+ return (0);
+}
+
+static inline int
+pci_bus_read_config_word(struct pci_bus *bus, unsigned int devfn, int pos, u16 *val)
+{
+ uint32_t tmp;
+ int ret;
+
+ ret = pci_bus_read_config(bus, devfn, pos, &tmp, 2);
+ *val = (u16)tmp;
+ return (ret);
+}
+
+static inline int
+pci_bus_read_config_byte(struct pci_bus *bus, unsigned int devfn, int pos, u8 *val)
+{
+ uint32_t tmp;
+ int ret;
+
+ ret = pci_bus_read_config(bus, devfn, pos, &tmp, 1);
+ *val = (u8)tmp;
+ return (ret);
+}
+
+static inline int
+pci_bus_write_config(struct pci_bus *bus, unsigned int devfn, int pos,
+ uint32_t val, int size)
+{
+
+ pci_write_config(bus->self->dev.bsddev, pos, val, size);
+ return (0);
+}
+
+static inline int
+pci_bus_write_config_byte(struct pci_bus *bus, unsigned int devfn, int pos,
+ uint8_t val)
+{
+ return (pci_bus_write_config(bus, devfn, pos, val, 1));
+}
+
+static inline int
+pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn, int pos,
+ uint16_t val)
+{
+ return (pci_bus_write_config(bus, devfn, pos, val, 2));
+}
+
+struct pci_dev *lkpi_pci_get_class(unsigned int class, struct pci_dev *from);
+#define pci_get_class(class, from) lkpi_pci_get_class(class, from)
+struct pci_dev *lkpi_pci_get_base_class(unsigned int class,
+ struct pci_dev *from);
+#define pci_get_base_class(class, from) lkpi_pci_get_base_class(class, from)
+
+/* -------------------------------------------------------------------------- */
+
+#define pcim_enable_device(pdev) linuxkpi_pcim_enable_device(pdev)
+#define pcim_iomap_table(pdev) linuxkpi_pcim_iomap_table(pdev)
+#define pcim_iomap_regions(pdev, mask, name) \
+ linuxkpi_pcim_iomap_regions(pdev, mask, name)
+
+static inline int
+pcim_iomap_regions_request_all(struct pci_dev *pdev, uint32_t mask, char *name)
+{
+ uint32_t requests, req_mask;
+ int bar, error;
+
+ /* Request all the BARs ("regions") we do not iomap. */
+ req_mask = ((1 << (PCIR_MAX_BAR_0 + 1)) - 1) & ~mask;
+ for (bar = requests = 0; requests != req_mask; bar++) {
+ if ((req_mask & (1 << bar)) == 0)
+ continue;
+ error = pci_request_region(pdev, bar, name);
+ if (error != 0 && error != -ENODEV)
+ goto err;
+ requests |= (1 << bar);
+ }
+
+ error = pcim_iomap_regions(pdev, mask, name);
+ if (error != 0)
+ goto err;
+
+ return (0);
+
+err:
+ for (bar = PCIR_MAX_BAR_0; bar >= 0; bar--) {
+ if ((requests & (1 << bar)) != 0)
+ pci_release_region(pdev, bar);
+ }
+
+ return (-EINVAL);
+}
+
+/*
+ * We cannot simply re-define pci_get_device() as we would normally do
+ * and then hide it in linux_pci.c as too many semi-native drivers still
+ * include linux/pci.h and run into the conflict with native PCI. Linux drivers
+ * using pci_get_device() need to be changed to call linuxkpi_pci_get_device().
+ */
+static inline struct pci_dev *
+linuxkpi_pci_get_device(uint16_t vendor, uint16_t device, struct pci_dev *odev)
+{
+
+ return (lkpi_pci_get_device(vendor, device, odev));
+}
+
+/* This is a FreeBSD extension so we can use bus_*(). */
+static inline void
+linuxkpi_pcim_want_to_use_bus_functions(struct pci_dev *pdev)
+{
+ pdev->want_iomap_res = true;
+}
+
+static inline bool
+pci_is_thunderbolt_attached(struct pci_dev *pdev)
+{
+
+ return (false);
+}
+
+static inline void *
+pci_platform_rom(struct pci_dev *pdev, size_t *size)
+{
+
+ return (NULL);
+}
+
+static inline void
+pci_ignore_hotplug(struct pci_dev *pdev)
+{
+}
+
+static inline const char *
+pci_power_name(pci_power_t state)
+{
+ int pstate = state + 1;
+
+ if (pstate >= 0 && pstate < nitems(pci_power_names))
+ return (pci_power_names[pstate]);
+ else
+ return (pci_power_names[0]);
+}
+
+static inline int
+pcie_get_readrq(struct pci_dev *dev)
+{
+ u16 ctl;
+
+ if (pcie_capability_read_word(dev, PCI_EXP_DEVCTL, &ctl))
+ return (-EINVAL);
+
+ return (128 << ((ctl & PCI_EXP_DEVCTL_READRQ) >> 12));
+}
+
+static inline bool
+pci_is_enabled(struct pci_dev *pdev)
+{
+
+ return ((pci_read_config(pdev->dev.bsddev, PCIR_COMMAND, 2) &
+ PCIM_CMD_BUSMASTEREN) != 0);
+}
+
+static inline int
+pci_wait_for_pending_transaction(struct pci_dev *pdev)
+{
+
+ return (0);
+}
+
+static inline int
+pci_assign_resource(struct pci_dev *pdev, int bar)
+{
+
+ return (0);
+}
+
+static inline int
+pci_irq_vector(struct pci_dev *pdev, unsigned int vector)
+{
+
+ if (!pdev->msix_enabled && !pdev->msi_enabled) {
+ if (vector != 0)
+ return (-EINVAL);
+ return (pdev->irq);
+ }
+
+ if (pdev->msix_enabled || pdev->msi_enabled) {
+ if ((pdev->dev.irq_start + vector) >= pdev->dev.irq_end)
+ return (-EINVAL);
+ return (pdev->dev.irq_start + vector);
+ }
+
+ return (-ENXIO);
+}
+
+static inline int
+pci_wake_from_d3(struct pci_dev *pdev, bool enable)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (0);
+}
+
+#endif /* _LINUXKPI_LINUX_PCI_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/pci_ids.h b/sys/compat/linuxkpi/common/include/linux/pci_ids.h
new file mode 100644
index 000000000000..e318f6f75ce7
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/pci_ids.h
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_PCI_IDS_H
+#define _LINUXKPI_LINUX_PCI_IDS_H
+
+#define PCI_CLASS_NETWORK_OTHER 0x0280
+
+#define PCI_BASE_CLASS_DISPLAY 0x03
+#define PCI_CLASS_DISPLAY_VGA 0x0300
+#define PCI_CLASS_DISPLAY_OTHER 0x0380
+
+#define PCI_BASE_CLASS_BRIDGE 0x06
+#define PCI_CLASS_BRIDGE_ISA 0x0601
+
+#define PCI_CLASS_ACCELERATOR_PROCESSING 0x1200
+
+
+/* XXX We should really generate these and use them throughout the tree. */
+
+#define PCI_VENDOR_ID_APPLE 0x106b
+#define PCI_VENDOR_ID_ASUSTEK 0x1043
+#define PCI_VENDOR_ID_ASMEDIA 0x1b21
+#define PCI_VENDOR_ID_ATHEROS 0x168c
+#define PCI_VENDOR_ID_ATI 0x1002
+#define PCI_VENDOR_ID_BROADCOM 0x14e4
+#define PCI_VENDOR_ID_DELL 0x1028
+#define PCI_VENDOR_ID_HP 0x103c
+#define PCI_VENDOR_ID_IBM 0x1014
+#define PCI_VENDOR_ID_INTEL 0x8086
+#define PCI_VENDOR_ID_ITTIM 0x0b48
+#define PCI_VENDOR_ID_MEDIATEK 0x14c3
+#define PCI_VENDOR_ID_MELLANOX 0x15b3
+#define PCI_VENDOR_ID_QCOM 0x17cb
+#define PCI_VENDOR_ID_REALTEK 0x10ec
+#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4
+#define PCI_VENDOR_ID_SERVERWORKS 0x1166
+#define PCI_VENDOR_ID_SONY 0x104d
+#define PCI_VENDOR_ID_TOPSPIN 0x1867
+#define PCI_VENDOR_ID_UBIQUITI 0x0777
+#define PCI_VENDOR_ID_VIA 0x1106
+#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4
+#define PCI_DEVICE_ID_ATI_RADEON_QY 0x5159
+#define PCI_DEVICE_ID_MELLANOX_TAVOR 0x5a44
+#define PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE 0x5a46
+#define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278
+#define PCI_DEVICE_ID_MELLANOX_ARBEL 0x6282
+#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c
+#define PCI_DEVICE_ID_MELLANOX_SINAI 0x6274
+#define PCI_SUBDEVICE_ID_QEMU 0x1100
+
+#endif /* _LINUXKPI_LINUX_PCI_IDS_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/perf_event.h b/sys/compat/linuxkpi/common/include/linux/perf_event.h
new file mode 100644
index 000000000000..86b0d06cdc1f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/perf_event.h
@@ -0,0 +1,34 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
+ *
+ * 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_PERF_EVENT_H_
+#define _LINUXKPI_LINUX_PERF_EVENT_H_
+
+#include <linux/cgroup.h>
+
+#endif /* _LINUXKPI_LINUX_PERF_EVENT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/pfn.h b/sys/compat/linuxkpi/common/include/linux/pfn.h
new file mode 100644
index 000000000000..26d47b9bc3b1
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/pfn.h
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_PFN_H_
+#define _LINUXKPI_LINUX_PFN_H_
+
+#include <linux/types.h>
+
+typedef struct {
+ u64 val;
+} pfn_t;
+
+#define PFN_ALIGN(x) (((unsigned long)(x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
+#define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT)
+#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
+#define PFN_PHYS(x) ((phys_addr_t)(x) << PAGE_SHIFT)
+#define PHYS_PFN(x) ((unsigned long)((x) >> PAGE_SHIFT))
+
+#endif /* _LINUXKPI_LINUX_PFN_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/pfn_t.h b/sys/compat/linuxkpi/common/include/linux/pfn_t.h
new file mode 100644
index 000000000000..f22289802cb8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/pfn_t.h
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_PFN_T_H_
+#define _LINUXKPI_LINUX_PFN_T_H_
+
+#include <linux/mm.h>
+
+CTASSERT(PAGE_SHIFT > 4);
+
+#define PFN_FLAGS_MASK (((u64)(PAGE_SIZE - 1)) << (64 - PAGE_SHIFT))
+#define PFN_SG_CHAIN (1ULL << (64 - 1))
+#define PFN_SG_LAST (1ULL << (64 - 2))
+#define PFN_DEV (1ULL << (64 - 3))
+#define PFN_MAP (1ULL << (64 - 4))
+
+static inline pfn_t
+__pfn_to_pfn_t(unsigned long pfn, u64 flags)
+{
+ pfn_t pfn_t = { pfn | (flags & PFN_FLAGS_MASK) };
+
+ return (pfn_t);
+}
+
+static inline pfn_t
+pfn_to_pfn_t(unsigned long pfn)
+{
+ return (__pfn_to_pfn_t (pfn, 0));
+}
+
+#endif /* _LINUXKPI_LINUX_PFN_T_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/pid.h b/sys/compat/linuxkpi/common/include/linux/pid.h
new file mode 100644
index 000000000000..60cb9f725b21
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/pid.h
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_PID_H_
+#define _LINUXKPI_LINUX_PID_H_
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+
+enum pid_type {
+ PIDTYPE_PID,
+ PIDTYPE_PGID,
+ PIDTYPE_SID,
+ PIDTYPE_MAX
+};
+
+#define pid_nr(n) (n)
+#define pid_vnr(n) (n)
+#define from_kuid_munged(a, uid) (uid)
+
+#define pid_task(pid, type) ({ \
+ struct task_struct *__ts; \
+ CTASSERT((type) == PIDTYPE_PID); \
+ __ts = linux_pid_task(pid); \
+ __ts; \
+})
+
+#define get_pid_task(pid, type) ({ \
+ struct task_struct *__ts; \
+ CTASSERT((type) == PIDTYPE_PID); \
+ __ts = linux_get_pid_task(pid); \
+ __ts; \
+})
+
+#define get_task_pid(task, type) ({ \
+ CTASSERT((type) == PIDTYPE_PID); \
+ (task)->task_thread->td_tid; \
+})
+
+struct task_struct;
+extern struct task_struct *linux_pid_task(pid_t);
+extern struct task_struct *linux_get_pid_task(pid_t);
+
+#endif /* _LINUXKPI_LINUX_PID_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/platform_device.h b/sys/compat/linuxkpi/common/include/linux/platform_device.h
new file mode 100644
index 000000000000..6853e709cb70
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/platform_device.h
@@ -0,0 +1,97 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020-2022 Bjoern A. Zeeb
+ *
+ * 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_PLATFORM_DEVICE_H
+#define _LINUXKPI_LINUX_PLATFORM_DEVICE_H
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+
+struct platform_device {
+ const char *name;
+ int id;
+ bool id_auto;
+ struct device dev;
+};
+
+struct platform_driver {
+ int (*remove)(struct platform_device *);
+ struct device_driver driver;
+};
+
+#define dev_is_platform(dev) (false)
+#define to_platform_device(dev) (NULL)
+
+static __inline int
+platform_driver_register(struct platform_driver *pdrv)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (-ENXIO);
+}
+
+static __inline void *
+dev_get_platdata(struct device *dev)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (NULL);
+}
+
+static __inline int
+platform_driver_probe(struct platform_driver *pdrv,
+ int(*pd_probe_f)(struct platform_device *))
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (-ENODEV);
+}
+
+static __inline void
+platform_driver_unregister(struct platform_driver *pdrv)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return;
+}
+
+static __inline int
+platform_device_register(struct platform_device *pdev)
+{
+ pr_debug("%s: TODO\n", __func__);
+ return (0);
+}
+
+static __inline void
+platform_device_unregister(struct platform_device *pdev)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return;
+}
+
+#endif /* _LINUXKPI_LINUX_PLATFORM_DEVICE_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/pm.h b/sys/compat/linuxkpi/common/include/linux/pm.h
new file mode 100644
index 000000000000..c8d943027909
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/pm.h
@@ -0,0 +1,100 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020-2024 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb 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_PM_H
+#define _LINUXKPI_LINUX_PM_H
+
+#include <linux/kernel.h> /* pr_debug */
+#include <asm/atomic.h>
+
+/* Needed but breaks linux_usb.c */
+/* #include <linux/completion.h> */
+/* #include <linux/wait.h> */
+
+struct device;
+
+typedef struct pm_message {
+ int event;
+} pm_message_t;
+
+struct dev_pm_domain {
+};
+
+struct dev_pm_info {
+ atomic_t usage_count;
+};
+
+#define PM_EVENT_FREEZE 0x0001
+#define PM_EVENT_SUSPEND 0x0002
+
+#define pm_sleep_ptr(_p) \
+ IS_ENABLED(CONFIG_PM_SLEEP) ? (_p) : NULL
+
+#ifdef CONFIG_PM_SLEEP
+#define __SET_PM_OPS(_suspendfunc, _resumefunc) \
+ .suspend = _suspendfunc, \
+ .resume = _resumefunc, \
+ .freeze = _suspendfunc, \
+ .thaw = _resumefunc, \
+ .poweroff = _suspendfunc, \
+ .restore = _resumefunc, \
+
+#define SIMPLE_DEV_PM_OPS(_name, _suspendfunc, _resumefunc) \
+const struct dev_pm_ops _name = { \
+ __SET_PM_OPS(_suspendfunc, _resumefunc) \
+}
+
+#define DEFINE_SIMPLE_DEV_PM_OPS(_name, _suspendfunc, _resumefunc) \
+const struct dev_pm_ops _name = { \
+ __SET_PM_OPS(_suspendfunc, _resumefunc) \
+}
+
+#define SET_SYSTEM_SLEEP_PM_OPS(_suspendfunc, _resumefunc) \
+ __SET_PM_OPS(_suspendfunc, _resumefunc)
+#else
+#define SIMPLE_DEV_PM_OPS(_name, _suspendfunc, _resumefunc) \
+const struct dev_pm_ops _name = { \
+}
+#define DEFINE_SIMPLE_DEV_PM_OPS(_name, _suspendfunc, _resumefunc) \
+const struct dev_pm_ops _name = { \
+}
+#endif
+
+bool linuxkpi_device_can_wakeup(struct device *);
+#define device_can_wakeup(_dev) linuxkpi_device_can_wakeup(_dev)
+
+static inline void
+pm_wakeup_event(struct device *dev __unused, unsigned int x __unused)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+}
+
+#endif /* _LINUXKPI_LINUX_PM_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/pm_qos.h b/sys/compat/linuxkpi/common/include/linux/pm_qos.h
new file mode 100644
index 000000000000..47c41a819ba8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/pm_qos.h
@@ -0,0 +1,57 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Bjoern A. Zeeb
+ *
+ * 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_PM_QOS_H
+#define _LINUXKPI_LINUX_PM_QOS_H
+
+#define PM_QOS_DEFAULT_VALUE (-1)
+
+struct pm_qos_request {
+};
+
+static inline void
+cpu_latency_qos_add_request(struct pm_qos_request *qos, int x)
+{
+}
+
+static inline void
+cpu_latency_qos_update_request(struct pm_qos_request *qos, int x)
+{
+}
+
+static inline void
+cpu_latency_qos_remove_request(struct pm_qos_request *qos)
+{
+}
+
+static inline bool
+cpu_latency_qos_request_active(struct pm_qos_request *qos)
+{
+ return (false);
+}
+
+#endif /* _LINUXKPI_LINUX_PM_QOS_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/pm_runtime.h b/sys/compat/linuxkpi/common/include/linux/pm_runtime.h
new file mode 100644
index 000000000000..6114b7b159d7
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/pm_runtime.h
@@ -0,0 +1,54 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_PM_RUNTIME_H_
+#define _LINUXKPI_LINUX_PM_RUNTIME_H_
+
+#include <linux/device.h>
+#include <linux/pm.h>
+
+#define pm_runtime_mark_last_busy(x) (void)(x)
+#define pm_runtime_use_autosuspend(x) (void)(x)
+#define pm_runtime_dont_use_autosuspend(x) (void)(x)
+#define pm_runtime_put_autosuspend(x) (void)(x)
+#define pm_runtime_set_autosuspend_delay(x, y) (void)(x); (void)(y)
+#define pm_runtime_set_active(x) (void)(x)
+#define pm_runtime_allow(x) (void)(x)
+#define pm_runtime_put_noidle(x) (void)(x)
+#define pm_runtime_forbid(x) (void)(x)
+#define pm_runtime_get_noresume(x) (void)(x)
+#define pm_runtime_put(x) (void)(x)
+#define pm_runtime_enable(x) (void)(x)
+#define pm_runtime_disable(x) (void)(x)
+#define pm_runtime_autosuspend(x) (void)(x)
+#define pm_runtime_resume(x) (void)(x)
+
+static inline int
+pm_runtime_get_sync(struct device *dev)
+{
+ return 0;
+}
+
+static inline int
+pm_runtime_get_if_in_use(struct device *dev)
+{
+ return 1;
+}
+
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION < 60900
+static inline int
+pm_runtime_get_if_active(struct device *dev, bool x)
+#else
+static inline int
+pm_runtime_get_if_active(struct device *dev)
+#endif
+{
+ return 1;
+}
+
+static inline int
+pm_runtime_suspended(struct device *dev)
+{
+ return 0;
+}
+
+#endif /* _LINUXKPI_LINUX_PM_RUNTIME_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/poison.h b/sys/compat/linuxkpi/common/include/linux/poison.h
new file mode 100644
index 000000000000..f1594c6dd1dc
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/poison.h
@@ -0,0 +1,9 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_POISON_H
+#define _LINUXKPI_LINUX_POISON_H
+
+#define POISON_INUSE 0xdb
+#define POISON_FREE 0xdf
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/poll.h b/sys/compat/linuxkpi/common/include/linux/poll.h
new file mode 100644
index 000000000000..3acb3c740954
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/poll.h
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_POLL_H_
+#define _LINUXKPI_LINUX_POLL_H_
+
+#include <sys/poll.h>
+#include <sys/fcntl.h>
+
+#include <linux/eventpoll.h>
+#include <linux/wait.h>
+#include <linux/file.h>
+
+typedef struct poll_table_struct {
+} poll_table;
+
+extern void linux_poll_wait(struct linux_file *, wait_queue_head_t *, poll_table *);
+#define poll_wait(...) linux_poll_wait(__VA_ARGS__)
+
+extern void linux_poll_wakeup(struct linux_file *);
+
+#endif /* _LINUXKPI_LINUX_POLL_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/power_supply.h b/sys/compat/linuxkpi/common/include/linux/power_supply.h
new file mode 100644
index 000000000000..8855cfff0539
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/power_supply.h
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot 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_POWER_SUPPLY_H_
+#define _LINUXKPI_LINUX_POWER_SUPPLY_H_
+
+#include <sys/types.h>
+#include <sys/power.h>
+
+static inline int
+power_supply_is_system_supplied(void)
+{
+
+ return (power_profile_get_state() == POWER_PROFILE_PERFORMANCE);
+}
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/preempt.h b/sys/compat/linuxkpi/common/include/linux/preempt.h
new file mode 100644
index 000000000000..32177d4a980c
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/preempt.h
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_PREEMPT_H_
+#define _LINUXKPI_LINUX_PREEMPT_H_
+
+#include <linux/hardirq.h>
+#include <linux/list.h>
+
+#define in_interrupt() \
+ (curthread->td_intr_nesting_level || curthread->td_critnest)
+
+#define in_task() (curthread->td_priority >= PI_SOFT)
+
+#define preempt_disable() critical_enter()
+#define preempt_enable() critical_exit()
+
+#endif /* _LINUXKPI_LINUX_PREEMPT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/prefetch.h b/sys/compat/linuxkpi/common/include/linux/prefetch.h
new file mode 100644
index 000000000000..71839f0ca191
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/prefetch.h
@@ -0,0 +1,34 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot 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_PREFETCH_H_
+#define _LINUXKPI_LINUX_PREFETCH_H_
+
+#define prefetchw(x) __builtin_prefetch(x,1)
+
+#endif /* _LINUXKPI_LINUX_PREFETCH_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/printk.h b/sys/compat/linuxkpi/common/include/linux/printk.h
new file mode 100644
index 000000000000..da9d45122d4d
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/printk.h
@@ -0,0 +1,97 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_PRINTK_H_
+#define _LINUXKPI_LINUX_PRINTK_H_
+
+#include <linux/kernel.h>
+
+/* GID printing macros */
+#define GID_PRINT_FMT "%.4x:%.4x:%.4x:%.4x:%.4x:%.4x:%.4x:%.4x"
+#define GID_PRINT_ARGS(gid_raw) htons(((u16 *)gid_raw)[0]), htons(((u16 *)gid_raw)[1]),\
+ htons(((u16 *)gid_raw)[2]), htons(((u16 *)gid_raw)[3]),\
+ htons(((u16 *)gid_raw)[4]), htons(((u16 *)gid_raw)[5]),\
+ htons(((u16 *)gid_raw)[6]), htons(((u16 *)gid_raw)[7])
+
+enum {
+ DUMP_PREFIX_NONE,
+ DUMP_PREFIX_ADDRESS,
+ DUMP_PREFIX_OFFSET
+};
+
+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);
+
+static inline void
+print_hex_dump(const char *level, const char *prefix_str,
+ const int prefix_type, const int rowsize, const int groupsize,
+ 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);
+}
+
+static inline void
+print_hex_dump_bytes(const char *prefix_str, const int prefix_type,
+ const void *buf, size_t len)
+{
+ print_hex_dump(NULL, prefix_str, prefix_type, 16, 1, buf, len, 0);
+}
+
+#define printk_ratelimit() ({ \
+ static linux_ratelimit_t __ratelimited; \
+ linux_ratelimited(&__ratelimited); \
+})
+
+#define printk_ratelimited(...) ({ \
+ bool __retval = printk_ratelimit(); \
+ if (__retval) \
+ printk(__VA_ARGS__); \
+ __retval; \
+})
+
+#define pr_err_ratelimited(fmt, ...) \
+ printk_ratelimited(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
+
+#define print_hex_dump_debug(...) \
+ print_hex_dump(KERN_DEBUG, ##__VA_ARGS__)
+
+#define pr_info_ratelimited(fmt, ...) \
+ printk_ratelimited(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
+
+#define no_printk(fmt, ...) \
+({ \
+ if (0) \
+ printk(pr_fmt(fmt), ##__VA_ARGS__); \
+ 0; \
+})
+
+#endif /* _LINUXKPI_LINUX_PRINTK_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/ptp_clock_kernel.h b/sys/compat/linuxkpi/common/include/linux/ptp_clock_kernel.h
new file mode 100644
index 000000000000..aad46cc25b1b
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/ptp_clock_kernel.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 2023 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb 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_PTP_CLOCK_KERNEL_H
+#define _LINUXKPI_LINUX_PTP_CLOCK_KERNEL_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/kernel.h> /* pr_debug */
+#include <linux/ktime.h> /* system_device_crosststamp */
+
+/* This very likely belongs elsewhere. */
+struct system_device_crosststamp {
+ ktime_t device;
+ ktime_t sys_realtime;
+ ktime_t sys_monotonic_raw; /* name guessed based on comment */
+};
+
+struct ptp_clock_info {
+ char name[32];
+ int max_adj;
+ void *owner; /* THIS_MODULE */
+ int (*adjfine)(struct ptp_clock_info *, long);
+ 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 *);
+};
+
+static inline struct ptp_clock *
+ptp_clock_register(struct ptp_clock_info *ptpci, struct device *dev)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (NULL);
+}
+
+static inline void
+ptp_clock_unregister(struct ptp_clock *ptpc)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static inline int
+ptp_clock_index(struct ptp_clock *ptpc)
+{
+ pr_debug("%s: TODO\n", __func__);
+ return (0);
+}
+
+#endif /* _LINUXKPI_LINUX_PTP_CLOCK_KERNEL_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/pwm.h b/sys/compat/linuxkpi/common/include/linux/pwm.h
new file mode 100644
index 000000000000..c0740db675e8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/pwm.h
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2022 Vladimir Kondratyev <wulf@FreeBSD.org>
+ *
+ * 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_PWM_H_
+#define _LINUXKPI_LINUX_PWM_H_
+
+#include <linux/device.h>
+#include <linux/err.h>
+
+struct pwm_state {
+ uint64_t period;
+ bool enabled;
+};
+
+struct pwm_device {
+ struct pwm_state state;
+};
+
+static inline struct pwm_device *
+pwm_get(struct device *dev, const char *consumer)
+{
+ return (ERR_PTR(-ENODEV));
+}
+
+static inline void
+pwm_put(struct pwm_device *pwm)
+{
+}
+
+static inline int
+pwm_enable(struct pwm_device *pwm)
+{
+ return (-EINVAL);
+}
+
+static inline void
+pwm_disable(struct pwm_device *pwm)
+{
+}
+
+static inline bool
+pwm_is_enabled(const struct pwm_device *pwm)
+{
+ return (false);
+}
+
+static inline unsigned int
+pwm_get_relative_duty_cycle(const struct pwm_state *state, unsigned int scale)
+{
+ return (0);
+}
+
+static inline int
+pwm_set_relative_duty_cycle(struct pwm_state *state, unsigned int duty_cycle,
+ unsigned int scale)
+{
+ return (0);
+}
+
+static inline void
+pwm_get_state(const struct pwm_device *pwm, struct pwm_state *state)
+{
+ *state = pwm->state;
+}
+
+static inline int
+pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state)
+{
+ return (-ENOTSUPP);
+}
+
+static inline int
+pwm_apply_might_sleep(struct pwm_device *pwm, const struct pwm_state *state)
+{
+ return (0);
+}
+
+#endif /* _LINUXKPI_LINUX_PWM_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/qrtr.h b/sys/compat/linuxkpi/common/include/linux/qrtr.h
new file mode 100644
index 000000000000..1d2af0efdce2
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/qrtr.h
@@ -0,0 +1,41 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Bjoern A. Zeeb
+ *
+ * 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_QRTR_H
+#define _LINUXKPI_LINUX_QRTR_H
+
+/* Qualcomm IPC Router (QRTR) */
+
+#include <sys/socket.h>
+
+struct sockaddr_qrtr {
+ sa_family_t sq_family;
+ uint32_t sq_node;
+ uint32_t sq_port;
+};
+
+#endif /* _LINUXKPI_LINUX_QRTR_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/radix-tree.h b/sys/compat/linuxkpi/common/include/linux/radix-tree.h
new file mode 100644
index 000000000000..ea75836c26fb
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/radix-tree.h
@@ -0,0 +1,84 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2018 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_RADIX_TREE_H_
+#define _LINUXKPI_LINUX_RADIX_TREE_H_
+
+#include <linux/rcupdate.h>
+#include <linux/types.h>
+
+#define RADIX_TREE_MAP_SHIFT 6
+#define RADIX_TREE_MAP_SIZE (1UL << RADIX_TREE_MAP_SHIFT)
+#define RADIX_TREE_MAP_MASK (RADIX_TREE_MAP_SIZE - 1UL)
+#define RADIX_TREE_MAX_HEIGHT \
+ howmany(sizeof(long) * NBBY, RADIX_TREE_MAP_SHIFT)
+
+#define RADIX_TREE_ENTRY_MASK 3UL
+#define RADIX_TREE_EXCEPTIONAL_ENTRY 2UL
+#define RADIX_TREE_EXCEPTIONAL_SHIFT 2
+
+struct radix_tree_node {
+ void *slots[RADIX_TREE_MAP_SIZE];
+ int count;
+};
+
+struct radix_tree_root {
+ struct radix_tree_node *rnode;
+ gfp_t gfp_mask;
+ int height;
+};
+
+struct radix_tree_iter {
+ unsigned long index;
+};
+
+#define RADIX_TREE_INIT(mask) \
+ { .rnode = NULL, .gfp_mask = mask, .height = 0 };
+#define INIT_RADIX_TREE(root, mask) \
+ { (root)->rnode = NULL; (root)->gfp_mask = mask; (root)->height = 0; }
+#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++)
+
+static inline int
+radix_tree_exception(void *arg)
+{
+ return ((uintptr_t)arg & RADIX_TREE_ENTRY_MASK);
+}
+
+void *radix_tree_lookup(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(struct radix_tree_root *, struct radix_tree_iter *, void ***);
+void radix_tree_iter_delete(struct radix_tree_root *, struct radix_tree_iter *, void **);
+
+#endif /* _LINUXKPI_LINUX_RADIX_TREE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/random.h b/sys/compat/linuxkpi/common/include/linux/random.h
new file mode 100644
index 000000000000..893ee2b7b728
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/random.h
@@ -0,0 +1,129 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ * Copyright 2023 The FreeBSD Foundation
+ *
+ * Portions of this software was developed by Björn Zeeb
+ * 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 unmodified, 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 ``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 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_RANDOM_H_
+#define _LINUXKPI_LINUX_RANDOM_H_
+
+#include <linux/types.h>
+#include <sys/random.h>
+#include <sys/libkern.h>
+
+static inline void
+get_random_bytes(void *buf, int nbytes)
+{
+
+ arc4random_buf(buf, nbytes);
+}
+
+static inline u_int
+get_random_int(void)
+{
+ u_int val;
+
+ get_random_bytes(&val, sizeof(val));
+ return (val);
+}
+
+static inline uint8_t
+get_random_u8(void)
+{
+ uint8_t val;
+
+ get_random_bytes(&val, sizeof(val));
+ return (val);
+}
+
+#define get_random_u32() get_random_int()
+
+/*
+ * See "Fast Random Integer Generation in an Interval" by Daniel Lemire
+ * [https://arxiv.org/pdf/1805.10941.pdf] for implementation insights.
+ */
+static inline uint32_t
+get_random_u32_inclusive(uint32_t floor, uint32_t ceil)
+{
+ uint64_t x;
+ uint32_t t, v;
+
+ MPASS(ceil >= floor);
+
+ v = get_random_u32();
+ t = ceil - floor + 1;
+ x = (uint64_t)t * v;
+ while (x < t)
+ x = (uint64_t)t * get_random_u32();
+ v = x >> 32;
+
+ return (floor + v);
+}
+
+static inline u_long
+get_random_long(void)
+{
+ u_long val;
+
+ get_random_bytes(&val, sizeof(val));
+ return (val);
+}
+
+static inline uint64_t
+get_random_u64(void)
+{
+ uint64_t val;
+
+ get_random_bytes(&val, sizeof(val));
+ return (val);
+}
+
+static inline uint32_t
+get_random_u32_below(uint32_t max)
+{
+ return (arc4random_uniform(max));
+}
+
+static __inline uint32_t
+prandom_u32(void)
+{
+ uint32_t val;
+
+ get_random_bytes(&val, sizeof(val));
+ return (val);
+}
+
+static inline u32
+prandom_u32_max(u32 max)
+{
+ return (arc4random_uniform(max));
+}
+
+#endif /* _LINUXKPI_LINUX_RANDOM_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/ratelimit.h b/sys/compat/linuxkpi/common/include/linux/ratelimit.h
new file mode 100644
index 000000000000..9585b4b994d7
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/ratelimit.h
@@ -0,0 +1,17 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_RATELIMIT_H
+#define _LINUXKPI_LINUX_RATELIMIT_H
+
+struct ratelimit_state {
+};
+
+#define DEFINE_RATELIMIT_STATE(name, interval, burst) \
+ int name __used = 1;
+
+#define __ratelimit(x) (1)
+
+#define ratelimit_state_init(x, y, z)
+#define ratelimit_set_flags(x, y)
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/rbtree.h b/sys/compat/linuxkpi/common/include/linux/rbtree.h
new file mode 100644
index 000000000000..e6033cfd760d
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/rbtree.h
@@ -0,0 +1,206 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_RBTREE_H_
+#define _LINUXKPI_LINUX_RBTREE_H_
+
+#ifndef _STANDALONE
+#include <sys/stddef.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/tree.h>
+
+struct rb_node {
+ RB_ENTRY(rb_node) __entry;
+};
+#define rb_left __entry.rbe_link[_RB_L]
+#define rb_right __entry.rbe_link[_RB_R]
+
+/*
+ * We provide a false structure that has the same bit pattern as tree.h
+ * presents so it matches the member names expected by linux.
+ */
+struct rb_root {
+ struct rb_node *rb_node;
+};
+
+struct rb_root_cached {
+ struct rb_root rb_root;
+ struct rb_node *rb_leftmost;
+};
+
+/*
+ * In linux all of the comparisons are done by the caller.
+ */
+int panic_cmp(struct rb_node *one, struct rb_node *two);
+
+RB_HEAD(linux_root, rb_node);
+RB_PROTOTYPE(linux_root, rb_node, __entry, panic_cmp);
+
+#define rb_parent(r) RB_PARENT(r, __entry)
+#define rb_entry(ptr, type, member) container_of(ptr, type, member)
+#define rb_entry_safe(ptr, type, member) \
+ ((ptr) != NULL ? rb_entry(ptr, type, member) : NULL)
+
+#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
+#define RB_EMPTY_NODE(node) (RB_PARENT(node, __entry) == node)
+#define RB_CLEAR_NODE(node) RB_SET_PARENT(node, node, __entry)
+
+#define rb_insert_color(node, root) do { \
+ if (rb_parent(node)) \
+ linux_root_RB_INSERT_COLOR((struct linux_root *)(root), \
+ rb_parent(node), (node)); \
+} while (0)
+#define rb_erase(node, root) \
+ linux_root_RB_REMOVE((struct linux_root *)(root), (node))
+#define rb_next(node) RB_NEXT(linux_root, NULL, (node))
+#define rb_prev(node) RB_PREV(linux_root, NULL, (node))
+#define rb_first(root) RB_MIN(linux_root, (struct linux_root *)(root))
+#define rb_last(root) RB_MAX(linux_root, (struct linux_root *)(root))
+#define rb_first_cached(root) (root)->rb_leftmost
+
+static inline struct rb_node *
+__rb_deepest_left(struct rb_node *node)
+{
+ struct rb_node *parent = NULL;
+ while (node != NULL) {
+ parent = node;
+ if (RB_LEFT(node, __entry))
+ node = RB_LEFT(node, __entry);
+ else
+ node = RB_RIGHT(node, __entry);
+ }
+ return (parent);
+}
+
+static inline struct rb_node *
+rb_next_postorder(const struct rb_node *node)
+{
+ struct rb_node *parent =
+ RB_PARENT(__DECONST(struct rb_node *, node), __entry);
+ /* left -> right, right -> root */
+ if (parent != NULL &&
+ (node == RB_LEFT(parent, __entry)) &&
+ (RB_RIGHT(parent, __entry)))
+ return (__rb_deepest_left(RB_RIGHT(parent, __entry)));
+ else
+ return (parent);
+}
+
+#define rbtree_postorder_for_each_entry_safe(x, y, head, member) \
+ for ((x) = rb_entry_safe(__rb_deepest_left((head)->rb_node), \
+ __typeof(*x), member); \
+ ((x) != NULL) && ((y) = \
+ rb_entry_safe(rb_next_postorder(&x->member), typeof(*x), member), 1); \
+ (x) = (y))
+
+static inline void
+rb_link_node(struct rb_node *node, struct rb_node *parent,
+ struct rb_node **rb_link)
+{
+ RB_SET(node, parent, __entry);
+ *rb_link = node;
+}
+
+static inline void
+rb_replace_node(struct rb_node *victim, struct rb_node *new,
+ struct rb_root *root)
+{
+
+ RB_SWAP_CHILD((struct linux_root *)root, rb_parent(victim),
+ victim, new, __entry);
+ if (RB_LEFT(victim, __entry))
+ RB_SET_PARENT(RB_LEFT(victim, __entry), new, __entry);
+ if (RB_RIGHT(victim, __entry))
+ RB_SET_PARENT(RB_RIGHT(victim, __entry), new, __entry);
+ *new = *victim;
+}
+
+static inline void
+rb_insert_color_cached(struct rb_node *node, struct rb_root_cached *root,
+ bool leftmost)
+{
+ if (rb_parent(node))
+ linux_root_RB_INSERT_COLOR((struct linux_root *)&root->rb_root,
+ rb_parent(node), node);
+ if (leftmost)
+ root->rb_leftmost = node;
+}
+
+static inline struct rb_node *
+rb_erase_cached(struct rb_node *node, struct rb_root_cached *root)
+{
+ struct rb_node *retval;
+
+ if (node == root->rb_leftmost)
+ retval = root->rb_leftmost = linux_root_RB_NEXT(node);
+ else
+ retval = NULL;
+ linux_root_RB_REMOVE((struct linux_root *)&root->rb_root, node);
+ return (retval);
+}
+
+static inline void
+rb_replace_node_cached(struct rb_node *old, struct rb_node *new,
+ struct rb_root_cached *root)
+{
+ rb_replace_node(old, new, &root->rb_root);
+ if (root->rb_leftmost == old)
+ root->rb_leftmost = new;
+}
+
+static inline struct rb_node *
+rb_add_cached(struct rb_node *node, struct rb_root_cached *tree,
+ bool (*less)(struct rb_node *, const struct rb_node *))
+{
+ struct rb_node **link = &tree->rb_root.rb_node;
+ struct rb_node *parent = NULL;
+ bool leftmost = true;
+
+ while (*link != NULL) {
+ parent = *link;
+ if (less(node, parent)) {
+ link = &RB_LEFT(parent, __entry);
+ } else {
+ link = &RB_RIGHT(parent, __entry);
+ leftmost = false;
+ }
+ }
+
+ rb_link_node(node, parent, link);
+ rb_insert_color_cached(node, tree, leftmost);
+
+ return (leftmost ? node : NULL);
+}
+
+#undef RB_ROOT
+#define RB_ROOT (struct rb_root) { NULL }
+#define RB_ROOT_CACHED (struct rb_root_cached) { RB_ROOT, NULL }
+
+#endif /* _LINUXKPI_LINUX_RBTREE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/rculist.h b/sys/compat/linuxkpi/common/include/linux/rculist.h
new file mode 100644
index 000000000000..066ed92b7996
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/rculist.h
@@ -0,0 +1,147 @@
+/*-
+ * Copyright (c) 2015 François Tigeot
+ * Copyright (c) 2016-2020 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_RCULIST_H_
+#define _LINUXKPI_LINUX_RCULIST_H_
+
+#include <linux/list.h>
+#include <linux/rcupdate.h>
+
+#define list_entry_rcu(ptr, type, member) \
+ container_of(READ_ONCE(ptr), type, member)
+
+#define list_next_rcu(head) (*((struct list_head **)(&(head)->next)))
+#define list_prev_rcu(head) (*((struct list_head **)(&(head)->prev)))
+
+#define list_for_each_entry_rcu(pos, head, member) \
+ for (pos = list_entry_rcu((head)->next, typeof(*(pos)), member); \
+ &(pos)->member != (head); \
+ pos = list_entry_rcu((pos)->member.next, typeof(*(pos)), member))
+
+#define list_for_each_entry_from_rcu(pos, head, member) \
+ for (; \
+ &(pos)->member != (head); \
+ pos = list_entry_rcu((pos)->member.next, typeof(*(pos)), member))
+
+#define list_for_each_entry_lockless(pos, head, member) \
+ list_for_each_entry_rcu(pos, head, member)
+
+static inline void
+linux_list_add_rcu(struct list_head *new, struct list_head *prev,
+ struct list_head *next)
+{
+ new->next = next;
+ new->prev = prev;
+ rcu_assign_pointer(list_next_rcu(prev), new);
+ next->prev = new;
+}
+
+static inline void
+list_add_rcu(struct list_head *new, struct list_head *head)
+{
+ linux_list_add_rcu(new, head, head->next);
+}
+
+static inline void
+list_add_tail_rcu(struct list_head *new, struct list_head *head)
+{
+ linux_list_add_rcu(new, head->prev, head);
+}
+
+static inline void
+__list_del_rcu(struct list_head *prev, struct list_head *next)
+{
+ next->prev = prev;
+ rcu_assign_pointer(list_next_rcu(prev), next);
+}
+
+static inline void
+__list_del_entry_rcu(struct list_head *entry)
+{
+ __list_del_rcu(entry->prev, entry->next);
+}
+
+static inline void
+list_del_rcu(struct list_head *entry)
+{
+ __list_del_rcu(entry->prev, entry->next);
+}
+
+#define hlist_first_rcu(head) (*((struct hlist_node **)(&(head)->first)))
+#define hlist_next_rcu(node) (*((struct hlist_node **)(&(node)->next)))
+#define hlist_pprev_rcu(node) (*((struct hlist_node **)((node)->pprev)))
+
+static inline void
+hlist_add_behind_rcu(struct hlist_node *n, struct hlist_node *prev)
+{
+ n->next = prev->next;
+ n->pprev = &prev->next;
+ rcu_assign_pointer(hlist_next_rcu(prev), n);
+ if (n->next)
+ n->next->pprev = &n->next;
+}
+
+#define hlist_for_each_entry_rcu(pos, head, member) \
+ for (pos = hlist_entry_safe (rcu_dereference_raw(hlist_first_rcu(head)),\
+ typeof(*(pos)), member); \
+ (pos); \
+ pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu( \
+ &(pos)->member)), typeof(*(pos)), member))
+
+static inline void
+hlist_del_rcu(struct hlist_node *n)
+{
+ struct hlist_node *next = n->next;
+ struct hlist_node **pprev = n->pprev;
+
+ WRITE_ONCE(*pprev, next);
+ if (next)
+ next->pprev = pprev;
+}
+
+static inline void
+hlist_add_head_rcu(struct hlist_node *n, struct hlist_head *h)
+{
+ struct hlist_node *first = h->first;
+
+ n->next = first;
+ n->pprev = &h->first;
+ rcu_assign_pointer(hlist_first_rcu(h), n);
+ if (first)
+ first->pprev = &n->next;
+}
+
+static inline void
+hlist_del_init_rcu(struct hlist_node *n)
+{
+ if (!hlist_unhashed(n)) {
+ hlist_del_rcu(n);
+ n->pprev = NULL;
+ }
+}
+
+#endif /* _LINUXKPI_LINUX_RCULIST_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/rcupdate.h b/sys/compat/linuxkpi/common/include/linux/rcupdate.h
new file mode 100644
index 000000000000..85d766c8dbc9
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/rcupdate.h
@@ -0,0 +1,165 @@
+/*-
+ * Copyright (c) 2016-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ * Copyright (c) 2024 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * 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 unmodified, 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 ``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 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_RCUPDATE_H_
+#define _LINUXKPI_LINUX_RCUPDATE_H_
+
+#include <sys/cdefs.h>
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <machine/atomic.h>
+
+extern int linuxkpi_rcu_debug;
+#define RCU_WARN_ONCE(c, ...) do { \
+ if (unlikely(linuxkpi_rcu_debug > 0)) \
+ WARN_ONCE((c), ##__VA_ARGS__); \
+} while(0)
+
+#define LINUX_KFREE_RCU_OFFSET_MAX 4096 /* exclusive */
+
+/* BSD specific defines */
+#define RCU_TYPE_REGULAR 0
+#define RCU_TYPE_SLEEPABLE 1
+#define RCU_TYPE_MAX 2
+
+#define RCU_INITIALIZER(v) \
+ ((__typeof(*(v)) *)(v))
+
+#define RCU_INIT_POINTER(p, v) do { \
+ (p) = (v); \
+} while (0)
+
+#define call_rcu(ptr, func) do { \
+ linux_call_rcu(RCU_TYPE_REGULAR, ptr, func); \
+} while (0)
+
+#define rcu_barrier(void) do { \
+ linux_rcu_barrier(RCU_TYPE_REGULAR); \
+} while (0)
+
+#define rcu_read_lock(void) do { \
+ linux_rcu_read_lock(RCU_TYPE_REGULAR); \
+} while (0)
+
+#define rcu_read_unlock(void) do { \
+ linux_rcu_read_unlock(RCU_TYPE_REGULAR);\
+} while (0)
+
+#define rcu_read_lock_held(void) \
+ linux_rcu_read_lock_held(RCU_TYPE_REGULAR)
+
+#define synchronize_rcu(void) do { \
+ linux_synchronize_rcu(RCU_TYPE_REGULAR); \
+} while (0)
+
+#define synchronize_rcu_expedited(void) do { \
+ linux_synchronize_rcu(RCU_TYPE_REGULAR); \
+} while (0)
+
+#define kfree_rcu(ptr, rcu_head) do { \
+ CTASSERT(offsetof(__typeof(*(ptr)), rcu_head) < \
+ LINUX_KFREE_RCU_OFFSET_MAX); \
+ call_rcu(&(ptr)->rcu_head, (rcu_callback_t)(uintptr_t) \
+ offsetof(__typeof(*(ptr)), rcu_head)); \
+} while (0)
+
+#define rcu_access_pointer(p) \
+ ((__typeof(*p) *)READ_ONCE(p))
+
+#define rcu_dereference(p) \
+ ((__typeof(*p) *)READ_ONCE(p))
+
+#define __rcu_var_name(n, f, l) \
+ __CONCAT(__CONCAT(__CONCAT(rcu_, n), _), __COUNTER__)
+
+#define __rcu_dereference_protected(p, c, n) \
+({ \
+ RCU_WARN_ONCE(!(c), "%s:%d: condition for %s failed\n", \
+ __func__, __LINE__, __XSTRING(n)); \
+ rcu_dereference(p); \
+})
+
+#define rcu_dereference_protected(p, c) \
+ __rcu_dereference_protected((p), (c), \
+ __rcu_var_name(protected, __func__, __LINE__))
+
+#define __rcu_dereference_check(p, c, n) \
+({ \
+ __typeof(*p) *n = rcu_dereference(p); \
+ RCU_WARN_ONCE(!(c), "%s:%d: condition for %s failed\n", \
+ __func__, __LINE__, __XSTRING(n)); \
+ n; \
+})
+
+#define rcu_dereference_check(p, c) \
+ __rcu_dereference_check((p), (c) || rcu_read_lock_held(), \
+ __rcu_var_name(check, __func__, __LINE__))
+
+#define rcu_dereference_raw(p) \
+ ((__typeof(*p) *)READ_ONCE(p))
+
+#define rcu_pointer_handoff(p) (p)
+
+#define rcu_assign_pointer(p, v) do { \
+ atomic_store_rel_ptr((volatile uintptr_t *)&(p), \
+ (uintptr_t)(v)); \
+} while (0)
+
+#define rcu_replace_pointer(rcu, ptr, c) \
+({ \
+ typeof(ptr) __tmp = rcu_dereference_protected(rcu, c); \
+ rcu_assign_pointer(rcu, ptr); \
+ __tmp; \
+})
+
+#define rcu_swap_protected(rcu, ptr, c) do { \
+ typeof(ptr) p = rcu_dereference_protected(rcu, c); \
+ rcu_assign_pointer(rcu, ptr); \
+ (ptr) = p; \
+} while (0)
+
+/* prototypes */
+
+void linux_call_rcu(unsigned type, struct rcu_head *ptr, rcu_callback_t func);
+void linux_rcu_barrier(unsigned type);
+void linux_rcu_read_lock(unsigned type);
+void linux_rcu_read_unlock(unsigned type);
+bool linux_rcu_read_lock_held(unsigned);
+void linux_synchronize_rcu(unsigned type);
+
+/* Empty implementation for !DEBUG */
+#define init_rcu_head(...)
+#define destroy_rcu_head(...)
+#define init_rcu_head_on_stack(...)
+#define destroy_rcu_head_on_stack(...)
+
+#endif /* _LINUXKPI_LINUX_RCUPDATE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/reboot.h b/sys/compat/linuxkpi/common/include/linux/reboot.h
new file mode 100644
index 000000000000..eb696d7b9d2e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/reboot.h
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2022 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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_REBOOT_H_
+#define _LINUXKPI_LINUX_REBOOT_H_
+
+#include <sys/reboot.h>
+
+static inline void
+orderly_poweroff(bool force)
+{
+
+ shutdown_nice(RB_POWEROFF);
+}
+
+#endif
+
diff --git a/sys/compat/linuxkpi/common/include/linux/ref_tracker.h b/sys/compat/linuxkpi/common/include/linux/ref_tracker.h
new file mode 100644
index 000000000000..fa510b2498e1
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/ref_tracker.h
@@ -0,0 +1,93 @@
+/*-
+ * 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_REF_TRACKER_H_
+#define _LINUXKPI_LINUX_REF_TRACKER_H_
+
+#include <linux/refcount.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/stackdepot.h>
+
+struct ref_tracker;
+
+struct ref_tracker_dir {
+};
+
+/*
+ * The following functions currently have dummy implementations that, on Linux,
+ * are used when CONFIG_REF_TRACKER is not set at compile time.
+ *
+ * The ref tracker is a tool to associate a refcount increase to a refcount
+ * decrease. This helps developers track, document and debug refcounts. We
+ * don't need this feature for now in linuxkpi.
+ */
+
+static inline void
+ref_tracker_dir_init(struct ref_tracker_dir *dir,
+ unsigned int quarantine_count, const char *name)
+{
+}
+
+static inline void
+ref_tracker_dir_exit(struct ref_tracker_dir *dir)
+{
+}
+
+static inline void
+ref_tracker_dir_print_locked(struct ref_tracker_dir *dir,
+ unsigned int display_limit)
+{
+}
+
+static inline void
+ref_tracker_dir_print(struct ref_tracker_dir *dir, unsigned int display_limit)
+{
+}
+
+static inline int
+ref_tracker_dir_snprint(struct ref_tracker_dir *dir, char *buf, size_t size)
+{
+ return (0);
+}
+
+static inline int
+ref_tracker_alloc(struct ref_tracker_dir *dir, struct ref_tracker **trackerp,
+ gfp_t gfp)
+{
+ return (0);
+}
+
+static inline int
+ref_tracker_free(struct ref_tracker_dir *dir, struct ref_tracker **trackerp)
+{
+ return (0);
+}
+
+#endif /* !defined(_LINUXKPI_LINUX_REF_TRACKER_H_) */
diff --git a/sys/compat/linuxkpi/common/include/linux/refcount.h b/sys/compat/linuxkpi/common/include/linux/refcount.h
new file mode 100644
index 000000000000..02a7eda3f4a9
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/refcount.h
@@ -0,0 +1,84 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot 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_REFCOUNT_H
+#define _LINUXKPI_LINUX_REFCOUNT_H
+
+#include <linux/atomic.h>
+
+typedef atomic_t refcount_t;
+
+static inline void
+refcount_set(refcount_t *ref, unsigned int i)
+{
+ atomic_set(ref, i);
+}
+
+static inline void
+refcount_inc(refcount_t *ref)
+{
+ atomic_inc(ref);
+}
+
+static inline bool
+refcount_inc_not_zero(refcount_t *ref)
+{
+ return (atomic_inc_not_zero(ref));
+}
+
+static inline void
+refcount_dec(refcount_t *ref)
+{
+ atomic_dec(ref);
+}
+
+static inline unsigned int
+refcount_read(refcount_t *ref)
+{
+ return atomic_read(ref);
+}
+
+static inline bool
+refcount_dec_and_lock_irqsave(refcount_t *ref, spinlock_t *lock,
+ unsigned long *flags)
+{
+ if (atomic_dec_and_test(ref) == true) {
+ spin_lock_irqsave(lock, flags);
+ return (true);
+ }
+ return (false);
+}
+
+static inline bool
+refcount_dec_and_test(refcount_t *r)
+{
+
+ return (atomic_dec_and_test(r));
+}
+
+#endif /* __LINUXKPI_LINUX_REFCOUNT_H__ */
diff --git a/sys/compat/linuxkpi/common/include/linux/rhashtable.h b/sys/compat/linuxkpi/common/include/linux/rhashtable.h
new file mode 100644
index 000000000000..c6958b6ee5f3
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/rhashtable.h
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2023 Bjoern A. Zeeb
+ *
+ * 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_RHASHTABLE_H
+#define _LINUXKPI_LINUX_RHASHTABLE_H
+
+#include <linux/kernel.h> /* pr_debug */
+
+struct rhash_head {
+};
+
+struct rhashtable_params {
+ uint16_t head_offset;
+ uint16_t key_len;
+ uint16_t key_offset;
+ uint16_t nelem_hint;
+ bool automatic_shrinking;
+};
+
+struct rhashtable {
+};
+
+static inline int
+rhashtable_init(struct rhashtable *rht,
+ const struct rhashtable_params *params)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (-1);
+}
+
+static inline void
+rhashtable_destroy(struct rhashtable *rht)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static inline void *
+rhashtable_lookup_fast(struct rhashtable *rht, const void *key,
+ const struct rhashtable_params params)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (NULL);
+}
+
+static inline void *
+rhashtable_lookup_get_insert_fast(struct rhashtable *rht,
+ struct rhash_head *obj, const struct rhashtable_params params)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (NULL);
+}
+
+static inline int
+rhashtable_remove_fast(struct rhashtable *rht,
+ struct rhash_head *obj, const struct rhashtable_params params)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (-ENOENT);
+}
+
+#endif /* _LINUXKPI_LINUX_RHASHTABLE_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/rwlock.h b/sys/compat/linuxkpi/common/include/linux/rwlock.h
new file mode 100644
index 000000000000..3030ec89ff1e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/rwlock.h
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_RWLOCK_H_
+#define _LINUXKPI_LINUX_RWLOCK_H_
+
+#include <sys/types.h>
+#include <sys/lock.h>
+#include <sys/rwlock.h>
+#include <sys/libkern.h>
+
+typedef struct rwlock rwlock_t;
+
+#define read_lock(_l) rw_rlock(_l)
+#define write_lock(_l) rw_wlock(_l)
+#define read_unlock(_l) rw_runlock(_l)
+#define write_unlock(_l) rw_wunlock(_l)
+#define read_lock_irq(lock) read_lock((lock))
+#define read_unlock_irq(lock) read_unlock((lock))
+#define write_lock_irq(lock) write_lock((lock))
+#define write_unlock_irq(lock) write_unlock((lock))
+#define read_lock_irqsave(lock, flags) \
+ do {(flags) = 0; read_lock(lock); } while (0)
+#define write_lock_irqsave(lock, flags) \
+ do {(flags) = 0; write_lock(lock); } while (0)
+#define read_unlock_irqrestore(lock, flags) \
+ do { read_unlock(lock); } while (0)
+#define write_unlock_irqrestore(lock, flags) \
+ do { write_unlock(lock); } while (0)
+#define rwlock_init(_l) rw_init_flags(_l, "lnxrw", RW_NOWITNESS | RW_NEW)
+
+#endif /* _LINUXKPI_LINUX_RWLOCK_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/rwsem.h b/sys/compat/linuxkpi/common/include/linux/rwsem.h
new file mode 100644
index 000000000000..b7a800b12e18
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/rwsem.h
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_RWSEM_H_
+#define _LINUXKPI_LINUX_RWSEM_H_
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/sx.h>
+#include <sys/libkern.h>
+#include <sys/kernel.h>
+
+struct rw_semaphore {
+ struct sx sx;
+};
+
+#define down_write(_rw) sx_xlock(&(_rw)->sx)
+#define up_write(_rw) sx_xunlock(&(_rw)->sx)
+#define down_read(_rw) sx_slock(&(_rw)->sx)
+#define up_read(_rw) sx_sunlock(&(_rw)->sx)
+#define down_read_trylock(_rw) !!sx_try_slock(&(_rw)->sx)
+#define down_read_killable(_rw) linux_down_read_killable(_rw)
+#define down_write_trylock(_rw) !!sx_try_xlock(&(_rw)->sx)
+#define down_write_killable(_rw) linux_down_write_killable(_rw)
+#define downgrade_write(_rw) sx_downgrade(&(_rw)->sx)
+#define down_read_nested(_rw, _sc) down_read(_rw)
+#define init_rwsem(_rw) linux_init_rwsem(_rw, rwsem_name("lnxrwsem"))
+#define down_write_nest_lock(sem, _rw) down_write(_rw)
+
+#ifdef WITNESS_ALL
+/* NOTE: the maximum WITNESS name is 64 chars */
+#define __rwsem_name(name, file, line) \
+ (((const char *){file ":" #line "-" name}) + \
+ (sizeof(file) > 16 ? sizeof(file) - 16 : 0))
+#else
+#define __rwsem_name(name, file, line) name
+#endif
+#define _rwsem_name(...) __rwsem_name(__VA_ARGS__)
+#define rwsem_name(name) _rwsem_name(name, __FILE__, __LINE__)
+
+#define DECLARE_RWSEM(name) \
+struct rw_semaphore name; \
+static void name##_rwsem_init(void *arg) \
+{ \
+ linux_init_rwsem(&name, rwsem_name(#name)); \
+} \
+SYSINIT(name, SI_SUB_LOCK, SI_ORDER_SECOND, name##_rwsem_init, NULL)
+
+static inline void
+linux_init_rwsem(struct rw_semaphore *rw, const char *name)
+{
+
+ memset(rw, 0, sizeof(*rw));
+ sx_init_flags(&rw->sx, name, SX_NOWITNESS);
+}
+
+extern int linux_down_read_killable(struct rw_semaphore *);
+extern int linux_down_write_killable(struct rw_semaphore *);
+
+#endif /* _LINUXKPI_LINUX_RWSEM_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/scatterlist.h b/sys/compat/linuxkpi/common/include/linux/scatterlist.h
new file mode 100644
index 000000000000..537f5bebc5aa
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/scatterlist.h
@@ -0,0 +1,684 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * Copyright (c) 2015 Matthew Dillon <dillon@backplane.com>
+ * Copyright (c) 2016 Matthew Macy
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_SCATTERLIST_H_
+#define _LINUXKPI_LINUX_SCATTERLIST_H_
+
+#include <sys/types.h>
+#include <sys/proc.h>
+#include <sys/sched.h>
+#include <sys/sf_buf.h>
+
+#include <linux/err.h>
+#include <linux/page.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+
+struct bus_dmamap;
+struct scatterlist {
+ unsigned long page_link;
+#define SG_PAGE_LINK_CHAIN 0x1UL
+#define SG_PAGE_LINK_LAST 0x2UL
+#define SG_PAGE_LINK_MASK 0x3UL
+ unsigned int offset;
+ unsigned int length;
+ dma_addr_t dma_address;
+ struct bus_dmamap *dma_map; /* FreeBSD specific */
+};
+
+CTASSERT((sizeof(struct scatterlist) & SG_PAGE_LINK_MASK) == 0);
+
+struct sg_table {
+ struct scatterlist *sgl;
+ unsigned int nents;
+ unsigned int orig_nents;
+};
+
+struct sg_page_iter {
+ struct scatterlist *sg;
+ unsigned int sg_pgoffset;
+ unsigned int maxents;
+ struct {
+ unsigned int nents;
+ int pg_advance;
+ } internal;
+};
+
+struct sg_dma_page_iter {
+ struct sg_page_iter base;
+};
+
+#define SCATTERLIST_MAX_SEGMENT (-1U & ~(PAGE_SIZE - 1))
+
+#define SG_MAX_SINGLE_ALLOC (PAGE_SIZE / sizeof(struct scatterlist))
+
+#define SG_MAGIC 0x87654321UL
+#define SG_CHAIN SG_PAGE_LINK_CHAIN
+#define SG_END SG_PAGE_LINK_LAST
+
+#define sg_is_chain(sg) ((sg)->page_link & SG_PAGE_LINK_CHAIN)
+#define sg_is_last(sg) ((sg)->page_link & SG_PAGE_LINK_LAST)
+#define sg_chain_ptr(sg) \
+ ((struct scatterlist *) ((sg)->page_link & ~SG_PAGE_LINK_MASK))
+
+#define sg_dma_address(sg) (sg)->dma_address
+#define sg_dma_len(sg) (sg)->length
+
+#define for_each_sg_page(sgl, iter, nents, pgoffset) \
+ for (_sg_iter_init(sgl, iter, nents, pgoffset); \
+ (iter)->sg; _sg_iter_next(iter))
+#define for_each_sg_dma_page(sgl, iter, nents, pgoffset) \
+ for_each_sg_page(sgl, &(iter)->base, nents, pgoffset)
+
+#define for_each_sg(sglist, sg, sgmax, iter) \
+ for (iter = 0, sg = (sglist); iter < (sgmax); iter++, sg = sg_next(sg))
+
+#define for_each_sgtable_sg(sgt, sg, i) \
+ for_each_sg((sgt)->sgl, sg, (sgt)->orig_nents, i)
+
+#define for_each_sgtable_page(sgt, iter, pgoffset) \
+ for_each_sg_page((sgt)->sgl, iter, (sgt)->orig_nents, pgoffset)
+
+#define for_each_sgtable_dma_sg(sgt, sg, iter) \
+ for_each_sg((sgt)->sgl, sg, (sgt)->nents, iter)
+
+#define for_each_sgtable_dma_page(sgt, iter, pgoffset) \
+ for_each_sg_dma_page((sgt)->sgl, iter, (sgt)->nents, pgoffset)
+
+typedef struct scatterlist *(sg_alloc_fn) (unsigned int, gfp_t);
+typedef void (sg_free_fn) (struct scatterlist *, unsigned int);
+
+static inline void
+sg_assign_page(struct scatterlist *sg, struct page *page)
+{
+ unsigned long page_link = sg->page_link & SG_PAGE_LINK_MASK;
+
+ sg->page_link = page_link | (unsigned long)page;
+}
+
+static inline void
+sg_set_page(struct scatterlist *sg, struct page *page, unsigned int len,
+ unsigned int offset)
+{
+ sg_assign_page(sg, page);
+ sg->offset = offset;
+ sg->length = len;
+}
+
+static inline struct page *
+sg_page(struct scatterlist *sg)
+{
+ return ((struct page *)((sg)->page_link & ~SG_PAGE_LINK_MASK));
+}
+
+static inline void
+sg_set_buf(struct scatterlist *sg, const void *buf, unsigned int buflen)
+{
+ sg_set_page(sg, virt_to_page(buf), buflen,
+ ((uintptr_t)buf) & (PAGE_SIZE - 1));
+}
+
+static inline struct scatterlist *
+sg_next(struct scatterlist *sg)
+{
+ if (sg_is_last(sg))
+ return (NULL);
+ sg++;
+ if (sg_is_chain(sg))
+ sg = sg_chain_ptr(sg);
+ return (sg);
+}
+
+static inline vm_paddr_t
+sg_phys(struct scatterlist *sg)
+{
+ return (page_to_phys(sg_page(sg)) + sg->offset);
+}
+
+static inline void *
+sg_virt(struct scatterlist *sg)
+{
+
+ return ((void *)((unsigned long)page_address(sg_page(sg)) + sg->offset));
+}
+
+static inline void
+sg_chain(struct scatterlist *prv, unsigned int prv_nents,
+ struct scatterlist *sgl)
+{
+ struct scatterlist *sg = &prv[prv_nents - 1];
+
+ sg->offset = 0;
+ sg->length = 0;
+ sg->page_link = ((unsigned long)sgl |
+ SG_PAGE_LINK_CHAIN) & ~SG_PAGE_LINK_LAST;
+}
+
+static inline void
+sg_mark_end(struct scatterlist *sg)
+{
+ sg->page_link |= SG_PAGE_LINK_LAST;
+ sg->page_link &= ~SG_PAGE_LINK_CHAIN;
+}
+
+static inline void
+sg_init_table(struct scatterlist *sg, unsigned int nents)
+{
+ bzero(sg, sizeof(*sg) * nents);
+ sg_mark_end(&sg[nents - 1]);
+}
+
+static inline void
+sg_init_one(struct scatterlist *sg, const void *buf, unsigned int buflen)
+{
+ sg_init_table(sg, 1);
+ sg_set_buf(sg, buf, buflen);
+}
+
+static struct scatterlist *
+sg_kmalloc(unsigned int nents, gfp_t gfp_mask)
+{
+ if (nents == SG_MAX_SINGLE_ALLOC) {
+ return ((void *)__get_free_page(gfp_mask));
+ } else
+ return (kmalloc(nents * sizeof(struct scatterlist), gfp_mask));
+}
+
+static inline void
+sg_kfree(struct scatterlist *sg, unsigned int nents)
+{
+ if (nents == SG_MAX_SINGLE_ALLOC) {
+ free_page((unsigned long)sg);
+ } else
+ kfree(sg);
+}
+
+static inline void
+__sg_free_table(struct sg_table *table, unsigned int max_ents,
+ bool skip_first_chunk, sg_free_fn * free_fn)
+{
+ struct scatterlist *sgl, *next;
+
+ if (unlikely(!table->sgl))
+ return;
+
+ sgl = table->sgl;
+ while (table->orig_nents) {
+ unsigned int alloc_size = table->orig_nents;
+ unsigned int sg_size;
+
+ if (alloc_size > max_ents) {
+ next = sg_chain_ptr(&sgl[max_ents - 1]);
+ alloc_size = max_ents;
+ sg_size = alloc_size - 1;
+ } else {
+ sg_size = alloc_size;
+ next = NULL;
+ }
+
+ table->orig_nents -= sg_size;
+ if (skip_first_chunk)
+ skip_first_chunk = 0;
+ else
+ free_fn(sgl, alloc_size);
+ sgl = next;
+ }
+
+ table->sgl = NULL;
+}
+
+static inline void
+sg_free_table(struct sg_table *table)
+{
+ __sg_free_table(table, SG_MAX_SINGLE_ALLOC, 0, sg_kfree);
+}
+
+static inline int
+__sg_alloc_table(struct sg_table *table, unsigned int nents,
+ unsigned int max_ents, struct scatterlist *first_chunk,
+ gfp_t gfp_mask, sg_alloc_fn *alloc_fn)
+{
+ struct scatterlist *sg, *prv;
+ unsigned int left;
+
+ memset(table, 0, sizeof(*table));
+
+ if (nents == 0)
+ return (-EINVAL);
+ left = nents;
+ prv = NULL;
+ do {
+ unsigned int sg_size;
+ unsigned int alloc_size = left;
+
+ if (alloc_size > max_ents) {
+ alloc_size = max_ents;
+ sg_size = alloc_size - 1;
+ } else
+ sg_size = alloc_size;
+
+ left -= sg_size;
+
+ if (first_chunk) {
+ sg = first_chunk;
+ first_chunk = NULL;
+ } else {
+ sg = alloc_fn(alloc_size, gfp_mask);
+ }
+ if (unlikely(!sg)) {
+ if (prv)
+ table->nents = ++table->orig_nents;
+
+ return (-ENOMEM);
+ }
+ sg_init_table(sg, alloc_size);
+ table->nents = table->orig_nents += sg_size;
+
+ if (prv)
+ sg_chain(prv, max_ents, sg);
+ else
+ table->sgl = sg;
+
+ if (!left)
+ sg_mark_end(&sg[sg_size - 1]);
+
+ prv = sg;
+ } while (left);
+
+ return (0);
+}
+
+static inline int
+sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
+{
+ int ret;
+
+ ret = __sg_alloc_table(table, nents, SG_MAX_SINGLE_ALLOC,
+ NULL, gfp_mask, sg_kmalloc);
+ if (unlikely(ret))
+ __sg_free_table(table, SG_MAX_SINGLE_ALLOC, 0, sg_kfree);
+
+ return (ret);
+}
+
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
+static inline struct scatterlist *
+__sg_alloc_table_from_pages(struct sg_table *sgt,
+ struct page **pages, unsigned int count,
+ unsigned long off, unsigned long size,
+ unsigned int max_segment,
+ struct scatterlist *prv, unsigned int left_pages,
+ gfp_t gfp_mask)
+#else
+static inline int
+__sg_alloc_table_from_pages(struct sg_table *sgt,
+ struct page **pages, unsigned int count,
+ unsigned long off, unsigned long size,
+ unsigned int max_segment, gfp_t gfp_mask)
+#endif
+{
+ unsigned int i, segs, cur, len;
+ int rc;
+ struct scatterlist *s, *sg_iter;
+
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
+ if (prv != NULL) {
+ panic(
+ "Support for prv != NULL not implemented in "
+ "__sg_alloc_table_from_pages()");
+ }
+#endif
+
+ if (__predict_false(!max_segment || offset_in_page(max_segment)))
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
+ return (ERR_PTR(-EINVAL));
+#else
+ return (-EINVAL);
+#endif
+
+ len = 0;
+ for (segs = i = 1; i < count; ++i) {
+ len += PAGE_SIZE;
+ if (len >= max_segment ||
+ page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1) {
+ ++segs;
+ len = 0;
+ }
+ }
+ if (__predict_false((rc = sg_alloc_table(sgt, segs, gfp_mask))))
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
+ return (ERR_PTR(rc));
+#else
+ return (rc);
+#endif
+
+ cur = 0;
+ for_each_sg(sgt->sgl, sg_iter, sgt->orig_nents, i) {
+ unsigned long seg_size;
+ unsigned int j;
+
+ /*
+ * We need to make sure that when we exit this loop "s" has the
+ * last sg in the chain so we can call sg_mark_end() on it.
+ * Only set this inside the loop since sg_iter will be iterated
+ * until it is NULL.
+ */
+ s = sg_iter;
+
+ len = 0;
+ for (j = cur + 1; j < count; ++j) {
+ len += PAGE_SIZE;
+ if (len >= max_segment || page_to_pfn(pages[j]) !=
+ page_to_pfn(pages[j - 1]) + 1)
+ break;
+ }
+
+ seg_size = ((j - cur) << PAGE_SHIFT) - off;
+ sg_set_page(s, pages[cur], MIN(size, seg_size), off);
+ size -= seg_size;
+ off = 0;
+ cur = j;
+ }
+ KASSERT(s != NULL, ("s is NULL after loop in __sg_alloc_table_from_pages()"));
+
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
+ if (left_pages == 0)
+ sg_mark_end(s);
+
+ return (s);
+#else
+ return (0);
+#endif
+}
+
+static inline int
+sg_alloc_table_from_pages(struct sg_table *sgt,
+ struct page **pages, unsigned int count,
+ unsigned long off, unsigned long size,
+ gfp_t gfp_mask)
+{
+
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
+ return (PTR_ERR_OR_ZERO(__sg_alloc_table_from_pages(sgt, pages, count, off, size,
+ SCATTERLIST_MAX_SEGMENT, NULL, 0, gfp_mask)));
+#else
+ return (__sg_alloc_table_from_pages(sgt, pages, count, off, size,
+ SCATTERLIST_MAX_SEGMENT, gfp_mask));
+#endif
+}
+
+static inline int
+sg_alloc_table_from_pages_segment(struct sg_table *sgt,
+ struct page **pages, unsigned int count, unsigned int off,
+ unsigned long size, unsigned int max_segment, gfp_t gfp_mask)
+{
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
+ return (PTR_ERR_OR_ZERO(__sg_alloc_table_from_pages(sgt, pages, count, off, size,
+ max_segment, NULL, 0, gfp_mask)));
+#else
+ return (__sg_alloc_table_from_pages(sgt, pages, count, off, size,
+ max_segment, gfp_mask));
+#endif
+}
+
+static inline int
+sg_nents(struct scatterlist *sg)
+{
+ int nents;
+
+ for (nents = 0; sg; sg = sg_next(sg))
+ nents++;
+ return (nents);
+}
+
+static inline void
+__sg_page_iter_start(struct sg_page_iter *piter,
+ struct scatterlist *sglist, unsigned int nents,
+ unsigned long pgoffset)
+{
+ piter->internal.pg_advance = 0;
+ piter->internal.nents = nents;
+
+ piter->sg = sglist;
+ piter->sg_pgoffset = pgoffset;
+}
+
+static inline void
+_sg_iter_next(struct sg_page_iter *iter)
+{
+ struct scatterlist *sg;
+ unsigned int pgcount;
+
+ sg = iter->sg;
+ pgcount = (sg->offset + sg->length + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ ++iter->sg_pgoffset;
+ while (iter->sg_pgoffset >= pgcount) {
+ iter->sg_pgoffset -= pgcount;
+ sg = sg_next(sg);
+ --iter->maxents;
+ if (sg == NULL || iter->maxents == 0)
+ break;
+ pgcount = (sg->offset + sg->length + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ }
+ iter->sg = sg;
+}
+
+static inline int
+sg_page_count(struct scatterlist *sg)
+{
+ return (PAGE_ALIGN(sg->offset + sg->length) >> PAGE_SHIFT);
+}
+#define sg_dma_page_count(sg) \
+ sg_page_count(sg)
+
+static inline bool
+__sg_page_iter_next(struct sg_page_iter *piter)
+{
+ unsigned int pgcount;
+
+ if (piter->internal.nents == 0)
+ return (0);
+ if (piter->sg == NULL)
+ return (0);
+
+ piter->sg_pgoffset += piter->internal.pg_advance;
+ piter->internal.pg_advance = 1;
+
+ while (1) {
+ pgcount = sg_page_count(piter->sg);
+ if (likely(piter->sg_pgoffset < pgcount))
+ break;
+ piter->sg_pgoffset -= pgcount;
+ piter->sg = sg_next(piter->sg);
+ if (--piter->internal.nents == 0)
+ return (0);
+ if (piter->sg == NULL)
+ return (0);
+ }
+ return (1);
+}
+#define __sg_page_iter_dma_next(itr) \
+ __sg_page_iter_next(&(itr)->base)
+
+static inline void
+_sg_iter_init(struct scatterlist *sgl, struct sg_page_iter *iter,
+ unsigned int nents, unsigned long pgoffset)
+{
+ if (nents) {
+ iter->sg = sgl;
+ iter->sg_pgoffset = pgoffset - 1;
+ iter->maxents = nents;
+ _sg_iter_next(iter);
+ } else {
+ iter->sg = NULL;
+ iter->sg_pgoffset = 0;
+ iter->maxents = 0;
+ }
+}
+
+/*
+ * sg_page_iter_dma_address() is implemented as a macro because it
+ * needs to accept two different and identical structure types. This
+ * allows both old and new code to co-exist. The compile time assert
+ * adds some safety, that the structure sizes match.
+ */
+#define sg_page_iter_dma_address(spi) ({ \
+ struct sg_page_iter *__spi = (void *)(spi); \
+ dma_addr_t __dma_address; \
+ CTASSERT(sizeof(*(spi)) == sizeof(*__spi)); \
+ __dma_address = __spi->sg->dma_address + \
+ (__spi->sg_pgoffset << PAGE_SHIFT); \
+ __dma_address; \
+})
+
+static inline struct page *
+sg_page_iter_page(struct sg_page_iter *piter)
+{
+ return (nth_page(sg_page(piter->sg), piter->sg_pgoffset));
+}
+
+static __inline size_t
+sg_pcopy_from_buffer(struct scatterlist *sgl, unsigned int nents,
+ const void *buf, size_t buflen, off_t skip)
+{
+ struct sg_page_iter piter;
+ struct page *page;
+ struct sf_buf *sf;
+ size_t len, copied;
+ char *p, *b;
+
+ if (buflen == 0)
+ return (0);
+
+ b = __DECONST(char *, buf);
+ copied = 0;
+ sched_pin();
+ for_each_sg_page(sgl, &piter, nents, 0) {
+
+ /* Skip to the start. */
+ if (piter.sg->length <= skip) {
+ skip -= piter.sg->length;
+ continue;
+ }
+
+ /* See how much to copy. */
+ KASSERT(((piter.sg->length - skip) != 0 && (buflen != 0)),
+ ("%s: sg len %u - skip %ju || buflen %zu is 0\n",
+ __func__, piter.sg->length, (uintmax_t)skip, buflen));
+ len = min(piter.sg->length - skip, buflen);
+
+ page = sg_page_iter_page(&piter);
+ sf = sf_buf_alloc(page, SFB_CPUPRIVATE | SFB_NOWAIT);
+ if (sf == NULL)
+ break;
+ p = (char *)sf_buf_kva(sf) + piter.sg_pgoffset + skip;
+ memcpy(p, b, len);
+ sf_buf_free(sf);
+
+ /* We copied so nothing more to skip. */
+ skip = 0;
+ copied += len;
+ /* Either we exactly filled the page, or we are done. */
+ buflen -= len;
+ if (buflen == 0)
+ break;
+ b += len;
+ }
+ sched_unpin();
+
+ return (copied);
+}
+
+static inline size_t
+sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents,
+ const void *buf, size_t buflen)
+{
+ return (sg_pcopy_from_buffer(sgl, nents, buf, buflen, 0));
+}
+
+static inline size_t
+sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents,
+ void *buf, size_t buflen, off_t offset)
+{
+ struct sg_page_iter iter;
+ struct scatterlist *sg;
+ struct page *page;
+ struct sf_buf *sf;
+ char *vaddr;
+ size_t total = 0;
+ size_t len;
+
+ if (!PMAP_HAS_DMAP)
+ sched_pin();
+ for_each_sg_page(sgl, &iter, nents, 0) {
+ sg = iter.sg;
+
+ if (offset >= sg->length) {
+ offset -= sg->length;
+ continue;
+ }
+ len = ulmin(buflen, sg->length - offset);
+ if (len == 0)
+ break;
+
+ page = sg_page_iter_page(&iter);
+ if (!PMAP_HAS_DMAP) {
+ sf = sf_buf_alloc(page, SFB_CPUPRIVATE | SFB_NOWAIT);
+ if (sf == NULL)
+ break;
+ vaddr = (char *)sf_buf_kva(sf);
+ } else
+ vaddr = (char *)PHYS_TO_DMAP(page_to_phys(page));
+ memcpy(buf, vaddr + sg->offset + offset, len);
+ if (!PMAP_HAS_DMAP)
+ sf_buf_free(sf);
+
+ /* start at beginning of next page */
+ offset = 0;
+
+ /* advance buffer */
+ buf = (char *)buf + len;
+ buflen -= len;
+ total += len;
+ }
+ if (!PMAP_HAS_DMAP)
+ sched_unpin();
+ return (total);
+}
+
+static inline void
+sg_set_folio(struct scatterlist *sg, struct folio *folio, size_t len,
+ size_t offset)
+{
+ sg_set_page(sg, &folio->page, len, offset);
+}
+
+#endif /* _LINUXKPI_LINUX_SCATTERLIST_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/sched.h b/sys/compat/linuxkpi/common/include/linux/sched.h
new file mode 100644
index 000000000000..3ad2f8e4ce8b
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/sched.h
@@ -0,0 +1,243 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2018 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_SCHED_H_
+#define _LINUXKPI_LINUX_SCHED_H_
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/rtprio.h>
+#include <sys/sched.h>
+#include <sys/sleepqueue.h>
+#include <sys/time.h>
+
+#include <linux/bitmap.h>
+#include <linux/compat.h>
+#include <linux/completion.h>
+#include <linux/hrtimer.h>
+#include <linux/mm_types.h>
+#include <linux/nodemask.h>
+#include <linux/pid.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+
+#include <linux/sched/mm.h>
+
+#include <asm/atomic.h>
+
+#define MAX_SCHEDULE_TIMEOUT LONG_MAX
+
+#define TASK_RUNNING 0x0000
+#define TASK_INTERRUPTIBLE 0x0001
+#define TASK_UNINTERRUPTIBLE 0x0002
+#define TASK_NORMAL (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)
+#define TASK_WAKING 0x0100
+#define TASK_PARKED 0x0200
+
+#define TASK_COMM_LEN (MAXCOMLEN + 1)
+
+struct seq_file;
+
+struct work_struct;
+struct task_struct {
+ struct thread *task_thread;
+ struct mm_struct *mm;
+ linux_task_fn_t *task_fn;
+ void *task_data;
+ int task_ret;
+ atomic_t usage;
+ atomic_t state;
+ atomic_t kthread_flags;
+ pid_t pid; /* BSD thread ID */
+ const char *comm;
+ void *bsd_ioctl_data;
+ unsigned bsd_ioctl_len;
+ struct completion parked;
+ struct completion exited;
+#define TS_RCU_TYPE_MAX 2
+ TAILQ_ENTRY(task_struct) rcu_entry[TS_RCU_TYPE_MAX];
+ int rcu_recurse[TS_RCU_TYPE_MAX];
+ int bsd_interrupt_value;
+ struct work_struct *work; /* current work struct, if set */
+ struct task_struct *group_leader;
+ unsigned rcu_section[TS_RCU_TYPE_MAX];
+ unsigned int fpu_ctx_level;
+};
+
+#define current ({ \
+ struct thread *__td = curthread; \
+ linux_set_current(__td); \
+ ((struct task_struct *)__td->td_lkpi_task); \
+})
+
+#define task_pid_group_leader(task) (task)->task_thread->td_proc->p_pid
+#define task_pid(task) ((task)->pid)
+#define task_pid_nr(task) ((task)->pid)
+#define task_pid_vnr(task) ((task)->pid)
+#define get_pid(x) (x)
+#define put_pid(x) do { } while (0)
+#define current_euid() (curthread->td_ucred->cr_uid)
+#define task_euid(task) ((task)->task_thread->td_ucred->cr_uid)
+
+#define get_task_state(task) atomic_read(&(task)->state)
+#define set_task_state(task, x) atomic_set(&(task)->state, (x))
+#define __set_task_state(task, x) ((task)->state.counter = (x))
+#define set_current_state(x) set_task_state(current, x)
+#define __set_current_state(x) __set_task_state(current, x)
+
+static inline void
+get_task_struct(struct task_struct *task)
+{
+ atomic_inc(&task->usage);
+}
+
+static inline void
+put_task_struct(struct task_struct *task)
+{
+ if (atomic_dec_and_test(&task->usage))
+ linux_free_current(task);
+}
+
+#define cond_resched() do { if (!cold) sched_relinquish(curthread); } while (0)
+
+#define yield() kern_yield(PRI_UNCHANGED)
+#define sched_yield() sched_relinquish(curthread)
+
+#define need_resched() (curthread->td_owepreempt || \
+ td_ast_pending(curthread, TDA_SCHED))
+
+static inline int
+cond_resched_lock(spinlock_t *lock)
+{
+
+ if (need_resched() == 0)
+ return (0);
+ spin_unlock(lock);
+ cond_resched();
+ spin_lock(lock);
+ return (1);
+}
+
+bool linux_signal_pending(struct task_struct *task);
+bool linux_fatal_signal_pending(struct task_struct *task);
+bool linux_signal_pending_state(long state, struct task_struct *task);
+void linux_send_sig(int signo, struct task_struct *task);
+
+#define signal_pending(task) linux_signal_pending(task)
+#define fatal_signal_pending(task) linux_fatal_signal_pending(task)
+#define signal_pending_state(state, task) \
+ linux_signal_pending_state(state, task)
+#define send_sig(signo, task, priv) do { \
+ CTASSERT((priv) == 0); \
+ linux_send_sig(signo, task); \
+} while (0)
+
+long linux_schedule_timeout(long timeout);
+
+static inline void
+linux_schedule_save_interrupt_value(struct task_struct *task, int value)
+{
+ task->bsd_interrupt_value = value;
+}
+
+bool linux_task_exiting(struct task_struct *task);
+
+#define current_exiting() \
+ linux_task_exiting(current)
+
+static inline int
+linux_schedule_get_interrupt_value(struct task_struct *task)
+{
+ int value = task->bsd_interrupt_value;
+ task->bsd_interrupt_value = 0;
+ return (value);
+}
+
+static inline void
+schedule(void)
+{
+ (void)linux_schedule_timeout(MAX_SCHEDULE_TIMEOUT);
+}
+
+#define schedule_timeout(timeout) \
+ linux_schedule_timeout(timeout)
+#define schedule_timeout_killable(timeout) \
+ schedule_timeout_interruptible(timeout)
+#define schedule_timeout_interruptible(timeout) ({ \
+ set_current_state(TASK_INTERRUPTIBLE); \
+ schedule_timeout(timeout); \
+})
+#define schedule_timeout_uninterruptible(timeout) ({ \
+ set_current_state(TASK_UNINTERRUPTIBLE); \
+ schedule_timeout(timeout); \
+})
+
+#define io_schedule() schedule()
+#define io_schedule_timeout(timeout) schedule_timeout(timeout)
+
+static inline uint64_t
+local_clock(void)
+{
+ struct timespec ts;
+
+ nanotime(&ts);
+ return ((uint64_t)ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec);
+}
+
+static inline const char *
+get_task_comm(char *buf, struct task_struct *task)
+{
+
+ buf[0] = 0; /* buffer is too small */
+ return (task->comm);
+}
+
+static inline void
+sched_set_fifo(struct task_struct *t)
+{
+ struct rtprio rtp;
+
+ rtp.prio = (RTP_PRIO_MIN + RTP_PRIO_MAX) / 2;
+ rtp.type = RTP_PRIO_FIFO;
+ rtp_to_pri(&rtp, t->task_thread);
+}
+
+static inline void
+sched_set_fifo_low(struct task_struct *t)
+{
+ struct rtprio rtp;
+
+ rtp.prio = RTP_PRIO_MAX; /* lowest priority */
+ rtp.type = RTP_PRIO_FIFO;
+ rtp_to_pri(&rtp, t->task_thread);
+}
+
+#endif /* _LINUXKPI_LINUX_SCHED_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/sched/mm.h b/sys/compat/linuxkpi/common/include/linux/sched/mm.h
new file mode 100644
index 000000000000..c26d99378974
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/sched/mm.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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_SCHED_MM_H_
+#define _LINUXKPI_LINUX_SCHED_MM_H_
+
+#include <linux/gfp.h>
+
+#define fs_reclaim_acquire(x) do { \
+ } while (0)
+#define fs_reclaim_release(x) do { \
+ } while (0)
+#define memalloc_nofs_save(x) 0
+#define memalloc_nofs_restore(x) do { \
+ } while (0)
+#define memalloc_noreclaim_save(x) 0
+#define memalloc_noreclaim_restore(x) do { \
+ } while (0)
+
+#endif /* _BSD_LKPI_LINUX_SCHED_MM_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/semaphore.h b/sys/compat/linuxkpi/common/include/linux/semaphore.h
new file mode 100644
index 000000000000..4b1a1502e589
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/semaphore.h
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_SEMAPHORE_H_
+#define _LINUXKPI_LINUX_SEMAPHORE_H_
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/sema.h>
+#include <sys/libkern.h>
+
+/*
+ * XXX BSD semaphores are disused and slow. They also do not provide a
+ * sema_wait_sig method. This must be resolved eventually.
+ */
+struct semaphore {
+ struct sema sema;
+};
+
+#define down(_sem) sema_wait(&(_sem)->sema)
+#define down_interruptible(_sem) sema_wait(&(_sem)->sema), 0
+#define down_trylock(_sem) !sema_trywait(&(_sem)->sema)
+#define up(_sem) sema_post(&(_sem)->sema)
+
+static inline void
+linux_sema_init(struct semaphore *sem, int val)
+{
+
+ memset(&sem->sema, 0, sizeof(sem->sema));
+ sema_init(&sem->sema, val, "lnxsema");
+}
+
+static inline void
+init_MUTEX(struct semaphore *sem)
+{
+
+ memset(&sem->sema, 0, sizeof(sem->sema));
+ sema_init(&sem->sema, 1, "lnxsema");
+}
+
+#define sema_init(...) linux_sema_init(__VA_ARGS__)
+
+#endif /* _LINUXKPI_LINUX_SEMAPHORE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/seq_file.h b/sys/compat/linuxkpi/common/include/linux/seq_file.h
new file mode 100644
index 000000000000..876ef9e8dfe5
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/seq_file.h
@@ -0,0 +1,108 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2016-2018, Matthew Macy <mmacy@freebsd.org>
+ *
+ * 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_SEQ_FILE_H_
+#define _LINUXKPI_LINUX_SEQ_FILE_H_
+
+#include <sys/types.h>
+#include <sys/sbuf.h>
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/string_helpers.h>
+#include <linux/printk.h>
+
+#undef file
+#define inode vnode
+
+MALLOC_DECLARE(M_LSEQ);
+
+#define DEFINE_SHOW_ATTRIBUTE(__name) \
+static int __name ## _open(struct inode *inode, struct linux_file *file) \
+{ \
+ return single_open(file, __name ## _show, inode->i_private); \
+} \
+ \
+static const struct file_operations __name ## _fops = { \
+ .owner = THIS_MODULE, \
+ .open = __name ## _open, \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+ .release = single_release, \
+}
+
+struct seq_file {
+ struct sbuf *buf;
+ size_t size;
+ const struct seq_operations *op;
+ const struct linux_file *file;
+ void *private;
+};
+
+struct seq_operations {
+ void * (*start) (struct seq_file *m, off_t *pos);
+ void (*stop) (struct seq_file *m, void *v);
+ void * (*next) (struct seq_file *m, void *v, off_t *pos);
+ int (*show) (struct seq_file *m, void *v);
+};
+
+ssize_t seq_read(struct linux_file *, char *, 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);
+bool seq_has_overflowed(struct seq_file *m);
+
+void *__seq_open_private(struct linux_file *, const struct seq_operations *, int);
+int seq_release_private(struct inode *, struct linux_file *);
+
+int seq_open(struct linux_file *f, const struct seq_operations *op);
+int seq_release(struct inode *inode, struct linux_file *file);
+
+off_t seq_lseek(struct linux_file *file, off_t offset, int whence);
+int single_open(struct linux_file *, int (*)(struct seq_file *, void *), void *);
+int single_open_size(struct linux_file *, int (*)(struct seq_file *, void *), void *, size_t);
+int single_release(struct inode *, struct linux_file *);
+
+void lkpi_seq_vprintf(struct seq_file *m, const char *fmt, va_list args);
+void lkpi_seq_printf(struct seq_file *m, const char *fmt, ...);
+
+#define seq_vprintf(...) lkpi_seq_vprintf(__VA_ARGS__)
+#define seq_printf(...) lkpi_seq_printf(__VA_ARGS__)
+
+int __lkpi_hexdump_sbuf_printf(void *, const char *, ...) __printflike(2, 3);
+
+static inline void
+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);
+}
+
+#define file linux_file
+
+#endif /* _LINUXKPI_LINUX_SEQ_FILE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/seqlock.h b/sys/compat/linuxkpi/common/include/linux/seqlock.h
new file mode 100644
index 000000000000..554fdfd6e202
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/seqlock.h
@@ -0,0 +1,184 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
+ *
+ * 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_SEQLOCK_H__
+#define _LINUXKPI_LINUX_SEQLOCK_H__
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/cdefs.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rwlock.h>
+#include <sys/seqc.h>
+
+struct lock_class_key;
+
+struct seqcount {
+ seqc_t seqc;
+};
+typedef struct seqcount seqcount_t;
+
+struct seqlock {
+ struct mtx seql_lock;
+ struct seqcount seql_count;
+};
+typedef struct seqlock seqlock_t;
+
+struct seqcount_mutex {
+ seqc_t seqc;
+};
+typedef struct seqcount_mutex seqcount_mutex_t;
+typedef struct seqcount_mutex seqcount_ww_mutex_t;
+
+static inline void
+__seqcount_init(struct seqcount *seqcount, const char *name __unused,
+ struct lock_class_key *key __unused)
+{
+ seqcount->seqc = 0;
+}
+#define seqcount_init(seqcount) __seqcount_init(seqcount, NULL, NULL)
+
+static inline void
+seqcount_mutex_init(struct seqcount_mutex *seqcount, void *mutex __unused)
+{
+ seqcount->seqc = 0;
+}
+
+#define seqcount_ww_mutex_init(seqcount, ww_mutex) \
+ seqcount_mutex_init((seqcount), (ww_mutex))
+
+#define write_seqcount_begin(s) \
+ _Generic(*(s), \
+ struct seqcount: seqc_sleepable_write_begin, \
+ struct seqcount_mutex: seqc_write_begin \
+ )(&(s)->seqc)
+
+#define write_seqcount_end(s) \
+ _Generic(*(s), \
+ struct seqcount: seqc_sleepable_write_end, \
+ struct seqcount_mutex: seqc_write_end \
+ )(&(s)->seqc)
+
+static inline void
+lkpi_write_seqcount_invalidate(seqc_t *seqcp)
+{
+ atomic_thread_fence_rel();
+ *seqcp += SEQC_MOD * 2;
+}
+#define write_seqcount_invalidate(s) lkpi_write_seqcount_invalidate(&(s)->seqc)
+
+#define read_seqcount_begin(s) seqc_read(&(s)->seqc)
+#define raw_read_seqcount(s) seqc_read_any(&(s)->seqc)
+
+static inline seqc_t
+lkpi_seqprop_sequence(const seqc_t *seqcp)
+{
+ return (atomic_load_int(seqcp));
+}
+#define seqprop_sequence(s) lkpi_seqprop_sequence(&(s)->seqc)
+
+/*
+ * XXX: Are predicts from inline functions still not honored by clang?
+ */
+#define __read_seqcount_retry(seqcount, gen) \
+ (!seqc_consistent_no_fence(&(seqcount)->seqc, gen))
+#define read_seqcount_retry(seqcount, gen) \
+ (!seqc_consistent(&(seqcount)->seqc, gen))
+
+static inline void
+seqlock_init(struct seqlock *seqlock)
+{
+ /*
+ * Don't enroll to witness(4) to avoid orphaned references after struct
+ * seqlock has been freed. There is no seqlock destructor exists so we
+ * can't expect automatic mtx_destroy() execution before free().
+ */
+ mtx_init(&seqlock->seql_lock, "seqlock", NULL, MTX_DEF|MTX_NOWITNESS);
+ seqcount_init(&seqlock->seql_count);
+}
+
+static inline void
+lkpi_write_seqlock(struct seqlock *seqlock, const bool irqsave)
+{
+ mtx_lock(&seqlock->seql_lock);
+ if (irqsave)
+ critical_enter();
+ write_seqcount_begin(&seqlock->seql_count);
+}
+
+static inline void
+write_seqlock(struct seqlock *seqlock)
+{
+ lkpi_write_seqlock(seqlock, false);
+}
+
+static inline void
+lkpi_write_sequnlock(struct seqlock *seqlock, const bool irqsave)
+{
+ write_seqcount_end(&seqlock->seql_count);
+ if (irqsave)
+ critical_exit();
+ mtx_unlock(&seqlock->seql_lock);
+}
+
+static inline void
+write_sequnlock(struct seqlock *seqlock)
+{
+ lkpi_write_sequnlock(seqlock, false);
+}
+
+/*
+ * Disable preemption when the consumer wants to disable interrupts. This
+ * ensures that the caller won't be starved if it is preempted by a
+ * higher-priority reader, but assumes that the caller won't perform any
+ * blocking operations while holding the write lock; probably a safe
+ * assumption.
+ */
+#define write_seqlock_irqsave(seqlock, flags) do { \
+ (flags) = 0; \
+ lkpi_write_seqlock(seqlock, true); \
+} while (0)
+
+static inline void
+write_sequnlock_irqrestore(struct seqlock *seqlock,
+ unsigned long flags __unused)
+{
+ lkpi_write_sequnlock(seqlock, true);
+}
+
+static inline unsigned
+read_seqbegin(const struct seqlock *seqlock)
+{
+ return (read_seqcount_begin(&seqlock->seql_count));
+}
+
+#define read_seqretry(seqlock, gen) \
+ read_seqcount_retry(&(seqlock)->seql_count, gen)
+
+#endif /* _LINUXKPI_LINUX_SEQLOCK_H__ */
diff --git a/sys/compat/linuxkpi/common/include/linux/shmem_fs.h b/sys/compat/linuxkpi/common/include/linux/shmem_fs.h
new file mode 100644
index 000000000000..5e91725d4a1c
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/shmem_fs.h
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2018 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_SHMEM_FS_H_
+#define _LINUXKPI_LINUX_SHMEM_FS_H_
+
+#include <linux/file.h>
+#include <linux/mempolicy.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+
+/* Shared memory support */
+struct page *linux_shmem_read_mapping_page_gfp(vm_object_t obj, int pindex,
+ gfp_t gfp);
+struct linux_file *linux_shmem_file_setup(const char *name, loff_t size,
+ unsigned long flags);
+void linux_shmem_truncate_range(vm_object_t obj, loff_t lstart,
+ loff_t lend);
+
+#define shmem_read_mapping_page(...) \
+ linux_shmem_read_mapping_page_gfp(__VA_ARGS__, 0)
+
+#define shmem_read_mapping_page_gfp(...) \
+ linux_shmem_read_mapping_page_gfp(__VA_ARGS__)
+
+#define shmem_file_setup(...) \
+ linux_shmem_file_setup(__VA_ARGS__)
+
+#define shmem_truncate_range(...) \
+ linux_shmem_truncate_range(__VA_ARGS__)
+
+static inline struct folio *
+shmem_read_folio_gfp(vm_object_t obj, int pindex, gfp_t gfp)
+{
+ struct page *page;
+
+ page = shmem_read_mapping_page_gfp(obj, pindex, gfp);
+
+ return (page_folio(page));
+}
+
+#endif /* _LINUXKPI_LINUX_SHMEM_FS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/shrinker.h b/sys/compat/linuxkpi/common/include/linux/shrinker.h
new file mode 100644
index 000000000000..eb95dafb83ce
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/shrinker.h
@@ -0,0 +1,79 @@
+/*-
+ * Copyright (c) 2020 Emmanuel Vadot <manu@FreeBSD.org>
+ *
+ * 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_SHRINKER_H_
+#define _LINUXKPI_LINUX_SHRINKER_H_
+
+#include <sys/queue.h>
+
+#include <linux/bitops.h>
+#include <linux/gfp.h>
+
+struct shrink_control {
+ gfp_t gfp_mask;
+ unsigned long nr_to_scan;
+ unsigned long nr_scanned;
+};
+
+struct shrinker {
+ unsigned long (*count_objects)(struct shrinker *, struct shrink_control *);
+ unsigned long (*scan_objects)(struct shrinker *, struct shrink_control *);
+ int seeks;
+ unsigned int flags;
+ void * private_data;
+ long batch;
+ TAILQ_ENTRY(shrinker) next;
+};
+
+#define SHRINK_STOP (~0UL)
+
+#define DEFAULT_SEEKS 2
+
+#define SHRINKER_REGISTERED BIT(0)
+#define SHRINKER_ALLOCATED BIT(1)
+
+struct shrinker *linuxkpi_shrinker_alloc(
+ unsigned int flags, const char *fmt, ...);
+int linuxkpi_register_shrinker(struct shrinker *s);
+void linuxkpi_unregister_shrinker(struct shrinker *s);
+void linuxkpi_shrinker_free(struct shrinker *shrinker);
+void linuxkpi_synchronize_shrinkers(void);
+
+#define shrinker_alloc(flags, fmt, ...) \
+ linuxkpi_shrinker_alloc(flags, fmt __VA_OPT__(,) __VA_ARGS__)
+#define shrinker_register(shrinker) \
+ linuxkpi_register_shrinker(shrinker)
+#define shrinker_free(shrinker) \
+ linuxkpi_shrinker_free(shrinker)
+
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 60000
+#define register_shrinker(s, ...) linuxkpi_register_shrinker(s)
+#else
+#define register_shrinker(s) linuxkpi_register_shrinker(s)
+#endif
+#define unregister_shrinker(s) linuxkpi_unregister_shrinker(s)
+#define synchronize_shrinkers() linuxkpi_synchronize_shrinkers()
+
+#endif /* _LINUXKPI_LINUX_SHRINKER_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/sizes.h b/sys/compat/linuxkpi/common/include/linux/sizes.h
new file mode 100644
index 000000000000..d8a6e75192f6
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/sizes.h
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot 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_SIZES_H_
+#define _LINUXKPI_LINUX_SIZES_H_
+
+#define SZ_1K (1024 * 1)
+#define SZ_2K (1024 * 2)
+#define SZ_4K (1024 * 4)
+#define SZ_8K (1024 * 8)
+#define SZ_16K (1024 * 16)
+#define SZ_32K (1024 * 32)
+#define SZ_64K (1024 * 64)
+#define SZ_128K (1024 * 128)
+#define SZ_256K (1024 * 256)
+#define SZ_512K (1024 * 512)
+
+#define SZ_1M (1024 * 1024 * 1)
+#define SZ_2M (1024 * 1024 * 2)
+#define SZ_4M (1024 * 1024 * 4)
+#define SZ_8M (1024 * 1024 * 8)
+#define SZ_16M (1024 * 1024 * 16)
+#define SZ_32M (1024 * 1024 * 32)
+#define SZ_64M (1024 * 1024 * 64)
+#define SZ_128M (1024 * 1024 * 128)
+#define SZ_256M (1024 * 1024 * 256)
+#define SZ_512M (1024 * 1024 * 512)
+
+#define SZ_1G (1024 * 1024 * 1024 * 1)
+#define SZ_2G (1024 * 1024 * 1024 * 2)
+#define SZ_4G (1024 * 1024 * 1024 * 4)
+#define SZ_8G (1024 * 1024 * 1024 * 8)
+#define SZ_16G (1024 * 1024 * 1024 * 16)
+#define SZ_32G (1024 * 1024 * 1024 * 32)
+
+#define SZ_64T (1024 * 1024 * 1024 * 1024 * 64)
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/skbuff.h b/sys/compat/linuxkpi/common/include/linux/skbuff.h
new file mode 100644
index 000000000000..c8ad90281e34
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/skbuff.h
@@ -0,0 +1,1167 @@
+/*-
+ * Copyright (c) 2020-2025 The FreeBSD Foundation
+ * Copyright (c) 2021-2023 Bjoern A. Zeeb
+ *
+ * This software was developed by Björn Zeeb 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.
+ */
+
+/*
+ * NOTE: this socket buffer compatibility code is highly EXPERIMENTAL.
+ * Do not rely on the internals of this implementation. They are highly
+ * likely to change as we will improve the integration to FreeBSD mbufs.
+ */
+
+#ifndef _LINUXKPI_LINUX_SKBUFF_H
+#define _LINUXKPI_LINUX_SKBUFF_H
+
+#include <linux/kernel.h>
+#include <linux/page.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdev_features.h>
+#include <linux/list.h>
+#include <linux/gfp.h>
+#include <linux/compiler.h>
+#include <linux/spinlock.h>
+#include <linux/ktime.h>
+#include <linux/compiler.h>
+
+#include "opt_wlan.h"
+
+/* Currently this is only used for wlan so we can depend on that. */
+#if defined(IEEE80211_DEBUG) && !defined(SKB_DEBUG)
+#define SKB_DEBUG
+#endif
+
+/* #define SKB_DEBUG */
+
+#ifdef SKB_DEBUG
+#define DSKB_TODO 0x01
+#define DSKB_IMPROVE 0x02
+#define DSKB_TRACE 0x10
+#define DSKB_TRACEX 0x20
+extern int linuxkpi_debug_skb;
+
+#define SKB_TODO() \
+ if (linuxkpi_debug_skb & DSKB_TODO) \
+ printf("SKB_TODO %s:%d\n", __func__, __LINE__)
+#define SKB_IMPROVE(...) \
+ if (linuxkpi_debug_skb & DSKB_IMPROVE) \
+ printf("SKB_IMPROVE %s:%d\n", __func__, __LINE__)
+#define SKB_TRACE(_s) \
+ if (linuxkpi_debug_skb & DSKB_TRACE) \
+ printf("SKB_TRACE %s:%d %p\n", __func__, __LINE__, _s)
+#define SKB_TRACE2(_s, _p) \
+ if (linuxkpi_debug_skb & DSKB_TRACE) \
+ printf("SKB_TRACE %s:%d %p, %p\n", __func__, __LINE__, _s, _p)
+#define SKB_TRACE_FMT(_s, _fmt, ...) \
+ if (linuxkpi_debug_skb & DSKB_TRACE) \
+ printf("SKB_TRACE %s:%d %p " _fmt "\n", __func__, __LINE__, _s, \
+ __VA_ARGS__)
+#else
+#define SKB_TODO() do { } while(0)
+#define SKB_IMPROVE(...) do { } while(0)
+#define SKB_TRACE(_s) do { } while(0)
+#define SKB_TRACE2(_s, _p) do { } while(0)
+#define SKB_TRACE_FMT(_s, ...) do { } while(0)
+#endif
+
+enum sk_buff_pkt_type {
+ PACKET_BROADCAST,
+ PACKET_MULTICAST,
+ PACKET_OTHERHOST,
+};
+
+struct skb_shared_hwtstamps {
+ ktime_t hwtstamp;
+};
+
+#define NET_SKB_PAD max(CACHE_LINE_SIZE, 32)
+#define SKB_DATA_ALIGN(_x) roundup2(_x, CACHE_LINE_SIZE)
+
+struct sk_buff_head {
+ /* XXX TODO */
+ union {
+ struct {
+ struct sk_buff *next;
+ struct sk_buff *prev;
+ };
+ struct sk_buff_head_l {
+ struct sk_buff *next;
+ struct sk_buff *prev;
+ } list;
+ };
+ size_t qlen;
+ spinlock_t lock;
+};
+
+enum sk_checksum_flags {
+ CHECKSUM_NONE = 0x00,
+ CHECKSUM_UNNECESSARY = 0x01,
+ CHECKSUM_PARTIAL = 0x02,
+ CHECKSUM_COMPLETE = 0x04,
+};
+
+struct skb_frag {
+ /* XXX TODO */
+ struct page *page; /* XXX-BZ These three are a wild guess so far! */
+ off_t offset;
+ size_t size;
+};
+typedef struct skb_frag skb_frag_t;
+
+enum skb_shared_info_gso_type {
+ SKB_GSO_TCPV4,
+ SKB_GSO_TCPV6,
+};
+
+struct skb_shared_info {
+ enum skb_shared_info_gso_type gso_type;
+ uint16_t gso_size;
+ uint16_t nr_frags;
+ struct sk_buff *frag_list;
+ skb_frag_t frags[64]; /* XXX TODO, 16xpage? */
+};
+
+struct sk_buff {
+ /* XXX TODO */
+ union {
+ /* struct sk_buff_head */
+ struct {
+ struct sk_buff *next;
+ struct sk_buff *prev;
+ };
+ struct list_head list;
+ };
+
+ uint8_t *head; /* Head of buffer. */
+ uint8_t *data; /* Head of data. */
+ uint8_t *tail; /* End of data. */
+ uint8_t *end; /* End of buffer. */
+
+ uint32_t len; /* ? */
+ uint32_t data_len; /* ? If we have frags? */
+ union {
+ __wsum csum;
+ struct {
+ uint16_t csum_offset;
+ uint16_t csum_start;
+ };
+ };
+ uint16_t protocol;
+ uint8_t ip_summed;
+ /* uint8_t */
+
+ /* "Scratch" area for layers to store metadata. */
+ /* ??? I see sizeof() operations so probably an array. */
+ uint8_t cb[64] __aligned(CACHE_LINE_SIZE);
+
+ struct skb_shared_info *shinfo __aligned(CACHE_LINE_SIZE);
+
+ uint32_t truesize; /* The total size of all buffers, incl. frags. */
+ uint32_t priority;
+ uint16_t qmap; /* queue mapping */
+ uint16_t _flags; /* Internal flags. */
+#define _SKB_FLAGS_SKBEXTFRAG 0x0001
+ uint16_t l3hdroff; /* network header offset from *head */
+ uint16_t l4hdroff; /* transport header offset from *head */
+ uint16_t mac_header; /* offset of mac_header */
+ uint16_t mac_len; /* Link-layer header length. */
+ enum sk_buff_pkt_type pkt_type;
+ refcount_t refcnt;
+
+ struct net_device *dev;
+ void *sk; /* XXX net/sock.h? */
+
+ /* FreeBSD specific bandaid (see linuxkpi_kfree_skb). */
+ void *m;
+ void(*m_free_func)(void *);
+
+ /* Force padding to CACHE_LINE_SIZE. */
+ uint8_t __scratch[0] __aligned(CACHE_LINE_SIZE);
+};
+
+/* -------------------------------------------------------------------------- */
+
+struct sk_buff *linuxkpi_alloc_skb(size_t, gfp_t);
+struct sk_buff *linuxkpi_dev_alloc_skb(size_t, gfp_t);
+struct sk_buff *linuxkpi_build_skb(void *, size_t);
+void linuxkpi_kfree_skb(struct sk_buff *);
+
+struct sk_buff *linuxkpi_skb_copy(const struct sk_buff *, gfp_t);
+
+/* -------------------------------------------------------------------------- */
+
+static inline struct sk_buff *
+alloc_skb(size_t size, gfp_t gfp)
+{
+ struct sk_buff *skb;
+
+ skb = linuxkpi_alloc_skb(size, gfp);
+ SKB_TRACE(skb);
+ return (skb);
+}
+
+static inline struct sk_buff *
+__dev_alloc_skb(size_t len, gfp_t gfp)
+{
+ struct sk_buff *skb;
+
+ skb = linuxkpi_dev_alloc_skb(len, gfp);
+ SKB_IMPROVE();
+ SKB_TRACE(skb);
+ return (skb);
+}
+
+static inline struct sk_buff *
+dev_alloc_skb(size_t len)
+{
+ struct sk_buff *skb;
+
+ skb = __dev_alloc_skb(len, GFP_NOWAIT);
+ SKB_IMPROVE();
+ SKB_TRACE(skb);
+ return (skb);
+}
+
+static inline void
+kfree_skb(struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ linuxkpi_kfree_skb(skb);
+}
+
+static inline void
+consume_skb(struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ kfree_skb(skb);
+}
+
+static inline void
+dev_kfree_skb(struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ kfree_skb(skb);
+}
+
+static inline void
+dev_kfree_skb_any(struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ dev_kfree_skb(skb);
+}
+
+static inline void
+dev_kfree_skb_irq(struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ SKB_IMPROVE("Do we have to defer this?");
+ dev_kfree_skb(skb);
+}
+
+static inline struct sk_buff *
+build_skb(void *data, unsigned int fragsz)
+{
+ struct sk_buff *skb;
+
+ skb = linuxkpi_build_skb(data, fragsz);
+ SKB_TRACE(skb);
+ return (skb);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static inline bool
+skb_is_nonlinear(struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ return ((skb->data_len > 0) ? true : false);
+}
+
+/* Add headroom; cannot do once there is data in there. */
+static inline void
+skb_reserve(struct sk_buff *skb, size_t len)
+{
+ SKB_TRACE(skb);
+#if 0
+ /* Apparently it is allowed to call skb_reserve multiple times in a row. */
+ KASSERT(skb->data == skb->head, ("%s: skb %p not empty head %p data %p "
+ "tail %p\n", __func__, skb, skb->head, skb->data, skb->tail));
+#else
+ KASSERT(skb->len == 0 && skb->data == skb->tail, ("%s: skb %p not "
+ "empty head %p data %p tail %p len %u\n", __func__, skb,
+ skb->head, skb->data, skb->tail, skb->len));
+#endif
+ skb->data += len;
+ skb->tail += len;
+}
+
+/*
+ * Remove headroom; return new data pointer; basically make space at the
+ * front to copy data in (manually).
+ */
+static inline void *
+__skb_push(struct sk_buff *skb, size_t len)
+{
+ SKB_TRACE(skb);
+ KASSERT(((skb->data - len) >= skb->head), ("%s: skb %p (data %p - "
+ "len %zu) < head %p\n", __func__, skb, skb->data, len, skb->data));
+ skb->len += len;
+ skb->data -= len;
+ return (skb->data);
+}
+
+static inline void *
+skb_push(struct sk_buff *skb, size_t len)
+{
+
+ SKB_TRACE(skb);
+ return (__skb_push(skb, len));
+}
+
+/*
+ * Length of the data on the skb (without any frags)???
+ */
+static inline size_t
+skb_headlen(struct sk_buff *skb)
+{
+
+ SKB_TRACE(skb);
+ return (skb->len - skb->data_len);
+}
+
+
+/* Return the end of data (tail pointer). */
+static inline uint8_t *
+skb_tail_pointer(struct sk_buff *skb)
+{
+
+ SKB_TRACE(skb);
+ return (skb->tail);
+}
+
+/* Return number of bytes available at end of buffer. */
+static inline unsigned int
+skb_tailroom(struct sk_buff *skb)
+{
+
+ SKB_TRACE(skb);
+ KASSERT((skb->end - skb->tail) >= 0, ("%s: skb %p tailroom < 0, "
+ "end %p tail %p\n", __func__, skb, skb->end, skb->tail));
+ if (unlikely(skb_is_nonlinear(skb)))
+ return (0);
+ return (skb->end - skb->tail);
+}
+
+/* Return number of bytes available at the beginning of buffer. */
+static inline unsigned int
+skb_headroom(const struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ KASSERT((skb->data - skb->head) >= 0, ("%s: skb %p headroom < 0, "
+ "data %p head %p\n", __func__, skb, skb->data, skb->head));
+ return (skb->data - skb->head);
+}
+
+
+/*
+ * Remove tailroom; return the old tail pointer; basically make space at
+ * the end to copy data in (manually). See also skb_put_data() below.
+ */
+static inline void *
+__skb_put(struct sk_buff *skb, size_t len)
+{
+ void *s;
+
+ SKB_TRACE(skb);
+ KASSERT(((skb->tail + len) <= skb->end), ("%s: skb %p (tail %p + "
+ "len %zu) > end %p, head %p data %p len %u\n", __func__,
+ skb, skb->tail, len, skb->end, skb->head, skb->data, skb->len));
+
+ s = skb_tail_pointer(skb);
+ if (len == 0)
+ return (s);
+ skb->tail += len;
+ skb->len += len;
+#ifdef SKB_DEBUG
+ if (linuxkpi_debug_skb & DSKB_TRACEX)
+ printf("%s: skb %p (%u) head %p data %p tail %p end %p, s %p len %zu\n",
+ __func__, skb, skb->len, skb->head, skb->data, skb->tail, skb->end,
+ s, len);
+#endif
+ return (s);
+}
+
+static inline void *
+skb_put(struct sk_buff *skb, size_t len)
+{
+
+ SKB_TRACE(skb);
+ return (__skb_put(skb, len));
+}
+
+/* skb_put() + copying data in. */
+static inline void *
+skb_put_data(struct sk_buff *skb, const void *buf, size_t len)
+{
+ void *s;
+
+ SKB_TRACE2(skb, buf);
+ s = skb_put(skb, len);
+ if (len == 0)
+ return (s);
+ memcpy(s, buf, len);
+ return (s);
+}
+
+/* skb_put() + filling with zeros. */
+static inline void *
+skb_put_zero(struct sk_buff *skb, size_t len)
+{
+ void *s;
+
+ SKB_TRACE(skb);
+ s = skb_put(skb, len);
+ memset(s, '\0', len);
+ return (s);
+}
+
+/*
+ * Remove len bytes from beginning of data.
+ *
+ * XXX-BZ ath10k checks for !NULL conditions so I assume this doesn't panic;
+ * we return the advanced data pointer so we don't have to keep a temp, correct?
+ */
+static inline void *
+skb_pull(struct sk_buff *skb, size_t len)
+{
+
+ SKB_TRACE(skb);
+#if 0 /* Apparently this doesn't barf... */
+ KASSERT(skb->len >= len, ("%s: skb %p skb->len %u < len %u, data %p\n",
+ __func__, skb, skb->len, len, skb->data));
+#endif
+ if (skb->len < len)
+ return (NULL);
+ skb->len -= len;
+ skb->data += len;
+ return (skb->data);
+}
+
+/* Reduce skb data to given length or do nothing if smaller already. */
+static inline void
+__skb_trim(struct sk_buff *skb, unsigned int len)
+{
+
+ SKB_TRACE(skb);
+ if (skb->len < len)
+ return;
+
+ skb->len = len;
+ skb->tail = skb->data + skb->len;
+}
+
+static inline void
+skb_trim(struct sk_buff *skb, unsigned int len)
+{
+
+ return (__skb_trim(skb, len));
+}
+
+static inline struct skb_shared_info *
+skb_shinfo(struct sk_buff *skb)
+{
+
+ SKB_TRACE(skb);
+ return (skb->shinfo);
+}
+
+static inline void
+skb_add_rx_frag(struct sk_buff *skb, int fragno, struct page *page,
+ off_t offset, size_t size, unsigned int truesize)
+{
+ struct skb_shared_info *shinfo;
+
+ SKB_TRACE(skb);
+#ifdef SKB_DEBUG
+ if (linuxkpi_debug_skb & DSKB_TRACEX)
+ printf("%s: skb %p head %p data %p tail %p end %p len %u fragno %d "
+ "page %#jx offset %ju size %zu truesize %u\n", __func__,
+ skb, skb->head, skb->data, skb->tail, skb->end, skb->len, fragno,
+ (uintmax_t)(uintptr_t)linux_page_address(page), (uintmax_t)offset,
+ size, truesize);
+#endif
+
+ shinfo = skb_shinfo(skb);
+ KASSERT(fragno >= 0 && fragno < nitems(shinfo->frags), ("%s: skb %p "
+ "fragno %d too big\n", __func__, skb, fragno));
+ shinfo->frags[fragno].page = page;
+ shinfo->frags[fragno].offset = offset;
+ shinfo->frags[fragno].size = size;
+ shinfo->nr_frags = fragno + 1;
+ skb->len += size;
+ skb->data_len += size;
+ skb->truesize += truesize;
+}
+
+/* -------------------------------------------------------------------------- */
+
+#define skb_queue_walk(_q, skb) \
+ for ((skb) = (_q)->next; (skb) != (struct sk_buff *)(_q); \
+ (skb) = (skb)->next)
+
+#define skb_queue_walk_safe(_q, skb, tmp) \
+ for ((skb) = (_q)->next, (tmp) = (skb)->next; \
+ (skb) != (struct sk_buff *)(_q); (skb) = (tmp), (tmp) = (skb)->next)
+
+#define skb_list_walk_safe(_q, skb, tmp) \
+ for ((skb) = (_q), (tmp) = ((skb) != NULL) ? (skb)->next ? NULL; \
+ ((skb) != NULL); \
+ (skb) = (tmp), (tmp) = ((skb) != NULL) ? (skb)->next ? NULL)
+
+static inline bool
+skb_queue_empty(const struct sk_buff_head *q)
+{
+ SKB_TRACE(q);
+ return (q->next == (const struct sk_buff *)q);
+}
+
+static inline bool
+skb_queue_empty_lockless(const struct sk_buff_head *q)
+{
+ SKB_TRACE(q);
+ return (READ_ONCE(q->next) == (const struct sk_buff *)q);
+}
+
+static inline void
+__skb_queue_head_init(struct sk_buff_head *q)
+{
+ SKB_TRACE(q);
+ q->prev = q->next = (struct sk_buff *)q;
+ q->qlen = 0;
+}
+
+static inline void
+skb_queue_head_init(struct sk_buff_head *q)
+{
+ SKB_TRACE(q);
+ __skb_queue_head_init(q);
+ spin_lock_init(&q->lock);
+}
+
+static inline void
+__skb_insert(struct sk_buff *new, struct sk_buff *prev, struct sk_buff *next,
+ struct sk_buff_head *q)
+{
+
+ SKB_TRACE_FMT(new, "prev %p next %p q %p", prev, next, q);
+ WRITE_ONCE(new->prev, prev);
+ WRITE_ONCE(new->next, next);
+ WRITE_ONCE(((struct sk_buff_head_l *)next)->prev, new);
+ WRITE_ONCE(((struct sk_buff_head_l *)prev)->next, new);
+ WRITE_ONCE(q->qlen, q->qlen + 1);
+}
+
+static inline void
+__skb_queue_after(struct sk_buff_head *q, struct sk_buff *skb,
+ struct sk_buff *new)
+{
+
+ SKB_TRACE_FMT(q, "skb %p new %p", skb, new);
+ __skb_insert(new, skb, ((struct sk_buff_head_l *)skb)->next, q);
+}
+
+static inline void
+__skb_queue_before(struct sk_buff_head *q, struct sk_buff *skb,
+ struct sk_buff *new)
+{
+
+ SKB_TRACE_FMT(q, "skb %p new %p", skb, new);
+ __skb_insert(new, skb->prev, skb, q);
+}
+
+static inline void
+__skb_queue_tail(struct sk_buff_head *q, struct sk_buff *new)
+{
+
+ SKB_TRACE2(q, new);
+ __skb_queue_before(q, (struct sk_buff *)q, new);
+}
+
+static inline void
+skb_queue_tail(struct sk_buff_head *q, struct sk_buff *new)
+{
+ unsigned long flags;
+
+ SKB_TRACE2(q, new);
+ spin_lock_irqsave(&q->lock, flags);
+ __skb_queue_tail(q, new);
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+
+static inline struct sk_buff *
+skb_peek(const struct sk_buff_head *q)
+{
+ struct sk_buff *skb;
+
+ skb = q->next;
+ SKB_TRACE2(q, skb);
+ if (skb == (const struct sk_buff *)q)
+ return (NULL);
+ return (skb);
+}
+
+static inline struct sk_buff *
+skb_peek_tail(const struct sk_buff_head *q)
+{
+ struct sk_buff *skb;
+
+ skb = READ_ONCE(q->prev);
+ SKB_TRACE2(q, skb);
+ if (skb == (const struct sk_buff *)q)
+ return (NULL);
+ return (skb);
+}
+
+static inline void
+__skb_unlink(struct sk_buff *skb, struct sk_buff_head *q)
+{
+ struct sk_buff *p, *n;
+
+ SKB_TRACE2(skb, q);
+
+ WRITE_ONCE(q->qlen, q->qlen - 1);
+ p = skb->prev;
+ n = skb->next;
+ WRITE_ONCE(n->prev, p);
+ WRITE_ONCE(p->next, n);
+ skb->prev = skb->next = NULL;
+}
+
+static inline void
+skb_unlink(struct sk_buff *skb, struct sk_buff_head *q)
+{
+ unsigned long flags;
+
+ SKB_TRACE2(skb, q);
+ spin_lock_irqsave(&q->lock, flags);
+ __skb_unlink(skb, q);
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+
+static inline struct sk_buff *
+__skb_dequeue(struct sk_buff_head *q)
+{
+ struct sk_buff *skb;
+
+ skb = skb_peek(q);
+ if (skb != NULL)
+ __skb_unlink(skb, q);
+ SKB_TRACE2(q, skb);
+ return (skb);
+}
+
+static inline struct sk_buff *
+skb_dequeue(struct sk_buff_head *q)
+{
+ unsigned long flags;
+ struct sk_buff *skb;
+
+ spin_lock_irqsave(&q->lock, flags);
+ skb = __skb_dequeue(q);
+ spin_unlock_irqrestore(&q->lock, flags);
+ SKB_TRACE2(q, skb);
+ return (skb);
+}
+
+static inline struct sk_buff *
+__skb_dequeue_tail(struct sk_buff_head *q)
+{
+ struct sk_buff *skb;
+
+ skb = skb_peek_tail(q);
+ if (skb != NULL)
+ __skb_unlink(skb, q);
+ SKB_TRACE2(q, skb);
+ return (skb);
+}
+
+static inline struct sk_buff *
+skb_dequeue_tail(struct sk_buff_head *q)
+{
+ unsigned long flags;
+ struct sk_buff *skb;
+
+ spin_lock_irqsave(&q->lock, flags);
+ skb = __skb_dequeue_tail(q);
+ spin_unlock_irqrestore(&q->lock, flags);
+ SKB_TRACE2(q, skb);
+ return (skb);
+}
+
+static inline void
+__skb_queue_head(struct sk_buff_head *q, struct sk_buff *skb)
+{
+
+ SKB_TRACE2(q, skb);
+ __skb_queue_after(q, (struct sk_buff *)q, skb);
+}
+
+static inline void
+skb_queue_head(struct sk_buff_head *q, struct sk_buff *skb)
+{
+ unsigned long flags;
+
+ SKB_TRACE2(q, skb);
+ spin_lock_irqsave(&q->lock, flags);
+ __skb_queue_head(q, skb);
+ spin_unlock_irqrestore(&q->lock, flags);
+}
+
+static inline uint32_t
+skb_queue_len(const struct sk_buff_head *q)
+{
+
+ SKB_TRACE(q);
+ return (q->qlen);
+}
+
+static inline uint32_t
+skb_queue_len_lockless(const struct sk_buff_head *q)
+{
+
+ SKB_TRACE(q);
+ return (READ_ONCE(q->qlen));
+}
+
+static inline void
+___skb_queue_splice(const struct sk_buff_head *from,
+ struct sk_buff *p, struct sk_buff *n)
+{
+ struct sk_buff *b, *e;
+
+ b = from->next;
+ e = from->prev;
+
+ WRITE_ONCE(b->prev, p);
+ WRITE_ONCE(((struct sk_buff_head_l *)p)->next, b);
+ WRITE_ONCE(e->next, n);
+ WRITE_ONCE(((struct sk_buff_head_l *)n)->prev, e);
+}
+
+static inline void
+skb_queue_splice_init(struct sk_buff_head *from, struct sk_buff_head *to)
+{
+
+ SKB_TRACE2(from, to);
+
+ if (skb_queue_empty(from))
+ return;
+
+ ___skb_queue_splice(from, (struct sk_buff *)to, to->next);
+ to->qlen += from->qlen;
+ __skb_queue_head_init(from);
+}
+
+static inline void
+skb_queue_splice_tail_init(struct sk_buff_head *from, struct sk_buff_head *to)
+{
+
+ SKB_TRACE2(from, to);
+
+ if (skb_queue_empty(from))
+ return;
+
+ ___skb_queue_splice(from, to->prev, (struct sk_buff *)to);
+ to->qlen += from->qlen;
+ __skb_queue_head_init(from);
+}
+
+
+static inline void
+__skb_queue_purge(struct sk_buff_head *q)
+{
+ struct sk_buff *skb;
+
+ SKB_TRACE(q);
+ while ((skb = __skb_dequeue(q)) != NULL)
+ kfree_skb(skb);
+ WARN_ONCE(skb_queue_len(q) != 0, "%s: queue %p not empty: %u",
+ __func__, q, skb_queue_len(q));
+}
+
+static inline void
+skb_queue_purge(struct sk_buff_head *q)
+{
+ struct sk_buff_head _q;
+ unsigned long flags;
+
+ SKB_TRACE(q);
+
+ if (skb_queue_empty_lockless(q))
+ return;
+
+ __skb_queue_head_init(&_q);
+ spin_lock_irqsave(&q->lock, flags);
+ skb_queue_splice_init(q, &_q);
+ spin_unlock_irqrestore(&q->lock, flags);
+ __skb_queue_purge(&_q);
+}
+
+static inline struct sk_buff *
+skb_queue_prev(struct sk_buff_head *q, struct sk_buff *skb)
+{
+
+ SKB_TRACE2(q, skb);
+ /* XXX what is the q argument good for? */
+ return (skb->prev);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static inline struct sk_buff *
+skb_copy(const struct sk_buff *skb, gfp_t gfp)
+{
+ struct sk_buff *new;
+
+ new = linuxkpi_skb_copy(skb, gfp);
+ SKB_TRACE2(skb, new);
+ return (new);
+}
+
+static inline uint16_t
+skb_checksum(struct sk_buff *skb, int offs, size_t len, int x)
+{
+ SKB_TRACE(skb);
+ SKB_TODO();
+ return (0xffff);
+}
+
+static inline int
+skb_checksum_start_offset(struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ SKB_TODO();
+ return (-1);
+}
+
+static inline dma_addr_t
+skb_frag_dma_map(struct device *dev, const skb_frag_t *frag, int x,
+ size_t fragsz, enum dma_data_direction dir)
+{
+ SKB_TRACE2(frag, dev);
+ SKB_TODO();
+ return (-1);
+}
+
+static inline size_t
+skb_frag_size(const skb_frag_t *frag)
+{
+ SKB_TRACE(frag);
+ return (frag->size);
+}
+
+#define skb_walk_frags(_skb, _frag) \
+ for ((_frag) = (_skb); false; (_frag)++)
+
+static inline void
+skb_checksum_help(struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ SKB_TODO();
+}
+
+static inline bool
+skb_ensure_writable(struct sk_buff *skb, size_t off)
+{
+ SKB_TRACE(skb);
+ SKB_TODO();
+ return (false);
+}
+
+static inline void *
+skb_frag_address(const skb_frag_t *frag)
+{
+ SKB_TRACE(frag);
+ return (page_address(frag->page + frag->offset));
+}
+
+static inline void
+skb_free_frag(void *frag)
+{
+
+ page_frag_free(frag);
+}
+
+static inline struct sk_buff *
+skb_gso_segment(struct sk_buff *skb, netdev_features_t netdev_flags)
+{
+ SKB_TRACE(skb);
+ SKB_TODO();
+ return (NULL);
+}
+
+static inline bool
+skb_is_gso(struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ SKB_IMPROVE("Really a TODO but get it away from logging");
+ return (false);
+}
+
+static inline void
+skb_mark_not_on_list(struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ skb->next = NULL;
+}
+
+static inline void
+skb_reset_transport_header(struct sk_buff *skb)
+{
+
+ SKB_TRACE(skb);
+ skb->l4hdroff = skb->data - skb->head;
+}
+
+static inline uint8_t *
+skb_transport_header(struct sk_buff *skb)
+{
+
+ SKB_TRACE(skb);
+ return (skb->head + skb->l4hdroff);
+}
+
+static inline uint8_t *
+skb_network_header(struct sk_buff *skb)
+{
+
+ SKB_TRACE(skb);
+ return (skb->head + skb->l3hdroff);
+}
+
+static inline int
+__skb_linearize(struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ SKB_TODO();
+ return (-ENXIO);
+}
+
+static inline int
+skb_linearize(struct sk_buff *skb)
+{
+ return (skb_is_nonlinear(skb) ? __skb_linearize(skb) : 0);
+}
+
+static inline int
+pskb_expand_head(struct sk_buff *skb, int x, int len, gfp_t gfp)
+{
+ SKB_TRACE(skb);
+ SKB_TODO();
+ return (-ENXIO);
+}
+
+/* Not really seen this one but need it as symmetric accessor function. */
+static inline void
+skb_set_queue_mapping(struct sk_buff *skb, uint16_t qmap)
+{
+
+ SKB_TRACE_FMT(skb, "qmap %u", qmap);
+ skb->qmap = qmap;
+}
+
+static inline uint16_t
+skb_get_queue_mapping(struct sk_buff *skb)
+{
+
+ SKB_TRACE_FMT(skb, "qmap %u", skb->qmap);
+ return (skb->qmap);
+}
+
+static inline void
+skb_copy_header(struct sk_buff *to, const struct sk_buff *from)
+{
+ SKB_TRACE2(to, from);
+ SKB_TODO();
+}
+
+static inline bool
+skb_header_cloned(struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ SKB_TODO();
+ return (true);
+}
+
+static inline uint8_t *
+skb_mac_header(const struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ return (skb->head + skb->mac_header);
+}
+
+static inline void
+skb_reset_mac_header(struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ skb->mac_header = skb->data - skb->head;
+}
+
+static inline void
+skb_set_mac_header(struct sk_buff *skb, const size_t len)
+{
+ SKB_TRACE(skb);
+ skb_reset_mac_header(skb);
+ skb->mac_header += len;
+}
+
+static inline struct skb_shared_hwtstamps *
+skb_hwtstamps(struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ SKB_TODO();
+ return (NULL);
+}
+
+static inline void
+skb_orphan(struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ SKB_TODO();
+}
+
+static inline __wsum
+csum_unfold(__sum16 sum)
+{
+ return (sum);
+}
+
+static __inline void
+skb_postpush_rcsum(struct sk_buff *skb, const void *data, size_t len)
+{
+ SKB_TODO();
+}
+
+static inline void
+skb_reset_tail_pointer(struct sk_buff *skb)
+{
+
+ SKB_TRACE(skb);
+#ifdef SKB_DOING_OFFSETS_US_NOT
+ skb->tail = (uint8_t *)(uintptr_t)(skb->data - skb->head);
+#endif
+ skb->tail = skb->data;
+ SKB_TRACE(skb);
+}
+
+static inline struct sk_buff *
+skb_get(struct sk_buff *skb)
+{
+
+ SKB_TRACE(skb);
+ refcount_inc(&skb->refcnt);
+ return (skb);
+}
+
+static inline struct sk_buff *
+skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom)
+{
+
+ SKB_TODO();
+ return (NULL);
+}
+
+static inline void
+skb_copy_from_linear_data(const struct sk_buff *skb, void *dst, size_t len)
+{
+
+ SKB_TRACE(skb);
+ /* Let us just hope the destination has len space ... */
+ memcpy(dst, skb->data, len);
+}
+
+static inline int
+skb_pad(struct sk_buff *skb, int pad)
+{
+
+ SKB_TRACE(skb);
+ SKB_TODO();
+ return (-1);
+}
+
+static inline void
+skb_list_del_init(struct sk_buff *skb)
+{
+
+ SKB_TRACE(skb);
+ __list_del_entry(&skb->list);
+ skb_mark_not_on_list(skb);
+}
+
+static inline void
+napi_consume_skb(struct sk_buff *skb, int budget)
+{
+
+ SKB_TRACE(skb);
+ SKB_TODO();
+}
+
+static inline struct sk_buff *
+napi_build_skb(void *data, size_t len)
+{
+
+ SKB_TODO();
+ return (NULL);
+}
+
+static inline uint32_t
+skb_get_hash(struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ SKB_TODO();
+ return (0);
+}
+
+static inline void
+skb_mark_for_recycle(struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ /* page_pool */
+ SKB_TODO();
+}
+
+static inline int
+skb_cow_head(struct sk_buff *skb, unsigned int headroom)
+{
+ SKB_TRACE(skb);
+ SKB_TODO();
+ return (-1);
+}
+
+#define SKB_WITH_OVERHEAD(_s) \
+ (_s) - ALIGN(sizeof(struct skb_shared_info), CACHE_LINE_SIZE)
+
+#endif /* _LINUXKPI_LINUX_SKBUFF_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/slab.h b/sys/compat/linuxkpi/common/include/linux/slab.h
new file mode 100644
index 000000000000..efa5c8cb67b3
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/slab.h
@@ -0,0 +1,284 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2021 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ * Copyright (c) 2024-2025 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * 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 unmodified, 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 ``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 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_SLAB_H_
+#define _LINUXKPI_LINUX_SLAB_H_
+
+#include <sys/types.h>
+#include <sys/malloc.h>
+#include <sys/limits.h>
+
+#include <linux/compat.h>
+#include <linux/types.h>
+#include <linux/gfp.h>
+#include <linux/llist.h>
+#include <linux/overflow.h>
+
+MALLOC_DECLARE(M_KMALLOC);
+
+#define kvzalloc(size, flags) kvmalloc(size, (flags) | __GFP_ZERO)
+#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 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)
+#define vfree(arg) kfree(arg)
+#define kvfree(arg) kfree(arg)
+#define vmalloc_node(size, node) __vmalloc_node(size, GFP_KERNEL, node)
+#define vmalloc_user(size) __vmalloc(size, GFP_KERNEL | __GFP_ZERO, 0)
+#define vmalloc(size) __vmalloc(size, GFP_KERNEL, 0)
+
+/*
+ * Prefix some functions with linux_ to avoid namespace conflict
+ * with the OpenSolaris code in the kernel.
+ */
+#define kmem_cache linux_kmem_cache
+#define kmem_cache_create(...) linux_kmem_cache_create(__VA_ARGS__)
+#define kmem_cache_alloc(...) lkpi_kmem_cache_alloc(__VA_ARGS__)
+#define kmem_cache_zalloc(...) lkpi_kmem_cache_zalloc(__VA_ARGS__)
+#define kmem_cache_free(...) lkpi_kmem_cache_free(__VA_ARGS__)
+#define kmem_cache_destroy(...) linux_kmem_cache_destroy(__VA_ARGS__)
+#define kmem_cache_shrink(x) (0)
+
+#define KMEM_CACHE(__struct, flags) \
+ linux_kmem_cache_create(#__struct, sizeof(struct __struct), \
+ __alignof(struct __struct), (flags), NULL)
+
+typedef void linux_kmem_ctor_t (void *);
+
+struct linux_kmem_cache;
+
+#define SLAB_HWCACHE_ALIGN (1 << 0)
+#define SLAB_TYPESAFE_BY_RCU (1 << 1)
+#define SLAB_RECLAIM_ACCOUNT (1 << 2)
+
+#define SLAB_DESTROY_BY_RCU \
+ SLAB_TYPESAFE_BY_RCU
+
+#define ARCH_KMALLOC_MINALIGN \
+ __alignof(unsigned long long)
+
+#define ZERO_SIZE_PTR ((void *)16)
+#define ZERO_OR_NULL_PTR(x) ((x) == NULL || (x) == ZERO_SIZE_PTR)
+
+struct linux_kmem_cache *linux_kmem_cache_create(const char *name,
+ size_t size, size_t align, unsigned flags, linux_kmem_ctor_t *ctor);
+void *lkpi_kmem_cache_alloc(struct linux_kmem_cache *, gfp_t);
+void *lkpi_kmem_cache_zalloc(struct linux_kmem_cache *, gfp_t);
+void lkpi_kmem_cache_free(struct linux_kmem_cache *, void *);
+void linux_kmem_cache_destroy(struct linux_kmem_cache *);
+
+void *lkpi_kmalloc(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_kfree(const void *);
+
+static inline gfp_t
+linux_check_m_flags(gfp_t flags)
+{
+ const gfp_t m = M_NOWAIT | M_WAITOK;
+
+ /* make sure either M_NOWAIT or M_WAITOK is set */
+ if ((flags & m) == 0)
+ flags |= M_NOWAIT;
+ else if ((flags & m) == m)
+ flags &= ~M_WAITOK;
+
+ /* mask away LinuxKPI specific flags */
+ return (flags & GFP_NATIVE_MASK);
+}
+
+/*
+ * Base functions with a native implementation.
+ */
+static inline void *
+kmalloc(size_t size, gfp_t flags)
+{
+ return (lkpi_kmalloc(size, flags));
+}
+
+static inline void *
+__kmalloc(size_t size, gfp_t flags)
+{
+ return (lkpi___kmalloc(size, flags));
+}
+
+static inline void *
+kmalloc_node(size_t size, gfp_t flags, int node)
+{
+ return (lkpi___kmalloc_node(size, flags, node));
+}
+
+static inline void *
+krealloc(void *ptr, size_t size, gfp_t flags)
+{
+ return (lkpi_krealloc(ptr, size, flags));
+}
+
+static inline void
+kfree(const void *ptr)
+{
+ lkpi_kfree(ptr);
+}
+
+/*
+ * Other k*alloc() funtions using the above as underlying allocator.
+ */
+/* kmalloc */
+static inline void *
+kmalloc_array(size_t n, size_t size, gfp_t flags)
+{
+ if (WOULD_OVERFLOW(n, size))
+ panic("%s: %zu * %zu overflowed", __func__, n, size);
+
+ return (kmalloc(size * n, flags));
+}
+
+static inline void *
+kcalloc(size_t n, size_t size, gfp_t flags)
+{
+ flags |= __GFP_ZERO;
+ return (kmalloc_array(n, size, flags));
+}
+
+/* kmalloc_node */
+static inline void *
+kmalloc_array_node(size_t n, size_t size, gfp_t flags, int node)
+{
+ if (WOULD_OVERFLOW(n, size))
+ panic("%s: %zu * %zu overflowed", __func__, n, size);
+
+ return (kmalloc_node(size * n, flags, node));
+}
+
+static inline void *
+kcalloc_node(size_t n, size_t size, gfp_t flags, int node)
+{
+ flags |= __GFP_ZERO;
+ return (kmalloc_array_node(n, size, flags, node));
+}
+
+/* krealloc */
+static inline void *
+krealloc_array(void *ptr, size_t n, size_t size, gfp_t flags)
+{
+ if (WOULD_OVERFLOW(n, size))
+ return NULL;
+
+ return (krealloc(ptr, n * size, flags));
+}
+
+/*
+ * vmalloc/kvalloc functions.
+ */
+static inline void *
+__vmalloc(size_t size, gfp_t flags, int other)
+{
+ return (malloc(size, M_KMALLOC, linux_check_m_flags(flags)));
+}
+
+static inline void *
+__vmalloc_node(size_t size, gfp_t flags, int node)
+{
+ return (malloc_domainset(size, M_KMALLOC,
+ linux_get_vm_domain_set(node), linux_check_m_flags(flags)));
+}
+
+static inline void *
+vmalloc_32(size_t size)
+{
+ return (contigmalloc(size, M_KMALLOC, M_WAITOK, 0, UINT_MAX, 1, 1));
+}
+
+/* May return non-contiguous memory. */
+static inline void *
+kvmalloc(size_t size, gfp_t flags)
+{
+ return (malloc(size, M_KMALLOC, linux_check_m_flags(flags)));
+}
+
+static inline void *
+kvmalloc_array(size_t n, size_t size, gfp_t flags)
+{
+ if (WOULD_OVERFLOW(n, size))
+ panic("%s: %zu * %zu overflowed", __func__, n, size);
+
+ return (kvmalloc(size * n, flags));
+}
+
+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));
+
+ newptr = kvmalloc(newsize, flags);
+ if (newptr != NULL) {
+ memcpy(newptr, ptr, oldsize);
+ kvfree(ptr);
+ }
+
+ return (newptr);
+}
+
+/*
+ * Misc.
+ */
+
+static __inline void
+kfree_sensitive(const void *ptr)
+{
+ if (ZERO_OR_NULL_PTR(ptr))
+ return;
+
+ zfree(__DECONST(void *, ptr), M_KMALLOC);
+}
+
+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))
+ return (size);
+ return (malloc_size(size));
+}
+
+#endif /* _LINUXKPI_LINUX_SLAB_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/smp.h b/sys/compat/linuxkpi/common/include/linux/smp.h
new file mode 100644
index 000000000000..b057953e6282
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/smp.h
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org>
+ *
+ * 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_SMP_H_
+#define _LINUXKPI_LINUX_SMP_H_
+
+#include <asm/smp.h>
+
+/*
+ * Important note about the use of the function provided below:
+ *
+ * The callback function passed to on_each_cpu() is called from a
+ * so-called critical section, and if you need a mutex you will have
+ * to rewrite the code to use native FreeBSD mtx spinlocks instead of
+ * the spinlocks provided by the LinuxKPI! Be very careful to not call
+ * any LinuxKPI functions inside the on_each_cpu()'s callback
+ * function, because they may sleep, unlike in native Linux.
+ *
+ * Enabling witness(4) when testing, can catch such issues.
+ */
+#define on_each_cpu(cb, data, wait) ({ \
+ CTASSERT(wait); \
+ linux_on_each_cpu(cb, data); \
+})
+
+extern int linux_on_each_cpu(void (*)(void *), void *);
+
+#endif /* _LINUXKPI_LINUX_SMP_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
new file mode 100644
index 000000000000..903053e7f6e8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h
@@ -0,0 +1,62 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022-2023 Bjoern A. Zeeb
+ *
+ * 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_SOC_MEDIATEK_MTK_WED_H
+#define _LINUXKPI_LINUX_SOC_MEDIATEK_MTK_WED_H
+
+struct mtk_wed_device {
+};
+
+#define WED_WO_STA_REC 0x6
+
+#define mtk_wed_device_start(_dev, _mask) do { } while(0)
+#define mtk_wed_device_detach(_dev) do { } while(0)
+#define mtk_wed_device_irq_get(_dev, _mask) 0
+#define mtk_wed_device_irq_set_mask(_dev, _mask) do { } while(0)
+#define mtk_wed_device_update_msg(_dev, _id, _msg, _len) (-ENODEV)
+#define mtk_wed_device_dma_reset(_dev) do {} while (0)
+#define mtk_wed_device_ppe_check(_dev, _skb, _reason, _entry) \
+ do {} while (0)
+#define mtk_wed_device_stop(_dev) do { } while(0)
+#define mtk_wed_device_start_hw_rro(_dev, _mask, _b) do { } while(0)
+#define mtk_wed_device_setup_tc(_dev, _ndev, _type, _tdata) (-EOPNOTSUPP)
+
+static inline bool
+mtk_wed_device_active(struct mtk_wed_device *dev __unused)
+{
+
+ return (false);
+}
+
+static inline bool
+mtk_wed_get_rx_capa(struct mtk_wed_device *dev __unused)
+{
+
+ return (false);
+}
+
+#endif /* _LINUXKPI_LINUX_SOC_MEDIATEK_MTK_WED_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/soc/qcom/qmi.h b/sys/compat/linuxkpi/common/include/linux/soc/qcom/qmi.h
new file mode 100644
index 000000000000..647eaf271d87
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/soc/qcom/qmi.h
@@ -0,0 +1,173 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022-2023 Bjoern A. Zeeb
+ *
+ * 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_SOC_QCOM_QMI_H
+#define _LINUXKPI_LINUX_SOC_QCOM_QMI_H
+
+/* QMI (Qualcomm MSM Interface) */
+
+#include <linux/qrtr.h>
+
+enum soc_qcom_qmi_data_type {
+ QMI_EOTI,
+ QMI_DATA_LEN,
+ QMI_OPT_FLAG,
+ QMI_UNSIGNED_1_BYTE,
+ QMI_UNSIGNED_2_BYTE,
+ QMI_UNSIGNED_4_BYTE,
+ QMI_UNSIGNED_8_BYTE,
+ QMI_SIGNED_4_BYTE_ENUM,
+ QMI_STRUCT,
+ QMI_STRING,
+};
+
+#define QMI_RESULT_SUCCESS_V01 __LINE__
+#define QMI_INDICATION __LINE__
+
+struct qmi_handle;
+
+enum soc_qcom_qmi_array_type {
+ NO_ARRAY,
+ STATIC_ARRAY,
+ VAR_LEN_ARRAY,
+};
+
+/* Should this become an enum? */
+#define QMI_COMMON_TLV_TYPE 0
+
+struct qmi_elem_info {
+ enum soc_qcom_qmi_data_type data_type;
+ uint32_t elem_len;
+ uint32_t elem_size;
+ enum soc_qcom_qmi_array_type array_type;
+ uint8_t tlv_type;
+ uint32_t offset;
+ const struct qmi_elem_info *ei_array;
+};
+
+struct qmi_response_type_v01 {
+ uint16_t result;
+ uint16_t error;
+};
+
+struct qmi_txn {
+};
+
+struct qmi_service {
+ uint32_t node;
+ uint32_t port;
+};
+
+struct qmi_msg_handler {
+ uint32_t type;
+ uint32_t msg_id;
+ const struct qmi_elem_info *ei;
+ size_t decoded_size;
+ void (*fn)(struct qmi_handle *, struct sockaddr_qrtr *, struct qmi_txn *, const void *);
+};
+
+struct qmi_ops {
+ int (*new_server)(struct qmi_handle *, struct qmi_service *);
+ void (*del_server)(struct qmi_handle *, struct qmi_service *);
+};
+
+struct qmi_handle {
+ int sock;
+
+ const struct qmi_msg_handler *handler;
+ struct qmi_ops ops;
+};
+
+
+/* XXX-TODO need implementation somewhere... it is not in ath1xk* */
+extern struct qmi_elem_info qmi_response_type_v01_ei[];
+
+static inline int
+qmi_handle_init(struct qmi_handle *handle, size_t resp_len_max,
+ const struct qmi_ops *ops, const struct qmi_msg_handler *handler)
+{
+
+ handle->handler = handler;
+ if (ops != NULL)
+ handle->ops = *ops;
+
+ /* We will find out what else to do here. */
+ /* XXX TODO */
+
+ return (0);
+}
+
+static __inline int
+qmi_add_lookup(struct qmi_handle *handle, uint32_t service, uint32_t version,
+ uint32_t service_ins_id)
+{
+
+ /* XXX TODO */
+ return (0);
+}
+
+static __inline void
+qmi_handle_release(struct qmi_handle *handle)
+{
+
+ /* XXX TODO */
+}
+
+static __inline int
+qmi_send_request(struct qmi_handle *handle, void *x, struct qmi_txn *txn,
+ uint32_t msd_id, size_t len, const struct qmi_elem_info *ei, void *req)
+{
+
+ /* XXX TODO */
+ return (-ENXIO);
+}
+
+static __inline void
+qmi_txn_cancel(struct qmi_txn *txn)
+{
+
+ /* XXX TODO */
+}
+
+static __inline int
+qmi_txn_init(struct qmi_handle *handle, struct qmi_txn *txn,
+ const struct qmi_elem_info *ei, void *resp)
+{
+
+ /* XXX TODO */
+ return (-ENXIO);
+}
+
+static __inline int
+qmi_txn_wait(struct qmi_txn *txn, uint64_t jiffies)
+{
+
+ /* XXX TODO */
+ return (-ENXIO);
+}
+
+#endif /* _LINUXKPI_LINUX_SOC_QCOM_QMI_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/socket.h b/sys/compat/linuxkpi/common/include/linux/socket.h
new file mode 100644
index 000000000000..638ee058c2f5
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/socket.h
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_SOCKET_H_
+#define _LINUXKPI_LINUX_SOCKET_H_
+
+#include <sys/socket.h>
+
+#define AF_QIPCRTR 42
+
+static inline int
+kernel_connect(int sd, struct sockaddr *sa, size_t salen, int flags)
+{
+
+ /* kern_connectat()? It is used for sockaddr_qrtr by ath1xk/qmi. */
+ pr_debug("%s: TODO\n", __func__);
+ return (-EINVAL);
+}
+
+#ifdef notyet
+static inline int
+memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len)
+{
+ struct uio uio;
+ int error;
+
+ uio.uio_iov = v;
+ uio.uio_iovcnt = -1;
+ uio.uio_offset = 0;
+ uio.uio_resid = len;
+ uio.uio_segflag = UIO_USERSPACE;
+ uio.uio_rw = UIO_READ;
+ error = -uiomove(kdata, len, &uio);
+ return (error);
+}
+
+static inline int
+memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
+{
+ struct uio uio;
+ int error;
+
+ uio.uio_iov = v;
+ uio.uio_iovcnt = -1;
+ uio.uio_offset = 0;
+ uio.uio_resid = len;
+ uio.uio_segflag = UIO_USERSPACE;
+ uio.uio_rw = UIO_WRITE;
+ error = -uiomove(kdata, len, &uio);
+}
+#endif
+
+#endif /* _LINUXKPI_LINUX_SOCKET_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/sort.h b/sys/compat/linuxkpi/common/include/linux/sort.h
new file mode 100644
index 000000000000..e6196d1f41c7
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/sort.h
@@ -0,0 +1,41 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
+ *
+ * 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 unmodified, 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 ``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 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_SORT_H_
+#define _LINUXKPI_LINUX_SORT_H_
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <sys/libkern.h>
+
+#define sort(base, num, size, cmp, swap) do { \
+ BUILD_BUG_ON_ZERO(swap); \
+ qsort(base, num, size, cmp); \
+} 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
new file mode 100644
index 000000000000..dc10b0457153
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/spinlock.h
@@ -0,0 +1,181 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_SPINLOCK_H_
+#define _LINUXKPI_LINUX_SPINLOCK_H_
+
+#include <asm/atomic.h>
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/kdb.h>
+
+#include <linux/compiler.h>
+#include <linux/rwlock.h>
+#include <linux/bottom_half.h>
+#include <linux/lockdep.h>
+
+typedef struct mtx spinlock_t;
+
+/*
+ * By defining CONFIG_SPIN_SKIP LinuxKPI spinlocks and asserts will be
+ * skipped during panic(). By default it is disabled due to
+ * performance reasons.
+ */
+#ifdef CONFIG_SPIN_SKIP
+#define SPIN_SKIP(void) unlikely(SCHEDULER_STOPPED() || kdb_active)
+#else
+#define SPIN_SKIP(void) 0
+#endif
+
+#define spin_lock(_l) do { \
+ if (SPIN_SKIP()) \
+ break; \
+ mtx_lock(_l); \
+ local_bh_disable(); \
+} while (0)
+
+#define spin_lock_bh(_l) do { \
+ spin_lock(_l); \
+ local_bh_disable(); \
+} while (0)
+
+#define spin_lock_irq(_l) do { \
+ spin_lock(_l); \
+} while (0)
+
+#define spin_unlock(_l) do { \
+ if (SPIN_SKIP()) \
+ break; \
+ local_bh_enable(); \
+ mtx_unlock(_l); \
+} while (0)
+
+#define spin_unlock_bh(_l) do { \
+ local_bh_enable(); \
+ spin_unlock(_l); \
+} while (0)
+
+#define spin_unlock_irq(_l) do { \
+ spin_unlock(_l); \
+} while (0)
+
+#define spin_trylock(_l) ({ \
+ int __ret; \
+ if (SPIN_SKIP()) { \
+ __ret = 1; \
+ } else { \
+ __ret = mtx_trylock(_l); \
+ if (likely(__ret != 0)) \
+ local_bh_disable(); \
+ } \
+ __ret; \
+})
+
+#define spin_trylock_irq(_l) \
+ spin_trylock(_l)
+
+#define spin_trylock_irqsave(_l, flags) ({ \
+ (flags) = 0; \
+ spin_trylock(_l); \
+})
+
+#define spin_lock_nested(_l, _n) do { \
+ if (SPIN_SKIP()) \
+ break; \
+ mtx_lock_flags(_l, MTX_DUPOK); \
+ local_bh_disable(); \
+} while (0)
+
+#define spin_lock_irqsave(_l, flags) do { \
+ (flags) = 0; \
+ spin_lock(_l); \
+} while (0)
+
+#define spin_lock_irqsave_nested(_l, flags, _n) do { \
+ (flags) = 0; \
+ spin_lock_nested(_l, _n); \
+} while (0)
+
+#define spin_unlock_irqrestore(_l, flags) do { \
+ (void)(flags); \
+ spin_unlock(_l); \
+} while (0)
+
+#ifdef WITNESS_ALL
+/* NOTE: the maximum WITNESS name is 64 chars */
+#define __spin_lock_name(name, file, line) \
+ (((const char *){file ":" #line "-" name}) + \
+ (sizeof(file) > 16 ? sizeof(file) - 16 : 0))
+#else
+#define __spin_lock_name(name, file, line) name
+#endif
+#define _spin_lock_name(...) __spin_lock_name(__VA_ARGS__)
+#define spin_lock_name(name) _spin_lock_name(name, __FILE__, __LINE__)
+
+#define spin_lock_init(lock) mtx_init(lock, spin_lock_name("lnxspin"), \
+ NULL, MTX_DEF | MTX_NOWITNESS | MTX_NEW)
+
+#define spin_lock_destroy(_l) mtx_destroy(_l)
+
+#define DEFINE_SPINLOCK(lock) \
+ spinlock_t lock; \
+ MTX_SYSINIT(lock, &lock, spin_lock_name("lnxspin"), MTX_DEF)
+
+#define assert_spin_locked(_l) do { \
+ if (SPIN_SKIP()) \
+ break; \
+ mtx_assert(_l, MA_OWNED); \
+} while (0)
+
+#define local_irq_save(flags) do { \
+ (flags) = 0; \
+} while (0)
+
+#define local_irq_restore(flags) do { \
+ (void)(flags); \
+} while (0)
+
+#define atomic_dec_and_lock_irqsave(cnt, lock, flags) \
+ _atomic_dec_and_lock_irqsave(cnt, lock, &(flags))
+static inline int
+_atomic_dec_and_lock_irqsave(atomic_t *cnt, spinlock_t *lock,
+ unsigned long *flags)
+{
+ if (atomic_add_unless(cnt, -1, 1))
+ return (0);
+
+ spin_lock_irqsave(lock, *flags);
+ if (atomic_dec_and_test(cnt))
+ return (1);
+ spin_unlock_irqrestore(lock, *flags);
+ return (0);
+}
+
+#endif /* _LINUXKPI_LINUX_SPINLOCK_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/srcu.h b/sys/compat/linuxkpi/common/include/linux/srcu.h
new file mode 100644
index 000000000000..b42c28a1311b
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/srcu.h
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2015-2020 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_SRCU_H_
+#define _LINUXKPI_LINUX_SRCU_H_
+
+#include <linux/compiler.h>
+
+struct srcu_struct {
+};
+
+#define srcu_dereference(p, srcu) \
+ ((__typeof(*(p)) *)READ_ONCE(p))
+
+#define DEFINE_STATIC_SRCU(name) \
+ static struct srcu_struct name
+
+/* prototypes */
+
+extern int srcu_read_lock(struct srcu_struct *);
+extern void srcu_read_unlock(struct srcu_struct *, int index);
+extern void synchronize_srcu(struct srcu_struct *);
+extern void srcu_barrier(struct srcu_struct *);
+extern int init_srcu_struct(struct srcu_struct *);
+extern void cleanup_srcu_struct(struct srcu_struct *);
+
+#define synchronize_srcu_expedited(srcu) do { \
+ synchronize_srcu(srcu); \
+} while (0)
+
+#endif /* _LINUXKPI_LINUX_SRCU_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/stackdepot.h b/sys/compat/linuxkpi/common/include/linux/stackdepot.h
new file mode 100644
index 000000000000..df223d46be6e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/stackdepot.h
@@ -0,0 +1,32 @@
+/*-
+ * Copyright (c) 2022 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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_STACKDEPOT_H_
+#define _LINUXKPI_LINUX_STACKDEPOT_H_
+
+typedef bool depot_stack_handle_t;
+
+#endif /* _LINUXKPI_LINUX_STACKDEPOT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/stdarg.h b/sys/compat/linuxkpi/common/include/linux/stdarg.h
new file mode 100644
index 000000000000..698ac45e9198
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/stdarg.h
@@ -0,0 +1,33 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
+ *
+ * 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 unmodified, 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 ``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 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_STDARG_H_
+#define _LINUXKPI_STDARG_H_
+
+#include <sys/stdarg.h>
+
+#endif /* _LINUXKPI_STDARG_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/stddef.h b/sys/compat/linuxkpi/common/include/linux/stddef.h
new file mode 100644
index 000000000000..d04a5a4bf516
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/stddef.h
@@ -0,0 +1,31 @@
+/* Public domain */
+
+#ifndef _LINUXKPI_LINUX_STDDEF_H_
+#define _LINUXKPI_LINUX_STDDEF_H_
+
+#include <sys/stddef.h>
+
+/*
+ * FreeBSD has multiple (vendor) drivers containing copies of this
+ * and including LinuxKPI headers. Put the #defines behind guards.
+ */
+
+#ifndef __struct_group
+#define __struct_group(_tag, _name, _attrs, _members...) \
+ union { \
+ struct { _members } _attrs; \
+ struct _tag { _members } _attrs _name; \
+ } _attrs
+#endif
+
+#ifndef struct_group
+#define struct_group(_name, _members...) \
+ __struct_group(/* no tag */, _name, /* no attrs */, _members)
+#endif
+
+#ifndef struct_group_tagged
+#define struct_group_tagged(_tag, _name, _members...) \
+ __struct_group(_tag, _name, /* no attrs */, _members)
+#endif
+
+#endif /* _LINUXKPI_LINUX_STDDEF_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/string.h b/sys/compat/linuxkpi/common/include/linux/string.h
new file mode 100644
index 000000000000..f7b64560d254
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/string.h
@@ -0,0 +1,329 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_STRING_H_
+#define _LINUXKPI_LINUX_STRING_H_
+
+#include <sys/ctype.h>
+
+#include <linux/types.h>
+#include <linux/gfp.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/err.h>
+#include <linux/bitops.h> /* for BITS_PER_LONG */
+#include <linux/overflow.h>
+#include <linux/stdarg.h>
+
+#include <sys/libkern.h>
+
+#define strnicmp(...) strncasecmp(__VA_ARGS__)
+
+static inline int
+match_string(const char *const *table, int n, const char *key)
+{
+ int i;
+
+ for (i = 0; i != n && table[i] != NULL; i++) {
+ if (strcmp(table[i], key) == 0)
+ return (i);
+ }
+ return (-EINVAL);
+}
+
+static inline void *
+memdup_user(const void *ptr, size_t len)
+{
+ void *retval;
+ int error;
+
+ retval = malloc(len, M_KMALLOC, M_WAITOK);
+ error = linux_copyin(ptr, retval, len);
+ if (error != 0) {
+ free(retval, M_KMALLOC);
+ return (ERR_PTR(error));
+ }
+ return (retval);
+}
+
+static inline void *
+memdup_user_nul(const void *ptr, size_t len)
+{
+ char *retval;
+ int error;
+
+ retval = malloc(len + 1, M_KMALLOC, M_WAITOK);
+ error = linux_copyin(ptr, retval, len);
+ if (error != 0) {
+ free(retval, M_KMALLOC);
+ return (ERR_PTR(error));
+ }
+ retval[len] = '\0';
+ return (retval);
+}
+
+static inline void *
+kmemdup(const void *src, size_t len, gfp_t gfp)
+{
+ void *dst;
+
+ dst = kmalloc(len, gfp);
+ if (dst != NULL)
+ memcpy(dst, src, len);
+ return (dst);
+}
+
+/* See slab.h for kvmalloc/kvfree(). */
+static inline void *
+kvmemdup(const void *src, size_t len, gfp_t gfp)
+{
+ void *dst;
+
+ dst = kvmalloc(len, gfp);
+ if (dst != NULL)
+ memcpy(dst, src, len);
+ return (dst);
+}
+
+static inline char *
+strndup_user(const char __user *ustr, long n)
+{
+ if (n < 1)
+ return (ERR_PTR(-EINVAL));
+
+ return (memdup_user_nul(ustr, n - 1));
+}
+
+static inline char *
+kstrdup(const char *string, gfp_t gfp)
+{
+ char *retval;
+ size_t len;
+
+ if (string == NULL)
+ return (NULL);
+ len = strlen(string) + 1;
+ retval = kmalloc(len, gfp);
+ if (retval != NULL)
+ memcpy(retval, string, len);
+ return (retval);
+}
+
+static inline char *
+kstrndup(const char *string, size_t len, gfp_t gfp)
+{
+ char *retval;
+
+ if (string == NULL)
+ return (NULL);
+ retval = kmalloc(len + 1, gfp);
+ if (retval != NULL)
+ strncpy(retval, string, len);
+ return (retval);
+}
+
+static inline const char *
+kstrdup_const(const char *src, gfp_t gfp)
+{
+ return (kmemdup(src, strlen(src) + 1, gfp));
+}
+
+static inline char *
+skip_spaces(const char *str)
+{
+ while (isspace(*str))
+ ++str;
+ return (__DECONST(char *, str));
+}
+
+/*
+ * This function trims whitespaces at the end of a string and returns a pointer
+ * to the first non-whitespace character.
+ */
+static inline char *
+strim(char *str)
+{
+ char *end;
+
+ end = str + strlen(str);
+ while (end >= str && (*end == '\0' || isspace(*end))) {
+ *end = '\0';
+ end--;
+ }
+
+ return (skip_spaces(str));
+}
+
+static inline void *
+memchr_inv(const void *start, int c, size_t length)
+{
+ const u8 *ptr;
+ const u8 *end;
+ u8 ch;
+
+ ch = c;
+ ptr = start;
+ end = ptr + length;
+
+ while (ptr != end) {
+ if (*ptr != ch)
+ return (__DECONST(void *, ptr));
+ ptr++;
+ }
+ return (NULL);
+}
+
+static inline size_t
+str_has_prefix(const char *str, const char *prefix)
+{
+ size_t len;
+
+ len = strlen(prefix);
+ return (strncmp(str, prefix, len) == 0 ? len : 0);
+}
+
+static inline char *
+strreplace(char *str, char old, char new)
+{
+ char *p;
+
+ p = strchrnul(str, old);
+ while (p != NULL && *p != '\0') {
+ *p = new;
+ p = strchrnul(str, old);
+ }
+ return (p);
+}
+
+static inline ssize_t
+strscpy(char* dst, const char* src, size_t len)
+{
+ size_t i;
+
+ if (len <= INT_MAX) {
+ for (i = 0; i < len; i++)
+ if ('\0' == (dst[i] = src[i]))
+ return ((ssize_t)i);
+ if (i != 0)
+ dst[--i] = '\0';
+ }
+
+ return (-E2BIG);
+}
+
+static inline ssize_t
+strscpy_pad(char* dst, const char* src, size_t len)
+{
+
+ bzero(dst, len);
+
+ return (strscpy(dst, src, len));
+}
+
+static inline char *
+strnchr(const char *cp, size_t n, int ch)
+{
+ char *p;
+
+ for (p = __DECONST(char *, cp); n--; ++p) {
+ if (*p == ch)
+ return (p);
+ if (*p == '\0')
+ break;
+ }
+
+ return (NULL);
+}
+
+static inline void *
+memset32(uint32_t *b, uint32_t c, size_t len)
+{
+ uint32_t *dst = b;
+
+ while (len--)
+ *dst++ = c;
+ return (b);
+}
+
+static inline void *
+memset64(uint64_t *b, uint64_t c, size_t len)
+{
+ uint64_t *dst = b;
+
+ while (len--)
+ *dst++ = c;
+ return (b);
+}
+
+static inline void *
+memset_p(void **p, void *v, size_t n)
+{
+
+ if (BITS_PER_LONG == 32)
+ return (memset32((uint32_t *)p, (uintptr_t)v, n));
+ else
+ return (memset64((uint64_t *)p, (uintptr_t)v, n));
+}
+
+static inline void
+memcpy_and_pad(void *dst, size_t dstlen, const void *src, size_t len, int ch)
+{
+
+ if (len >= dstlen) {
+ memcpy(dst, src, dstlen);
+ } else {
+ memcpy(dst, src, len);
+ /* Pad with given padding character. */
+ memset((char *)dst + len, ch, dstlen - len);
+ }
+}
+
+#define memset_startat(ptr, bytepat, smember) \
+({ \
+ uint8_t *_ptr = (uint8_t *)(ptr); \
+ int _c = (int)(bytepat); \
+ size_t _o = offsetof(typeof(*(ptr)), smember); \
+ memset(_ptr + _o, _c, sizeof(*(ptr)) - _o); \
+})
+
+#define memset_after(ptr, bytepat, smember) \
+({ \
+ uint8_t *_ptr = (uint8_t *)(ptr); \
+ int _c = (int)(bytepat); \
+ size_t _o = offsetofend(typeof(*(ptr)), smember); \
+ memset(_ptr + _o, _c, sizeof(*(ptr)) - _o); \
+})
+
+static inline void
+memzero_explicit(void *p, size_t s)
+{
+ memset(p, 0, s);
+ __asm__ __volatile__("": :"r"(p) :"memory");
+}
+
+#endif /* _LINUXKPI_LINUX_STRING_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/string_helpers.h b/sys/compat/linuxkpi/common/include/linux/string_helpers.h
new file mode 100644
index 000000000000..1bdff2730361
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/string_helpers.h
@@ -0,0 +1,69 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
+ *
+ * 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 unmodified, 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 ``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 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_STRING_HELPERS_H_
+#define _LINUXKPI_LINUX_STRING_HELPERS_H_
+
+#include <sys/types.h>
+
+static inline const char *
+str_yes_no(bool value)
+{
+ if (value)
+ return "yes";
+ else
+ return "no";
+}
+
+static inline const char *
+str_on_off(bool value)
+{
+ if (value)
+ return "on";
+ else
+ return "off";
+}
+
+static inline const char *
+str_enabled_disabled(bool value)
+{
+ if (value)
+ return "enabled";
+ else
+ return "disabled";
+}
+
+static inline const char *
+str_enable_disable(bool value)
+{
+ if (value)
+ return "enable";
+ else
+ return "disable";
+}
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/stringify.h b/sys/compat/linuxkpi/common/include/linux/stringify.h
new file mode 100644
index 000000000000..9345bdc441aa
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/stringify.h
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_STRINGIFY_H_
+#define _LINUXKPI_LINUX_STRINGIFY_H_
+
+#include <sys/cdefs.h>
+
+#define ___stringify(...) #__VA_ARGS__
+#define __stringify(...) ___stringify(__VA_ARGS__)
+
+#endif /* _LINUXKPI_LINUX_STRINGIFY_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/suspend.h b/sys/compat/linuxkpi/common/include/linux/suspend.h
new file mode 100644
index 000000000000..dacecbebdc08
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/suspend.h
@@ -0,0 +1,23 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_SUSPEND_H_
+#define _LINUXKPI_LINUX_SUSPEND_H_
+
+typedef int suspend_state_t;
+
+extern suspend_state_t pm_suspend_target_state;
+
+#define PM_SUSPEND_ON 0
+#define PM_SUSPEND_TO_IDLE 1
+#define PM_SUSPEND_STANDBY 2
+#define PM_SUSPEND_MEM 3
+#define PM_SUSPEND_MIN PM_SUSPEND_TO_IDLE
+#define PM_SUSPEND_MAX 4
+
+static inline int
+pm_suspend_via_firmware(void)
+{
+ 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
new file mode 100644
index 000000000000..5828db7ae392
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/swap.h
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 2018 Intel Corporation
+ *
+ * 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_SWAP_H_
+#define _LINUXKPI_LINUX_SWAP_H_
+
+#include <sys/param.h>
+#include <sys/domainset.h>
+#include <sys/queue.h>
+#include <sys/proc.h>
+#include <sys/pcpu.h>
+
+#include <vm/vm.h>
+#include <vm/swap_pager.h>
+#include <vm/vm_pageout.h>
+
+#include <linux/pagemap.h>
+#include <linux/page-flags.h>
+
+static inline long
+get_nr_swap_pages(void)
+{
+ int i, j;
+
+ /* NB: This could be done cheaply by obtaining swap_total directly */
+ swap_pager_status(&i, &j);
+ return i - j;
+}
+
+static inline int
+current_is_kswapd(void)
+{
+
+ return (curproc == pageproc);
+}
+
+static inline void
+folio_mark_accessed(struct folio *folio)
+{
+ mark_page_accessed(&folio->page);
+}
+
+static inline void
+check_move_unevictable_folios(struct folio_batch *fbatch)
+{
+}
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/sysfs.h b/sys/compat/linuxkpi/common/include/linux/sysfs.h
new file mode 100644
index 000000000000..65e023031bb2
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/sysfs.h
@@ -0,0 +1,487 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_SYSFS_H_
+#define _LINUXKPI_LINUX_SYSFS_H_
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/errno.h>
+
+#include <linux/kobject.h>
+#include <linux/stringify.h>
+#include <linux/mm.h>
+
+struct sysfs_ops {
+ ssize_t (*show)(struct kobject *, struct attribute *, char *);
+ ssize_t (*store)(struct kobject *, struct attribute *, const char *,
+ 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;
+ ssize_t (*read)(struct linux_file *, struct kobject *,
+ struct bin_attribute *, char *, loff_t, size_t);
+ ssize_t (*write)(struct linux_file *, struct kobject *,
+ struct bin_attribute *, char *, loff_t, size_t);
+};
+
+#define __ATTR(_name, _mode, _show, _store) { \
+ .attr = { .name = __stringify(_name), .mode = _mode }, \
+ .show = _show, .store = _store, \
+}
+#define __ATTR_RO(_name) { \
+ .attr = { .name = __stringify(_name), .mode = 0444 }, \
+ .show = _name##_show, \
+}
+#define __ATTR_WO(_name) __ATTR(_name, 0200, NULL, _name##_store)
+#define __ATTR_RW(_name) __ATTR(_name, 0644, _name##_show, _name##_store)
+#define __ATTR_NULL { .attr = { .name = NULL } }
+
+#define ATTRIBUTE_GROUPS(_name) \
+ static struct attribute_group _name##_group = { \
+ .name = __stringify(_name), \
+ .attrs = _name##_attrs, \
+ }; \
+ static const struct attribute_group *_name##_groups[] = { \
+ &_name##_group, \
+ NULL, \
+ }
+
+#define __BIN_ATTR(_name, _mode, _read, _write, _size) { \
+ .attr = { .name = __stringify(_name), .mode = _mode }, \
+ .read = _read, .write = _write, .size = _size, \
+}
+#define __BIN_ATTR_RO(_name, _size) { \
+ .attr = { .name = __stringify(_name), .mode = 0444 }, \
+ .read = _name##_read, .size = _size, \
+}
+#define __BIN_ATTR_WO(_name, _size) { \
+ .attr = { .name = __stringify(_name), .mode = 0200 }, \
+ .write = _name##_write, .size = _size, \
+}
+#define __BIN_ATTR_WR(_name, _size) { \
+ .attr = { .name = __stringify(_name), .mode = 0644 }, \
+ .read = _name##_read, .write = _name##_write, .size = _size, \
+}
+
+#define BIN_ATTR(_name, _mode, _read, _write, _size) \
+struct bin_attribute bin_attr_##_name = \
+ __BIN_ATTR(_name, _mode, _read, _write, _size);
+
+#define BIN_ATTR_RO(_name, _size) \
+struct bin_attribute bin_attr_##_name = \
+ __BIN_ATTR_RO(_name, _size);
+
+#define BIN_ATTR_WO(_name, _size) \
+struct bin_attribute bin_attr_##_name = \
+ __BIN_ATTR_WO(_name, _size);
+
+#define BIN_ATTR_WR(_name, _size) \
+struct bin_attribute bin_attr_##_name = \
+ __BIN_ATTR_WR(_name, _size);
+
+/*
+ * Handle our generic '\0' terminated 'C' string.
+ * Two cases:
+ * a variable string: point arg1 at it, arg2 is max length.
+ * a constant string: point arg1 at it, arg2 is zero.
+ */
+
+static inline int
+sysctl_handle_attr(SYSCTL_HANDLER_ARGS)
+{
+ struct kobject *kobj;
+ struct attribute *attr;
+ const struct sysfs_ops *ops;
+ char *buf;
+ int error;
+ ssize_t len;
+
+ kobj = arg1;
+ attr = (struct attribute *)(intptr_t)arg2;
+ if (kobj->ktype == NULL || kobj->ktype->sysfs_ops == NULL)
+ return (ENODEV);
+ buf = (char *)get_zeroed_page(GFP_KERNEL);
+ if (buf == NULL)
+ return (ENOMEM);
+ ops = kobj->ktype->sysfs_ops;
+ if (ops->show) {
+ len = ops->show(kobj, attr, buf);
+ /*
+ * It's valid to not have a 'show' so just return an
+ * empty string.
+ */
+ if (len < 0) {
+ error = -len;
+ if (error != EIO)
+ goto out;
+ buf[0] = '\0';
+ } else if (len) {
+ len--;
+ if (len >= PAGE_SIZE)
+ len = PAGE_SIZE - 1;
+ /* Trim trailing newline. */
+ buf[len] = '\0';
+ }
+ }
+
+ /* Leave one trailing byte to append a newline. */
+ error = sysctl_handle_string(oidp, buf, PAGE_SIZE - 1, req);
+ if (error != 0 || req->newptr == NULL || ops->store == NULL)
+ goto out;
+ len = strlcat(buf, "\n", PAGE_SIZE);
+ KASSERT(len < PAGE_SIZE, ("new attribute truncated"));
+ len = ops->store(kobj, attr, buf, len);
+ if (len < 0)
+ error = -len;
+out:
+ free_page((unsigned long)buf);
+
+ return (error);
+}
+
+static inline int
+sysfs_create_file(struct kobject *kobj, const struct attribute *attr)
+{
+ struct sysctl_oid *oid;
+
+ oid = SYSCTL_ADD_OID(NULL, SYSCTL_CHILDREN(kobj->oidp), OID_AUTO,
+ attr->name, CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_MPSAFE, kobj,
+ (uintptr_t)attr, sysctl_handle_attr, "A", "");
+ if (!oid) {
+ return (-ENOMEM);
+ }
+
+ return (0);
+}
+
+static inline void
+sysfs_remove_file(struct kobject *kobj, const struct attribute *attr)
+{
+
+ if (kobj->oidp)
+ sysctl_remove_name(kobj->oidp, attr->name, 1, 1);
+}
+
+static inline int
+sysctl_handle_bin_attr(SYSCTL_HANDLER_ARGS)
+{
+ struct kobject *kobj;
+ struct bin_attribute *attr;
+ char *buf;
+ int error;
+ ssize_t len;
+
+ kobj = arg1;
+ attr = (struct bin_attribute *)(intptr_t)arg2;
+ if (kobj->ktype == NULL || kobj->ktype->sysfs_ops == NULL)
+ return (ENODEV);
+ buf = (char *)get_zeroed_page(GFP_KERNEL);
+ if (buf == NULL)
+ return (ENOMEM);
+
+ if (attr->read) {
+ len = attr->read(
+ NULL, /* <-- struct file, unimplemented */
+ kobj, attr, buf, req->oldidx, PAGE_SIZE);
+ if (len < 0) {
+ error = -len;
+ if (error != EIO)
+ goto out;
+ }
+ }
+
+ error = sysctl_handle_opaque(oidp, buf, PAGE_SIZE, req);
+ if (error != 0 || req->newptr == NULL || attr->write == NULL)
+ goto out;
+
+ len = attr->write(
+ NULL, /* <-- struct file, unimplemented */
+ kobj, attr, buf, req->newidx, req->newlen);
+ if (len < 0)
+ error = -len;
+out:
+ free_page((unsigned long)buf);
+
+ return (error);
+}
+
+static inline int
+sysfs_create_bin_file(struct kobject *kobj, const struct bin_attribute *attr)
+{
+ struct sysctl_oid *oid;
+ int ctlflags;
+
+ ctlflags = CTLTYPE_OPAQUE | CTLFLAG_MPSAFE;
+ if (attr->attr.mode & (S_IRUSR | S_IWUSR))
+ ctlflags |= CTLFLAG_RW;
+ else if (attr->attr.mode & S_IRUSR)
+ ctlflags |= CTLFLAG_RD;
+ else if (attr->attr.mode & S_IWUSR)
+ ctlflags |= CTLFLAG_WR;
+
+ oid = SYSCTL_ADD_OID(NULL, SYSCTL_CHILDREN(kobj->oidp), OID_AUTO,
+ attr->attr.name, ctlflags, kobj,
+ (uintptr_t)attr, sysctl_handle_bin_attr, "", "");
+ if (oid == NULL)
+ return (-ENOMEM);
+
+ return (0);
+}
+
+static inline void
+sysfs_remove_bin_file(struct kobject *kobj, const struct bin_attribute *attr)
+{
+
+ if (kobj->oidp)
+ sysctl_remove_name(kobj->oidp, attr->attr.name, 1, 1);
+}
+
+static inline int
+sysfs_create_link(struct kobject *kobj __unused,
+ struct kobject *target __unused, const char *name __unused)
+{
+ /* TODO */
+
+ return (0);
+}
+
+static inline void
+sysfs_remove_link(struct kobject *kobj, const char *name)
+{
+ /* TODO (along with sysfs_create_link) */
+}
+
+static inline int
+sysfs_create_files(struct kobject *kobj, const struct attribute * const *attrs)
+{
+ int error = 0;
+ int i;
+
+ for (i = 0; attrs[i] && !error; i++)
+ error = sysfs_create_file(kobj, attrs[i]);
+ while (error && --i >= 0)
+ sysfs_remove_file(kobj, attrs[i]);
+
+ return (error);
+}
+
+static inline void
+sysfs_remove_files(struct kobject *kobj, const struct attribute * const *attrs)
+{
+ int i;
+
+ for (i = 0; attrs[i]; i++)
+ sysfs_remove_file(kobj, attrs[i]);
+}
+
+static inline int
+sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp)
+{
+ struct attribute **attr;
+ struct sysctl_oid *oidp;
+
+ /* Don't create the group node if grp->name is undefined. */
+ if (grp->name)
+ oidp = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(kobj->oidp),
+ OID_AUTO, grp->name, CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, grp->name);
+ else
+ oidp = kobj->oidp;
+ for (attr = grp->attrs; *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", "");
+ }
+
+ return (0);
+}
+
+static inline void
+sysfs_remove_group(struct kobject *kobj, const struct attribute_group *grp)
+{
+
+ if (kobj->oidp)
+ sysctl_remove_name(kobj->oidp, grp->name, 1, 1);
+}
+
+static inline int
+sysfs_create_groups(struct kobject *kobj, const struct attribute_group **grps)
+{
+ int error = 0;
+ int i;
+
+ if (grps == NULL)
+ goto done;
+ for (i = 0; grps[i] && !error; i++)
+ error = sysfs_create_group(kobj, grps[i]);
+ while (error && --i >= 0)
+ sysfs_remove_group(kobj, grps[i]);
+done:
+ return (error);
+}
+
+static inline void
+sysfs_remove_groups(struct kobject *kobj, const struct attribute_group **grps)
+{
+ int i;
+
+ if (grps == NULL)
+ return;
+ for (i = 0; grps[i]; i++)
+ sysfs_remove_group(kobj, grps[i]);
+}
+
+static inline int
+sysfs_merge_group(struct kobject *kobj, const struct attribute_group *grp)
+{
+
+ /* Really expected behavior is to return failure if group exists. */
+ return (sysfs_create_group(kobj, grp));
+}
+
+static inline void
+sysfs_unmerge_group(struct kobject *kobj, const struct attribute_group *grp)
+{
+ struct attribute **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++) {
+ sysctl_remove_name(oidp, (*attr)->name, 1, 1);
+ }
+ }
+}
+
+static inline int
+sysfs_create_dir(struct kobject *kobj)
+{
+ struct sysctl_oid *oid;
+
+ oid = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(kobj->parent->oidp),
+ OID_AUTO, kobj->name, CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, kobj->name);
+ if (!oid) {
+ return (-ENOMEM);
+ }
+ kobj->oidp = oid;
+
+ return (0);
+}
+
+static inline void
+sysfs_remove_dir(struct kobject *kobj)
+{
+
+ if (kobj->oidp == NULL)
+ return;
+ sysctl_remove_oid(kobj->oidp, 1, 1);
+}
+
+static inline bool
+sysfs_streq(const char *s1, const char *s2)
+{
+ int l1, l2;
+
+ l1 = strlen(s1);
+ l2 = strlen(s2);
+
+ if (l1 != 0 && s1[l1-1] == '\n')
+ l1--;
+ if (l2 != 0 && s2[l2-1] == '\n')
+ l2--;
+
+ return (l1 == l2 && strncmp(s1, s2, l1) == 0);
+}
+
+static inline int
+sysfs_emit(char *buf, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ if (!buf || offset_in_page(buf)) {
+ pr_warn("invalid sysfs_emit: buf:%p\n", buf);
+ return (0);
+ }
+
+ va_start(args, fmt);
+ i = vscnprintf(buf, PAGE_SIZE, fmt, args);
+ va_end(args);
+
+ return (i);
+}
+
+static inline int
+sysfs_emit_at(char *buf, int at, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ if (!buf || offset_in_page(buf) || at < 0 || at >= PAGE_SIZE) {
+ pr_warn("invalid sysfs_emit: buf:%p at:%d\n", buf, at);
+ return (0);
+ }
+
+ va_start(args, fmt);
+ i = vscnprintf(buf + at, PAGE_SIZE - at, fmt, args);
+ va_end(args);
+
+ return (i);
+}
+
+static inline int
+_sysfs_match_string(const char * const *a, size_t l, const char *s)
+{
+ const char *p;
+ int i;
+
+ for (i = 0; i < l; i++) {
+ p = a[i];
+ if (p == NULL)
+ break;
+ if (sysfs_streq(p, s))
+ return (i);
+ }
+
+ return (-ENOENT);
+}
+#define sysfs_match_string(a, s) _sysfs_match_string(a, ARRAY_SIZE(a), s)
+
+#define sysfs_attr_init(attr) do {} while(0)
+
+#endif /* _LINUXKPI_LINUX_SYSFS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/tcp.h b/sys/compat/linuxkpi/common/include/linux/tcp.h
new file mode 100644
index 000000000000..3e461d8e7075
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/tcp.h
@@ -0,0 +1,70 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020-2021 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb 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_TCP_H
+#define _LINUXKPI_LINUX_TCP_H
+
+#include <sys/types.h>
+#include <linux/skbuff.h>
+
+/* (u) unconfirmed structure field names; using FreeBSD's meanwhile. */
+struct tcphdr {
+ uint16_t source; /* (u) */
+ uint16_t dest; /* (u) */
+ uint32_t th_seq; /* (u) */
+ uint32_t th_ack; /* (u) */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ uint8_t th_x2:4, doff:4;
+#elif BYTE_ORDER == BIG_ENDIAN
+ uint8_t doff:4, th_x2:4;
+#endif
+ uint8_t th_flags; /* (u) */
+ uint16_t th_win; /* (u) */
+ uint16_t check;
+ uint16_t th_urg; /* (u) */
+};
+
+static __inline struct tcphdr *
+tcp_hdr(struct sk_buff *skb)
+{
+
+ return (struct tcphdr *)skb_transport_header(skb);
+}
+
+static __inline uint32_t
+tcp_hdrlen(struct sk_buff *skb)
+{
+ struct tcphdr *th;
+
+ th = tcp_hdr(skb);
+ return (4 * th->doff);
+}
+
+#endif /* _LINUXKPI_LINUX_TCP_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/time.h b/sys/compat/linuxkpi/common/include/linux/time.h
new file mode 100644
index 000000000000..ca77a20516ff
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/time.h
@@ -0,0 +1,141 @@
+/*-
+ * Copyright (c) 2014-2015 François Tigeot
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_TIME_H_
+#define _LINUXKPI_LINUX_TIME_H_
+
+#define MSEC_PER_SEC 1000L
+
+#define NSEC_PER_USEC 1000L
+#define NSEC_PER_MSEC 1000000L
+#define NSEC_PER_SEC 1000000000L
+
+#define USEC_PER_MSEC 1000L
+#define USEC_PER_SEC 1000000L
+
+#define timespec64 timespec
+
+#include <sys/time.h>
+#include <sys/stdint.h>
+
+#include <linux/math64.h>
+
+typedef int64_t time64_t;
+
+static inline struct timeval
+ns_to_timeval(const int64_t nsec)
+{
+ struct timeval tv;
+ long rem;
+
+ if (nsec == 0) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ return (tv);
+ }
+
+ tv.tv_sec = nsec / NSEC_PER_SEC;
+ rem = nsec % NSEC_PER_SEC;
+ if (rem < 0) {
+ tv.tv_sec--;
+ rem += NSEC_PER_SEC;
+ }
+ tv.tv_usec = rem / 1000;
+ return (tv);
+}
+
+static inline int64_t
+timeval_to_ns(const struct timeval *tv)
+{
+ return ((int64_t)tv->tv_sec * NSEC_PER_SEC) +
+ tv->tv_usec * NSEC_PER_USEC;
+}
+
+#define getrawmonotonic(ts) nanouptime(ts)
+
+static inline struct timespec
+timespec_sub(struct timespec lhs, struct timespec rhs)
+{
+ struct timespec ts;
+
+ timespecsub(&lhs, &rhs, &ts);
+
+ return ts;
+}
+
+static inline void
+set_normalized_timespec(struct timespec *ts, time_t sec, int64_t nsec)
+{
+ /* XXX: this doesn't actually normalize anything */
+ ts->tv_sec = sec;
+ ts->tv_nsec = nsec;
+}
+
+static inline int64_t
+timespec_to_ns(const struct timespec *ts)
+{
+ return ((ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec);
+}
+
+static inline struct timespec
+ns_to_timespec(const int64_t nsec)
+{
+ struct timespec ts;
+ int32_t rem;
+
+ if (nsec == 0) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ return (ts);
+ }
+
+ ts.tv_sec = nsec / NSEC_PER_SEC;
+ rem = nsec % NSEC_PER_SEC;
+ if (rem < 0) {
+ ts.tv_sec--;
+ rem += NSEC_PER_SEC;
+ }
+ ts.tv_nsec = rem;
+ return (ts);
+}
+
+#define ns_to_timespec64(_x) ns_to_timespec(_x)
+
+static inline int
+timespec_valid(const struct timespec *ts)
+{
+ if (ts->tv_sec < 0 || ts->tv_sec > 100000000 ||
+ ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000)
+ return (0);
+ return (1);
+}
+
+static inline unsigned long
+get_seconds(void)
+{
+ return time_uptime;
+}
+
+#endif /* _LINUXKPI_LINUX_TIME_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/timer.h b/sys/compat/linuxkpi/common/include/linux/timer.h
new file mode 100644
index 000000000000..a635f0faea59
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/timer.h
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_TIMER_H_
+#define _LINUXKPI_LINUX_TIMER_H_
+
+#include <linux/types.h>
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/callout.h>
+
+struct timer_list {
+ struct callout callout;
+ union {
+ void (*function) (unsigned long); /* < v4.15 */
+ void (*function_415) (struct timer_list *);
+ };
+ unsigned long data;
+ unsigned long expires;
+};
+
+extern unsigned long linux_timer_hz_mask;
+
+#define TIMER_IRQSAFE 0x0001
+
+#define from_timer(var, arg, field) \
+ container_of(arg, typeof(*(var)), field)
+
+#define timer_setup(timer, func, flags) do { \
+ CTASSERT(((flags) & ~TIMER_IRQSAFE) == 0); \
+ (timer)->function_415 = (func); \
+ (timer)->data = (unsigned long)(timer); \
+ callout_init(&(timer)->callout, 1); \
+} while (0)
+
+#define setup_timer(timer, func, dat) do { \
+ (timer)->function = (func); \
+ (timer)->data = (dat); \
+ callout_init(&(timer)->callout, 1); \
+} while (0)
+
+#define __setup_timer(timer, func, dat, flags) do { \
+ CTASSERT(((flags) & ~TIMER_IRQSAFE) == 0); \
+ setup_timer(timer, func, dat); \
+} while (0)
+
+#define init_timer(timer) do { \
+ (timer)->function = NULL; \
+ (timer)->data = 0; \
+ callout_init(&(timer)->callout, 1); \
+} while (0)
+
+extern int mod_timer(struct timer_list *, unsigned long);
+extern void add_timer(struct timer_list *);
+extern void add_timer_on(struct timer_list *, int cpu);
+extern int del_timer(struct timer_list *);
+extern int del_timer_sync(struct timer_list *);
+extern int timer_delete_sync(struct timer_list *);
+extern int timer_shutdown_sync(struct timer_list *);
+
+#define timer_pending(timer) callout_pending(&(timer)->callout)
+#define round_jiffies(j) \
+ ((unsigned long)(((j) + linux_timer_hz_mask) & ~linux_timer_hz_mask))
+#define round_jiffies_relative(j) round_jiffies(j)
+#define round_jiffies_up(j) round_jiffies(j)
+#define round_jiffies_up_relative(j) round_jiffies_up(j)
+
+#endif /* _LINUXKPI_LINUX_TIMER_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/tracepoint.h b/sys/compat/linuxkpi/common/include/linux/tracepoint.h
new file mode 100644
index 000000000000..8ce7992306b9
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/tracepoint.h
@@ -0,0 +1,48 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Bjoern A. Zeeb
+ *
+ * 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_TRACEPOINT_H
+#define _LINUXKPI_LINUX_TRACEPOINT_H
+
+#define TP_PROTO(...) __VA_ARGS__
+#define TP_ARGS(...)
+#define TP_STRUCT__entry(...)
+#define TP_fast_assign(...)
+#define TP_printk(...)
+
+#define TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
+static inline void trace_ ## _name(_proto) \
+{ \
+}
+
+#define DECLARE_EVENT_CLASS(...)
+#define DEFINE_EVENT(_x, _name, _proto, _args) \
+static inline void trace_ ## _name(_proto) \
+{ \
+}
+
+#endif /* _LINUXKPI_LINUX_TRACEPOINT_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/typecheck.h b/sys/compat/linuxkpi/common/include/linux/typecheck.h
new file mode 100644
index 000000000000..0e813962a7f5
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/typecheck.h
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2022 Beckhoff Automation GmbH & Co. KG
+ *
+ * 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_TYPECHECK_H_
+#define _LINUXKPI_LINUX_TYPECHECK_H_
+
+#define typecheck(type,x) \
+({ type __var1; \
+ typeof(x) __var2; \
+ (void)(&__var1 == &__var2); \
+ 1; \
+})
+
+
+#endif /* _LINUXKPI_LINUX_TYPECHECK_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/types.h b/sys/compat/linuxkpi/common/include/linux/types.h
new file mode 100644
index 000000000000..fcc455e5f731
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/types.h
@@ -0,0 +1,96 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_TYPES_H_
+#define _LINUXKPI_LINUX_TYPES_H_
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <linux/compiler.h>
+#include <asm/types.h>
+
+#ifndef __bitwise__
+#ifdef __CHECKER__
+#define __bitwise__ __attribute__((bitwise))
+#else
+#define __bitwise__
+#endif
+#endif
+
+typedef uint16_t __le16;
+typedef uint16_t __be16;
+typedef uint32_t __le32;
+typedef uint32_t __be32;
+typedef uint64_t __le64;
+typedef uint64_t __be64;
+
+typedef uint16_t __aligned_u16 __aligned(sizeof(uint16_t));
+typedef uint32_t __aligned_u32 __aligned(sizeof(uint32_t));
+typedef uint64_t __aligned_u64 __aligned(sizeof(uint64_t));
+
+#ifdef _KERNEL
+typedef unsigned short ushort;
+typedef unsigned int uint;
+#endif
+typedef unsigned long ulong;
+typedef unsigned gfp_t;
+typedef off_t loff_t;
+typedef vm_paddr_t resource_size_t;
+typedef uint16_t __bitwise__ __sum16;
+typedef uint32_t __bitwise__ __wsum;
+typedef unsigned long pgoff_t;
+typedef unsigned __poll_t;
+
+typedef uint64_t phys_addr_t;
+
+typedef size_t __kernel_size_t;
+typedef unsigned long kernel_ulong_t;
+
+#define DECLARE_BITMAP(n, bits) \
+ unsigned long n[howmany(bits, sizeof(long) * 8)]
+
+typedef unsigned long irq_hw_number_t;
+
+#ifndef LIST_HEAD_DEF
+#define LIST_HEAD_DEF
+struct list_head {
+ struct list_head *next;
+ struct list_head *prev;
+};
+#endif
+
+struct rcu_head {
+ void *raw[2];
+} __aligned(sizeof(void *));
+
+typedef void (*rcu_callback_t)(struct rcu_head *head);
+typedef void (*call_rcu_func_t)(struct rcu_head *head, rcu_callback_t func);
+typedef int linux_task_fn_t(void *data);
+
+#endif /* _LINUXKPI_LINUX_TYPES_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/uaccess.h b/sys/compat/linuxkpi/common/include/linux/uaccess.h
new file mode 100644
index 000000000000..660e84e6af3b
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/uaccess.h
@@ -0,0 +1,115 @@
+/*-
+ * 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.
+ *
+ * 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 unmodified, 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 ``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 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_UACCESS_H_
+#define _LINUXKPI_LINUX_UACCESS_H_
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/proc.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+
+#include <linux/compiler.h>
+
+#define VERIFY_READ VM_PROT_READ
+#define VERIFY_WRITE VM_PROT_WRITE
+
+#define __get_user(_x, _p) ({ \
+ int __err; \
+ __typeof(*(_p)) __x; \
+ __err = linux_copyin((_p), &(__x), sizeof(*(_p))); \
+ (_x) = __x; \
+ __err; \
+})
+
+#define __put_user(_x, _p) ({ \
+ __typeof(*(_p)) __x = (_x); \
+ linux_copyout(&(__x), (_p), sizeof(*(_p))); \
+})
+#define get_user(_x, _p) linux_copyin((_p), &(_x), sizeof(*(_p)))
+#define put_user(_x, _p) __put_user(_x, _p)
+#define clear_user(...) linux_clear_user(__VA_ARGS__)
+
+#define access_ok(a,b) linux_access_ok(a,b)
+
+extern int linux_copyin(const void *uaddr, void *kaddr, size_t len);
+extern int linux_copyout(const void *kaddr, void *uaddr, size_t len);
+extern size_t linux_clear_user(void *uaddr, size_t len);
+extern int linux_access_ok(const void *uaddr, size_t len);
+
+/*
+ * NOTE: Each pagefault_disable() call must have a corresponding
+ * pagefault_enable() call in the same scope. The former creates a new
+ * block and defines a temporary variable, and the latter uses the
+ * temporary variable and closes the block. Failure to balance the
+ * calls will result in a compile-time error.
+ */
+#define pagefault_disable(void) do { \
+ int __saved_pflags = \
+ vm_fault_disable_pagefaults()
+
+#define pagefault_enable(void) \
+ vm_fault_enable_pagefaults(__saved_pflags); \
+} while (0)
+
+static inline bool
+pagefault_disabled(void)
+{
+ return ((curthread->td_pflags & TDP_NOFAULTING) != 0);
+}
+
+static inline int
+__copy_to_user_inatomic(void __user *to, const void *from, unsigned n)
+{
+
+ return (copyout_nofault(from, to, n) != 0 ? n : 0);
+}
+#define __copy_to_user_inatomic_nocache(to, from, n) \
+ __copy_to_user_inatomic((to), (from), (n))
+
+static inline unsigned long
+__copy_from_user_inatomic(void *to, const void __user *from,
+ unsigned long n)
+{
+ /*
+ * XXXKIB. Equivalent Linux function is implemented using
+ * MOVNTI for aligned moves. For unaligned head and tail,
+ * normal move is performed. As such, it is not incorrect, if
+ * only somewhat slower, to use normal copyin. All uses
+ * except shmem_pwrite_fast() have the destination mapped WC.
+ */
+ return ((copyin_nofault(__DECONST(void *, from), to, n) != 0 ? n : 0));
+}
+#define __copy_from_user_inatomic_nocache(to, from, n) \
+ __copy_from_user_inatomic((to), (from), (n))
+
+#endif /* _LINUXKPI_LINUX_UACCESS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/udp.h b/sys/compat/linuxkpi/common/include/linux/udp.h
new file mode 100644
index 000000000000..f3cd40cf8bb7
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/udp.h
@@ -0,0 +1,52 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020-2021 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb 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_UDP_H
+#define _LINUXKPI_LINUX_UDP_H
+
+#include <sys/types.h>
+#include <linux/skbuff.h>
+
+/* (u) unconfirmed structure field names. */
+struct udphdr {
+ uint16_t source; /* (u) */
+ uint16_t dest;
+ uint16_t len; /* (u) */
+ uint16_t check;
+};
+
+static __inline struct udphdr *
+udp_hdr(struct sk_buff *skb)
+{
+
+ return (struct udphdr *)skb_transport_header(skb);
+}
+
+#endif /* _LINUXKPI_LINUX_UDP_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/units.h b/sys/compat/linuxkpi/common/include/linux/units.h
new file mode 100644
index 000000000000..304b5c27d87f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/units.h
@@ -0,0 +1,40 @@
+/*-
+ * 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_UNITS_H_
+#define _LINUXKPI_LINUX_UNITS_H_
+
+#define NANOHZ_PER_HZ 1000000000UL
+#define MICROHZ_PER_HZ 1000000UL
+#define MILLIHZ_PER_HZ 1000UL
+#define HZ_PER_KHZ 1000UL
+#define KHZ_PER_MHZ 1000UL
+#define HZ_PER_MHZ 1000000UL
+
+#endif /* _LINUXKPI_LINUX_UNITS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/usb.h b/sys/compat/linuxkpi/common/include/linux/usb.h
new file mode 100644
index 000000000000..d9649dcb5471
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/usb.h
@@ -0,0 +1,318 @@
+/*-
+ * Copyright (c) 2007 Luigi Rizzo - Universita` di Pisa. All rights reserved.
+ * Copyright (c) 2007 Hans Petter Selasky. All rights reserved.
+ *
+ * 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 _USB_COMPAT_LINUX_H
+#define _USB_COMPAT_LINUX_H
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/condvar.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+
+#include <linux/pm.h>
+
+struct usb_device;
+struct usb_interface;
+struct usb_driver;
+struct urb;
+
+typedef void (usb_complete_t)(struct urb *);
+
+#define USB_MAX_FULL_SPEED_ISOC_FRAMES (60 * 1)
+#define USB_MAX_HIGH_SPEED_ISOC_FRAMES (60 * 8)
+
+#define USB_DEVICE_ID_MATCH_DEVICE \
+ (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT)
+
+#define USB_DEVICE(vend,prod) \
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = (vend), \
+ .idProduct = (prod)
+
+/* The "usb_driver" structure holds the Linux USB device driver
+ * callbacks, and a pointer to device ID's which this entry should
+ * match against. Usually this entry is exposed to the USB emulation
+ * layer using the "USB_DRIVER_EXPORT()" macro, which is defined
+ * below.
+ */
+struct usb_driver {
+ const char *name;
+
+ int (*probe)(struct usb_interface *intf,
+ const struct usb_device_id *id);
+
+ void (*disconnect)(struct usb_interface *intf);
+
+ int (*ioctl)(struct usb_interface *intf, unsigned int code, void *buf);
+
+ int (*suspend)(struct usb_interface *intf, pm_message_t message);
+ int (*resume)(struct usb_interface *intf);
+
+ const struct usb_device_id *id_table;
+
+ void (*shutdown)(struct usb_interface *intf);
+
+ LIST_ENTRY(usb_driver) linux_driver_list;
+};
+
+#define USB_DRIVER_EXPORT(id,p_usb_drv) \
+ SYSINIT(id,SI_SUB_KLD,SI_ORDER_FIRST,usb_linux_register,p_usb_drv); \
+ SYSUNINIT(id,SI_SUB_KLD,SI_ORDER_ANY,usb_linux_deregister,p_usb_drv)
+
+#define USB_DT_ENDPOINT_SIZE 7
+#define USB_DT_ENDPOINT_AUDIO_SIZE 9
+
+/*
+ * Endpoints
+ */
+#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
+#define USB_ENDPOINT_DIR_MASK 0x80
+
+#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
+#define USB_ENDPOINT_XFER_CONTROL 0
+#define USB_ENDPOINT_XFER_ISOC 1
+#define USB_ENDPOINT_XFER_BULK 2
+#define USB_ENDPOINT_XFER_INT 3
+#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80
+
+/* CONTROL REQUEST SUPPORT */
+
+/*
+ * Definition of direction mask for
+ * "bEndpointAddress" and "bmRequestType":
+ */
+#define USB_DIR_MASK 0x80
+#define USB_DIR_OUT 0x00 /* write to USB device */
+#define USB_DIR_IN 0x80 /* read from USB device */
+
+/*
+ * Definition of type mask for
+ * "bmRequestType":
+ */
+#define USB_TYPE_MASK (0x03 << 5)
+#define USB_TYPE_STANDARD (0x00 << 5)
+#define USB_TYPE_CLASS (0x01 << 5)
+#define USB_TYPE_VENDOR (0x02 << 5)
+#define USB_TYPE_RESERVED (0x03 << 5)
+
+/*
+ * Definition of receiver mask for
+ * "bmRequestType":
+ */
+#define USB_RECIP_MASK 0x1f
+#define USB_RECIP_DEVICE 0x00
+#define USB_RECIP_INTERFACE 0x01
+#define USB_RECIP_ENDPOINT 0x02
+#define USB_RECIP_OTHER 0x03
+
+/*
+ * Definition of standard request values for
+ * "bRequest":
+ */
+#define USB_REQ_GET_STATUS 0x00
+#define USB_REQ_CLEAR_FEATURE 0x01
+#define USB_REQ_SET_FEATURE 0x03
+#define USB_REQ_SET_ADDRESS 0x05
+#define USB_REQ_GET_DESCRIPTOR 0x06
+#define USB_REQ_SET_DESCRIPTOR 0x07
+#define USB_REQ_GET_CONFIGURATION 0x08
+#define USB_REQ_SET_CONFIGURATION 0x09
+#define USB_REQ_GET_INTERFACE 0x0A
+#define USB_REQ_SET_INTERFACE 0x0B
+#define USB_REQ_SYNCH_FRAME 0x0C
+
+#define USB_REQ_SET_ENCRYPTION 0x0D /* Wireless USB */
+#define USB_REQ_GET_ENCRYPTION 0x0E
+#define USB_REQ_SET_HANDSHAKE 0x0F
+#define USB_REQ_GET_HANDSHAKE 0x10
+#define USB_REQ_SET_CONNECTION 0x11
+#define USB_REQ_SET_SECURITY_DATA 0x12
+#define USB_REQ_GET_SECURITY_DATA 0x13
+#define USB_REQ_SET_WUSB_DATA 0x14
+#define USB_REQ_LOOPBACK_DATA_WRITE 0x15
+#define USB_REQ_LOOPBACK_DATA_READ 0x16
+#define USB_REQ_SET_INTERFACE_DS 0x17
+
+/*
+ * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and
+ * are read as a bit array returned by USB_REQ_GET_STATUS. (So there
+ * are at most sixteen features of each type.)
+ */
+#define USB_DEVICE_SELF_POWERED 0 /* (read only) */
+#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */
+#define USB_DEVICE_TEST_MODE 2 /* (wired high speed only) */
+#define USB_DEVICE_BATTERY 2 /* (wireless) */
+#define USB_DEVICE_B_HNP_ENABLE 3 /* (otg) dev may initiate HNP */
+#define USB_DEVICE_WUSB_DEVICE 3 /* (wireless) */
+#define USB_DEVICE_A_HNP_SUPPORT 4 /* (otg) RH port supports HNP */
+#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* (otg) other RH port does */
+#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */
+
+#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */
+
+#define PIPE_ISOCHRONOUS 0x01 /* UE_ISOCHRONOUS */
+#define PIPE_INTERRUPT 0x03 /* UE_INTERRUPT */
+#define PIPE_CONTROL 0x00 /* UE_CONTROL */
+#define PIPE_BULK 0x02 /* UE_BULK */
+
+/* Whenever Linux references an USB endpoint:
+ * a) to initialize "urb->endpoint"
+ * b) second argument passed to "usb_control_msg()"
+ *
+ * Then it uses one of the following macros. The "endpoint" argument
+ * is the physical endpoint value masked by 0xF. The "dev" argument
+ * is a pointer to "struct usb_device".
+ */
+#define usb_sndctrlpipe(dev,endpoint) \
+ usb_find_host_endpoint(dev, PIPE_CONTROL, (endpoint) | USB_DIR_OUT)
+
+#define usb_rcvctrlpipe(dev,endpoint) \
+ usb_find_host_endpoint(dev, PIPE_CONTROL, (endpoint) | USB_DIR_IN)
+
+#define usb_sndisocpipe(dev,endpoint) \
+ usb_find_host_endpoint(dev, PIPE_ISOCHRONOUS, (endpoint) | USB_DIR_OUT)
+
+#define usb_rcvisocpipe(dev,endpoint) \
+ usb_find_host_endpoint(dev, PIPE_ISOCHRONOUS, (endpoint) | USB_DIR_IN)
+
+#define usb_sndbulkpipe(dev,endpoint) \
+ usb_find_host_endpoint(dev, PIPE_BULK, (endpoint) | USB_DIR_OUT)
+
+#define usb_rcvbulkpipe(dev,endpoint) \
+ usb_find_host_endpoint(dev, PIPE_BULK, (endpoint) | USB_DIR_IN)
+
+#define usb_sndintpipe(dev,endpoint) \
+ usb_find_host_endpoint(dev, PIPE_INTERRUPT, (endpoint) | USB_DIR_OUT)
+
+#define usb_rcvintpipe(dev,endpoint) \
+ usb_find_host_endpoint(dev, PIPE_INTERRUPT, (endpoint) | USB_DIR_IN)
+
+/*
+ * The following structure is used to extend "struct urb" when we are
+ * dealing with an isochronous endpoint. It contains information about
+ * the data offset and data length of an isochronous packet.
+ * The "actual_length" field is updated before the "complete"
+ * callback in the "urb" structure is called.
+ */
+struct usb_iso_packet_descriptor {
+ uint32_t offset; /* depreciated buffer offset (the
+ * packets are usually back to back) */
+ uint16_t length; /* expected length */
+ uint16_t actual_length;
+ int16_t status; /* transfer status */
+};
+
+/*
+ * The following structure holds various information about an USB
+ * transfer. This structure is used for all kinds of USB transfers.
+ *
+ * URB is short for USB Request Block.
+ */
+struct urb {
+ TAILQ_ENTRY(urb) bsd_urb_list;
+ struct cv cv_wait;
+
+ struct usb_device *dev; /* (in) pointer to associated device */
+ struct usb_host_endpoint *endpoint; /* (in) pipe pointer */
+ uint8_t *setup_packet; /* (in) setup packet (control only) */
+ uint8_t *bsd_data_ptr;
+ void *transfer_buffer; /* (in) associated data buffer */
+ void *context; /* (in) context for completion */
+ usb_complete_t *complete; /* (in) completion routine */
+
+ usb_size_t transfer_buffer_length;/* (in) data buffer length */
+ usb_size_t bsd_length_rem;
+ usb_size_t actual_length; /* (return) actual transfer length */
+ usb_timeout_t timeout; /* FreeBSD specific */
+
+ uint16_t transfer_flags; /* (in) */
+#define URB_SHORT_NOT_OK 0x0001 /* report short transfers like errors */
+#define URB_ISO_ASAP 0x0002 /* ignore "start_frame" field */
+#define URB_ZERO_PACKET 0x0004 /* the USB transfer ends with a short
+ * packet */
+#define URB_NO_TRANSFER_DMA_MAP 0x0008 /* "transfer_dma" is valid on submit */
+#define URB_WAIT_WAKEUP 0x0010 /* custom flags */
+#define URB_IS_SLEEPING 0x0020 /* custom flags */
+
+ usb_frcount_t start_frame; /* (modify) start frame (ISO) */
+ usb_frcount_t number_of_packets; /* (in) number of ISO packets */
+ uint16_t interval; /* (modify) transfer interval
+ * (INT/ISO) */
+ uint16_t error_count; /* (return) number of ISO errors */
+ int16_t status; /* (return) status */
+
+ uint8_t setup_dma; /* (in) not used on FreeBSD */
+ uint8_t transfer_dma; /* (in) not used on FreeBSD */
+ uint8_t bsd_isread;
+ uint8_t kill_count; /* FreeBSD specific */
+
+ struct usb_iso_packet_descriptor iso_frame_desc[]; /* (in) ISO ONLY */
+};
+
+/* various prototypes */
+
+int usb_submit_urb(struct urb *urb, uint16_t mem_flags);
+int usb_unlink_urb(struct urb *urb);
+int usb_clear_halt(struct usb_device *dev, struct usb_host_endpoint *uhe);
+int usb_control_msg(struct usb_device *dev, struct usb_host_endpoint *ep,
+ uint8_t request, uint8_t requesttype, uint16_t value,
+ uint16_t index, void *data, uint16_t size, usb_timeout_t timeout);
+int usb_set_interface(struct usb_device *dev, uint8_t ifnum,
+ uint8_t alternate);
+int usb_setup_endpoint(struct usb_device *dev,
+ struct usb_host_endpoint *uhe, usb_frlength_t bufsize);
+
+struct usb_host_endpoint *usb_find_host_endpoint(struct usb_device *dev,
+ uint8_t type, uint8_t ep);
+struct urb *usb_alloc_urb(uint16_t iso_packets, uint16_t mem_flags);
+struct usb_host_interface *usb_altnum_to_altsetting(
+ const struct usb_interface *intf, uint8_t alt_index);
+struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, uint8_t iface_no);
+
+void *usb_buffer_alloc(struct usb_device *dev, usb_size_t size,
+ uint16_t mem_flags, uint8_t *dma_addr);
+void *usbd_get_intfdata(struct usb_interface *intf);
+
+void usb_buffer_free(struct usb_device *dev, usb_size_t size, void *addr, uint8_t dma_addr);
+void usb_free_urb(struct urb *urb);
+void usb_init_urb(struct urb *urb);
+void usb_kill_urb(struct urb *urb);
+void usb_set_intfdata(struct usb_interface *intf, void *data);
+void usb_linux_register(void *arg);
+void usb_linux_deregister(void *arg);
+
+void usb_fill_bulk_urb(struct urb *, struct usb_device *,
+ struct usb_host_endpoint *, void *, int, usb_complete_t, void *);
+int usb_bulk_msg(struct usb_device *, struct usb_host_endpoint *,
+ void *, int, uint16_t *, usb_timeout_t);
+
+#define interface_to_usbdev(intf) (intf)->linux_udev
+#define interface_to_bsddev(intf) (intf)->linux_udev
+
+#endif /* _USB_COMPAT_LINUX_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/utsname.h b/sys/compat/linuxkpi/common/include/linux/utsname.h
new file mode 100644
index 000000000000..3239801ca17b
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/utsname.h
@@ -0,0 +1,51 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Bjoern A. Zeeb
+ *
+ * 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_UTSNAME_H
+#define _LINUXKPI_LINUX_UTSNAME_H
+
+#include <sys/types.h>
+#include <sys/jail.h>
+
+struct _utsname {
+ char release[OSRELEASELEN];
+};
+
+struct uts_namespace {
+ struct _utsname name;
+};
+
+extern struct uts_namespace init_uts_ns;
+
+static inline struct _utsname *
+init_utsname(void)
+{
+
+ return &init_uts_ns.name;
+}
+
+#endif /* _LINUXKPI_LINUX_UTSNAME_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/uuid.h b/sys/compat/linuxkpi/common/include/linux/uuid.h
new file mode 100644
index 000000000000..4f6f4a8b34f0
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/uuid.h
@@ -0,0 +1,77 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021,2023 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb 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_UUID_H
+#define _LINUXKPI_LINUX_UUID_H
+
+#include <linux/random.h>
+
+#define UUID_STRING_LEN 36
+
+#define GUID_INIT(x0_3, x4_5, x6_7, x8, x9, x10, x11, x12, x13, x14, x15) \
+ ((guid_t) { .x = { \
+ [0] = (x0_3) & 0xff, \
+ [1] = ((x0_3) >> 8) & 0xff, \
+ [2] = ((x0_3) >> 16) & 0xff, \
+ [3] = ((x0_3) >> 24) & 0xff, \
+ [4] = (x4_5) & 0xff, \
+ [5] = ((x4_5) >> 8) & 0xff, \
+ [6] = (x6_7) & 0xff, \
+ [7] = ((x6_7) >> 8) & 0xff, \
+ [8] = (x8), \
+ [9] = (x9), \
+ [10] = (x10), \
+ [11] = (x11), \
+ [12] = (x12), \
+ [13] = (x13), \
+ [14] = (x14), \
+ [15] = (x15) \
+}})
+
+typedef struct {
+ char x[16];
+} guid_t;
+
+static inline void
+guid_gen(guid_t *g)
+{
+
+ get_random_bytes(g, 16);
+ g->x[7] = (g->x[7] & 0x0f) | 0x40;
+ g->x[8] = (g->x[8] & 0x3f) | 0x80;
+}
+
+static inline void
+guid_copy(guid_t *dst, const guid_t *src)
+{
+ memcpy(dst, src, sizeof(*dst));
+}
+
+#endif /* _LINUXKPI_LINUX_UUID_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/vgaarb.h b/sys/compat/linuxkpi/common/include/linux/vgaarb.h
new file mode 100644
index 000000000000..d43a88136864
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/vgaarb.h
@@ -0,0 +1,281 @@
+/*
+ * The VGA aribiter manages VGA space routing and VGA resource decode to
+ * allow multiple VGA devices to be used in a system in a safe way.
+ *
+ * (C) Copyright 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ * (C) Copyright 2007 Paulo R. Zanoni <przanoni@gmail.com>
+ * (C) Copyright 2007, 2009 Tiago Vignatti <vignatti@freedesktop.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _LINUXKPI_LINUX_VGA_H_
+#define _LINUXKPI_LINUX_VGA_H_
+
+#include <video/vga.h>
+
+/* Legacy VGA regions */
+#define VGA_RSRC_NONE 0x00
+#define VGA_RSRC_LEGACY_IO 0x01
+#define VGA_RSRC_LEGACY_MEM 0x02
+#define VGA_RSRC_LEGACY_MASK (VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM)
+/* Non-legacy access */
+#define VGA_RSRC_NORMAL_IO 0x04
+#define VGA_RSRC_NORMAL_MEM 0x08
+
+/* Passing that instead of a pci_dev to use the system "default"
+ * device, that is the one used by vgacon. Archs will probably
+ * have to provide their own vga_default_device();
+ */
+#define VGA_DEFAULT_DEVICE (NULL)
+
+struct pci_dev;
+
+/* For use by clients */
+
+/**
+ * vga_set_legacy_decoding
+ *
+ * @pdev: pci device of the VGA card
+ * @decodes: bit mask of what legacy regions the card decodes
+ *
+ * Indicates to the arbiter if the card decodes legacy VGA IOs,
+ * legacy VGA Memory, both, or none. All cards default to both,
+ * the card driver (fbdev for example) should tell the arbiter
+ * if it has disabled legacy decoding, so the card can be left
+ * out of the arbitration process (and can be safe to take
+ * interrupts at any time.
+ */
+#if defined(CONFIG_VGA_ARB)
+extern void vga_set_legacy_decoding(struct pci_dev *pdev,
+ unsigned int decodes);
+#else
+static inline void vga_set_legacy_decoding(struct pci_dev *pdev,
+ unsigned int decodes) { };
+#endif
+
+/**
+ * vga_get - acquire & locks VGA resources
+ *
+ * @pdev: pci device of the VGA card or NULL for the system default
+ * @rsrc: bit mask of resources to acquire and lock
+ * @interruptible: blocking should be interruptible by signals ?
+ *
+ * This function acquires VGA resources for the given
+ * card and mark those resources locked. If the resource requested
+ * are "normal" (and not legacy) resources, the arbiter will first check
+ * whether the card is doing legacy decoding for that type of resource. If
+ * yes, the lock is "converted" into a legacy resource lock.
+ * The arbiter will first look for all VGA cards that might conflict
+ * and disable their IOs and/or Memory access, including VGA forwarding
+ * on P2P bridges if necessary, so that the requested resources can
+ * be used. Then, the card is marked as locking these resources and
+ * the IO and/or Memory accesse are enabled on the card (including
+ * VGA forwarding on parent P2P bridges if any).
+ * This function will block if some conflicting card is already locking
+ * one of the required resources (or any resource on a different bus
+ * segment, since P2P bridges don't differenciate VGA memory and IO
+ * afaik). You can indicate whether this blocking should be interruptible
+ * by a signal (for userland interface) or not.
+ * Must not be called at interrupt time or in atomic context.
+ * If the card already owns the resources, the function succeeds.
+ * Nested calls are supported (a per-resource counter is maintained)
+ */
+
+#if defined(CONFIG_VGA_ARB)
+extern int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible);
+#else
+static inline int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible) { return 0; }
+#endif
+
+/**
+ * vga_get_interruptible
+ *
+ * Shortcut to vga_get
+ */
+
+static inline int vga_get_interruptible(struct pci_dev *pdev,
+ unsigned int rsrc)
+{
+ return vga_get(pdev, rsrc, 1);
+}
+
+/**
+ * vga_get_uninterruptible
+ *
+ * Shortcut to vga_get
+ */
+
+static inline int vga_get_uninterruptible(struct pci_dev *pdev,
+ unsigned int rsrc)
+{
+ return vga_get(pdev, rsrc, 0);
+}
+
+/**
+ * vga_tryget - try to acquire & lock legacy VGA resources
+ *
+ * @pdev: pci devivce of VGA card or NULL for system default
+ * @rsrc: bit mask of resources to acquire and lock
+ *
+ * This function performs the same operation as vga_get(), but
+ * will return an error (-EBUSY) instead of blocking if the resources
+ * are already locked by another card. It can be called in any context
+ */
+
+#if defined(CONFIG_VGA_ARB)
+extern int vga_tryget(struct pci_dev *pdev, unsigned int rsrc);
+#else
+static inline int vga_tryget(struct pci_dev *pdev, unsigned int rsrc) { return 0; }
+#endif
+
+/**
+ * vga_put - release lock on legacy VGA resources
+ *
+ * @pdev: pci device of VGA card or NULL for system default
+ * @rsrc: but mask of resource to release
+ *
+ * This function releases resources previously locked by vga_get()
+ * or vga_tryget(). The resources aren't disabled right away, so
+ * that a subsequence vga_get() on the same card will succeed
+ * immediately. Resources have a counter, so locks are only
+ * released if the counter reaches 0.
+ */
+
+#if defined(CONFIG_VGA_ARB)
+extern void vga_put(struct pci_dev *pdev, unsigned int rsrc);
+#else
+#define vga_put(pdev, rsrc)
+#endif
+
+
+/**
+ * vga_default_device
+ *
+ * This can be defined by the platform. The default implementation
+ * is rather dumb and will probably only work properly on single
+ * vga card setups and/or x86 platforms.
+ *
+ * If your VGA default device is not PCI, you'll have to return
+ * NULL here. In this case, I assume it will not conflict with
+ * any PCI card. If this is not true, I'll have to define two archs
+ * hooks for enabling/disabling the VGA default device if that is
+ * possible. This may be a problem with real _ISA_ VGA cards, in
+ * addition to a PCI one. I don't know at this point how to deal
+ * with that card. Can theirs IOs be disabled at all ? If not, then
+ * I suppose it's a matter of having the proper arch hook telling
+ * us about it, so we basically never allow anybody to succeed a
+ * vga_get()...
+ */
+
+#ifdef CONFIG_VGA_ARB
+extern struct pci_dev *vga_default_device(void);
+extern void vga_set_default_device(struct pci_dev *pdev);
+#else
+static inline struct pci_dev *vga_default_device(void) { return NULL; };
+static inline void vga_set_default_device(struct pci_dev *pdev) { };
+#endif
+
+/**
+ * vga_conflicts
+ *
+ * Architectures should define this if they have several
+ * independent PCI domains that can afford concurrent VGA
+ * decoding
+ */
+
+#ifndef __ARCH_HAS_VGA_CONFLICT
+static inline int vga_conflicts(struct pci_dev *p1, struct pci_dev *p2)
+{
+ return 1;
+}
+#endif
+
+/**
+ * vga_client_register
+ *
+ * @pdev: pci device of the VGA client
+ * @cookie: client cookie to be used in callbacks
+ * @irq_set_state: irq state change callback
+ * @set_vga_decode: vga decode change callback
+ *
+ * return value: 0 on success, -1 on failure
+ * Register a client with the VGA arbitration logic
+ *
+ * Clients have two callback mechanisms they can use.
+ * irq enable/disable callback -
+ * If a client can't disable its GPUs VGA resources, then we
+ * need to be able to ask it to turn off its irqs when we
+ * turn off its mem and io decoding.
+ * set_vga_decode
+ * If a client can disable its GPU VGA resource, it will
+ * get a callback from this to set the encode/decode state
+ *
+ * Rationale: we cannot disable VGA decode resources unconditionally
+ * some single GPU laptops seem to require ACPI or BIOS access to the
+ * VGA registers to control things like backlights etc.
+ * Hopefully newer multi-GPU laptops do something saner, and desktops
+ * won't have any special ACPI for this.
+ * They driver will get a callback when VGA arbitration is first used
+ * by userspace since we some older X servers have issues.
+ */
+#if defined(CONFIG_VGA_ARB)
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51501
+int vga_client_register(struct pci_dev *pdev,
+ unsigned int (*set_vga_decode)(struct pci_dev *pdev, bool state));
+#elif defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51500
+int vga_client_register(struct pci_dev *pdev, void *cookie,
+ unsigned int (*set_vga_decode)(void *cookie, bool state));
+#else
+int vga_client_register(struct pci_dev *pdev, void *cookie,
+ void (*irq_set_state)(void *cookie, bool state),
+ unsigned int (*set_vga_decode)(void *cookie, bool state));
+#endif
+#else
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51501
+static inline int vga_client_register(struct pci_dev *pdev,
+ unsigned int (*set_vga_decode)(struct pci_dev *pdev, bool state))
+#elif defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51500
+static inline int vga_client_register(struct pci_dev *pdev, void *cookie,
+ unsigned int (*set_vga_decode)(void *cookie, bool state))
+#else
+static inline int vga_client_register(struct pci_dev *pdev, void *cookie,
+ void (*irq_set_state)(void *cookie, bool state),
+ unsigned int (*set_vga_decode)(void *cookie, bool state))
+#endif
+{
+ return 0;
+}
+
+static inline int vga_client_unregister(struct pci_dev *pdev)
+{
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51501
+ return (vga_client_register(NULL, NULL));
+#elif defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51500
+ return (vga_client_register(NULL, NULL, NULL));
+#else
+ return (vga_client_register(NULL, NULL, NULL, NULL));
+#endif
+}
+#endif
+
+#endif /* _LINUXKPI_LINUX_VGA_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/vmalloc.h b/sys/compat/linuxkpi/common/include/linux/vmalloc.h
new file mode 100644
index 000000000000..00650a2df9b6
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/vmalloc.h
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_VMALLOC_H_
+#define _LINUXKPI_LINUX_VMALLOC_H_
+
+#include <linux/overflow.h>
+#include <linux/page.h>
+
+#define VM_MAP 0x0000
+#define PAGE_KERNEL 0x0000
+
+void *vmap(struct page **pages, unsigned int count, unsigned long flags,
+ int prot);
+void vunmap(void *addr);
+
+#endif /* _LINUXKPI_LINUX_VMALLOC_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/wait.h b/sys/compat/linuxkpi/common/include/linux/wait.h
new file mode 100644
index 000000000000..03ddce2c06f5
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/wait.h
@@ -0,0 +1,319 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
+ * Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_WAIT_H_
+#define _LINUXKPI_LINUX_WAIT_H_
+
+#include <linux/compiler.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+
+#include <asm/atomic.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#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;
+
+#define wait_queue_entry wait_queue
+
+typedef struct wait_queue wait_queue_t;
+typedef struct wait_queue_entry wait_queue_entry_t;
+typedef struct wait_queue_head wait_queue_head_t;
+
+typedef int wait_queue_func_t(wait_queue_t *, unsigned int, int, void *);
+
+#define WQ_FLAG_WOKEN 0x02
+
+/*
+ * Many API consumers directly reference these fields and those of
+ * wait_queue_head.
+ */
+struct wait_queue {
+ unsigned int flags;
+ void *private;
+ wait_queue_func_t *func;
+ union {
+ struct list_head task_list; /* < v4.13 */
+ struct list_head entry; /* >= v4.13 */
+ };
+};
+
+struct wait_queue_head {
+ spinlock_t lock;
+ union {
+ struct list_head task_list; /* < v4.13 */
+ struct list_head head; /* >= v4.13 */
+ };
+};
+
+/*
+ * This function is referenced by at least one DRM driver, so it may not be
+ * renamed and furthermore must be the default wait queue callback.
+ */
+wait_queue_func_t autoremove_wake_function;
+wait_queue_func_t default_wake_function;
+wait_queue_func_t woken_wake_function;
+
+long linux_wait_woken(wait_queue_t *wq, unsigned state, long timeout);
+
+#define wait_woken(wq, state, timeout) \
+ linux_wait_woken((wq), (state), (timeout))
+
+#define DEFINE_WAIT_FUNC(name, function) \
+ wait_queue_t name = { \
+ .private = current, \
+ .func = function, \
+ .task_list = LINUX_LIST_HEAD_INIT(name.task_list) \
+ }
+
+#define DEFINE_WAIT(name) \
+ DEFINE_WAIT_FUNC(name, autoremove_wake_function)
+
+#define DECLARE_WAITQUEUE(name, task) \
+ wait_queue_t name = { \
+ .private = task, \
+ .task_list = LINUX_LIST_HEAD_INIT(name.task_list) \
+ }
+
+#define DECLARE_WAIT_QUEUE_HEAD(name) \
+ wait_queue_head_t name = { \
+ .task_list = LINUX_LIST_HEAD_INIT(name.task_list), \
+ }; \
+ MTX_SYSINIT(name, &(name).lock, spin_lock_name("wqhead"), MTX_DEF)
+
+#define init_waitqueue_head(wqh) do { \
+ mtx_init(&(wqh)->lock, spin_lock_name("wqhead"), \
+ NULL, MTX_DEF | MTX_NEW | MTX_NOWITNESS); \
+ INIT_LIST_HEAD(&(wqh)->task_list); \
+} while (0)
+
+#define __init_waitqueue_head(wqh, name, lk) init_waitqueue_head(wqh)
+
+void linux_init_wait_entry(wait_queue_t *, int);
+void linux_wake_up(wait_queue_head_t *, unsigned int, int, bool);
+
+#define init_wait_entry(wq, flags) \
+ linux_init_wait_entry(wq, flags)
+#define wake_up(wqh) \
+ linux_wake_up(wqh, TASK_NORMAL, 1, false)
+#define wake_up_all(wqh) \
+ linux_wake_up(wqh, TASK_NORMAL, 0, false)
+#define wake_up_locked(wqh) \
+ linux_wake_up(wqh, TASK_NORMAL, 1, true)
+#define wake_up_all_locked(wqh) \
+ linux_wake_up(wqh, TASK_NORMAL, 0, true)
+#define wake_up_interruptible(wqh) \
+ linux_wake_up(wqh, TASK_INTERRUPTIBLE, 1, false)
+#define wake_up_interruptible_all(wqh) \
+ linux_wake_up(wqh, TASK_INTERRUPTIBLE, 0, false)
+
+int linux_wait_event_common(wait_queue_head_t *, wait_queue_t *, long,
+ unsigned int, spinlock_t *);
+
+/*
+ * Returns -ERESTARTSYS for a signal, 0 if cond is false after timeout, 1 if
+ * cond is true after timeout, remaining jiffies (> 0) if cond is true before
+ * timeout.
+ */
+#define __wait_event_common(wqh, cond, timeout, state, lock) ({ \
+ DEFINE_WAIT(__wq); \
+ const long __timeout = ((long)(timeout)) < 1 ? 1 : (timeout); \
+ long __start = jiffies; \
+ long __ret = 0; \
+ \
+ for (;;) { \
+ linux_prepare_to_wait(&(wqh), &__wq, state); \
+ if (cond) \
+ break; \
+ __ret = linux_wait_event_common(&(wqh), &__wq, \
+ __timeout, state, lock); \
+ if (__ret != 0) \
+ break; \
+ } \
+ linux_finish_wait(&(wqh), &__wq); \
+ if (__timeout != MAX_SCHEDULE_TIMEOUT) { \
+ if (__ret == -EWOULDBLOCK) \
+ __ret = !!(cond); \
+ else if (__ret != -ERESTARTSYS) { \
+ __ret = __timeout + __start - jiffies; \
+ /* range check return value */ \
+ if (__ret < 1) \
+ __ret = 1; \
+ else if (__ret > __timeout) \
+ __ret = __timeout; \
+ } \
+ } \
+ __ret; \
+})
+
+#define wait_event(wqh, cond) do { \
+ (void) __wait_event_common(wqh, cond, MAX_SCHEDULE_TIMEOUT, \
+ TASK_UNINTERRUPTIBLE, NULL); \
+} while (0)
+
+#define wait_event_timeout(wqh, cond, timeout) ({ \
+ __wait_event_common(wqh, cond, timeout, TASK_UNINTERRUPTIBLE, \
+ NULL); \
+})
+
+#define wait_event_killable(wqh, cond) ({ \
+ __wait_event_common(wqh, cond, MAX_SCHEDULE_TIMEOUT, \
+ TASK_INTERRUPTIBLE, NULL); \
+})
+
+#define wait_event_interruptible(wqh, cond) ({ \
+ __wait_event_common(wqh, cond, MAX_SCHEDULE_TIMEOUT, \
+ TASK_INTERRUPTIBLE, NULL); \
+})
+
+#define wait_event_interruptible_timeout(wqh, cond, timeout) ({ \
+ __wait_event_common(wqh, cond, timeout, TASK_INTERRUPTIBLE, \
+ NULL); \
+})
+
+/*
+ * Wait queue is already locked.
+ */
+#define wait_event_interruptible_locked(wqh, cond) ({ \
+ int __ret; \
+ \
+ spin_unlock(&(wqh).lock); \
+ __ret = __wait_event_common(wqh, cond, MAX_SCHEDULE_TIMEOUT, \
+ TASK_INTERRUPTIBLE, NULL); \
+ spin_lock(&(wqh).lock); \
+ __ret; \
+})
+
+/*
+ * The passed spinlock is held when testing the condition.
+ */
+#define wait_event_interruptible_lock_irq(wqh, cond, lock) ({ \
+ __wait_event_common(wqh, cond, MAX_SCHEDULE_TIMEOUT, \
+ TASK_INTERRUPTIBLE, &(lock)); \
+})
+
+/*
+ * The passed spinlock is held when testing the condition.
+ */
+#define wait_event_lock_irq(wqh, cond, lock) ({ \
+ __wait_event_common(wqh, cond, MAX_SCHEDULE_TIMEOUT, \
+ TASK_UNINTERRUPTIBLE, &(lock)); \
+})
+
+static inline void
+__add_wait_queue(wait_queue_head_t *wqh, wait_queue_t *wq)
+{
+ list_add(&wq->task_list, &wqh->task_list);
+}
+
+static inline void
+add_wait_queue(wait_queue_head_t *wqh, wait_queue_t *wq)
+{
+
+ spin_lock(&wqh->lock);
+ __add_wait_queue(wqh, wq);
+ spin_unlock(&wqh->lock);
+}
+
+static inline void
+__add_wait_queue_tail(wait_queue_head_t *wqh, wait_queue_t *wq)
+{
+ list_add_tail(&wq->task_list, &wqh->task_list);
+}
+
+static inline void
+__add_wait_queue_entry_tail(wait_queue_head_t *wqh, wait_queue_entry_t *wq)
+{
+ list_add_tail(&wq->entry, &wqh->head);
+}
+
+static inline void
+__remove_wait_queue(wait_queue_head_t *wqh, wait_queue_t *wq)
+{
+ list_del(&wq->task_list);
+}
+
+static inline void
+remove_wait_queue(wait_queue_head_t *wqh, wait_queue_t *wq)
+{
+
+ spin_lock(&wqh->lock);
+ __remove_wait_queue(wqh, wq);
+ spin_unlock(&wqh->lock);
+}
+
+bool linux_waitqueue_active(wait_queue_head_t *);
+
+#define waitqueue_active(wqh) linux_waitqueue_active(wqh)
+
+void linux_prepare_to_wait(wait_queue_head_t *, wait_queue_t *, int);
+void linux_finish_wait(wait_queue_head_t *, wait_queue_t *);
+
+#define prepare_to_wait(wqh, wq, state) linux_prepare_to_wait(wqh, wq, state)
+#define finish_wait(wqh, wq) linux_finish_wait(wqh, wq)
+
+void linux_wake_up_bit(void *, int);
+int linux_wait_on_bit_timeout(unsigned long *, int, unsigned int, long);
+void linux_wake_up_atomic_t(atomic_t *);
+int linux_wait_on_atomic_t(atomic_t *, unsigned int);
+
+#define wake_up_bit(word, bit) linux_wake_up_bit(word, bit)
+#define wait_on_bit(word, bit, state) \
+ linux_wait_on_bit_timeout(word, bit, state, MAX_SCHEDULE_TIMEOUT)
+#define wait_on_bit_timeout(word, bit, state, timeout) \
+ linux_wait_on_bit_timeout(word, bit, state, timeout)
+#define wake_up_atomic_t(a) linux_wake_up_atomic_t(a)
+/*
+ * All existing callers have a cb that just schedule()s. To avoid adding
+ * complexity, just emulate that internally. The prototype is different so that
+ * callers must be manually modified; a cb that does something other than call
+ * schedule() will require special treatment.
+ */
+#define wait_on_atomic_t(a, state) linux_wait_on_atomic_t(a, state)
+
+struct task_struct;
+bool linux_wake_up_state(struct task_struct *, unsigned int);
+
+#define wake_up_process(task) linux_wake_up_state(task, TASK_NORMAL)
+#define wake_up_state(task, state) linux_wake_up_state(task, state)
+
+#endif /* _LINUXKPI_LINUX_WAIT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/wait_bit.h b/sys/compat/linuxkpi/common/include/linux/wait_bit.h
new file mode 100644
index 000000000000..573798590b73
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/wait_bit.h
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Emmanuel Vadot 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_WAITBIT_H__
+#define __LINUXKPI_LINUX_WAITBIT_H__
+
+#include <linux/wait.h>
+#include <linux/bitops.h>
+
+extern wait_queue_head_t linux_bit_waitq;
+extern wait_queue_head_t linux_var_waitq;
+
+#define wait_var_event_killable(var, cond) \
+ wait_event_killable(linux_var_waitq, cond)
+
+#define wait_var_event_interruptible(var, cond) \
+ wait_event_interruptible(linux_var_waitq, cond)
+
+static inline void
+clear_and_wake_up_bit(int bit, void *word)
+{
+ clear_bit_unlock(bit, word);
+ wake_up_bit(word, bit);
+}
+
+static inline wait_queue_head_t *
+bit_waitqueue(void *word, int bit)
+{
+
+ return (&linux_bit_waitq);
+}
+
+static inline void
+wake_up_var(void *var)
+{
+
+ wake_up(&linux_var_waitq);
+}
+
+static inline wait_queue_head_t *
+__var_waitqueue(void *p)
+{
+ return (&linux_var_waitq);
+}
+
+#endif /* __LINUXKPI_LINUX_WAITBIT_H__ */
diff --git a/sys/compat/linuxkpi/common/include/linux/workqueue.h b/sys/compat/linuxkpi/common/include/linux/workqueue.h
new file mode 100644
index 000000000000..66d3981d4229
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/workqueue.h
@@ -0,0 +1,267 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_WORKQUEUE_H_
+#define _LINUXKPI_LINUX_WORKQUEUE_H_
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+
+#include <asm/atomic.h>
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/taskqueue.h>
+#include <sys/mutex.h>
+
+#define WORK_CPU_UNBOUND MAXCPU
+#define WQ_UNBOUND (1 << 0)
+#define WQ_HIGHPRI (1 << 1)
+
+struct work_struct;
+typedef void (*work_func_t)(struct work_struct *);
+
+struct work_exec {
+ TAILQ_ENTRY(work_exec) entry;
+ struct work_struct *target;
+};
+
+struct workqueue_struct {
+ struct taskqueue *taskqueue;
+ struct mtx exec_mtx;
+ TAILQ_HEAD(, work_exec) exec_head;
+ atomic_t draining;
+};
+
+#define WQ_EXEC_LOCK(wq) mtx_lock(&(wq)->exec_mtx)
+#define WQ_EXEC_UNLOCK(wq) mtx_unlock(&(wq)->exec_mtx)
+
+struct work_struct {
+ struct task work_task;
+ struct workqueue_struct *work_queue;
+ work_func_t func;
+ atomic_t state;
+};
+
+struct rcu_work {
+ struct work_struct work;
+ struct rcu_head rcu;
+
+ struct workqueue_struct *wq;
+};
+
+#define DECLARE_WORK(name, fn) \
+ struct work_struct name; \
+ static void name##_init(void *arg) \
+ { \
+ INIT_WORK(&name, fn); \
+ } \
+ SYSINIT(name, SI_SUB_LOCK, SI_ORDER_SECOND, name##_init, NULL)
+
+struct delayed_work {
+ struct work_struct work;
+ struct {
+ struct callout callout;
+ struct mtx mtx;
+ unsigned long expires;
+ } timer;
+};
+
+#define DECLARE_DELAYED_WORK(name, fn) \
+ struct delayed_work name; \
+ static void __linux_delayed_ ## name ## _init(void *arg) \
+ { \
+ linux_init_delayed_work(&name, fn); \
+ } \
+ SYSINIT(name, SI_SUB_LOCK, SI_ORDER_SECOND, \
+ __linux_delayed_ ## name##_init, NULL)
+
+static inline struct delayed_work *
+to_delayed_work(struct work_struct *work)
+{
+ return (container_of(work, struct delayed_work, work));
+}
+
+#define INIT_WORK(work, fn) \
+do { \
+ (work)->func = (fn); \
+ (work)->work_queue = NULL; \
+ atomic_set(&(work)->state, 0); \
+ TASK_INIT(&(work)->work_task, 0, linux_work_fn, (work)); \
+} while (0)
+
+#define INIT_RCU_WORK(_work, _fn) \
+ INIT_WORK(&(_work)->work, (_fn))
+
+#define INIT_WORK_ONSTACK(work, fn) \
+ INIT_WORK(work, fn)
+
+#define INIT_DELAYED_WORK(dwork, fn) \
+ linux_init_delayed_work(dwork, fn)
+
+#define INIT_DELAYED_WORK_ONSTACK(dwork, fn) \
+ linux_init_delayed_work(dwork, fn)
+
+#define INIT_DEFERRABLE_WORK(dwork, fn) \
+ INIT_DELAYED_WORK(dwork, fn)
+
+#define flush_scheduled_work() \
+ taskqueue_drain_all(system_wq->taskqueue)
+
+#define queue_work(wq, work) \
+ linux_queue_work_on(WORK_CPU_UNBOUND, wq, work)
+
+#define schedule_work(work) \
+ linux_queue_work_on(WORK_CPU_UNBOUND, system_wq, work)
+
+#define queue_delayed_work(wq, dwork, delay) \
+ linux_queue_delayed_work_on(WORK_CPU_UNBOUND, wq, dwork, delay)
+
+#define schedule_delayed_work_on(cpu, dwork, delay) \
+ linux_queue_delayed_work_on(cpu, system_wq, dwork, delay)
+
+#define queue_work_on(cpu, wq, work) \
+ linux_queue_work_on(cpu, wq, work)
+
+#define schedule_delayed_work(dwork, delay) \
+ linux_queue_delayed_work_on(WORK_CPU_UNBOUND, system_wq, dwork, delay)
+
+#define queue_delayed_work_on(cpu, wq, dwork, delay) \
+ linux_queue_delayed_work_on(cpu, wq, dwork, delay)
+
+#define create_singlethread_workqueue(name) \
+ linux_create_workqueue_common(name, 1)
+
+#define create_workqueue(name) \
+ linux_create_workqueue_common(name, mp_ncpus)
+
+#define alloc_ordered_workqueue(name, flags) \
+ linux_create_workqueue_common(name, 1)
+
+#define alloc_workqueue(name, flags, max_active) \
+ linux_create_workqueue_common(name, max_active)
+
+#define flush_workqueue(wq) \
+ taskqueue_drain_all((wq)->taskqueue)
+
+#define drain_workqueue(wq) do { \
+ atomic_inc(&(wq)->draining); \
+ taskqueue_drain_all((wq)->taskqueue); \
+ atomic_dec(&(wq)->draining); \
+} while (0)
+
+#define mod_delayed_work(wq, dwork, delay) ({ \
+ bool __retval; \
+ __retval = linux_cancel_delayed_work(dwork); \
+ linux_queue_delayed_work_on(WORK_CPU_UNBOUND, \
+ wq, dwork, delay); \
+ __retval; \
+})
+
+#define delayed_work_pending(dwork) \
+ linux_work_pending(&(dwork)->work)
+
+#define cancel_work(work) \
+ linux_cancel_work(work)
+
+#define cancel_delayed_work(dwork) \
+ linux_cancel_delayed_work(dwork)
+
+#define cancel_work_sync(work) \
+ linux_cancel_work_sync(work)
+
+#define cancel_delayed_work_sync(dwork) \
+ linux_cancel_delayed_work_sync(dwork)
+
+#define flush_work(work) \
+ linux_flush_work(work)
+
+#define queue_rcu_work(wq, rwork) \
+ linux_queue_rcu_work(wq, rwork)
+
+#define flush_rcu_work(rwork) \
+ linux_flush_rcu_work(rwork)
+
+#define flush_delayed_work(dwork) \
+ linux_flush_delayed_work(dwork)
+
+#define work_pending(work) \
+ linux_work_pending(work)
+
+#define work_busy(work) \
+ linux_work_busy(work)
+
+#define destroy_work_on_stack(work) \
+ do { } while (0)
+
+#define destroy_delayed_work_on_stack(dwork) \
+ do { } while (0)
+
+#define destroy_workqueue(wq) \
+ linux_destroy_workqueue(wq)
+
+#define current_work() \
+ linux_current_work()
+
+/* prototypes */
+
+extern struct workqueue_struct *system_wq;
+extern struct workqueue_struct *system_long_wq;
+extern struct workqueue_struct *system_unbound_wq;
+extern struct workqueue_struct *system_highpri_wq;
+extern struct workqueue_struct *system_power_efficient_wq;
+
+extern void linux_init_delayed_work(struct delayed_work *, work_func_t);
+extern void linux_work_fn(void *, int);
+extern void linux_delayed_work_fn(void *, int);
+extern struct workqueue_struct *linux_create_workqueue_common(const char *, int);
+extern void linux_destroy_workqueue(struct workqueue_struct *);
+extern bool linux_queue_work_on(int cpu, struct workqueue_struct *, struct work_struct *);
+extern bool linux_queue_delayed_work_on(int cpu, struct workqueue_struct *,
+ struct delayed_work *, unsigned long delay);
+extern bool linux_cancel_work(struct work_struct *);
+extern bool linux_cancel_delayed_work(struct delayed_work *);
+extern bool linux_cancel_work_sync(struct work_struct *);
+extern bool linux_cancel_delayed_work_sync(struct delayed_work *);
+extern bool linux_flush_work(struct work_struct *);
+extern bool linux_flush_delayed_work(struct delayed_work *);
+extern bool linux_work_pending(struct work_struct *);
+extern bool linux_work_busy(struct work_struct *);
+extern struct work_struct *linux_current_work(void);
+extern bool linux_queue_rcu_work(struct workqueue_struct *wq, struct rcu_work *rwork);
+extern bool linux_flush_rcu_work(struct rcu_work *rwork);
+
+static inline bool
+queue_work_node(int node __unused, struct workqueue_struct *wq, struct work_struct *work)
+{
+ return (queue_work(wq, work));
+}
+
+#endif /* _LINUXKPI_LINUX_WORKQUEUE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/ww_mutex.h b/sys/compat/linuxkpi/common/include/linux/ww_mutex.h
new file mode 100644
index 000000000000..9219755bb78e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/ww_mutex.h
@@ -0,0 +1,149 @@
+/*-
+ * Copyright (c) 2017 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_WW_MUTEX_H_
+#define _LINUXKPI_LINUX_WW_MUTEX_H_
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/condvar.h>
+#include <sys/kernel.h>
+
+#include <linux/mutex.h>
+
+struct ww_class {
+ const char *mutex_name;
+};
+
+struct ww_acquire_ctx {
+};
+
+struct ww_mutex {
+ struct mutex base;
+ struct cv condvar;
+ struct ww_acquire_ctx *ctx;
+};
+
+#define DEFINE_WW_CLASS(name) \
+ struct ww_class name = { \
+ .mutex_name = mutex_name(#name "_mutex") \
+ }
+
+#define DEFINE_WW_MUTEX(name, ww_class) \
+ struct ww_mutex name; \
+ static void name##_init(void *arg) \
+ { \
+ ww_mutex_init(&name, &ww_class); \
+ } \
+ SYSINIT(name, SI_SUB_LOCK, SI_ORDER_SECOND, name##_init, NULL)
+
+#define DEFINE_WD_CLASS(name) DEFINE_WW_CLASS(name)
+
+#define ww_mutex_is_locked(_m) \
+ sx_xlocked(&(_m)->base.sx)
+
+#define ww_mutex_lock_slow(_m, _x) \
+ ww_mutex_lock(_m, _x)
+
+#define ww_mutex_lock_slow_interruptible(_m, _x) \
+ ww_mutex_lock_interruptible(_m, _x)
+
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51600
+static inline int __must_check
+ww_mutex_trylock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx __unused)
+#else
+static inline int __must_check
+ww_mutex_trylock(struct ww_mutex *lock)
+#endif
+{
+ return (mutex_trylock(&lock->base));
+}
+
+extern int linux_ww_mutex_lock_sub(struct ww_mutex *,
+ struct ww_acquire_ctx *, int catch_signal);
+
+static inline int
+ww_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
+{
+ if (MUTEX_SKIP())
+ return (0);
+ else if ((struct thread *)SX_OWNER(lock->base.sx.sx_lock) == curthread)
+ return (-EALREADY);
+ else
+ return (linux_ww_mutex_lock_sub(lock, ctx, 0));
+}
+
+static inline int
+ww_mutex_lock_interruptible(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
+{
+ if (MUTEX_SKIP())
+ return (0);
+ else if ((struct thread *)SX_OWNER(lock->base.sx.sx_lock) == curthread)
+ return (-EALREADY);
+ else
+ return (linux_ww_mutex_lock_sub(lock, ctx, 1));
+}
+
+extern void linux_ww_mutex_unlock_sub(struct ww_mutex *);
+
+static inline void
+ww_mutex_unlock(struct ww_mutex *lock)
+{
+ if (MUTEX_SKIP())
+ return;
+ else
+ linux_ww_mutex_unlock_sub(lock);
+}
+
+static inline void
+ww_mutex_destroy(struct ww_mutex *lock)
+{
+ cv_destroy(&lock->condvar);
+ mutex_destroy(&lock->base);
+}
+
+static inline void
+ww_acquire_init(struct ww_acquire_ctx *ctx, struct ww_class *ww_class)
+{
+}
+
+static inline void
+ww_mutex_init(struct ww_mutex *lock, struct ww_class *ww_class)
+{
+ linux_mutex_init(&lock->base, ww_class->mutex_name, SX_NOWITNESS);
+ cv_init(&lock->condvar, "lkpi-ww");
+}
+
+static inline void
+ww_acquire_fini(struct ww_acquire_ctx *ctx)
+{
+}
+
+static inline void
+ww_acquire_done(struct ww_acquire_ctx *ctx)
+{
+}
+
+#endif /* _LINUXKPI_LINUX_WW_MUTEX_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/xarray.h b/sys/compat/linuxkpi/common/include/linux/xarray.h
new file mode 100644
index 000000000000..fba36eea0ab5
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/xarray.h
@@ -0,0 +1,149 @@
+/*-
+ * Copyright (c) 2020 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * 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 unmodified, 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 ``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 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_XARRAY_H_
+#define _LINUXKPI_LINUX_XARRAY_H_
+
+#include <linux/gfp.h>
+#include <linux/radix-tree.h>
+#include <linux/err.h>
+#include <linux/kconfig.h>
+
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#define XA_LIMIT(min, max) \
+ ({ CTASSERT((min) == 0); (uint32_t)(max); })
+
+#define XA_FLAGS_ALLOC (1U << 0)
+#define XA_FLAGS_LOCK_IRQ (1U << 1)
+#define XA_FLAGS_ALLOC1 (1U << 2)
+
+#define XA_ERROR(x) \
+ ERR_PTR(x)
+
+#define xa_is_err(x) \
+ IS_ERR(x)
+
+#define xa_limit_32b XA_LIMIT(0, 0xFFFFFFFF)
+
+#define XA_ASSERT_LOCKED(xa) mtx_assert(&(xa)->xa_lock, MA_OWNED)
+#define xa_lock(xa) mtx_lock(&(xa)->xa_lock)
+#define xa_unlock(xa) mtx_unlock(&(xa)->xa_lock)
+
+struct xarray {
+ struct radix_tree_root xa_head;
+ struct mtx xa_lock; /* internal mutex */
+ uint32_t xa_flags; /* see XA_FLAGS_XXX */
+};
+
+/*
+ * Extensible arrays API implemented as a wrapper
+ * around the radix tree implementation.
+ */
+void *xa_erase(struct xarray *, uint32_t);
+void *xa_load(struct xarray *, uint32_t);
+int xa_alloc(struct xarray *, uint32_t *, void *, uint32_t, gfp_t);
+int xa_alloc_cyclic(struct xarray *, uint32_t *, void *, uint32_t, uint32_t *, gfp_t);
+int xa_alloc_cyclic_irq(struct xarray *, uint32_t *, void *, uint32_t, uint32_t *, gfp_t);
+int xa_insert(struct xarray *, uint32_t, void *, gfp_t);
+void *xa_store(struct xarray *, uint32_t, void *, gfp_t);
+void xa_init_flags(struct xarray *, uint32_t);
+bool xa_empty(struct xarray *);
+void xa_destroy(struct xarray *);
+void *xa_next(struct xarray *, unsigned long *, bool);
+
+#define xa_for_each(xa, index, entry) \
+ for ((entry) = NULL, (index) = 0; \
+ ((entry) = xa_next(xa, &index, (entry) != NULL)) != NULL; )
+
+/*
+ * Unlocked version of functions above.
+ */
+void *__xa_erase(struct xarray *, uint32_t);
+int __xa_alloc(struct xarray *, uint32_t *, void *, uint32_t, gfp_t);
+int __xa_alloc_cyclic(struct xarray *, uint32_t *, void *, uint32_t, uint32_t *, gfp_t);
+int __xa_insert(struct xarray *, uint32_t, void *, gfp_t);
+void *__xa_store(struct xarray *, uint32_t, void *, gfp_t);
+bool __xa_empty(struct xarray *);
+void *__xa_next(struct xarray *, unsigned long *, bool);
+
+#define xa_store_irq(xa, index, ptr, gfp) \
+ xa_store((xa), (index), (ptr), (gfp))
+
+#define xa_erase_irq(xa, index) \
+ xa_erase((xa), (index))
+
+#define xa_lock_irq(xa) xa_lock(xa)
+#define xa_unlock_irq(xa) xa_unlock(xa)
+
+#define xa_lock_irqsave(xa, flags) \
+ do { \
+ xa_lock((xa)); \
+ flags = 0; \
+ } while (0)
+
+#define xa_unlock_irqrestore(xa, flags) \
+ do { \
+ xa_unlock((xa)); \
+ flags == 0; \
+ } while (0)
+
+static inline int
+xa_err(void *ptr)
+{
+ return (PTR_ERR_OR_ZERO(ptr));
+}
+
+static inline void
+xa_init(struct xarray *xa)
+{
+ xa_init_flags(xa, 0);
+}
+
+static inline void *
+xa_mk_value(unsigned long v)
+{
+ unsigned long r = (v << 1) | 1;
+
+ return ((void *)r);
+}
+
+static inline bool
+xa_is_value(const void *e)
+{
+ unsigned long v = (unsigned long)e;
+
+ return (v & 1);
+}
+
+static inline unsigned long
+xa_to_value(const void *e)
+{
+ unsigned long v = (unsigned long)e;
+
+ return (v >> 1);
+}
+#endif /* _LINUXKPI_LINUX_XARRAY_H_ */