Index: sys/compat/linuxkpi/common/include/asm/atomic.h =================================================================== --- sys/compat/linuxkpi/common/include/asm/atomic.h +++ sys/compat/linuxkpi/common/include/asm/atomic.h @@ -159,6 +159,23 @@ return (ret); } +static inline int +atomic_dec_if_positive(atomic_t *v) { + int c, old, dec; + + c = atomic_read(v); + for (;;) { + dec = c - 1; + if (unlikely(dec < 0)) + break; + old = atomic_cmpxchg((v), c, dec); + if (likely(old == c)) + break; + c = old; + } + return dec; +} + #define cmpxchg(ptr, old, new) ({ \ union { \ __typeof(*(ptr)) val; \ Index: sys/compat/linuxkpi/common/include/asm/msr.h =================================================================== --- sys/compat/linuxkpi/common/include/asm/msr.h +++ sys/compat/linuxkpi/common/include/asm/msr.h @@ -32,5 +32,6 @@ #include #define rdmsrl(msr, val) ((val) = rdmsr(msr)) +#define rdmsrl_safe(msr, val) rdmsr_safe((msr), (val)) #endif /* _ASM_MSR_H_ */ Index: sys/compat/linuxkpi/common/include/asm/uaccess.h =================================================================== --- sys/compat/linuxkpi/common/include/asm/uaccess.h +++ sys/compat/linuxkpi/common/include/asm/uaccess.h @@ -31,25 +31,32 @@ #ifndef _ASM_UACCESS_H_ #define _ASM_UACCESS_H_ -#include +/* -static inline long -copy_to_user(void *to, const void *from, unsigned long n) -{ - if (linux_copyout(from, to, n) != 0) - return n; - return 0; -} -#define __copy_to_user(...) copy_to_user(__VA_ARGS__) +Disable. Need __{get,put}_user_size() functions... +Use defaults in linux/uaccess.h for now. -static inline long -copy_from_user(void *to, const void *from, unsigned long n) -{ - if (linux_copyin(from, to, n) != 0) - return n; - return 0; -} -#define __copy_from_user(...) copy_from_user(__VA_ARGS__) -#define __copy_in_user(...) copy_from_user(__VA_ARGS__) +#define user_access_begin() stac() +#define user_access_end() clac() + +#define unsafe_put_user(x, ptr, err_label) \ + do { \ + int __error; \ + __typeof__(*(ptr)) __x = (x); \ + __put_user_size(__x, (ptr), sizeof(*(ptr)), \ + __error, -EFAULT); \ + if (unlikely(__error)) goto err_label; \ + } while (0) + +#define unsafe_get_user(x, ptr, err_label) \ + do { \ + int __error; \ + __inttype(*(ptr)) __x; \ + __get_user_size(__x, (ptr), sizeof(*(ptr)), \ + __error, -EFAULT); \ + (x) = (__force __typeof__(*(ptr)))__x; \ + if (unlikely(__error)) goto err_label; \ + } while (0) +*/ #endif /* _ASM_UACCESS_H_ */ Index: sys/compat/linuxkpi/common/include/linux/compiler.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/compiler.h +++ sys/compat/linuxkpi/common/include/linux/compiler.h @@ -34,6 +34,10 @@ #include +#ifndef __LinuxKPI_version +#define __LinuxKPI_version 40009 +#endif + #define __user #define __kernel #define __safe Index: sys/compat/linuxkpi/common/include/linux/device.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/device.h +++ sys/compat/linuxkpi/common/include/linux/device.h @@ -461,6 +461,12 @@ device_unregister(device_get_softc(bsddev)); } +static inline void +dev_pm_set_driver_flags(struct device *dev, u32 flags) +{ + printf("%s: missing implementation\n", __func__); +} + static inline void linux_class_kfree(struct class *class) { Index: sys/compat/linuxkpi/common/include/linux/export.h =================================================================== --- /dev/null +++ sys/compat/linuxkpi/common/include/linux/export.h @@ -0,0 +1,8 @@ +#ifndef _LINUX_EXPORT_H +#define _LINUX_EXPORT_H + +#define NR_IRQS 512 /* XXX Need correct value */ +#define EXPORT_SYMBOL(name) +#define EXPORT_SYMBOL_GPL(name) + +#endif Index: sys/compat/linuxkpi/common/include/linux/kernel.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/kernel.h +++ sys/compat/linuxkpi/common/include/linux/kernel.h @@ -88,7 +88,9 @@ #define BUILD_BUG() do { CTASSERT(0); } while (0) #define BUILD_BUG_ON(x) CTASSERT(!(x)) +#ifndef BUILD_BUG_ON_MSG #define BUILD_BUG_ON_MSG(x, msg) BUILD_BUG_ON(x) +#endif #define BUILD_BUG_ON_NOT_POWER_OF_2(x) BUILD_BUG_ON(!powerof2(x)) #define BUILD_BUG_ON_INVALID(expr) while (0) { (void)(expr); } @@ -372,6 +374,56 @@ return (0); } +static inline int +kstrtobool(const char *s, bool *res) +{ + if (!s) + return -EINVAL; + + switch (s[0]) { + case 'y': + case 'Y': + case '1': + *res = true; + return 0; + case 'n': + case 'N': + case '0': + *res = false; + return 0; + case 'o': + case 'O': + switch (s[1]) { + case 'n': + case 'N': + *res = true; + return 0; + case 'f': + case 'F': + *res = false; + return 0; + default: + break; + } + default: + break; + } + + return -EINVAL; +} + +static inline int +kstrtobool_from_user(const char __user *s, size_t count, bool *res) +{ + char buf[4]; + + count = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, s, count)) + return -EFAULT; + buf[count] = '\0'; + return kstrtobool(buf, res); +} + #define min(x, y) ((x) < (y) ? (x) : (y)) #define max(x, y) ((x) > (y) ? (x) : (y)) Index: sys/compat/linuxkpi/common/include/linux/ktime.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/ktime.h +++ sys/compat/linuxkpi/common/include/linux/ktime.h @@ -127,6 +127,22 @@ return (lhs + rhs); } +static inline int +ktime_compare(const ktime_t cmp1, const ktime_t cmp2) +{ + if (cmp1 < cmp2) + return -1; + if (cmp1 > cmp2) + return 1; + return 0; +} + +static inline bool +ktime_after(const ktime_t cmp1, const ktime_t cmp2) +{ + return ktime_compare(cmp1, cmp2) > 0; +} + static inline ktime_t timespec_to_ktime(struct timespec ts) { @@ -140,6 +156,7 @@ } #define ktime_to_timespec(kt) ns_to_timespec(kt) +#define ktime_to_timespec64(kt) ns_to_timespec(kt) #define ktime_to_timeval(kt) ns_to_timeval(kt) #define ktime_to_ns(kt) (kt) Index: sys/compat/linuxkpi/common/include/linux/list.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/list.h +++ sys/compat/linuxkpi/common/include/linux/list.h @@ -337,16 +337,23 @@ hlist_empty(const struct hlist_head *h) { - return !h->first; + return !READ_ONCE(h->first); +} + +static inline void +__hlist_del(struct hlist_node *n) +{ + + WRITE_ONCE(*(n->pprev), n->next); + if (n->next) + n->next->pprev = n->pprev; } static inline void hlist_del(struct hlist_node *n) { - if (n->next) - n->next->pprev = n->pprev; - *n->pprev = n->next; + __hlist_del(n); } static inline void @@ -366,7 +373,7 @@ n->next = h->first; if (h->first) h->first->pprev = &n->next; - h->first = n; + WRITE_ONCE(h->first, n); n->pprev = &h->first; } @@ -377,18 +384,19 @@ n->pprev = next->pprev; n->next = next; next->pprev = &n->next; - *(n->pprev) = n; + WRITE_ONCE(*(n->pprev), n); } static inline void -hlist_add_after(struct hlist_node *n, struct hlist_node *next) +hlist_add_behind(struct hlist_node *n, struct hlist_node *prev) { - next->next = n->next; - n->next = next; - next->pprev = &n->next; - if (next->next) - next->next->pprev = &next->next; + n->next = prev->next; + WRITE_ONCE(prev->next, n); + n->pprev = &prev->next; + + if (n->next) + n->next->pprev = &n->next; } static inline void Index: sys/compat/linuxkpi/common/include/linux/mmu_context.h =================================================================== --- /dev/null +++ sys/compat/linuxkpi/common/include/linux/mmu_context.h @@ -0,0 +1,20 @@ +#ifndef _LINUX_MMU_CONTEXT_H +#define _LINUX_MMU_CONTEXT_H + +struct mm_struct; + +static inline void +use_mm(struct mm_struct *mm) +{ + + printf("%s: missing implementation!\n", __func__); +} + +static inline void +unuse_mm(struct mm_struct *mm) +{ + + printf("%s: missing implementation!\n", __func__); +} + +#endif Index: sys/compat/linuxkpi/common/include/linux/module.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/module.h +++ sys/compat/linuxkpi/common/include/linux/module.h @@ -42,6 +42,7 @@ #include #include #include +#include #define MODULE_AUTHOR(name) #define MODULE_DESCRIPTION(name) @@ -51,8 +52,6 @@ #define THIS_MODULE ((struct module *)0) -#define EXPORT_SYMBOL(name) -#define EXPORT_SYMBOL_GPL(name) #define __MODULE_STRING(x) __stringify(x) /* OFED pre-module initialization */ Index: sys/compat/linuxkpi/common/include/linux/slab.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/slab.h +++ sys/compat/linuxkpi/common/include/linux/slab.h @@ -85,6 +85,8 @@ #define SLAB_DESTROY_BY_RCU \ SLAB_TYPESAFE_BY_RCU +#define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long long) + static inline gfp_t linux_check_m_flags(gfp_t flags) { Index: sys/compat/linuxkpi/common/include/linux/time.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/time.h +++ sys/compat/linuxkpi/common/include/linux/time.h @@ -38,6 +38,8 @@ #include #include +#define timespec64 timespec + static inline struct timeval ns_to_timeval(const int64_t nsec) { Index: sys/compat/linuxkpi/common/include/linux/timer.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/timer.h +++ sys/compat/linuxkpi/common/include/linux/timer.h @@ -64,7 +64,7 @@ #define setup_timer(timer, func, dat) do { \ (timer)->function = (func); \ (timer)->data = (dat); \ - callout_init(&(timer)->callout, 1); \ + callout_init(&(timer)->callout, 1); \ } while (0) #define __setup_timer(timer, func, dat, flags) do { \ @@ -75,7 +75,7 @@ #define init_timer(timer) do { \ (timer)->function = NULL; \ (timer)->data = 0; \ - callout_init(&(timer)->callout, 1); \ + callout_init(&(timer)->callout, 1); \ } while (0) extern void mod_timer(struct timer_list *, int); Index: sys/compat/linuxkpi/common/include/linux/uaccess.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/uaccess.h +++ sys/compat/linuxkpi/common/include/linux/uaccess.h @@ -42,6 +42,8 @@ #include +#include + #define VERIFY_READ VM_PROT_READ #define VERIFY_WRITE VM_PROT_WRITE @@ -67,6 +69,25 @@ extern size_t linux_clear_user(void *uaddr, size_t len); extern int linux_access_ok(int rw, const void *uaddr, size_t len); +static inline long +copy_to_user(void *to, const void *from, unsigned long n) +{ + if (linux_copyout(from, to, n) != 0) + return n; + return 0; +} +#define __copy_to_user(...) copy_to_user(__VA_ARGS__) + +static inline long +copy_from_user(void *to, const void *from, unsigned long n) +{ + if (linux_copyin(from, to, n) != 0) + return n; + return 0; +} +#define __copy_from_user(...) copy_from_user(__VA_ARGS__) +#define __copy_in_user(...) copy_from_user(__VA_ARGS__) + /* * NOTE: Each pagefault_disable() call must have a corresponding * pagefault_enable() call in the same scope. The former creates a new @@ -88,4 +109,20 @@ return ((curthread->td_pflags & TDP_NOFAULTING) != 0); } +#ifndef user_access_begin +#define user_access_begin() do { } while (0) +#define user_access_end() do { } while (0) + +#define unsafe_get_user(x, ptr, err) do { \ + if (unlikely(__get_user(x, ptr))) \ + goto err; \ + } while (0) + +#define unsafe_put_user(x, ptr, err) do { \ + if (unlikely(__put_user(x, ptr))) \ + goto err; \ + } while (0) + +#endif + #endif /* _LINUX_UACCESS_H_ */ Index: sys/compat/linuxkpi/common/include/linux/wait.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/wait.h +++ sys/compat/linuxkpi/common/include/linux/wait.h @@ -47,12 +47,19 @@ #define might_sleep() \ WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "might_sleep()") +#define might_sleep_if(cond) do { if (cond) might_sleep(); } while (0) + +#if __LinuxKPI_version >= 40013 +#define __add_wait_queue_entry_tail(wqh,wq) __add_wait_queue_tail((wqh),(wq)) +#define wait_queue_entry wait_queue +#define wait_queue_entry_t wait_queue_t +#endif + struct wait_queue; struct wait_queue_head; typedef struct wait_queue wait_queue_t; typedef struct wait_queue_head wait_queue_head_t; - typedef int wait_queue_func_t(wait_queue_t *, unsigned int, int, void *); /* @@ -63,12 +70,23 @@ unsigned int flags; /* always 0 */ void *private; wait_queue_func_t *func; - struct list_head task_list; + union { + /* + * Changes in Linux v4.13. + * Remove deprecated code when we + * don't depend on < 4.13 any more. + */ + struct list_head task_list; /* < v.4.13 */ + struct list_head entry; /* >= v4.13 */ + }; }; struct wait_queue_head { spinlock_t lock; - struct list_head task_list; + union { + struct list_head task_list; /* < v.4.13 */ + struct list_head head; /* >= v4.13 */ + }; }; /* @@ -106,8 +124,12 @@ INIT_LIST_HEAD(&(wqh)->task_list); \ } while (0) +void linux_init_wait_entry(wait_queue_t *wait, int flags); void linux_wake_up(wait_queue_head_t *, unsigned int, int, bool); +#define init_wait_entry(w, f) \ + linux_init_wait_entry(w, f) + #define wake_up(wqh) \ linux_wake_up(wqh, TASK_NORMAL, 1, false) #define wake_up_all(wqh) \ Index: sys/compat/linuxkpi/common/include/linux/ww_mutex.h =================================================================== --- sys/compat/linuxkpi/common/include/linux/ww_mutex.h +++ sys/compat/linuxkpi/common/include/linux/ww_mutex.h @@ -35,6 +35,8 @@ #include +struct task_struct; + struct ww_class { const char *mutex_name; }; @@ -44,6 +46,7 @@ struct ww_mutex { struct mutex base; + struct ww_acquire_ctx *ctx; struct cv condvar; }; @@ -111,32 +114,35 @@ } static inline void -ww_mutex_destroy(struct ww_mutex *lock) +ww_mutex_init(struct ww_mutex *lock, struct ww_class *ww_class) { - cv_destroy(&lock->condvar); - mutex_destroy(&lock->base); + linux_mutex_init(&lock->base, ww_class->mutex_name, SX_NOWITNESS); + cv_init(&lock->condvar, "lkpi-ww"); } static inline void -ww_acquire_init(struct ww_acquire_ctx *ctx, struct ww_class *ww_class) +ww_mutex_destroy(struct ww_mutex *lock) { + cv_destroy(&lock->condvar); + mutex_destroy(&lock->base); } static inline void -ww_mutex_init(struct ww_mutex *lock, struct ww_class *ww_class) +ww_acquire_init(struct ww_acquire_ctx *ctx, struct ww_class *ww_class) { - linux_mutex_init(&lock->base, ww_class->mutex_name, SX_NOWITNESS); - cv_init(&lock->condvar, "lkpi-ww"); + // NOP is deliberate } static inline void ww_acquire_fini(struct ww_acquire_ctx *ctx) { + // NOP is deliberate } static inline void ww_acquire_done(struct ww_acquire_ctx *ctx) { + // NOP is deliberate } #endif /* _LINUX_WW_MUTEX_H_ */ Index: sys/compat/linuxkpi/common/src/linux_schedule.c =================================================================== --- sys/compat/linuxkpi/common/src/linux_schedule.c +++ sys/compat/linuxkpi/common/src/linux_schedule.c @@ -187,6 +187,15 @@ return (wake_up_task(wq->private, state)); } +void +linux_init_wait_entry(wait_queue_t *wait, int flags) +{ + wait->flags = flags; + wait->private = current; + wait->func = autoremove_wake_function; + INIT_LIST_HEAD(&wait->task_list); +} + void linux_wake_up(wait_queue_head_t *wqh, unsigned int state, int nr, bool locked) {