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_amd_wbrf.h97
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bitops.h8
-rw-r--r--sys/compat/linuxkpi/common/include/linux/completion.h3
-rw-r--r--sys/compat/linuxkpi/common/include/linux/container_of.h8
-rw-r--r--sys/compat/linuxkpi/common/include/linux/debugfs.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/devcoredump.h9
-rw-r--r--sys/compat/linuxkpi/common/include/linux/device.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dma-mapping.h64
-rw-r--r--sys/compat/linuxkpi/common/include/linux/etherdevice.h8
-rw-r--r--sys/compat/linuxkpi/common/include/linux/fs.h5
-rw-r--r--sys/compat/linuxkpi/common/include/linux/gfp.h3
-rw-r--r--sys/compat/linuxkpi/common/include/linux/highmem.h32
-rw-r--r--sys/compat/linuxkpi/common/include/linux/idr.h7
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ieee80211.h38
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ioport.h1
-rw-r--r--sys/compat/linuxkpi/common/include/linux/jiffies.h40
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kmod.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kobject.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ktime.h7
-rw-r--r--sys/compat/linuxkpi/common/include/linux/leds.h3
-rw-r--r--sys/compat/linuxkpi/common/include/linux/math64.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mm.h82
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mm_types.h11
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mutex.h1
-rw-r--r--sys/compat/linuxkpi/common/include/linux/netdev_features.h25
-rw-r--r--sys/compat/linuxkpi/common/include/linux/nl80211.h5
-rw-r--r--sys/compat/linuxkpi/common/include/linux/page-flags.h7
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pagemap.h11
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pagevec.h68
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pci.h98
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pci_ids.h1
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pm_runtime.h5
-rw-r--r--sys/compat/linuxkpi/common/include/linux/printk.h60
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ref_tracker.h93
-rw-r--r--sys/compat/linuxkpi/common/include/linux/refcount.h1
-rw-r--r--sys/compat/linuxkpi/common/include/linux/scatterlist.h7
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sched.h4
-rw-r--r--sys/compat/linuxkpi/common/include/linux/seq_file.h29
-rw-r--r--sys/compat/linuxkpi/common/include/linux/shmem_fs.h10
-rw-r--r--sys/compat/linuxkpi/common/include/linux/skbuff.h55
-rw-r--r--sys/compat/linuxkpi/common/include/linux/slab.h159
-rw-r--r--sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h1
-rw-r--r--sys/compat/linuxkpi/common/include/linux/spinlock.h8
-rw-r--r--sys/compat/linuxkpi/common/include/linux/stdarg.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/stddef.h26
-rw-r--r--sys/compat/linuxkpi/common/include/linux/swap.h14
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sysfs.h191
-rw-r--r--sys/compat/linuxkpi/common/include/linux/time.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/timer.h6
-rw-r--r--sys/compat/linuxkpi/common/include/linux/topology.h35
-rw-r--r--sys/compat/linuxkpi/common/include/linux/types.h1
-rw-r--r--sys/compat/linuxkpi/common/include/linux/wait.h26
-rw-r--r--sys/compat/linuxkpi/common/include/linux/workqueue.h10
53 files changed, 1117 insertions, 280 deletions
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/bitops.h b/sys/compat/linuxkpi/common/include/linux/bitops.h
index 23aabb546cb2..00dd1f9a1ec0 100644
--- a/sys/compat/linuxkpi/common/include/linux/bitops.h
+++ b/sys/compat/linuxkpi/common/include/linux/bitops.h
@@ -62,10 +62,10 @@
#define hweight64(x) bitcount64(x)
#define hweight_long(x) bitcountl(x)
-#define HWEIGHT8(x) (bitcount8((uint8_t)(x)) + 1)
-#define HWEIGHT16(x) (bitcount16(x) + 1)
-#define HWEIGHT32(x) (bitcount32(x) + 1)
-#define HWEIGHT64(x) (bitcount64(x) + 1)
+#define HWEIGHT8(x) (__builtin_popcountg((uint8_t)(x)))
+#define HWEIGHT16(x) (__builtin_popcountg((uint16_t)(x)))
+#define HWEIGHT32(x) (__builtin_popcountg((uint32_t)(x)))
+#define HWEIGHT64(x) (__builtin_popcountg((uint64_t)(x)))
static inline int
__ffs(int mask)
diff --git a/sys/compat/linuxkpi/common/include/linux/completion.h b/sys/compat/linuxkpi/common/include/linux/completion.h
index 26e41a51c10b..9f8bebb4cf82 100644
--- a/sys/compat/linuxkpi/common/include/linux/completion.h
+++ b/sys/compat/linuxkpi/common/include/linux/completion.h
@@ -60,7 +60,8 @@ struct completion {
extern void linux_complete_common(struct completion *, int);
extern int linux_wait_for_common(struct completion *, int);
-extern int linux_wait_for_timeout_common(struct completion *, int, 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 *);
diff --git a/sys/compat/linuxkpi/common/include/linux/container_of.h b/sys/compat/linuxkpi/common/include/linux/container_of.h
index 449507fcf9c1..7210d531b055 100644
--- a/sys/compat/linuxkpi/common/include/linux/container_of.h
+++ b/sys/compat/linuxkpi/common/include/linux/container_of.h
@@ -41,6 +41,14 @@
(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/debugfs.h b/sys/compat/linuxkpi/common/include/linux/debugfs.h
index 54145b61503e..4d146e085a7b 100644
--- a/sys/compat/linuxkpi/common/include/linux/debugfs.h
+++ b/sys/compat/linuxkpi/common/include/linux/debugfs.h
@@ -115,6 +115,8 @@ 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);
diff --git a/sys/compat/linuxkpi/common/include/linux/devcoredump.h b/sys/compat/linuxkpi/common/include/linux/devcoredump.h
index b58c490615ad..5fa06c6595a8 100644
--- a/sys/compat/linuxkpi/common/include/linux/devcoredump.h
+++ b/sys/compat/linuxkpi/common/include/linux/devcoredump.h
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2020 The FreeBSD Foundation
+ * Copyright (c) 2020-2025 The FreeBSD Foundation
*
* This software was developed by Björn Zeeb under sponsorship from
* the FreeBSD Foundation.
@@ -71,4 +71,11 @@ dev_coredumpsg(struct device *dev __unused, struct scatterlist *table,
_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
index a5f6874a07f6..2556b0c45e49 100644
--- a/sys/compat/linuxkpi/common/include/linux/device.h
+++ b/sys/compat/linuxkpi/common/include/linux/device.h
@@ -90,6 +90,8 @@ struct dev_pm_ops {
struct device_driver {
const char *name;
const struct dev_pm_ops *pm;
+
+ void (*shutdown) (struct device *);
};
struct device_type {
diff --git a/sys/compat/linuxkpi/common/include/linux/dma-mapping.h b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h
index 84f0361de765..2d8e1196d3d3 100644
--- a/sys/compat/linuxkpi/common/include/linux/dma-mapping.h
+++ b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h
@@ -96,13 +96,17 @@ 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);
-void linux_dma_unmap(struct device *dev, dma_addr_t dma_addr, size_t size);
+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 dir __unused,
+ 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 dir __unused,
+ 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);
@@ -173,16 +177,17 @@ dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
dma_addr_t dma_addr)
{
- linux_dma_unmap(dev, dma_addr, size);
+ 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 dir, unsigned long attrs)
+ size_t size, enum dma_data_direction direction, unsigned long attrs)
{
- return (linux_dma_map_phys(dev, page_to_phys(page) + offset, size));
+ 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 */
@@ -197,7 +202,8 @@ dma_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size, enum dma_data_direction direction)
{
- return (linux_dma_map_phys(dev, page_to_phys(page) + offset, size));
+ return (lkpi_dma_map_phys(dev, page_to_phys(page) + offset, size,
+ direction, 0));
}
static inline void
@@ -205,7 +211,21 @@ dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
enum dma_data_direction direction)
{
- linux_dma_unmap(dev, dma_address, size);
+ 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
@@ -263,28 +283,33 @@ dma_sync_single_for_device(struct device *dev, dma_addr_t dma,
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, int direction)
+ 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, int direction)
+ 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)
@@ -306,24 +331,17 @@ static inline unsigned int dma_set_max_seg_size(struct device *dev,
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 __unused)
+ enum dma_data_direction direction, unsigned long attrs)
{
- dma_addr_t dma;
-
- dma = linux_dma_map_phys(dev, vtophys(ptr), size);
- if (!dma_mapping_error(dev, dma))
- dma_sync_single_for_device(dev, dma, size, direction);
-
- return (dma);
+ 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 __unused)
+ enum dma_data_direction direction, unsigned long attrs)
{
-
- dma_sync_single_for_cpu(dev, dma, size, direction);
- linux_dma_unmap(dev, dma, size);
+ lkpi_dma_unmap(dev, dma, size, direction, attrs);
}
static inline size_t
diff --git a/sys/compat/linuxkpi/common/include/linux/etherdevice.h b/sys/compat/linuxkpi/common/include/linux/etherdevice.h
index 5d3df744ae0e..1f2d6cf22d7e 100644
--- a/sys/compat/linuxkpi/common/include/linux/etherdevice.h
+++ b/sys/compat/linuxkpi/common/include/linux/etherdevice.h
@@ -58,9 +58,15 @@ is_zero_ether_addr(const u8 * addr)
}
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 (0x01 & addr[0]);
+ return ((addr[0] & 0x01) == 0x01);
}
static inline bool
diff --git a/sys/compat/linuxkpi/common/include/linux/fs.h b/sys/compat/linuxkpi/common/include/linux/fs.h
index 76a81e676744..f1568ad6282d 100644
--- a/sys/compat/linuxkpi/common/include/linux/fs.h
+++ b/sys/compat/linuxkpi/common/include/linux/fs.h
@@ -150,6 +150,11 @@ struct file_operations {
* 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);
diff --git a/sys/compat/linuxkpi/common/include/linux/gfp.h b/sys/compat/linuxkpi/common/include/linux/gfp.h
index 35dbe3e2a436..7a32e7862338 100644
--- a/sys/compat/linuxkpi/common/include/linux/gfp.h
+++ b/sys/compat/linuxkpi/common/include/linux/gfp.h
@@ -34,6 +34,7 @@
#include <sys/malloc.h>
#include <linux/page.h>
+#include <linux/topology.h>
#include <vm/vm_param.h>
#include <vm/vm_object.h>
@@ -134,6 +135,8 @@ 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:
*/
diff --git a/sys/compat/linuxkpi/common/include/linux/highmem.h b/sys/compat/linuxkpi/common/include/linux/highmem.h
index b8874481f9c6..58a9cdcdf60f 100644
--- a/sys/compat/linuxkpi/common/include/linux/highmem.h
+++ b/sys/compat/linuxkpi/common/include/linux/highmem.h
@@ -79,9 +79,7 @@ kmap_atomic_prot(struct page *page, pgprot_t prot)
vm_memattr_t attr = pgprot2cachemode(prot);
if (attr != VM_MEMATTR_DEFAULT) {
- vm_page_lock(page);
page->flags |= PG_FICTITIOUS;
- vm_page_unlock(page);
pmap_page_set_memattr(page, attr);
}
return (kmap(page));
@@ -139,4 +137,34 @@ 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/idr.h b/sys/compat/linuxkpi/common/include/linux/idr.h
index 535d8ce07fb4..06850c94a5e9 100644
--- a/sys/compat/linuxkpi/common/include/linux/idr.h
+++ b/sys/compat/linuxkpi/common/include/linux/idr.h
@@ -147,6 +147,13 @@ 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_range(struct ida *ida, unsigned int min, unsigned int max, gfp_t gfp)
+{
+
+ return (ida_simple_get(ida, min, max, gfp));
+}
+
static inline int ida_alloc(struct ida *ida, gfp_t gfp)
{
return (ida_alloc_max(ida, ~0u, gfp));
diff --git a/sys/compat/linuxkpi/common/include/linux/ieee80211.h b/sys/compat/linuxkpi/common/include/linux/ieee80211.h
index efac2a26e27e..5851ac08f083 100644
--- a/sys/compat/linuxkpi/common/include/linux/ieee80211.h
+++ b/sys/compat/linuxkpi/common/include/linux/ieee80211.h
@@ -35,6 +35,7 @@
#include <asm/unaligned.h>
#include <linux/kernel.h>
#include <linux/bitops.h>
+#include <linux/bitfield.h>
#include <linux/if_ether.h>
/* linux_80211.c */
@@ -121,7 +122,20 @@ enum ieee80211_rate_control_changed_flags {
/* 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 */
+/*
+ * 802.11-2020, 9.4.2.157.2 VHT Capabilities Information field,
+ * Table 9-271-Subfields of the VHT Capabilities Information field (continued).
+ */
+enum ieee80211_vht_max_ampdu_len_exp {
+ IEEE80211_VHT_MAX_AMPDU_8K = 0,
+ IEEE80211_VHT_MAX_AMPDU_16K = 1,
+ IEEE80211_VHT_MAX_AMPDU_32K = 2,
+ IEEE80211_VHT_MAX_AMPDU_64K = 3,
+ IEEE80211_VHT_MAX_AMPDU_128K = 4,
+ IEEE80211_VHT_MAX_AMPDU_256K = 5,
+ IEEE80211_VHT_MAX_AMPDU_512K = 6,
+ IEEE80211_VHT_MAX_AMPDU_1024K = 7,
+};
#define IEEE80211_WEP_IV_LEN 3 /* net80211: IEEE80211_WEP_IVLEN */
#define IEEE80211_WEP_ICV_LEN 4
@@ -295,6 +309,7 @@ enum ieee80211_ac_numbers {
#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
@@ -303,7 +318,7 @@ struct ieee80211_mcs_info {
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 {
@@ -313,7 +328,7 @@ struct ieee80211_ht_cap {
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
@@ -349,6 +364,7 @@ enum ieee80211_chanctx_change_flags {
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 {
@@ -426,6 +442,7 @@ enum ieee80211_tx_control_flags {
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. */
};
@@ -783,6 +800,20 @@ struct ieee80211_bss_load_elem {
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)
@@ -1225,5 +1256,4 @@ ieee80211_get_qos_ctl(struct ieee80211_hdr *hdr)
return (u8 *)hdr + 24;
}
-
#endif /* _LINUXKPI_LINUX_IEEE80211_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/ioport.h b/sys/compat/linuxkpi/common/include/linux/ioport.h
index 444f3ad94602..763af2de7c4f 100644
--- a/sys/compat/linuxkpi/common/include/linux/ioport.h
+++ b/sys/compat/linuxkpi/common/include/linux/ioport.h
@@ -40,6 +40,7 @@
struct resource {
resource_size_t start;
resource_size_t end;
+ const char *name;
};
static inline resource_size_t
diff --git a/sys/compat/linuxkpi/common/include/linux/jiffies.h b/sys/compat/linuxkpi/common/include/linux/jiffies.h
index f099caa1ce18..c2409726e874 100644
--- a/sys/compat/linuxkpi/common/include/linux/jiffies.h
+++ b/sys/compat/linuxkpi/common/include/linux/jiffies.h
@@ -32,21 +32,21 @@
#include <linux/types.h>
#include <linux/time.h>
-#include <sys/time.h>
#include <sys/kernel.h>
#include <sys/limits.h>
+#include <sys/time.h>
-#define jiffies ticks
-#define jiffies_64 ticks
+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 ((INT_MAX >> 1) - 1)
+#define MAX_JIFFY_OFFSET ((LONG_MAX >> 1) - 1)
-#define time_after(a, b) ((int)((b) - (a)) < 0)
+#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) ((int)((a) - (b)) >= 0)
+#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))
@@ -68,7 +68,7 @@ extern uint64_t lkpi_msec2hz_rem;
extern uint64_t lkpi_msec2hz_div;
extern uint64_t lkpi_msec2hz_max;
-static inline int
+static inline unsigned long
msecs_to_jiffies(uint64_t msec)
{
uint64_t result;
@@ -79,10 +79,10 @@ msecs_to_jiffies(uint64_t msec)
if (result > MAX_JIFFY_OFFSET)
result = MAX_JIFFY_OFFSET;
- return ((int)result);
+ return ((unsigned long)result);
}
-static inline int
+static inline unsigned long
usecs_to_jiffies(uint64_t usec)
{
uint64_t result;
@@ -93,7 +93,7 @@ usecs_to_jiffies(uint64_t usec)
if (result > MAX_JIFFY_OFFSET)
result = MAX_JIFFY_OFFSET;
- return ((int)result);
+ return ((unsigned long)result);
}
static inline uint64_t
@@ -120,34 +120,24 @@ nsecs_to_jiffies(uint64_t nsec)
}
static inline uint64_t
-jiffies_to_nsecs(int j)
+jiffies_to_nsecs(unsigned long j)
{
- return ((1000000000ULL / hz) * (uint64_t)(unsigned int)j);
+ return ((1000000000ULL / hz) * (uint64_t)j);
}
static inline uint64_t
-jiffies_to_usecs(int j)
+jiffies_to_usecs(unsigned long j)
{
- return ((1000000ULL / hz) * (uint64_t)(unsigned int)j);
+ return ((1000000ULL / hz) * (uint64_t)j);
}
static inline uint64_t
get_jiffies_64(void)
{
- return ((uint64_t)(unsigned int)ticks);
-}
-
-static inline int
-linux_timer_jiffies_until(int expires)
-{
- int delta = expires - jiffies;
- /* guard against already expired values */
- if (delta < 1)
- delta = 1;
- return (delta);
+ return ((uint64_t)jiffies);
}
#endif /* _LINUXKPI_LINUX_JIFFIES_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kmod.h b/sys/compat/linuxkpi/common/include/linux/kmod.h
index b3cbe2ed2e02..8f9f034aabd8 100644
--- a/sys/compat/linuxkpi/common/include/linux/kmod.h
+++ b/sys/compat/linuxkpi/common/include/linux/kmod.h
@@ -33,7 +33,7 @@
#include <sys/syscallsubr.h>
#include <sys/refcount.h>
#include <sys/sbuf.h>
-#include <machine/stdarg.h>
+#include <sys/stdarg.h>
#include <sys/proc.h>
#define request_module(...) \
diff --git a/sys/compat/linuxkpi/common/include/linux/kobject.h b/sys/compat/linuxkpi/common/include/linux/kobject.h
index 512f47f9e4b4..98f55d1234c4 100644
--- a/sys/compat/linuxkpi/common/include/linux/kobject.h
+++ b/sys/compat/linuxkpi/common/include/linux/kobject.h
@@ -29,7 +29,7 @@
#ifndef _LINUXKPI_LINUX_KOBJECT_H_
#define _LINUXKPI_LINUX_KOBJECT_H_
-#include <machine/stdarg.h>
+#include <sys/stdarg.h>
#include <linux/kernel.h>
#include <linux/kref.h>
diff --git a/sys/compat/linuxkpi/common/include/linux/ktime.h b/sys/compat/linuxkpi/common/include/linux/ktime.h
index 53c2abd64fc6..6a2f04f3d789 100644
--- a/sys/compat/linuxkpi/common/include/linux/ktime.h
+++ b/sys/compat/linuxkpi/common/include/linux/ktime.h
@@ -232,6 +232,13 @@ 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)
{
diff --git a/sys/compat/linuxkpi/common/include/linux/leds.h b/sys/compat/linuxkpi/common/include/linux/leds.h
index f7ee7a68dcf5..89f7286f6800 100644
--- a/sys/compat/linuxkpi/common/include/linux/leds.h
+++ b/sys/compat/linuxkpi/common/include/linux/leds.h
@@ -27,7 +27,7 @@
#define _LINUXKPI_LINUX_LEDS_H
enum led_brightness {
- __DUMMY,
+ LED_OFF,
};
struct led_classdev {
@@ -35,6 +35,7 @@ struct led_classdev {
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/math64.h b/sys/compat/linuxkpi/common/include/linux/math64.h
index cae5e30b08df..a216d350570f 100644
--- a/sys/compat/linuxkpi/common/include/linux/math64.h
+++ b/sys/compat/linuxkpi/common/include/linux/math64.h
@@ -61,6 +61,8 @@ 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)
{
diff --git a/sys/compat/linuxkpi/common/include/linux/mm.h b/sys/compat/linuxkpi/common/include/linux/mm.h
index b4c8bf3c1c30..156b00a0c0f0 100644
--- a/sys/compat/linuxkpi/common/include/linux/mm.h
+++ b/sys/compat/linuxkpi/common/include/linux/mm.h
@@ -161,6 +161,14 @@ 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.
@@ -184,7 +192,7 @@ get_order(unsigned long size)
*
* NOTE: This function only works for pages allocated by the kernel.
*/
-void *linux_page_address(struct page *);
+void *linux_page_address(const struct page *);
#define page_address(page) linux_page_address(page)
static inline void *
@@ -275,6 +283,38 @@ 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 **);
@@ -331,12 +371,6 @@ pin_user_pages_remote(struct task_struct *task, struct mm_struct *mm,
task, mm, start, nr_pages, gup_flags, pages, vmas);
}
-static inline void
-put_page(struct page *page)
-{
- vm_page_unwire(page, PQ_ACTIVE);
-}
-
#define unpin_user_page(page) put_page(page)
#define unpin_user_pages(pages, npages) release_pages(pages, npages)
@@ -372,14 +406,14 @@ vmalloc_to_page(const void *addr)
static inline int
trylock_page(struct page *page)
{
- return (vm_page_trylock(page));
+ return (vm_page_tryxbusy(page));
}
static inline void
unlock_page(struct page *page)
{
- vm_page_unlock(page);
+ vm_page_xunbusy(page);
}
extern int is_vmalloc_addr(const void *addr);
@@ -412,4 +446,34 @@ 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
index c08e2511725b..3ea68e97004c 100644
--- a/sys/compat/linuxkpi/common/include/linux/mm_types.h
+++ b/sys/compat/linuxkpi/common/include/linux/mm_types.h
@@ -79,4 +79,15 @@ mmgrab(struct mm_struct *mm)
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/mutex.h b/sys/compat/linuxkpi/common/include/linux/mutex.h
index 1d85ba20baca..6fb6a7744a89 100644
--- a/sys/compat/linuxkpi/common/include/linux/mutex.h
+++ b/sys/compat/linuxkpi/common/include/linux/mutex.h
@@ -35,6 +35,7 @@
#include <sys/sx.h>
#include <linux/kernel.h>
+#include <linux/cleanup.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <asm/atomic.h>
diff --git a/sys/compat/linuxkpi/common/include/linux/netdev_features.h b/sys/compat/linuxkpi/common/include/linux/netdev_features.h
index 06e88d107708..fae82776b071 100644
--- a/sys/compat/linuxkpi/common/include/linux/netdev_features.h
+++ b/sys/compat/linuxkpi/common/include/linux/netdev_features.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2020-2021 The FreeBSD Foundation
+ * Copyright (c) 2020-2025 The FreeBSD Foundation
*
* Portions of this software were developed by Björn Zeeb
* under sponsorship from the FreeBSD Foundation.
@@ -33,15 +33,20 @@
typedef uint32_t netdev_features_t;
-#define NETIF_F_HIGHDMA BIT(0)
-#define NETIF_F_SG BIT(1)
-#define NETIF_F_IP_CSUM BIT(2)
-#define NETIF_F_IPV6_CSUM BIT(3)
-#define NETIF_F_TSO BIT(4)
-#define NETIF_F_TSO6 BIT(5)
-#define NETIF_F_RXCSUM BIT(6)
-#define NETIF_F_HW_CSUM BIT(7)
+#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_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/nl80211.h b/sys/compat/linuxkpi/common/include/linux/nl80211.h
index b2a33a28b3a7..f3979d3a2abc 100644
--- a/sys/compat/linuxkpi/common/include/linux/nl80211.h
+++ b/sys/compat/linuxkpi/common/include/linux/nl80211.h
@@ -190,8 +190,6 @@ enum nl80211_tdls_operation {
NL80211_TDLS_ENABLE_LINK,
NL80211_TDLS_DISABLE_LINK,
NL80211_TDLS_DISCOVERY_REQ,
- NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
- NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY,
};
enum nl80211_cqm_rssi_threshold_event {
@@ -436,6 +434,9 @@ 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
diff --git a/sys/compat/linuxkpi/common/include/linux/page-flags.h b/sys/compat/linuxkpi/common/include/linux/page-flags.h
index 9dd49c8492a5..a22b3a24c330 100644
--- a/sys/compat/linuxkpi/common/include/linux/page-flags.h
+++ b/sys/compat/linuxkpi/common/include/linux/page-flags.h
@@ -29,6 +29,13 @@
#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/pagemap.h b/sys/compat/linuxkpi/common/include/linux/pagemap.h
index 7244b61257dc..cb6a1820ea8b 100644
--- a/sys/compat/linuxkpi/common/include/linux/pagemap.h
+++ b/sys/compat/linuxkpi/common/include/linux/pagemap.h
@@ -33,6 +33,8 @@
#include <linux/highmem.h>
#include <linux/vmalloc.h>
+struct folio_batch;
+
#define invalidate_mapping_pages(...) \
linux_invalidate_mapping_pages(__VA_ARGS__)
@@ -40,15 +42,6 @@ unsigned long linux_invalidate_mapping_pages(vm_object_t obj, pgoff_t start,
pgoff_t end);
static inline void
-release_pages(struct page **pages, int nr)
-{
- int i;
-
- for (i = 0; i < nr; i++)
- put_page(pages[i]);
-}
-
-static inline void
mapping_clear_unevictable(vm_object_t mapping)
{
}
diff --git a/sys/compat/linuxkpi/common/include/linux/pagevec.h b/sys/compat/linuxkpi/common/include/linux/pagevec.h
index 9ba8ff8effa0..0a952e965b5a 100644
--- a/sys/compat/linuxkpi/common/include/linux/pagevec.h
+++ b/sys/compat/linuxkpi/common/include/linux/pagevec.h
@@ -66,4 +66,72 @@ 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
index afd6c827b3b4..3fd4191b9917 100644
--- a/sys/compat/linuxkpi/common/include/linux/pci.h
+++ b/sys/compat/linuxkpi/common/include/linux/pci.h
@@ -4,7 +4,7 @@
* Copyright (c) 2010 Panasas, Inc.
* Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
* All rights reserved.
- * Copyright (c) 2020-2022 The FreeBSD Foundation
+ * Copyright (c) 2020-2025 The FreeBSD Foundation
*
* Portions of this software were developed by Björn Zeeb
* under sponsorship from the FreeBSD Foundation.
@@ -72,6 +72,10 @@ struct pci_device_id {
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) \
\
@@ -85,11 +89,10 @@ static driver_t _ ## _bus ## _ ## _table ## _driver = { \
0 \
}; \
\
-DRIVER_MODULE(lkpi_ ## _table, pci, _ ## _bus ## _ ## _table ## _driver,\
+DRIVER_MODULE(lkpi_ ## _table, _bus, _ ## _bus ## _ ## _table ## _driver,\
0, 0); \
\
-MODULE_PNP_INFO("U32:vendor;U32:device;V32:subvendor;V32:subdevice", \
- _bus, lkpi_ ## _table, _table, nitems(_table) - 1)
+MODULE_DEVICE_TABLE_BUS_ ## _bus(_bus, _table)
#define PCI_ANY_ID -1U
@@ -220,11 +223,11 @@ enum pcie_link_width {
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_D0 PCI_POWERSTATE_D0
+#define PCI_D1 PCI_POWERSTATE_D1
+#define PCI_D2 PCI_POWERSTATE_D2
+#define PCI_D3hot PCI_POWERSTATE_D3_HOT
+#define PCI_D3cold PCI_POWERSTATE_D3_COLD
#define PCI_POWER_ERROR PCI_POWERSTATE_UNKNOWN
@@ -359,9 +362,9 @@ 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_iomap_range(struct pci_dev *, int,
+ unsigned long, unsigned long);
+void *linuxkpi_pci_iomap(struct pci_dev *, int, unsigned long);
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);
@@ -374,13 +377,15 @@ int linuxkpi_pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries,
/* 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 pci_dev *lkpi_pci_get_device(uint32_t, uint32_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__)
+ 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)
@@ -523,7 +528,20 @@ pci_upstream_bridge(struct pci_dev *pdev)
if (pdev == pdev->bus->self) {
device_t bridge;
- bridge = device_get_parent(pdev->dev.bsddev);
+ /*
+ * 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);
@@ -543,10 +561,12 @@ 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)
+#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)
@@ -712,8 +732,10 @@ 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)
+#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
@@ -722,10 +744,11 @@ void linux_pci_unregister_drm_driver(struct pci_driver *pdrv);
* 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(...) \
+ linuxkpi_pci_enable_msix(__VA_ARGS__)
-#define pci_enable_msix_range(...) \
- linux_pci_enable_msix_range(__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,
@@ -750,8 +773,8 @@ pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
return (nvec);
}
-#define pci_enable_msi(pdev) \
- linux_pci_enable_msi(pdev)
+#define pci_enable_msi(pdev) \
+ linux_pci_enable_msi(pdev)
static inline int
pci_enable_msi(struct pci_dev *pdev)
@@ -776,11 +799,12 @@ 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)
+#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)
@@ -1369,10 +1393,12 @@ struct pci_dev *lkpi_pci_get_base_class(unsigned int class,
/* -------------------------------------------------------------------------- */
-#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)
+#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)
@@ -1413,7 +1439,7 @@ err:
* 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)
+linuxkpi_pci_get_device(uint32_t vendor, uint32_t device, struct pci_dev *odev)
{
return (lkpi_pci_get_device(vendor, device, odev));
diff --git a/sys/compat/linuxkpi/common/include/linux/pci_ids.h b/sys/compat/linuxkpi/common/include/linux/pci_ids.h
index 2f02d6ad1c14..e318f6f75ce7 100644
--- a/sys/compat/linuxkpi/common/include/linux/pci_ids.h
+++ b/sys/compat/linuxkpi/common/include/linux/pci_ids.h
@@ -46,6 +46,7 @@
#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
diff --git a/sys/compat/linuxkpi/common/include/linux/pm_runtime.h b/sys/compat/linuxkpi/common/include/linux/pm_runtime.h
index 616dd508e562..6114b7b159d7 100644
--- a/sys/compat/linuxkpi/common/include/linux/pm_runtime.h
+++ b/sys/compat/linuxkpi/common/include/linux/pm_runtime.h
@@ -34,8 +34,13 @@ 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;
}
diff --git a/sys/compat/linuxkpi/common/include/linux/printk.h b/sys/compat/linuxkpi/common/include/linux/printk.h
index 3840a6e5fb8a..d2d197682782 100644
--- a/sys/compat/linuxkpi/common/include/linux/printk.h
+++ b/sys/compat/linuxkpi/common/include/linux/printk.h
@@ -44,57 +44,19 @@ enum {
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)
{
- typedef const struct { long long value; } __packed *print_64p_t;
- typedef const struct { uint32_t value; } __packed *print_32p_t;
- typedef const struct { uint16_t value; } __packed *print_16p_t;
- const void *buf_old = buf;
- int row;
-
- while (len > 0) {
- if (level != NULL)
- printf("%s", level);
- if (prefix_str != NULL)
- printf("%s ", prefix_str);
-
- switch (prefix_type) {
- case DUMP_PREFIX_ADDRESS:
- printf("[%p] ", buf);
- break;
- case DUMP_PREFIX_OFFSET:
- printf("[%#tx] ", ((const char *)buf -
- (const char *)buf_old));
- break;
- default:
- break;
- }
- for (row = 0; row != rowsize; row++) {
- if (groupsize == 8 && len > 7) {
- printf("%016llx ", ((print_64p_t)buf)->value);
- buf = (const uint8_t *)buf + 8;
- len -= 8;
- } else if (groupsize == 4 && len > 3) {
- printf("%08x ", ((print_32p_t)buf)->value);
- buf = (const uint8_t *)buf + 4;
- len -= 4;
- } else if (groupsize == 2 && len > 1) {
- printf("%04x ", ((print_16p_t)buf)->value);
- buf = (const uint8_t *)buf + 2;
- len -= 2;
- } else if (len > 0) {
- printf("%02x ", *(const uint8_t *)buf);
- buf = (const uint8_t *)buf + 1;
- len--;
- } else {
- break;
- }
- }
- printf("\n");
- }
+ lkpi_hex_dump(__lkpi_hexdump_printf, NULL, level, prefix_str, prefix_type,
+ rowsize, groupsize, buf, len, ascii);
}
static inline void
@@ -132,4 +94,10 @@ print_hex_dump_bytes(const char *prefix_str, const int prefix_type,
0; \
})
+#define FW_BUG "[Firmware Bug]: "
+#define FW_WARN "[Firmware Warn]: "
+#define FW_INFO "[Firmware Info]: "
+#define HW_ERR "[Hardware Error]: "
+#define DEPRECATED "[Deprecated]: "
+
#endif /* _LINUXKPI_LINUX_PRINTK_H_ */
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
index 02a7eda3f4a9..46e501a65396 100644
--- a/sys/compat/linuxkpi/common/include/linux/refcount.h
+++ b/sys/compat/linuxkpi/common/include/linux/refcount.h
@@ -30,6 +30,7 @@
#define _LINUXKPI_LINUX_REFCOUNT_H
#include <linux/atomic.h>
+#include <linux/spinlock.h>
typedef atomic_t refcount_t;
diff --git a/sys/compat/linuxkpi/common/include/linux/scatterlist.h b/sys/compat/linuxkpi/common/include/linux/scatterlist.h
index 51ced19e6b5b..537f5bebc5aa 100644
--- a/sys/compat/linuxkpi/common/include/linux/scatterlist.h
+++ b/sys/compat/linuxkpi/common/include/linux/scatterlist.h
@@ -674,4 +674,11 @@ sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents,
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
index 80354493f955..3ad2f8e4ce8b 100644
--- a/sys/compat/linuxkpi/common/include/linux/sched.h
+++ b/sys/compat/linuxkpi/common/include/linux/sched.h
@@ -53,7 +53,7 @@
#include <asm/atomic.h>
-#define MAX_SCHEDULE_TIMEOUT INT_MAX
+#define MAX_SCHEDULE_TIMEOUT LONG_MAX
#define TASK_RUNNING 0x0000
#define TASK_INTERRUPTIBLE 0x0001
@@ -160,7 +160,7 @@ void linux_send_sig(int signo, struct task_struct *task);
linux_send_sig(signo, task); \
} while (0)
-int linux_schedule_timeout(int timeout);
+long linux_schedule_timeout(long timeout);
static inline void
linux_schedule_save_interrupt_value(struct task_struct *task, int value)
diff --git a/sys/compat/linuxkpi/common/include/linux/seq_file.h b/sys/compat/linuxkpi/common/include/linux/seq_file.h
index d8b327f59538..47da16ab8688 100644
--- a/sys/compat/linuxkpi/common/include/linux/seq_file.h
+++ b/sys/compat/linuxkpi/common/include/linux/seq_file.h
@@ -28,9 +28,13 @@
#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
@@ -51,6 +55,21 @@ static const struct file_operations __name ## _fops = { \
.release = single_release, \
}
+#define DEFINE_SHOW_STORE_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, \
+ .write = __name ## _write, \
+ .llseek = seq_lseek, \
+ .release = single_release, \
+}
+
struct seq_file {
struct sbuf *buf;
size_t size;
@@ -89,6 +108,16 @@ 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/shmem_fs.h b/sys/compat/linuxkpi/common/include/linux/shmem_fs.h
index efa2c855fe7d..5e91725d4a1c 100644
--- a/sys/compat/linuxkpi/common/include/linux/shmem_fs.h
+++ b/sys/compat/linuxkpi/common/include/linux/shmem_fs.h
@@ -54,4 +54,14 @@ void linux_shmem_truncate_range(vm_object_t obj, loff_t lstart,
#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/skbuff.h b/sys/compat/linuxkpi/common/include/linux/skbuff.h
index 9db29c72e20c..c8ad90281e34 100644
--- a/sys/compat/linuxkpi/common/include/linux/skbuff.h
+++ b/sys/compat/linuxkpi/common/include/linux/skbuff.h
@@ -154,38 +154,46 @@ struct sk_buff {
};
struct list_head list;
};
- uint32_t _alloc_len; /* Length of alloc data-buf. XXX-BZ give up for truesize? */
+
+ 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. */
- uint16_t mac_len; /* Link-layer header length. */
- __sum16 csum;
- uint16_t l3hdroff; /* network header offset from *head */
- uint16_t l4hdroff; /* transport header offset from *head */
uint32_t priority;
uint16_t qmap; /* queue mapping */
uint16_t _flags; /* Internal flags. */
#define _SKB_FLAGS_SKBEXTFRAG 0x0001
- enum sk_buff_pkt_type pkt_type;
+ 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;
- /* "Scratch" area for layers to store metadata. */
- /* ??? I see sizeof() operations so probably an array. */
- uint8_t cb[64] __aligned(CACHE_LINE_SIZE);
-
struct net_device *dev;
void *sk; /* XXX net/sock.h? */
- int csum_offset, csum_start, ip_summed, protocol;
-
- uint8_t *head; /* Head of buffer. */
- uint8_t *data; /* Head of data. */
- uint8_t *tail; /* End of data. */
- uint8_t *end; /* End of buffer. */
-
- struct skb_shared_info *shinfo;
-
/* FreeBSD specific bandaid (see linuxkpi_kfree_skb). */
void *m;
void(*m_free_func)(void *);
@@ -993,6 +1001,13 @@ skb_get_queue_mapping(struct sk_buff *skb)
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)
{
@@ -1038,7 +1053,7 @@ skb_orphan(struct sk_buff *skb)
SKB_TODO();
}
-static inline __sum16
+static inline __wsum
csum_unfold(__sum16 sum)
{
return (sum);
diff --git a/sys/compat/linuxkpi/common/include/linux/slab.h b/sys/compat/linuxkpi/common/include/linux/slab.h
index 07c16884b00e..47e3d133eb6c 100644
--- a/sys/compat/linuxkpi/common/include/linux/slab.h
+++ b/sys/compat/linuxkpi/common/include/linux/slab.h
@@ -4,6 +4,10 @@
* 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
@@ -41,13 +45,12 @@
MALLOC_DECLARE(M_KMALLOC);
-#define kmalloc(size, flags) lkpi_kmalloc(size, flags)
-#define kvmalloc(size, flags) kmalloc(size, flags)
-#define kvzalloc(size, flags) kmalloc(size, (flags) | __GFP_ZERO)
+#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)
@@ -85,15 +88,22 @@ struct linux_kmem_cache;
#define ARCH_KMALLOC_MINALIGN \
__alignof(unsigned long long)
-/* drm-kmod 5.4 compat */
-#define kfree_async(ptr) kfree(ptr);
-
#define ZERO_SIZE_PTR ((void *)16)
#define ZERO_OR_NULL_PTR(x) ((x) == NULL || (x) == ZERO_SIZE_PTR)
-extern void *lkpi_kmalloc(size_t size, gfp_t flags);
-void *lkpi___kmalloc(size_t size, gfp_t flags);
-#define __kmalloc(_s, _f) lkpi___kmalloc(_s, _f)
+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_kvmalloc(size_t, gfp_t);
+void *lkpi___kmalloc(size_t, gfp_t);
+void *lkpi___kmalloc_node(size_t, gfp_t, int);
+void *lkpi_krealloc(void *, size_t, gfp_t);
+void lkpi_kfree(const void *);
static inline gfp_t
linux_check_m_flags(gfp_t flags)
@@ -110,103 +120,122 @@ linux_check_m_flags(gfp_t flags)
return (flags & GFP_NATIVE_MASK);
}
+/*
+ * Base functions with a native implementation.
+ */
static inline void *
-kmalloc_node(size_t size, gfp_t flags, int node)
+kmalloc(size_t size, gfp_t flags)
{
- return (malloc_domainset(size, M_KMALLOC,
- linux_get_vm_domain_set(node), linux_check_m_flags(flags)));
+ return (lkpi_kmalloc(size, flags));
}
static inline void *
-kcalloc(size_t n, size_t size, gfp_t flags)
+__kmalloc(size_t size, gfp_t flags)
{
- flags |= __GFP_ZERO;
- return (mallocarray(n, size, M_KMALLOC, linux_check_m_flags(flags)));
+ return (lkpi___kmalloc(size, flags));
}
static inline void *
-kcalloc_node(size_t n, size_t size, gfp_t flags, int node)
+kmalloc_node(size_t size, gfp_t flags, int node)
{
- flags |= __GFP_ZERO;
- return (mallocarray_domainset(n, size, M_KMALLOC,
- linux_get_vm_domain_set(node), linux_check_m_flags(flags)));
+ return (lkpi___kmalloc_node(size, flags, node));
}
static inline void *
-__vmalloc(size_t size, gfp_t flags, int other)
+krealloc(void *ptr, size_t size, gfp_t flags)
{
- return (malloc(size, M_KMALLOC, linux_check_m_flags(flags)));
+ return (lkpi_krealloc(ptr, size, flags));
}
-static inline void *
-__vmalloc_node(size_t size, gfp_t flags, int node)
+static inline void
+kfree(const void *ptr)
{
- return (malloc_domainset(size, M_KMALLOC,
- linux_get_vm_domain_set(node), linux_check_m_flags(flags)));
+ lkpi_kfree(ptr);
}
+/*
+ * Other k*alloc() funtions using the above as underlying allocator.
+ */
+/* kmalloc */
static inline void *
-vmalloc_32(size_t size)
+kmalloc_array(size_t n, size_t size, gfp_t flags)
{
- return (contigmalloc(size, M_KMALLOC, M_WAITOK, 0, UINT_MAX, 1, 1));
+ if (WOULD_OVERFLOW(n, size))
+ panic("%s: %zu * %zu overflowed", __func__, n, size);
+
+ return (kmalloc(size * n, flags));
}
static inline void *
-kmalloc_array(size_t n, size_t size, gfp_t flags)
+kcalloc(size_t n, size_t size, gfp_t flags)
{
- return (mallocarray(n, size, M_KMALLOC, linux_check_m_flags(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)
{
- return (mallocarray_domainset(n, size, M_KMALLOC,
- linux_get_vm_domain_set(node), linux_check_m_flags(flags)));
-}
+ if (WOULD_OVERFLOW(n, size))
+ panic("%s: %zu * %zu overflowed", __func__, n, size);
-static inline void *
-kvmalloc_array(size_t n, size_t size, gfp_t flags)
-{
- return (mallocarray(n, size, M_KMALLOC, linux_check_m_flags(flags)));
+ return (kmalloc_node(size * n, flags, node));
}
static inline void *
-krealloc(void *ptr, size_t size, gfp_t flags)
+kcalloc_node(size_t n, size_t size, gfp_t flags, int node)
{
- return (realloc(ptr, size, M_KMALLOC, linux_check_m_flags(flags)));
+ 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)) {
+ if (WOULD_OVERFLOW(n, size))
return NULL;
- }
- return (realloc(ptr, n * size, M_KMALLOC, linux_check_m_flags(flags)));
+ 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)));
}
-extern void linux_kfree_async(void *);
+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
-kfree(const void *ptr)
+static inline void *
+vmalloc_32(size_t size)
{
- if (ZERO_OR_NULL_PTR(ptr))
- return;
+ return (contigmalloc(size, M_KMALLOC, M_WAITOK, 0, UINT_MAX, 1, 1));
+}
- if (curthread->td_critnest != 0)
- linux_kfree_async(__DECONST(void *, ptr));
- else
- free(__DECONST(void *, ptr), M_KMALLOC);
+/* May return non-contiguous memory. */
+static inline void *
+kvmalloc(size_t size, gfp_t flags)
+{
+ return (lkpi_kvmalloc(size, flags));
}
-static __inline void
-kfree_sensitive(const void *ptr)
+static inline void *
+kvmalloc_array(size_t n, size_t size, gfp_t flags)
{
- if (ZERO_OR_NULL_PTR(ptr))
- return;
+ if (WOULD_OVERFLOW(n, size))
+ panic("%s: %zu * %zu overflowed", __func__, n, size);
- zfree(__DECONST(void *, ptr), M_KMALLOC);
+ return (kvmalloc(size * n, flags));
}
static inline void *
@@ -226,6 +255,19 @@ kvrealloc(const void *ptr, size_t oldsize, size_t newsize, gfp_t flags)
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)
{
@@ -240,11 +282,4 @@ kmalloc_size_roundup(size_t size)
return (malloc_size(size));
}
-extern struct linux_kmem_cache *linux_kmem_cache_create(const char *name,
- size_t size, size_t align, unsigned flags, linux_kmem_ctor_t *ctor);
-extern void *lkpi_kmem_cache_alloc(struct linux_kmem_cache *, gfp_t);
-extern void *lkpi_kmem_cache_zalloc(struct linux_kmem_cache *, gfp_t);
-extern void lkpi_kmem_cache_free(struct linux_kmem_cache *, void *);
-extern void linux_kmem_cache_destroy(struct linux_kmem_cache *);
-
#endif /* _LINUXKPI_LINUX_SLAB_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h b/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h
index 74038f0e7520..903053e7f6e8 100644
--- a/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h
+++ b/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h
@@ -43,6 +43,7 @@ struct mtk_wed_device {
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)
diff --git a/sys/compat/linuxkpi/common/include/linux/spinlock.h b/sys/compat/linuxkpi/common/include/linux/spinlock.h
index 2992e41c9c02..dc10b0457153 100644
--- a/sys/compat/linuxkpi/common/include/linux/spinlock.h
+++ b/sys/compat/linuxkpi/common/include/linux/spinlock.h
@@ -154,6 +154,14 @@ typedef struct mtx spinlock_t;
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
diff --git a/sys/compat/linuxkpi/common/include/linux/stdarg.h b/sys/compat/linuxkpi/common/include/linux/stdarg.h
index ab2fdf7534e5..698ac45e9198 100644
--- a/sys/compat/linuxkpi/common/include/linux/stdarg.h
+++ b/sys/compat/linuxkpi/common/include/linux/stdarg.h
@@ -28,6 +28,6 @@
#ifndef _LINUXKPI_STDARG_H_
#define _LINUXKPI_STDARG_H_
-#include <machine/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
index a3bc6b13765e..d04a5a4bf516 100644
--- a/sys/compat/linuxkpi/common/include/linux/stddef.h
+++ b/sys/compat/linuxkpi/common/include/linux/stddef.h
@@ -5,11 +5,27 @@
#include <sys/stddef.h>
-#define struct_group(NAME, ...) \
+/*
+ * 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 { __VA_ARGS__ }; \
- struct { __VA_ARGS__ } NAME; \
- }
+ struct { _members } _attrs; \
+ struct _tag { _members } _attrs _name; \
+ } _attrs
+#endif
-#endif /* _LINUXKPI_LINUX_STDDEF_H_ */
+#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/swap.h b/sys/compat/linuxkpi/common/include/linux/swap.h
index a353d353cd33..5828db7ae392 100644
--- a/sys/compat/linuxkpi/common/include/linux/swap.h
+++ b/sys/compat/linuxkpi/common/include/linux/swap.h
@@ -37,6 +37,9 @@
#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)
{
@@ -54,4 +57,15 @@ 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
index b5ad73e4460b..470c224a9778 100644
--- a/sys/compat/linuxkpi/common/include/linux/sysfs.h
+++ b/sys/compat/linuxkpi/common/include/linux/sysfs.h
@@ -50,6 +50,15 @@ struct attribute_group {
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, \
@@ -72,6 +81,39 @@ struct attribute_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:
@@ -147,6 +189,50 @@ sysfs_create_file(struct kobject *kobj, const struct attribute *attr)
return (0);
}
+static inline struct kobject *
+__sysfs_lookup_group(struct kobject *kobj, const char *group)
+{
+ int found;
+ struct sysctl_oid *group_oidp;
+ struct kobject *group_kobj;
+
+ found = 0;
+ if (group != NULL) {
+ SYSCTL_FOREACH(group_oidp, SYSCTL_CHILDREN(kobj->oidp)) {
+ if (strcmp(group_oidp->oid_name, group) != 0)
+ continue;
+ found = 1;
+ break;
+ }
+ } else {
+ found = 1;
+ group_oidp = kobj->oidp;
+ }
+
+ if (!found)
+ return (NULL);
+
+ group_kobj = group_oidp->oid_arg1;
+
+ return (group_kobj);
+}
+
+static inline int
+sysfs_add_file_to_group(struct kobject *kobj,
+ const struct attribute *attr, const char *group)
+{
+ int ret;
+ struct kobject *group_kobj;
+
+ group_kobj = __sysfs_lookup_group(kobj, group);
+ if (group_kobj == NULL)
+ return (-ENOENT);
+
+ ret = sysfs_create_file(group_kobj, attr);
+
+ return (ret);
+}
+
static inline void
sysfs_remove_file(struct kobject *kobj, const struct attribute *attr)
{
@@ -155,6 +241,93 @@ sysfs_remove_file(struct kobject *kobj, const struct attribute *attr)
sysctl_remove_name(kobj->oidp, attr->name, 1, 1);
}
+static inline void
+sysfs_remove_file_from_group(struct kobject *kobj,
+ const struct attribute *attr, const char *group)
+{
+ struct kobject *group_kobj;
+
+ group_kobj = __sysfs_lookup_group(kobj, group);
+ if (group_kobj == NULL)
+ return;
+
+ sysfs_remove_file(group_kobj, attr);
+}
+
+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)
@@ -348,6 +521,24 @@ sysfs_emit_at(char *buf, int at, const char *fmt, ...)
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/time.h b/sys/compat/linuxkpi/common/include/linux/time.h
index 6c9a781d5e0e..ca77a20516ff 100644
--- a/sys/compat/linuxkpi/common/include/linux/time.h
+++ b/sys/compat/linuxkpi/common/include/linux/time.h
@@ -42,6 +42,8 @@
#include <linux/math64.h>
+typedef int64_t time64_t;
+
static inline struct timeval
ns_to_timeval(const int64_t nsec)
{
diff --git a/sys/compat/linuxkpi/common/include/linux/timer.h b/sys/compat/linuxkpi/common/include/linux/timer.h
index 8bea082c3e6c..a635f0faea59 100644
--- a/sys/compat/linuxkpi/common/include/linux/timer.h
+++ b/sys/compat/linuxkpi/common/include/linux/timer.h
@@ -42,7 +42,7 @@ struct timer_list {
void (*function_415) (struct timer_list *);
};
unsigned long data;
- int expires;
+ unsigned long expires;
};
extern unsigned long linux_timer_hz_mask;
@@ -76,7 +76,7 @@ extern unsigned long linux_timer_hz_mask;
callout_init(&(timer)->callout, 1); \
} while (0)
-extern int mod_timer(struct timer_list *, int);
+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 *);
@@ -86,7 +86,7 @@ extern int timer_shutdown_sync(struct timer_list *);
#define timer_pending(timer) callout_pending(&(timer)->callout)
#define round_jiffies(j) \
- ((int)(((j) + linux_timer_hz_mask) & ~linux_timer_hz_mask))
+ ((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)
diff --git a/sys/compat/linuxkpi/common/include/linux/topology.h b/sys/compat/linuxkpi/common/include/linux/topology.h
new file mode 100644
index 000000000000..16baffc024d1
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/topology.h
@@ -0,0 +1,35 @@
+/*-
+ * 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_TOPOLOGY_H_
+#define _LINUXKPI_LINUX_TOPOLOGY_H_
+
+#include <asm/topology.h>
+
+#endif /* _LINUXKPI_LINUX_TOPOLOGY_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/types.h b/sys/compat/linuxkpi/common/include/linux/types.h
index b11ce1cdd805..fcc455e5f731 100644
--- a/sys/compat/linuxkpi/common/include/linux/types.h
+++ b/sys/compat/linuxkpi/common/include/linux/types.h
@@ -63,6 +63,7 @@ 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;
diff --git a/sys/compat/linuxkpi/common/include/linux/wait.h b/sys/compat/linuxkpi/common/include/linux/wait.h
index 309c7816aa7b..03ddce2c06f5 100644
--- a/sys/compat/linuxkpi/common/include/linux/wait.h
+++ b/sys/compat/linuxkpi/common/include/linux/wait.h
@@ -61,12 +61,14 @@ 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; /* always 0 */
+ unsigned int flags;
void *private;
wait_queue_func_t *func;
union {
@@ -87,8 +89,14 @@ struct wait_queue_head {
* 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.
*/
-extern wait_queue_func_t autoremove_wake_function;
-extern wait_queue_func_t default_wake_function;
+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 = { \
@@ -138,7 +146,7 @@ void linux_wake_up(wait_queue_head_t *, unsigned int, int, bool);
#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 *, int,
+int linux_wait_event_common(wait_queue_head_t *, wait_queue_t *, long,
unsigned int, spinlock_t *);
/*
@@ -148,9 +156,9 @@ int linux_wait_event_common(wait_queue_head_t *, wait_queue_t *, int,
*/
#define __wait_event_common(wqh, cond, timeout, state, lock) ({ \
DEFINE_WAIT(__wq); \
- const int __timeout = ((int)(timeout)) < 1 ? 1 : (timeout); \
- int __start = ticks; \
- int __ret = 0; \
+ const long __timeout = ((long)(timeout)) < 1 ? 1 : (timeout); \
+ long __start = jiffies; \
+ long __ret = 0; \
\
for (;;) { \
linux_prepare_to_wait(&(wqh), &__wq, state); \
@@ -166,7 +174,7 @@ int linux_wait_event_common(wait_queue_head_t *, wait_queue_t *, int,
if (__ret == -EWOULDBLOCK) \
__ret = !!(cond); \
else if (__ret != -ERESTARTSYS) { \
- __ret = __timeout + __start - ticks; \
+ __ret = __timeout + __start - jiffies; \
/* range check return value */ \
if (__ret < 1) \
__ret = 1; \
@@ -284,7 +292,7 @@ void linux_finish_wait(wait_queue_head_t *, wait_queue_t *);
#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, 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);
diff --git a/sys/compat/linuxkpi/common/include/linux/workqueue.h b/sys/compat/linuxkpi/common/include/linux/workqueue.h
index 1c9df9fcb74d..66d3981d4229 100644
--- a/sys/compat/linuxkpi/common/include/linux/workqueue.h
+++ b/sys/compat/linuxkpi/common/include/linux/workqueue.h
@@ -90,7 +90,7 @@ struct delayed_work {
struct {
struct callout callout;
struct mtx mtx;
- int expires;
+ unsigned long expires;
} timer;
};
@@ -245,7 +245,7 @@ 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 delay);
+ 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 *);
@@ -258,4 +258,10 @@ 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_ */