diff options
Diffstat (limited to 'sys/compat/linuxkpi/common/include/linux')
97 files changed, 2927 insertions, 994 deletions
diff --git a/sys/compat/linuxkpi/common/include/linux/acpi.h b/sys/compat/linuxkpi/common/include/linux/acpi.h index 610aa0784cb9..3e1ec1b20626 100644 --- a/sys/compat/linuxkpi/common/include/linux/acpi.h +++ b/sys/compat/linuxkpi/common/include/linux/acpi.h @@ -39,6 +39,10 @@ #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 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/aperture.h b/sys/compat/linuxkpi/common/include/linux/aperture.h index e0387ed0225d..7eced3cc3cb1 100644 --- a/sys/compat/linuxkpi/common/include/linux/aperture.h +++ b/sys/compat/linuxkpi/common/include/linux/aperture.h @@ -16,7 +16,9 @@ int devm_aperture_acquire_for_platform_device(struct platform_device *pdev, resource_size_t size); int aperture_remove_conflicting_devices(resource_size_t base, resource_size_t size, - bool primary, const char *name); + 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 @@ -28,7 +30,12 @@ static inline int devm_aperture_acquire_for_platform_device(struct platform_devi } static inline int aperture_remove_conflicting_devices(resource_size_t base, resource_size_t size, - bool primary, const char *name) + const char *name) +{ + return 0; +} + +static inline int __aperture_remove_legacy_vga_devices(struct pci_dev *pdev) { return 0; } @@ -41,7 +48,6 @@ static inline int aperture_remove_conflicting_pci_devices(struct pci_dev *pdev, /** * aperture_remove_all_conflicting_devices - remove all existing framebuffers - * @primary: also kick vga16fb if present; only relevant for VGA devices * @name: a descriptive name of the requesting driver * * This function removes all graphics device drivers. Use this function on systems @@ -50,9 +56,9 @@ static inline int aperture_remove_conflicting_pci_devices(struct pci_dev *pdev, * Returns: * 0 on success, or a negative errno code otherwise */ -static inline int aperture_remove_all_conflicting_devices(bool primary, const char *name) +static inline int aperture_remove_all_conflicting_devices(const char *name) { - return aperture_remove_conflicting_devices(0, (resource_size_t)-1, primary, name); + return aperture_remove_conflicting_devices(0, (resource_size_t)-1, name); } #endif diff --git a/sys/compat/linuxkpi/common/include/linux/bitfield.h b/sys/compat/linuxkpi/common/include/linux/bitfield.h index a2020d247489..8a91b0663f37 100644 --- a/sys/compat/linuxkpi/common/include/linux/bitfield.h +++ b/sys/compat/linuxkpi/common/include/linux/bitfield.h @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2020 The FreeBSD Foundation + * Copyright (c) 2020-2024 The FreeBSD Foundation * * This software was developed by Björn Zeeb under sponsorship from * the FreeBSD Foundation. @@ -131,6 +131,10 @@ _uX_replace_bits(8) #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))) diff --git a/sys/compat/linuxkpi/common/include/linux/bitops.h b/sys/compat/linuxkpi/common/include/linux/bitops.h index 1415d5224084..bc776a0db9c4 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) (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) @@ -288,6 +288,15 @@ find_next_zero_bit(const unsigned long *addr, unsigned long size, #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) { diff --git a/sys/compat/linuxkpi/common/include/linux/cc_platform.h b/sys/compat/linuxkpi/common/include/linux/cc_platform.h index 01c0de17f7d2..1544c141614b 100644 --- a/sys/compat/linuxkpi/common/include/linux/cc_platform.h +++ b/sys/compat/linuxkpi/common/include/linux/cc_platform.h @@ -8,6 +8,7 @@ enum cc_attr { CC_ATTR_MEM_ENCRYPT, + CC_ATTR_GUEST_MEM_ENCRYPT, }; static inline bool 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/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/compiler.h b/sys/compat/linuxkpi/common/include/linux/compiler.h index d59e6faed12d..fb5ad3bf4fe4 100644 --- a/sys/compat/linuxkpi/common/include/linux/compiler.h +++ b/sys/compat/linuxkpi/common/include/linux/compiler.h @@ -48,7 +48,9 @@ #define __cond_lock(x,c) (c) #define __bitwise #define __devinitdata +#ifndef __deprecated #define __deprecated +#endif #define __init #define __initconst #define __devinit @@ -89,6 +91,10 @@ #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)) 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/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/debugfs.h b/sys/compat/linuxkpi/common/include/linux/debugfs.h index 470b50cb730c..4d146e085a7b 100644 --- a/sys/compat/linuxkpi/common/include/linux/debugfs.h +++ b/sys/compat/linuxkpi/common/include/linux/debugfs.h @@ -82,12 +82,16 @@ 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); @@ -111,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 668fe9cb8650..2556b0c45e49 100644 --- a/sys/compat/linuxkpi/common/include/linux/device.h +++ b/sys/compat/linuxkpi/common/include/linux/device.h @@ -57,7 +57,6 @@ struct device; struct class { const char *name; - struct module *owner; struct kobject kobj; devclass_t bsdclass; const struct dev_pm_ops *pm; @@ -91,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 { @@ -331,6 +332,13 @@ 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__) @@ -342,7 +350,12 @@ put_device(struct device *dev) kobject_put(&dev->kobj); } -struct class *class_create(struct module *owner, const char *name); +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) @@ -698,4 +711,8 @@ int lkpi_devm_add_action_or_reset(struct device *dev, void (*action)(void *), vo #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-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/efi.h b/sys/compat/linuxkpi/common/include/linux/efi.h index a485b4b1fd94..aa33371bd0e8 100644 --- a/sys/compat/linuxkpi/common/include/linux/efi.h +++ b/sys/compat/linuxkpi/common/include/linux/efi.h @@ -41,9 +41,6 @@ static inline bool __efi_enabled(int feature) { -#if defined(MODINFOMD_EFI_MAP) && !defined(__amd64__) - caddr_t kmdp; -#endif bool enabled = false; switch (feature) { @@ -52,10 +49,7 @@ __efi_enabled(int feature) /* Use cached value on amd64 */ enabled = efi_boot; #elif defined(MODINFOMD_EFI_MAP) - kmdp = preload_search_by_type("elf kernel"); - if (kmdp == NULL) - kmdp = preload_search_by_type("elf64 kernel"); - enabled = preload_search_info(kmdp, + enabled = preload_search_info(preload_kmdp, MODINFO_METADATA | MODINFOMD_EFI_MAP) != NULL; #endif break; diff --git a/sys/compat/linuxkpi/common/include/linux/errno.h b/sys/compat/linuxkpi/common/include/linux/errno.h index ea258587c6f7..d634675d43d0 100644 --- a/sys/compat/linuxkpi/common/include/linux/errno.h +++ b/sys/compat/linuxkpi/common/include/linux/errno.h @@ -68,5 +68,6 @@ #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 index 89cd4c8e0ba0..1f2d6cf22d7e 100644 --- a/sys/compat/linuxkpi/common/include/linux/etherdevice.h +++ b/sys/compat/linuxkpi/common/include/linux/etherdevice.h @@ -53,19 +53,27 @@ struct ethtool_modinfo { static inline bool is_zero_ether_addr(const u8 * addr) { - return ((addr[0] + addr[1] + addr[2] + addr[3] + addr[4] + addr[5]) == 0x00); + 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 (0x01 & addr[0]); + 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]) == (6 * 0xff)); + return ((addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) == + 0xff); } static inline bool diff --git a/sys/compat/linuxkpi/common/include/linux/file.h b/sys/compat/linuxkpi/common/include/linux/file.h index f94e3d89ced1..f6e988c2d88e 100644 --- a/sys/compat/linuxkpi/common/include/linux/file.h +++ b/sys/compat/linuxkpi/common/include/linux/file.h @@ -43,7 +43,7 @@ struct linux_file; #undef file -extern struct fileops linuxfileops; +extern const struct fileops linuxfileops; static inline struct linux_file * linux_fget(unsigned int fd) diff --git a/sys/compat/linuxkpi/common/include/linux/fs.h b/sys/compat/linuxkpi/common/include/linux/fs.h index a28d5bf97121..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); @@ -264,12 +269,18 @@ get_file(struct linux_file *f) 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) @@ -353,9 +364,8 @@ 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 *read_pos = ((char *) orig) + *ppos; + void *p, *read_pos = ((char *) orig) + *ppos; size_t buf_remain = buf_size - *ppos; - ssize_t num_read; if (buf_remain < 0 || buf_remain > buf_size) return -EINVAL; @@ -363,18 +373,23 @@ simple_read_from_buffer(void __user *dest, size_t read_size, loff_t *ppos, if (read_size > buf_remain) read_size = buf_remain; - /* copy_to_user returns number of bytes NOT read */ - num_read = read_size - copy_to_user(dest, read_pos, read_size); - if (num_read == 0) - return -EFAULT; - *ppos += num_read; - - return (num_read); + /* + * 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) \ +#define __DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt, __wrfunc)\ static inline int \ __fops ## _open(struct inode *inode, struct file *filp) \ { \ @@ -385,10 +400,15 @@ static const struct file_operations __fops = { \ .open = __fops ## _open, \ .release = simple_attr_release, \ .read = simple_attr_read, \ - .write = simple_attr_write, \ + .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); @@ -399,4 +419,7 @@ ssize_t simple_attr_read(struct file *filp, char *buf, size_t read_size, loff_t 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/gfp.h b/sys/compat/linuxkpi/common/include/linux/gfp.h index f6cce379924d..4c4caa621789 100644 --- a/sys/compat/linuxkpi/common/include/linux/gfp.h +++ b/sys/compat/linuxkpi/common/include/linux/gfp.h @@ -43,7 +43,6 @@ #define __GFP_NOWARN 0 #define __GFP_HIGHMEM 0 #define __GFP_ZERO M_ZERO -#define __GFP_NORETRY 0 #define __GFP_NOMEMALLOC 0 #define __GFP_RECLAIM 0 #define __GFP_RECLAIMABLE 0 @@ -57,7 +56,8 @@ #define __GFP_KSWAPD_RECLAIM 0 #define __GFP_WAIT M_WAITOK #define __GFP_DMA32 (1U << 24) /* LinuxKPI only */ -#define __GFP_BITS_SHIFT 25 +#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 @@ -85,19 +85,10 @@ struct page_frag_cache { }; /* - * Resolve a page into a virtual address: - * - * NOTE: This function only works for pages allocated by the kernel. - */ -extern void *linux_page_address(struct page *); - -#define page_address(page) linux_page_address(page) - -/* * Page management for unmapped pages: */ -extern struct page *linux_alloc_pages(gfp_t flags, unsigned int order); -extern void linux_free_pages(struct page *page, unsigned int order); +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); @@ -143,11 +134,13 @@ 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: */ -extern vm_offset_t linux_alloc_kmem(gfp_t flags, unsigned int order); -extern void linux_free_kmem(vm_offset_t, unsigned int order); +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) 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/hdmi.h b/sys/compat/linuxkpi/common/include/linux/hdmi.h index c8ec982ff498..e07578167d69 100644 --- a/sys/compat/linuxkpi/common/include/linux/hdmi.h +++ b/sys/compat/linuxkpi/common/include/linux/hdmi.h @@ -170,19 +170,19 @@ 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; - bool itc; 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 char pixel_repeat; unsigned short top_bar; unsigned short bottom_bar; unsigned short left_bar; @@ -336,7 +336,14 @@ 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(struct hdmi_audio_infoframe *frame); +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, diff --git a/sys/compat/linuxkpi/common/include/linux/highmem.h b/sys/compat/linuxkpi/common/include/linux/highmem.h index f770bef6b3b7..58a9cdcdf60f 100644 --- a/sys/compat/linuxkpi/common/include/linux/highmem.h +++ b/sys/compat/linuxkpi/common/include/linux/highmem.h @@ -43,6 +43,7 @@ #include <vm/vm_page.h> #include <vm/pmap.h> +#include <linux/mm.h> #include <linux/page.h> #define PageHighMem(p) (0) @@ -78,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)); @@ -94,6 +93,12 @@ kmap_atomic(struct page *page) } 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) { @@ -132,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 ca3f8171ff44..535d8ce07fb4 100644 --- a/sys/compat/linuxkpi/common/include/linux/idr.h +++ b/sys/compat/linuxkpi/common/include/linux/idr.h @@ -34,6 +34,8 @@ #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 diff --git a/sys/compat/linuxkpi/common/include/linux/ieee80211.h b/sys/compat/linuxkpi/common/include/linux/ieee80211.h index 2000e7480ff8..3644ef80861b 100644 --- a/sys/compat/linuxkpi/common/include/linux/ieee80211.h +++ b/sys/compat/linuxkpi/common/include/linux/ieee80211.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2020-2023 The FreeBSD Foundation + * Copyright (c) 2020-2025 The FreeBSD Foundation * * This software was developed by Björn Zeeb under sponsorship from * the FreeBSD Foundation. @@ -33,9 +33,18 @@ #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 { @@ -55,6 +64,7 @@ struct ieee80211_mmie_16 { #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 @@ -91,7 +101,9 @@ struct ieee80211_mmie_16 { #define IEEE80211_QOS_CTL_ACK_POLICY_NOACK 0x0020 #define IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT 0x0100 -#define IEEE80211_RATE_SHORT_PREAMBLE BIT(0) +enum ieee80211_rate_flags { + IEEE80211_RATE_SHORT_PREAMBLE = BIT(0), +}; enum ieee80211_rate_control_changed_flags { IEEE80211_RC_BW_CHANGED = BIT(0), @@ -106,7 +118,8 @@ enum ieee80211_rate_control_changed_flags { #define IEEE80211_TKIP_ICV_LEN 4 #define IEEE80211_TKIP_IV_LEN 8 /* WEP + KID + EXT */ -#define IEEE80211_VHT_EXT_NSS_BW_CAPABLE (1 << 13) /* assigned to tx_highest */ +/* 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 */ @@ -125,19 +138,23 @@ enum wlan_ht_cap_sm_ps { WLAN_HT_CAP_SM_PS_DISABLED, }; -#define WLAN_MAX_KEY_LEN 32 /* TODO FIXME brcmfmac */ -#define WLAN_PMKID_LEN 16 /* TODO FIXME brcmfmac */ - -#define WLAN_KEY_LEN_WEP40 5 -#define WLAN_KEY_LEN_WEP104 13 -#define WLAN_KEY_LEN_TKIP 32 -#define WLAN_KEY_LEN_CCMP 16 -#define WLAN_KEY_LEN_GCMP 16 -#define WLAN_KEY_LEN_AES_CMAC 16 -#define WLAN_KEY_LEN_GCMP_256 32 -#define WLAN_KEY_LEN_BIP_CMAC_256 32 -#define WLAN_KEY_LEN_BIP_GMAC_128 16 -#define WLAN_KEY_LEN_BIP_GMAC_256 32 +#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 { @@ -178,6 +195,7 @@ enum ieee80211_min_mpdu_start_spacing { #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? */ @@ -254,20 +272,20 @@ enum ieee80211_ac_numbers { #define IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL 0xf -/* XXX net80211 calls these IEEE80211_HTCAP_* */ -#define IEEE80211_HT_CAP_LDPC_CODING 0x0001 /* IEEE80211_HTCAP_LDPC */ -#define IEEE80211_HT_CAP_SUP_WIDTH_20_40 0x0002 /* IEEE80211_HTCAP_CHWIDTH40 */ -#define IEEE80211_HT_CAP_SM_PS 0x000c /* IEEE80211_HTCAP_SMPS */ +/* 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 0x0010 /* IEEE80211_HTCAP_GREENFIELD */ -#define IEEE80211_HT_CAP_SGI_20 0x0020 /* IEEE80211_HTCAP_SHORTGI20 */ -#define IEEE80211_HT_CAP_SGI_40 0x0040 /* IEEE80211_HTCAP_SHORTGI40 */ -#define IEEE80211_HT_CAP_TX_STBC 0x0080 /* IEEE80211_HTCAP_TXSTBC */ -#define IEEE80211_HT_CAP_RX_STBC 0x0100 /* IEEE80211_HTCAP_RXSTBC */ -#define IEEE80211_HT_CAP_RX_STBC_SHIFT 8 /* IEEE80211_HTCAP_RXSTBC_S */ -#define IEEE80211_HT_CAP_MAX_AMSDU 0x0800 /* IEEE80211_HTCAP_MAXAMSDU */ -#define IEEE80211_HT_CAP_DSSSCCK40 0x1000 /* IEEE80211_HTCAP_DSSSCCK40 */ -#define IEEE80211_HT_CAP_LSIG_TXOP_PROT 0x8000 /* IEEE80211_HTCAP_LSIGTXOPPROT */ +#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 @@ -277,13 +295,16 @@ 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 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 { @@ -293,7 +314,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 @@ -328,6 +349,8 @@ enum ieee80211_chanctx_change_flags { 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 { @@ -371,14 +394,6 @@ enum ieee80211_sta_state { IEEE80211_STA_AUTHORIZED = 4, /* 802.1x */ }; -enum ieee80211_sta_rx_bw { - IEEE80211_STA_RX_BW_20, - IEEE80211_STA_RX_BW_40, - IEEE80211_STA_RX_BW_80, - IEEE80211_STA_RX_BW_160, - IEEE80211_STA_RX_BW_320, -}; - enum ieee80211_tx_info_flags { /* XXX TODO .. right shift numbers - not sure where that came from? */ IEEE80211_TX_CTL_AMPDU = BIT(0), @@ -402,7 +417,7 @@ enum ieee80211_tx_info_flags { 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), @@ -413,6 +428,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. */ }; @@ -469,9 +485,14 @@ 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 */ @@ -490,6 +511,12 @@ struct ieee80211_mgmt { 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]; @@ -543,6 +570,7 @@ struct ieee80211_mgmt { } wnm_timing_msr; } u; } action; + DECLARE_FLEX_ARRAY(uint8_t, body); } u; }; @@ -567,6 +595,8 @@ struct ieee80211_rts { /* net80211::ieee80211_frame_rts */ #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) @@ -584,6 +614,7 @@ enum ieee80211_eid { 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 */ @@ -595,6 +626,7 @@ enum ieee80211_eid { 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 */ }; @@ -640,10 +672,10 @@ struct ieee80211_trigger { /* 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-BAR = 0x2, MU-RTS = 0x3, BSRP = 0x4, GCR MU-BAR = 0x5, @@ -654,6 +686,12 @@ enum { 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) @@ -694,12 +732,74 @@ struct ieee80211_bssid_index { int bssid_index; }; -enum ieee80211_reg_ap_power { +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) @@ -800,4 +900,346 @@ ieee80211_is_trigger(__le16 fc) 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_ether.h b/sys/compat/linuxkpi/common/include/linux/if_ether.h index 3735ad2f5527..6676e8fc142f 100644 --- a/sys/compat/linuxkpi/common/include/linux/if_ether.h +++ b/sys/compat/linuxkpi/common/include/linux/if_ether.h @@ -34,6 +34,7 @@ #define _LINUXKPI_LINUX_IF_ETHER_H_ #include <linux/types.h> +#include <linux/skbuff.h> #include <net/ethernet.h> @@ -69,4 +70,13 @@ struct ethhdr { 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/interrupt.h b/sys/compat/linuxkpi/common/include/linux/interrupt.h index d5f9a0ae7a47..dfd9816da8be 100644 --- a/sys/compat/linuxkpi/common/include/linux/interrupt.h +++ b/sys/compat/linuxkpi/common/include/linux/interrupt.h @@ -133,7 +133,7 @@ irq_set_affinity_hint(int vector, const cpumask_t *mask) int error; if (mask != NULL) - error = intr_setaffinity(vector, CPU_WHICH_IRQ, __DECONST(cpumask_t *, mask)); + error = intr_setaffinity(vector, CPU_WHICH_IRQ, mask); else error = intr_setaffinity(vector, CPU_WHICH_IRQ, cpuset_root); diff --git a/sys/compat/linuxkpi/common/include/linux/io.h b/sys/compat/linuxkpi/common/include/linux/io.h index bce70ed0cb8d..2d6fef4e7c52 100644 --- a/sys/compat/linuxkpi/common/include/linux/io.h +++ b/sys/compat/linuxkpi/common/include/linux/io.h @@ -36,6 +36,7 @@ #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> @@ -395,11 +396,7 @@ iowrite32be(uint32_t v, volatile void *addr) #define iowrite32be(v, addr) iowrite32be(v, addr) #if defined(__i386__) || defined(__amd64__) -static inline void -_outb(u_char data, u_int port) -{ - __asm __volatile("outb %0, %w1" : : "a" (data), "Nd" (port)); -} +#define _outb(data, port) outb((data), (port)) #endif #if defined(__i386__) || defined(__amd64__) || defined(__powerpc__) || defined(__aarch64__) || defined(__riscv) @@ -541,30 +538,29 @@ void lkpi_arch_phys_wc_del(int); #define arch_phys_wc_index(x) \ (((x) < __MTRR_ID_BASE) ? -1 : ((x) - __MTRR_ID_BASE)) -#if defined(__amd64__) || defined(__i386__) || defined(__aarch64__) || defined(__powerpc__) || defined(__riscv) 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); - -#ifdef VM_MEMATTR_WRITE_COMBINING return (-pmap_change_attr(va, size, VM_MEMATTR_WRITE_COMBINING)); #else - return (-pmap_change_attr(va, size, VM_MEMATTR_UNCACHEABLE)); + 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/jiffies.h b/sys/compat/linuxkpi/common/include/linux/jiffies.h index d5cb6e14860e..c2409726e874 100644 --- a/sys/compat/linuxkpi/common/include/linux/jiffies.h +++ b/sys/compat/linuxkpi/common/include/linux/jiffies.h @@ -32,26 +32,27 @@ #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)) #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 @@ -67,20 +68,7 @@ extern uint64_t lkpi_msec2hz_rem; extern uint64_t lkpi_msec2hz_div; extern uint64_t lkpi_msec2hz_max; -static inline int -timespec_to_jiffies(const struct timespec *ts) -{ - u64 result; - - result = ((u64)hz * ts->tv_sec) + - (((u64)hz * ts->tv_nsec + NSEC_PER_SEC - 1) / NSEC_PER_SEC); - if (result > MAX_JIFFY_OFFSET) - result = MAX_JIFFY_OFFSET; - - return ((int)result); -} - -static inline int +static inline unsigned long msecs_to_jiffies(uint64_t msec) { uint64_t result; @@ -91,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; @@ -105,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 @@ -132,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/kernel.h b/sys/compat/linuxkpi/common/include/linux/kernel.h index ed4320e80fa7..11a13cbd49b4 100644 --- a/sys/compat/linuxkpi/common/include/linux/kernel.h +++ b/sys/compat/linuxkpi/common/include/linux/kernel.h @@ -44,10 +44,12 @@ #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/sched.h> #include <linux/types.h> #include <linux/typecheck.h> #include <linux/jiffies.h> @@ -123,10 +125,7 @@ extern int linuxkpi_warn_dump_stack; #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 DIV_ROUND_UP(x, n) howmany(x, n) #define __KERNEL_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)) * (n)) #define FIELD_SIZEOF(t, f) sizeof(((t *)0)->f) #define printk(...) printf(__VA_ARGS__) @@ -270,286 +269,9 @@ extern int linuxkpi_debug; #define _RET_IP_ __builtin_return_address(0) -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, u8 *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 != (u8)temp) - return (-ERANGE); - return (0); -} - -static inline int -kstrtou16(const char *cp, unsigned int base, u16 *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 != (u16)temp) - return (-ERANGE); - return (0); -} - -static inline int -kstrtou32(const char *cp, unsigned int base, u32 *res) -{ - - return (kstrtouint(cp, base, 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, (u64 *)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, - u8 *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)); -} - -#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_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 offsetofend(t, m) \ (offsetof(t, m) + sizeof((((t *)0)->m))) -#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) - -/* - * 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 smp_processor_id() PCPU_GET(cpuid) #define num_possible_cpus() mp_ncpus #define num_online_cpus() mp_ncpus @@ -559,31 +281,6 @@ extern bool linux_cpu_has_clflush; #define cpu_has_clflush linux_cpu_has_clflush #endif -/* Swap values of a and b */ -#define swap(a, b) do { \ - typeof(a) _swap_tmp = a; \ - a = b; \ - b = _swap_tmp; \ -} while (0) - -#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; \ -}) - -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)); -} - typedef struct linux_ratelimit { struct timeval lasttime; int counter; @@ -644,7 +341,7 @@ static inline bool mac_pton(const char *macin, uint8_t *macout) { const char *s, *d; - uint8_t mac[6], hx, lx;; + uint8_t mac[6], hx, lx; int i; if (strlen(macin) < (3 * 6 - 1)) 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/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/kref.h b/sys/compat/linuxkpi/common/include/linux/kref.h index 47d61c9ee316..b2fba468f7df 100644 --- a/sys/compat/linuxkpi/common/include/linux/kref.h +++ b/sys/compat/linuxkpi/common/include/linux/kref.h @@ -41,8 +41,7 @@ #include <asm/atomic.h> struct kref { - /* XXX In Linux this is a refcount_t */ - atomic_t refcount; + refcount_t refcount; }; static inline void 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/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/list.h b/sys/compat/linuxkpi/common/include/linux/list.h index eecb517d780e..a6c74a324dac 100644 --- a/sys/compat/linuxkpi/common/include/linux/list.h +++ b/sys/compat/linuxkpi/common/include/linux/list.h @@ -234,6 +234,11 @@ list_del_init(struct list_head *entry) 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) { diff --git a/sys/compat/linuxkpi/common/include/linux/lockdep.h b/sys/compat/linuxkpi/common/include/linux/lockdep.h index a379e191aad7..93fe445f7057 100644 --- a/sys/compat/linuxkpi/common/include/linux/lockdep.h +++ b/sys/compat/linuxkpi/common/include/linux/lockdep.h @@ -30,6 +30,7 @@ #ifndef _LINUXKPI_LINUX_LOCKDEP_H_ #define _LINUXKPI_LINUX_LOCKDEP_H_ +#include <sys/systm.h> #include <sys/types.h> #include <sys/lock.h> @@ -50,8 +51,8 @@ struct pin_cookie { #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(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); \ @@ -70,17 +71,6 @@ struct pin_cookie { #define lockdep_assert_none_held_once() do { } while (0) -static __inline bool -lockdep_is_held(void *__m) -{ - struct lock_object *__lock; - struct thread *__td; - - __lock = __m; - return (LOCK_CLASS(__lock)->lc_owner(__lock, &__td) != 0); -} -#define lockdep_is_held_type(_m, _t) lockdep_is_held(_m) - #else #define lockdep_assert(cond) do { } while (0) #define lockdep_assert_once(cond) do { } while (0) @@ -91,10 +81,23 @@ lockdep_is_held(void *__m) #define lockdep_assert_held_once(m) do { (void)(m); } while (0) -#define lockdep_is_held(m) 1 -#define lockdep_is_held_type(_m, _t) 1 #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) diff --git a/sys/compat/linuxkpi/common/include/linux/log2.h b/sys/compat/linuxkpi/common/include/linux/log2.h index 27e91a8bdbe0..660e9adb6fa9 100644 --- a/sys/compat/linuxkpi/common/include/linux/log2.h +++ b/sys/compat/linuxkpi/common/include/linux/log2.h @@ -33,97 +33,9 @@ #include <sys/libkern.h> -static inline unsigned long -roundup_pow_of_two(unsigned long x) -{ - return (1UL << flsl(x - 1)); -} - -static inline int -is_power_of_2(unsigned long n) -{ - return (n == roundup_pow_of_two(n)); -} - -static inline unsigned long -rounddown_pow_of_two(unsigned long x) -{ - return (1UL << (flsl(x) - 1)); -} - -#define ilog2(n) \ -( \ - __builtin_constant_p(n) ? ( \ - (n) < 1 ? -1 : \ - (n) & (1ULL << 63) ? 63 : \ - (n) & (1ULL << 62) ? 62 : \ - (n) & (1ULL << 61) ? 61 : \ - (n) & (1ULL << 60) ? 60 : \ - (n) & (1ULL << 59) ? 59 : \ - (n) & (1ULL << 58) ? 58 : \ - (n) & (1ULL << 57) ? 57 : \ - (n) & (1ULL << 56) ? 56 : \ - (n) & (1ULL << 55) ? 55 : \ - (n) & (1ULL << 54) ? 54 : \ - (n) & (1ULL << 53) ? 53 : \ - (n) & (1ULL << 52) ? 52 : \ - (n) & (1ULL << 51) ? 51 : \ - (n) & (1ULL << 50) ? 50 : \ - (n) & (1ULL << 49) ? 49 : \ - (n) & (1ULL << 48) ? 48 : \ - (n) & (1ULL << 47) ? 47 : \ - (n) & (1ULL << 46) ? 46 : \ - (n) & (1ULL << 45) ? 45 : \ - (n) & (1ULL << 44) ? 44 : \ - (n) & (1ULL << 43) ? 43 : \ - (n) & (1ULL << 42) ? 42 : \ - (n) & (1ULL << 41) ? 41 : \ - (n) & (1ULL << 40) ? 40 : \ - (n) & (1ULL << 39) ? 39 : \ - (n) & (1ULL << 38) ? 38 : \ - (n) & (1ULL << 37) ? 37 : \ - (n) & (1ULL << 36) ? 36 : \ - (n) & (1ULL << 35) ? 35 : \ - (n) & (1ULL << 34) ? 34 : \ - (n) & (1ULL << 33) ? 33 : \ - (n) & (1ULL << 32) ? 32 : \ - (n) & (1ULL << 31) ? 31 : \ - (n) & (1ULL << 30) ? 30 : \ - (n) & (1ULL << 29) ? 29 : \ - (n) & (1ULL << 28) ? 28 : \ - (n) & (1ULL << 27) ? 27 : \ - (n) & (1ULL << 26) ? 26 : \ - (n) & (1ULL << 25) ? 25 : \ - (n) & (1ULL << 24) ? 24 : \ - (n) & (1ULL << 23) ? 23 : \ - (n) & (1ULL << 22) ? 22 : \ - (n) & (1ULL << 21) ? 21 : \ - (n) & (1ULL << 20) ? 20 : \ - (n) & (1ULL << 19) ? 19 : \ - (n) & (1ULL << 18) ? 18 : \ - (n) & (1ULL << 17) ? 17 : \ - (n) & (1ULL << 16) ? 16 : \ - (n) & (1ULL << 15) ? 15 : \ - (n) & (1ULL << 14) ? 14 : \ - (n) & (1ULL << 13) ? 13 : \ - (n) & (1ULL << 12) ? 12 : \ - (n) & (1ULL << 11) ? 11 : \ - (n) & (1ULL << 10) ? 10 : \ - (n) & (1ULL << 9) ? 9 : \ - (n) & (1ULL << 8) ? 8 : \ - (n) & (1ULL << 7) ? 7 : \ - (n) & (1ULL << 6) ? 6 : \ - (n) & (1ULL << 5) ? 5 : \ - (n) & (1ULL << 4) ? 4 : \ - (n) & (1ULL << 3) ? 3 : \ - (n) & (1ULL << 2) ? 2 : \ - (n) & (1ULL << 1) ? 1 : \ - (n) & (1ULL << 0) ? 0 : \ - -1) : \ - (sizeof(n) <= 4) ? \ - fls((u32)(n)) - 1 : flsll((u64)(n)) - 1 \ -) - -#define order_base_2(x) ilog2(roundup_pow_of_two(x)) +#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 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/mhi.h b/sys/compat/linuxkpi/common/include/linux/mhi.h index 2e0b74f29def..24b3205d6f5a 100644 --- a/sys/compat/linuxkpi/common/include/linux/mhi.h +++ b/sys/compat/linuxkpi/common/include/linux/mhi.h @@ -75,6 +75,8 @@ struct mhi_controller { void *regs; int *irq; const char *fw_image; + const u8 *fw_data; + size_t fw_sz; bool fbc_download; size_t rddm_size; 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/mm.h b/sys/compat/linuxkpi/common/include/linux/mm.h index 109bfffe7d6a..156b00a0c0f0 100644 --- a/sys/compat/linuxkpi/common/include/linux/mm.h +++ b/sys/compat/linuxkpi/common/include/linux/mm.h @@ -35,6 +35,7 @@ #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> @@ -160,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. @@ -178,6 +187,14 @@ get_order(unsigned long size) 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) { @@ -266,18 +283,65 @@ get_page(struct page *page) vm_page_wire(page); } -extern long -get_user_pages(unsigned long start, unsigned long nr_pages, - unsigned int gup_flags, struct page **, - struct vm_area_struct **); +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); + 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, @@ -307,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) @@ -348,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); @@ -388,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/mmzone.h b/sys/compat/linuxkpi/common/include/linux/mmzone.h index 49cc218c6fce..57d3dcac9597 100644 --- a/sys/compat/linuxkpi/common/include/linux/mmzone.h +++ b/sys/compat/linuxkpi/common/include/linux/mmzone.h @@ -4,8 +4,12 @@ #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/module.h b/sys/compat/linuxkpi/common/include/linux/module.h index 9d98ef7cf3db..079dacf8df6c 100644 --- a/sys/compat/linuxkpi/common/include/linux/module.h +++ b/sys/compat/linuxkpi/common/include/linux/module.h @@ -32,6 +32,8 @@ #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> @@ -51,7 +53,26 @@ #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) 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/netdevice.h b/sys/compat/linuxkpi/common/include/linux/netdevice.h index 3d2b309909b4..cd7d23077a62 100644 --- a/sys/compat/linuxkpi/common/include/linux/netdevice.h +++ b/sys/compat/linuxkpi/common/include/linux/netdevice.h @@ -75,6 +75,10 @@ struct wireless_dev; /* net/cfg80211.h */ #define NET_NAME_UNKNOWN 0 +enum net_addr_assign_type { + NET_ADDR_RANDOM, +}; + enum netdev_tx { NETDEV_TX_OK = 0, }; @@ -95,6 +99,10 @@ enum net_device_reg_state { 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 *); @@ -122,6 +130,7 @@ struct net_device { 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; @@ -457,6 +466,8 @@ 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) diff --git a/sys/compat/linuxkpi/common/include/linux/nl80211.h b/sys/compat/linuxkpi/common/include/linux/nl80211.h index 5b43ff675e19..f3979d3a2abc 100644 --- a/sys/compat/linuxkpi/common/include/linux/nl80211.h +++ b/sys/compat/linuxkpi/common/include/linux/nl80211.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2020-2023 The FreeBSD Foundation + * Copyright (c) 2020-2024 The FreeBSD Foundation * * This software was developed by Björn Zeeb under sponsorship from * the FreeBSD Foundation. @@ -80,6 +80,11 @@ enum nl80211_reg_rule_flags { 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) @@ -128,11 +133,13 @@ enum nl80211_band { /* Keep this last. */ NUM_NL80211_BANDS -}; +} __packed; -enum nl80211_chan_flags { - /* XXX TODO */ +enum nl80211_channel_type { NL80211_CHAN_NO_HT, + NL80211_CHAN_HT20, + NL80211_CHAN_HT40PLUS, + NL80211_CHAN_HT40MINUS, }; enum nl80211_chan_width { @@ -183,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 { @@ -230,17 +235,26 @@ enum nl80211_ext_feature { 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, @@ -416,6 +430,13 @@ 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 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/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/page.h b/sys/compat/linuxkpi/common/include/linux/page.h index aa5acac4f5fe..37ab593a64e9 100644 --- a/sys/compat/linuxkpi/common/include/linux/page.h +++ b/sys/compat/linuxkpi/common/include/linux/page.h @@ -72,6 +72,7 @@ pgprot2cachemode(pgprot_t prot) 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)) 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 be3b13f07e53..af19829f1cbb 100644 --- a/sys/compat/linuxkpi/common/include/linux/pci.h +++ b/sys/compat/linuxkpi/common/include/linux/pci.h @@ -36,6 +36,7 @@ #define CONFIG_PCI_MSI #include <linux/types.h> +#include <linux/device/driver.h> #include <sys/param.h> #include <sys/bus.h> @@ -59,6 +60,8 @@ #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; @@ -69,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) \ \ @@ -82,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 @@ -113,6 +119,10 @@ MODULE_PNP_INFO("U32:vendor;U32:device;V32:subvendor;V32:subdevice", \ #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 @@ -223,6 +233,8 @@ typedef int pci_power_t; 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 @@ -232,10 +244,14 @@ extern const char *pci_power_names[6]; #define PCI_L1SS_CTL1 0x8 #define PCI_L1SS_CTL1_L1SS_MASK 0xf -#define PCI_IRQ_LEGACY 0x01 +#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_LEGACY) +#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; @@ -274,24 +290,8 @@ extern spinlock_t pci_lock; #define __devexit_p(x) x -#define module_pci_driver(_driver) \ - \ -static inline int \ -_pci_init(void) \ -{ \ - \ - return (linux_pci_register_driver(&_driver)); \ -} \ - \ -static inline void \ -_pci_exit(void) \ -{ \ - \ - linux_pci_unregister_driver(&_driver); \ -} \ - \ -module_init(_pci_init); \ -module_exit(_pci_exit) +#define module_pci_driver(_drv) \ + module_driver(_drv, linux_pci_register_driver, linux_pci_unregister_driver) struct msi_msg { uint32_t data; @@ -362,6 +362,8 @@ 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, @@ -380,6 +382,11 @@ 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) { @@ -521,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); @@ -774,6 +794,8 @@ 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) @@ -1268,6 +1290,29 @@ pci_dev_present(const struct pci_device_id *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) \ @@ -1336,6 +1381,9 @@ pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn, int pos, 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) /* -------------------------------------------------------------------------- */ @@ -1478,4 +1526,12 @@ pci_irq_vector(struct pci_dev *pdev, unsigned int 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 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/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/pm.h b/sys/compat/linuxkpi/common/include/linux/pm.h index 871c7b587864..c8d943027909 100644 --- a/sys/compat/linuxkpi/common/include/linux/pm.h +++ b/sys/compat/linuxkpi/common/include/linux/pm.h @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2020 The FreeBSD Foundation + * Copyright (c) 2020-2024 The FreeBSD Foundation * * This software was developed by Björn Zeeb under sponsorship from * the FreeBSD Foundation. @@ -58,25 +58,26 @@ struct dev_pm_info { 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 = { \ - .suspend = _suspendfunc, \ - .resume = _resumefunc, \ - .freeze = _suspendfunc, \ - .thaw = _resumefunc, \ - .poweroff = _suspendfunc, \ - .restore = _resumefunc, \ + __SET_PM_OPS(_suspendfunc, _resumefunc) \ } #define DEFINE_SIMPLE_DEV_PM_OPS(_name, _suspendfunc, _resumefunc) \ const struct dev_pm_ops _name = { \ - .suspend = _suspendfunc, \ - .resume = _resumefunc, \ - .freeze = _suspendfunc, \ - .thaw = _resumefunc, \ - .poweroff = _suspendfunc, \ - .restore = _resumefunc, \ + __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 = { \ @@ -86,6 +87,9 @@ 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) { 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 933d5aa6f94a..da9d45122d4d 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 @@ -125,4 +87,11 @@ print_hex_dump_bytes(const char *prefix_str, const int prefix_type, #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/pwm.h b/sys/compat/linuxkpi/common/include/linux/pwm.h index 59a17f525c91..c0740db675e8 100644 --- a/sys/compat/linuxkpi/common/include/linux/pwm.h +++ b/sys/compat/linuxkpi/common/include/linux/pwm.h @@ -91,4 +91,10 @@ 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/radix-tree.h b/sys/compat/linuxkpi/common/include/linux/radix-tree.h index a1204cb20a79..ea75836c26fb 100644 --- a/sys/compat/linuxkpi/common/include/linux/radix-tree.h +++ b/sys/compat/linuxkpi/common/include/linux/radix-tree.h @@ -29,6 +29,7 @@ #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 diff --git a/sys/compat/linuxkpi/common/include/linux/random.h b/sys/compat/linuxkpi/common/include/linux/random.h index 808c5bc55974..893ee2b7b728 100644 --- a/sys/compat/linuxkpi/common/include/linux/random.h +++ b/sys/compat/linuxkpi/common/include/linux/random.h @@ -54,6 +54,15 @@ get_random_int(void) 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() /* diff --git a/sys/compat/linuxkpi/common/include/linux/rbtree.h b/sys/compat/linuxkpi/common/include/linux/rbtree.h index 78bf938eb000..e6033cfd760d 100644 --- a/sys/compat/linuxkpi/common/include/linux/rbtree.h +++ b/sys/compat/linuxkpi/common/include/linux/rbtree.h @@ -175,6 +175,30 @@ rb_replace_node_cached(struct rb_node *old, struct rb_node *new, 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 } diff --git a/sys/compat/linuxkpi/common/include/linux/rcupdate.h b/sys/compat/linuxkpi/common/include/linux/rcupdate.h index 95332217f8f5..85d766c8dbc9 100644 --- a/sys/compat/linuxkpi/common/include/linux/rcupdate.h +++ b/sys/compat/linuxkpi/common/include/linux/rcupdate.h @@ -1,6 +1,10 @@ /*- * 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 @@ -26,11 +30,20 @@ #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 */ @@ -61,6 +74,9 @@ 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) @@ -79,14 +95,34 @@ #define rcu_access_pointer(p) \ ((__typeof(*p) *)READ_ONCE(p)) -#define rcu_dereference_protected(p, c) \ +#define rcu_dereference(p) \ ((__typeof(*p) *)READ_ONCE(p)) -#define rcu_dereference(p) \ - rcu_dereference_protected(p, 0) +#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_protected(p, c) +#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)) @@ -113,11 +149,12 @@ /* prototypes */ -extern void linux_call_rcu(unsigned type, struct rcu_head *ptr, rcu_callback_t func); -extern void linux_rcu_barrier(unsigned type); -extern void linux_rcu_read_lock(unsigned type); -extern void linux_rcu_read_unlock(unsigned type); -extern void linux_synchronize_rcu(unsigned type); +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(...) 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 61947485945d..02a7eda3f4a9 100644 --- a/sys/compat/linuxkpi/common/include/linux/refcount.h +++ b/sys/compat/linuxkpi/common/include/linux/refcount.h @@ -31,58 +31,51 @@ #include <linux/atomic.h> -struct refcount_linux { - atomic_t value; -}; -typedef struct refcount_linux refcount_t; +typedef atomic_t refcount_t; static inline void refcount_set(refcount_t *ref, unsigned int i) { - atomic_set(&ref->value, i); + atomic_set(ref, i); } static inline void refcount_inc(refcount_t *ref) { - atomic_inc(&ref->value); + atomic_inc(ref); } static inline bool refcount_inc_not_zero(refcount_t *ref) { - return (atomic_inc_not_zero(&ref->value)); + return (atomic_inc_not_zero(ref)); } static inline void refcount_dec(refcount_t *ref) { - atomic_dec(&ref->value); + atomic_dec(ref); } static inline unsigned int refcount_read(refcount_t *ref) { - return atomic_read(&ref->value); + 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->value) == true) { + if (atomic_dec_and_test(ref) == true) { spin_lock_irqsave(lock, flags); return (true); } return (false); } -/* - * struct kref uses atomic_t and not refcount_t so - * we differ from Linux here. - */ static inline bool -refcount_dec_and_test(atomic_t *r) +refcount_dec_and_test(refcount_t *r) { return (atomic_dec_and_test(r)); diff --git a/sys/compat/linuxkpi/common/include/linux/rwlock.h b/sys/compat/linuxkpi/common/include/linux/rwlock.h index 8c1ee36ac4de..3030ec89ff1e 100644 --- a/sys/compat/linuxkpi/common/include/linux/rwlock.h +++ b/sys/compat/linuxkpi/common/include/linux/rwlock.h @@ -34,14 +34,12 @@ #include <sys/rwlock.h> #include <sys/libkern.h> -typedef struct { - struct rwlock rw; -} rwlock_t; +typedef struct rwlock rwlock_t; -#define read_lock(_l) rw_rlock(&(_l)->rw) -#define write_lock(_l) rw_wlock(&(_l)->rw) -#define read_unlock(_l) rw_runlock(&(_l)->rw) -#define write_unlock(_l) rw_wunlock(&(_l)->rw) +#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)) @@ -54,13 +52,6 @@ typedef struct { do { read_unlock(lock); } while (0) #define write_unlock_irqrestore(lock, flags) \ do { write_unlock(lock); } while (0) - -static inline void -rwlock_init(rwlock_t *lock) -{ - - memset(&lock->rw, 0, sizeof(lock->rw)); - rw_init_flags(&lock->rw, "lnxrw", RW_NOWITNESS); -} +#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/scatterlist.h b/sys/compat/linuxkpi/common/include/linux/scatterlist.h index e462d5c649f1..537f5bebc5aa 100644 --- a/sys/compat/linuxkpi/common/include/linux/scatterlist.h +++ b/sys/compat/linuxkpi/common/include/linux/scatterlist.h @@ -32,8 +32,11 @@ #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> @@ -671,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 8cb6b12100d5..3ad2f8e4ce8b 100644 --- a/sys/compat/linuxkpi/common/include/linux/sched.h +++ b/sys/compat/linuxkpi/common/include/linux/sched.h @@ -42,6 +42,7 @@ #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> @@ -52,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 @@ -159,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..876ef9e8dfe5 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 @@ -89,6 +93,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/seqlock.h b/sys/compat/linuxkpi/common/include/linux/seqlock.h index 48e42efc10fe..554fdfd6e202 100644 --- a/sys/compat/linuxkpi/common/include/linux/seqlock.h +++ b/sys/compat/linuxkpi/common/include/linux/seqlock.h @@ -99,7 +99,7 @@ lkpi_write_seqcount_invalidate(seqc_t *seqcp) static inline seqc_t lkpi_seqprop_sequence(const seqc_t *seqcp) { - return (atomic_load_int(__DECONST(seqc_t *, seqcp))); + return (atomic_load_int(seqcp)); } #define seqprop_sequence(s) lkpi_seqprop_sequence(&(s)->seqc) 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/shrinker.h b/sys/compat/linuxkpi/common/include/linux/shrinker.h index a865241cc7cb..eb95dafb83ce 100644 --- a/sys/compat/linuxkpi/common/include/linux/shrinker.h +++ b/sys/compat/linuxkpi/common/include/linux/shrinker.h @@ -27,6 +27,8 @@ #define _LINUXKPI_LINUX_SHRINKER_H_ #include <sys/queue.h> + +#include <linux/bitops.h> #include <linux/gfp.h> struct shrink_control { @@ -39,6 +41,8 @@ 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; }; @@ -47,10 +51,23 @@ struct shrinker { #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 diff --git a/sys/compat/linuxkpi/common/include/linux/skbuff.h b/sys/compat/linuxkpi/common/include/linux/skbuff.h index ee3f427aa6e9..c8ad90281e34 100644 --- a/sys/compat/linuxkpi/common/include/linux/skbuff.h +++ b/sys/compat/linuxkpi/common/include/linux/skbuff.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2020-2023 The FreeBSD Foundation + * 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 @@ -45,8 +45,17 @@ #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 @@ -145,37 +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 */ - - /* "Scratch" area for layers to store metadata. */ - /* ??? I see sizeof() operations so probably an array. */ - uint8_t cb[64] __aligned(CACHE_LINE_SIZE); + 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? */ - 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 *); @@ -191,7 +209,7 @@ 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(struct sk_buff *, gfp_t); +struct sk_buff *linuxkpi_skb_copy(const struct sk_buff *, gfp_t); /* -------------------------------------------------------------------------- */ @@ -235,6 +253,13 @@ kfree_skb(struct sk_buff *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); @@ -268,9 +293,12 @@ build_skb(void *data, unsigned int fragsz) /* -------------------------------------------------------------------------- */ -/* XXX BZ review this one for terminal condition as Linux "queues" are special. */ -#define skb_list_walk_safe(_q, skb, tmp) \ - for ((skb) = (_q)->next; (skb) != NULL && ((tmp) = (skb)->next); (skb) = (tmp)) +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 @@ -342,12 +370,14 @@ 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 numer of bytes available at the beginning of buffer. */ +/* Return number of bytes available at the beginning of buffer. */ static inline unsigned int -skb_headroom(struct sk_buff *skb) +skb_headroom(const struct sk_buff *skb) { SKB_TRACE(skb); KASSERT((skb->data - skb->head) >= 0, ("%s: skb %p headroom < 0, " @@ -494,13 +524,10 @@ skb_add_rx_frag(struct sk_buff *skb, int fragno, struct page *page, skb->len += size; skb->data_len += size; skb->truesize += truesize; - - /* XXX TODO EXTEND truesize? */ } /* -------------------------------------------------------------------------- */ -/* XXX BZ review this one for terminal condition as Linux "queues" are special. */ #define skb_queue_walk(_q, skb) \ for ((skb) = (_q)->next; (skb) != (struct sk_buff *)(_q); \ (skb) = (skb)->next) @@ -509,12 +536,23 @@ skb_add_rx_frag(struct sk_buff *skb, int fragno, struct page *page, 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(struct sk_buff_head *q) +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 (q->qlen == 0); + return (READ_ONCE(q->next) == (const struct sk_buff *)q); } static inline void @@ -529,7 +567,8 @@ static inline void skb_queue_head_init(struct sk_buff_head *q) { SKB_TRACE(q); - return (__skb_queue_head_init(q)); + __skb_queue_head_init(q); + spin_lock_init(&q->lock); } static inline void @@ -538,11 +577,11 @@ __skb_insert(struct sk_buff *new, struct sk_buff *prev, struct sk_buff *next, { SKB_TRACE_FMT(new, "prev %p next %p q %p", prev, next, q); - new->prev = prev; - new->next = next; - ((struct sk_buff_head_l *)next)->prev = new; - ((struct sk_buff_head_l *)prev)->next = new; - q->qlen++; + 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 @@ -574,53 +613,62 @@ __skb_queue_tail(struct sk_buff_head *q, struct sk_buff *new) static inline void skb_queue_tail(struct sk_buff_head *q, struct sk_buff *new) { + unsigned long flags; + SKB_TRACE2(q, new); - return (__skb_queue_tail(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(struct sk_buff_head *q) +skb_peek(const struct sk_buff_head *q) { struct sk_buff *skb; skb = q->next; SKB_TRACE2(q, skb); - if (skb == (struct sk_buff *)q) + if (skb == (const struct sk_buff *)q) return (NULL); return (skb); } static inline struct sk_buff * -skb_peek_tail(struct sk_buff_head *q) +skb_peek_tail(const struct sk_buff_head *q) { struct sk_buff *skb; - skb = q->prev; + skb = READ_ONCE(q->prev); SKB_TRACE2(q, skb); - if (skb == (struct sk_buff *)q) + if (skb == (const struct sk_buff *)q) return (NULL); return (skb); } static inline void -__skb_unlink(struct sk_buff *skb, struct sk_buff_head *head) +__skb_unlink(struct sk_buff *skb, struct sk_buff_head *q) { - SKB_TRACE2(skb, head); - struct sk_buff *p, *n;; + struct sk_buff *p, *n; + + SKB_TRACE2(skb, q); - head->qlen--; + WRITE_ONCE(q->qlen, q->qlen - 1); p = skb->prev; n = skb->next; - p->next = n; - n->prev = p; + 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 *head) +skb_unlink(struct sk_buff *skb, struct sk_buff_head *q) { - SKB_TRACE2(skb, head); - return (__skb_unlink(skb, head)); + 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 * @@ -628,32 +676,47 @@ __skb_dequeue(struct sk_buff_head *q) { struct sk_buff *skb; - SKB_TRACE(q); - skb = q->next; - if (skb == (struct sk_buff *)q) - return (NULL); + skb = skb_peek(q); if (skb != NULL) __skb_unlink(skb, q); - SKB_TRACE(skb); + SKB_TRACE2(q, skb); return (skb); } static inline struct sk_buff * skb_dequeue(struct sk_buff_head *q) { - SKB_TRACE(q); - return (__skb_dequeue(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) +__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); } @@ -669,28 +732,75 @@ __skb_queue_head(struct sk_buff_head *q, struct sk_buff *skb) static inline void skb_queue_head(struct sk_buff_head *q, struct sk_buff *skb) { + unsigned long flags; SKB_TRACE2(q, skb); - __skb_queue_after(q, (struct sk_buff *)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(struct sk_buff_head *head) +skb_queue_len(const struct sk_buff_head *q) { - SKB_TRACE(head); - return (head->qlen); + SKB_TRACE(q); + return (q->qlen); } static inline uint32_t -skb_queue_len_lockless(const struct sk_buff_head *head) +skb_queue_len_lockless(const struct sk_buff_head *q) { - SKB_TRACE(head); - return (READ_ONCE(head->qlen)); + 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; @@ -698,13 +808,26 @@ __skb_queue_purge(struct sk_buff_head *q) 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); - return (__skb_queue_purge(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 * @@ -719,7 +842,7 @@ skb_queue_prev(struct sk_buff_head *q, struct sk_buff *skb) /* -------------------------------------------------------------------------- */ static inline struct sk_buff * -skb_copy(struct sk_buff *skb, gfp_t gfp) +skb_copy(const struct sk_buff *skb, gfp_t gfp) { struct sk_buff *new; @@ -728,13 +851,6 @@ skb_copy(struct sk_buff *skb, gfp_t gfp) return (new); } -static inline void -consume_skb(struct sk_buff *skb) -{ - SKB_TRACE(skb); - SKB_TODO(); -} - static inline uint16_t skb_checksum(struct sk_buff *skb, int offs, size_t len, int x) { @@ -764,8 +880,7 @@ static inline size_t skb_frag_size(const skb_frag_t *frag) { SKB_TRACE(frag); - SKB_TODO(); - return (-1); + return (frag->size); } #define skb_walk_frags(_skb, _frag) \ @@ -790,8 +905,7 @@ static inline void * skb_frag_address(const skb_frag_t *frag) { SKB_TRACE(frag); - SKB_TODO(); - return (NULL); + return (page_address(frag->page + frag->offset)); } static inline void @@ -821,50 +935,7 @@ static inline void skb_mark_not_on_list(struct sk_buff *skb) { SKB_TRACE(skb); - SKB_TODO(); -} - -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; - - b->prev = p; - ((struct sk_buff_head_l *)p)->next = b; - e->next = n; - ((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); + skb->next = NULL; } static inline void @@ -891,25 +962,17 @@ skb_network_header(struct sk_buff *skb) return (skb->head + skb->l3hdroff); } -static inline bool -skb_is_nonlinear(struct sk_buff *skb) -{ - SKB_TRACE(skb); - return ((skb->data_len > 0) ? true : false); -} - static inline int __skb_linearize(struct sk_buff *skb) { SKB_TRACE(skb); SKB_TODO(); - return (ENXIO); + return (-ENXIO); } static inline int skb_linearize(struct sk_buff *skb) { - return (skb_is_nonlinear(skb) ? __skb_linearize(skb) : 0); } @@ -938,12 +1001,19 @@ 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) { SKB_TRACE(skb); SKB_TODO(); - return (false); + return (true); } static inline uint8_t * @@ -983,10 +1053,9 @@ skb_orphan(struct sk_buff *skb) SKB_TODO(); } -static inline __sum16 +static inline __wsum csum_unfold(__sum16 sum) { - SKB_TODO(); return (sum); } @@ -1012,7 +1081,8 @@ static inline struct sk_buff * skb_get(struct sk_buff *skb) { - SKB_TODO(); /* XXX refcnt? as in get/put_device? */ + SKB_TRACE(skb); + refcount_inc(&skb->refcnt); return (skb); } @@ -1047,7 +1117,8 @@ skb_list_del_init(struct sk_buff *skb) { SKB_TRACE(skb); - SKB_TODO(); + __list_del_entry(&skb->list); + skb_mark_not_on_list(skb); } static inline void @@ -1078,6 +1149,7 @@ static inline void skb_mark_for_recycle(struct sk_buff *skb) { SKB_TRACE(skb); + /* page_pool */ SKB_TODO(); } diff --git a/sys/compat/linuxkpi/common/include/linux/slab.h b/sys/compat/linuxkpi/common/include/linux/slab.h index 298306b6ea05..f3a840d9bf4b 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 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,12 +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) +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) { @@ -106,35 +119,89 @@ linux_check_m_flags(gfp_t 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 (malloc(MAX(size, sizeof(struct llist_node)), M_KMALLOC, - linux_check_m_flags(flags))); + return (lkpi___kmalloc(size, flags)); } static inline void * kmalloc_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))); + 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 (mallocarray(n, size, M_KMALLOC, linux_check_m_flags(flags))); + 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 (mallocarray_domainset(n, size, M_KMALLOC, - linux_get_vm_domain_set(node), linux_check_m_flags(flags))); + 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) { @@ -154,55 +221,43 @@ 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 * -kmalloc_array(size_t n, size_t size, gfp_t flags) +kvmalloc(size_t size, gfp_t flags) { - return (mallocarray(n, size, M_KMALLOC, linux_check_m_flags(flags))); -} - -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))); + return (malloc(size, M_KMALLOC, linux_check_m_flags(flags))); } 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))); -} + if (WOULD_OVERFLOW(n, size)) + panic("%s: %zu * %zu overflowed", __func__, n, size); -static inline void * -krealloc(void *ptr, size_t size, gfp_t flags) -{ - return (realloc(ptr, size, M_KMALLOC, linux_check_m_flags(flags))); + return (kvmalloc(size * n, flags)); } static inline void * -krealloc_array(void *ptr, size_t n, size_t size, gfp_t flags) +kvrealloc(const void *ptr, size_t oldsize, size_t newsize, gfp_t flags) { - if (WOULD_OVERFLOW(n, size)) { - return NULL; - } - - return (realloc(ptr, n * size, M_KMALLOC, linux_check_m_flags(flags))); -} + void *newptr; -extern void linux_kfree_async(void *); + if (newsize <= oldsize) + return (__DECONST(void *, ptr)); -static inline void -kfree(const void *ptr) -{ - if (ZERO_OR_NULL_PTR(ptr)) - return; + newptr = kvmalloc(newsize, flags); + if (newptr != NULL) { + memcpy(newptr, ptr, oldsize); + kvfree(ptr); + } - if (curthread->td_critnest != 0) - linux_kfree_async(__DECONST(void *, ptr)); - else - free(__DECONST(void *, ptr), M_KMALLOC); + return (newptr); } +/* + * Misc. + */ + static __inline void kfree_sensitive(const void *ptr) { @@ -218,12 +273,12 @@ ksize(const void *ptr) return (malloc_usable_size(ptr)); } -extern void *lkpi_kmalloc(size_t size, gfp_t flags); -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 *); +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/soc/mediatek/mtk_wed.h b/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h index b0aec2d4afbd..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 @@ -42,6 +42,8 @@ struct mtk_wed_device { #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) diff --git a/sys/compat/linuxkpi/common/include/linux/spinlock.h b/sys/compat/linuxkpi/common/include/linux/spinlock.h index 4bc1e2a2d431..dc10b0457153 100644 --- a/sys/compat/linuxkpi/common/include/linux/spinlock.h +++ b/sys/compat/linuxkpi/common/include/linux/spinlock.h @@ -41,9 +41,7 @@ #include <linux/bottom_half.h> #include <linux/lockdep.h> -typedef struct { - struct mtx m; -} spinlock_t; +typedef struct mtx spinlock_t; /* * By defining CONFIG_SPIN_SKIP LinuxKPI spinlocks and asserts will be @@ -59,7 +57,7 @@ typedef struct { #define spin_lock(_l) do { \ if (SPIN_SKIP()) \ break; \ - mtx_lock(&(_l)->m); \ + mtx_lock(_l); \ local_bh_disable(); \ } while (0) @@ -76,7 +74,7 @@ typedef struct { if (SPIN_SKIP()) \ break; \ local_bh_enable(); \ - mtx_unlock(&(_l)->m); \ + mtx_unlock(_l); \ } while (0) #define spin_unlock_bh(_l) do { \ @@ -93,7 +91,7 @@ typedef struct { if (SPIN_SKIP()) { \ __ret = 1; \ } else { \ - __ret = mtx_trylock(&(_l)->m); \ + __ret = mtx_trylock(_l); \ if (likely(__ret != 0)) \ local_bh_disable(); \ } \ @@ -111,7 +109,7 @@ typedef struct { #define spin_lock_nested(_l, _n) do { \ if (SPIN_SKIP()) \ break; \ - mtx_lock_flags(&(_l)->m, MTX_DUPOK); \ + mtx_lock_flags(_l, MTX_DUPOK); \ local_bh_disable(); \ } while (0) @@ -141,31 +139,27 @@ typedef struct { #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) linux_spin_lock_init(lock, spin_lock_name("lnxspin")) +#define spin_lock_init(lock) mtx_init(lock, spin_lock_name("lnxspin"), \ + NULL, MTX_DEF | MTX_NOWITNESS | MTX_NEW) -static inline void -linux_spin_lock_init(spinlock_t *lock, const char *name) -{ - - memset(lock, 0, sizeof(*lock)); - mtx_init(&lock->m, name, NULL, MTX_DEF | MTX_NOWITNESS); -} - -static inline void -spin_lock_destroy(spinlock_t *lock) -{ - - mtx_destroy(&lock->m); -} +#define spin_lock_destroy(_l) mtx_destroy(_l) #define DEFINE_SPINLOCK(lock) \ spinlock_t lock; \ - MTX_SYSINIT(lock, &(lock).m, spin_lock_name("lnxspin"), MTX_DEF) + MTX_SYSINIT(lock, &lock, spin_lock_name("lnxspin"), MTX_DEF) #define assert_spin_locked(_l) do { \ if (SPIN_SKIP()) \ break; \ - mtx_assert(&(_l)->m, MA_OWNED); \ + 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) \ 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/string.h b/sys/compat/linuxkpi/common/include/linux/string.h index 9e1818a38594..f7b64560d254 100644 --- a/sys/compat/linuxkpi/common/include/linux/string.h +++ b/sys/compat/linuxkpi/common/include/linux/string.h @@ -98,6 +98,18 @@ kmemdup(const void *src, size_t len, gfp_t gfp) 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) { @@ -149,6 +161,24 @@ skip_spaces(const char *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) { 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..65e023031bb2 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: @@ -156,6 +198,80 @@ sysfs_remove_file(struct kobject *kobj, const struct attribute *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 +464,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/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/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/wait.h b/sys/compat/linuxkpi/common/include/linux/wait.h index d50003d44955..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 = { \ @@ -110,10 +118,10 @@ extern wait_queue_func_t default_wake_function; wait_queue_head_t name = { \ .task_list = LINUX_LIST_HEAD_INIT(name.task_list), \ }; \ - MTX_SYSINIT(name, &(name).lock.m, spin_lock_name("wqhead"), MTX_DEF) + MTX_SYSINIT(name, &(name).lock, spin_lock_name("wqhead"), MTX_DEF) #define init_waitqueue_head(wqh) do { \ - mtx_init(&(wqh)->lock.m, spin_lock_name("wqhead"), \ + mtx_init(&(wqh)->lock, spin_lock_name("wqhead"), \ NULL, MTX_DEF | MTX_NEW | MTX_NOWITNESS); \ INIT_LIST_HEAD(&(wqh)->task_list); \ } while (0) @@ -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_ */ diff --git a/sys/compat/linuxkpi/common/include/linux/xarray.h b/sys/compat/linuxkpi/common/include/linux/xarray.h index d293a8f7c2a3..fba36eea0ab5 100644 --- a/sys/compat/linuxkpi/common/include/linux/xarray.h +++ b/sys/compat/linuxkpi/common/include/linux/xarray.h @@ -49,14 +49,14 @@ #define xa_limit_32b XA_LIMIT(0, 0xFFFFFFFF) -#define XA_ASSERT_LOCKED(xa) mtx_assert(&(xa)->mtx, MA_OWNED) -#define xa_lock(xa) mtx_lock(&(xa)->mtx) -#define xa_unlock(xa) mtx_unlock(&(xa)->mtx) +#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 root; - struct mtx mtx; /* internal mutex */ - uint32_t flags; /* see XA_FLAGS_XXX */ + struct radix_tree_root xa_head; + struct mtx xa_lock; /* internal mutex */ + uint32_t xa_flags; /* see XA_FLAGS_XXX */ }; /* @@ -67,6 +67,7 @@ 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); |