aboutsummaryrefslogtreecommitdiff
path: root/sys/compat
diff options
context:
space:
mode:
Diffstat (limited to 'sys/compat')
-rw-r--r--sys/compat/freebsd32/Makefile1
-rw-r--r--sys/compat/freebsd32/freebsd32.h16
-rw-r--r--sys/compat/freebsd32/freebsd32_abort2.c5
-rw-r--r--sys/compat/freebsd32/freebsd32_capability.c9
-rw-r--r--sys/compat/freebsd32/freebsd32_ioctl.c3
-rw-r--r--sys/compat/freebsd32/freebsd32_ioctl.h2
-rw-r--r--sys/compat/freebsd32/freebsd32_ipc.h36
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c225
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.h4
-rw-r--r--sys/compat/freebsd32/freebsd32_proto.h35
-rw-r--r--sys/compat/freebsd32/freebsd32_signal.h6
-rw-r--r--sys/compat/freebsd32/freebsd32_syscall.h16
-rw-r--r--sys/compat/freebsd32/freebsd32_syscalls.c15
-rw-r--r--sys/compat/freebsd32/freebsd32_sysent.c15
-rw-r--r--sys/compat/freebsd32/freebsd32_systrace_args.c327
-rw-r--r--sys/compat/freebsd32/freebsd32_util.h6
-rw-r--r--sys/compat/freebsd32/syscalls.conf6
-rw-r--r--sys/compat/ia32/ia32_genassym.c2
-rw-r--r--sys/compat/ia32/ia32_signal.h6
-rw-r--r--sys/compat/ia32/ia32_sysvec.c13
-rw-r--r--sys/compat/ia32/ia32_util.h2
-rw-r--r--sys/compat/lindebugfs/lindebugfs.c421
-rw-r--r--sys/compat/linprocfs/linprocfs.c253
-rw-r--r--sys/compat/linsysfs/linsysfs.c163
-rw-r--r--sys/compat/linsysfs/linsysfs.h38
-rw-r--r--sys/compat/linsysfs/linsysfs_net.c353
-rw-r--r--sys/compat/linux/check_error.d2
-rw-r--r--sys/compat/linux/check_internal_locks.d2
-rw-r--r--sys/compat/linux/linux.c323
-rw-r--r--sys/compat/linux/linux.h105
-rw-r--r--sys/compat/linux/linux_common.c10
-rw-r--r--sys/compat/linux/linux_common.h18
-rw-r--r--sys/compat/linux/linux_dtrace.h4
-rw-r--r--sys/compat/linux/linux_dummy.c67
-rw-r--r--sys/compat/linux/linux_elf.c273
-rw-r--r--sys/compat/linux/linux_elf.h40
-rw-r--r--sys/compat/linux/linux_elf32.c5
-rw-r--r--sys/compat/linux/linux_elf64.c5
-rw-r--r--sys/compat/linux/linux_emul.c62
-rw-r--r--sys/compat/linux/linux_emul.h13
-rw-r--r--sys/compat/linux/linux_errno.c6
-rw-r--r--sys/compat/linux/linux_errno.h4
-rw-r--r--sys/compat/linux/linux_errno.inc4
-rw-r--r--sys/compat/linux/linux_event.c473
-rw-r--r--sys/compat/linux/linux_event.h10
-rw-r--r--sys/compat/linux/linux_file.c541
-rw-r--r--sys/compat/linux/linux_file.h15
-rw-r--r--sys/compat/linux/linux_fork.c10
-rw-r--r--sys/compat/linux/linux_fork.h6
-rw-r--r--sys/compat/linux/linux_futex.c17
-rw-r--r--sys/compat/linux/linux_futex.h13
-rw-r--r--sys/compat/linux/linux_getcwd.c13
-rw-r--r--sys/compat/linux/linux_ioctl.c561
-rw-r--r--sys/compat/linux/linux_ioctl.h6
-rw-r--r--sys/compat/linux/linux_ipc.c303
-rw-r--r--sys/compat/linux/linux_ipc.h4
-rw-r--r--sys/compat/linux/linux_ipc64.h6
-rw-r--r--sys/compat/linux/linux_mib.c17
-rw-r--r--sys/compat/linux/linux_mib.h15
-rw-r--r--sys/compat/linux/linux_misc.c819
-rw-r--r--sys/compat/linux/linux_misc.h30
-rw-r--r--sys/compat/linux/linux_mmap.c23
-rw-r--r--sys/compat/linux/linux_mmap.h2
-rw-r--r--sys/compat/linux/linux_netlink.c622
-rw-r--r--sys/compat/linux/linux_persona.h3
-rw-r--r--sys/compat/linux/linux_ptrace.c56
-rw-r--r--sys/compat/linux/linux_rseq.c3
-rw-r--r--sys/compat/linux/linux_siginfo.h2
-rw-r--r--sys/compat/linux/linux_signal.c19
-rw-r--r--sys/compat/linux/linux_signal.h8
-rw-r--r--sys/compat/linux/linux_socket.c544
-rw-r--r--sys/compat/linux/linux_socket.h45
-rw-r--r--sys/compat/linux/linux_stats.c405
-rw-r--r--sys/compat/linux/linux_sysctl.c12
-rw-r--r--sys/compat/linux/linux_time.c19
-rw-r--r--sys/compat/linux/linux_time.h (renamed from sys/compat/linux/linux_timer.h)10
-rw-r--r--sys/compat/linux/linux_timer.c10
-rw-r--r--sys/compat/linux/linux_uid16.c55
-rw-r--r--sys/compat/linux/linux_util.c82
-rw-r--r--sys/compat/linux/linux_util.h50
-rw-r--r--sys/compat/linux/linux_vdso.c37
-rw-r--r--sys/compat/linux/linux_vdso.h30
-rw-r--r--sys/compat/linux/linux_vdso_gtod.inc16
-rw-r--r--sys/compat/linux/linux_videodev2_compat.h4
-rw-r--r--sys/compat/linux/linux_videodev_compat.h4
-rw-r--r--sys/compat/linux/linux_xattr.c460
-rw-r--r--sys/compat/linux/stats_timing.d2
-rw-r--r--sys/compat/linux/trace_futexes.d2
-rw-r--r--sys/compat/linuxkpi/common/include/acpi/acpi.h10
-rw-r--r--sys/compat/linuxkpi/common/include/acpi/acpi_bus.h8
-rw-r--r--sys/compat/linuxkpi/common/include/acpi/actbl.h1
-rw-r--r--sys/compat/linuxkpi/common/include/acpi/video.h30
-rw-r--r--sys/compat/linuxkpi/common/include/asm/atomic-long.h10
-rw-r--r--sys/compat/linuxkpi/common/include/asm/atomic.h7
-rw-r--r--sys/compat/linuxkpi/common/include/asm/atomic64.h5
-rw-r--r--sys/compat/linuxkpi/common/include/asm/barrier.h2
-rw-r--r--sys/compat/linuxkpi/common/include/asm/byteorder.h2
-rw-r--r--sys/compat/linuxkpi/common/include/asm/fcntl.h2
-rw-r--r--sys/compat/linuxkpi/common/include/asm/fpu/api.h4
-rw-r--r--sys/compat/linuxkpi/common/include/asm/hypervisor.h19
-rw-r--r--sys/compat/linuxkpi/common/include/asm/intel-family.h6
-rw-r--r--sys/compat/linuxkpi/common/include/asm/io.h9
-rw-r--r--sys/compat/linuxkpi/common/include/asm/memtype.h18
-rw-r--r--sys/compat/linuxkpi/common/include/asm/msr.h2
-rw-r--r--sys/compat/linuxkpi/common/include/asm/neon.h4
-rw-r--r--sys/compat/linuxkpi/common/include/asm/pgtable.h17
-rw-r--r--sys/compat/linuxkpi/common/include/asm/processor.h63
-rw-r--r--sys/compat/linuxkpi/common/include/asm/set_memory.h36
-rw-r--r--sys/compat/linuxkpi/common/include/asm/smp.h6
-rw-r--r--sys/compat/linuxkpi/common/include/asm/types.h2
-rw-r--r--sys/compat/linuxkpi/common/include/asm/uaccess.h2
-rw-r--r--sys/compat/linuxkpi/common/include/asm/unaligned.h20
-rw-r--r--sys/compat/linuxkpi/common/include/crypto/hash.h94
-rw-r--r--sys/compat/linuxkpi/common/include/linux/acpi.h4
-rw-r--r--sys/compat/linuxkpi/common/include/linux/agp_backend.h28
-rw-r--r--sys/compat/linuxkpi/common/include/linux/anon_inodes.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/apple-gmux.h12
-rw-r--r--sys/compat/linuxkpi/common/include/linux/atomic.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/average.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/backlight.h16
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bcd.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bitfield.h5
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bitmap.h100
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bitops.h3
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bottom_half.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/bsearch.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/build_bug.h65
-rw-r--r--sys/compat/linuxkpi/common/include/linux/cache.h3
-rw-r--r--sys/compat/linuxkpi/common/include/linux/capability.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/cc_platform.h20
-rw-r--r--sys/compat/linuxkpi/common/include/linux/cdev.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/clocksource.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/compat.h12
-rw-r--r--sys/compat/linuxkpi/common/include/linux/compiler.h23
-rw-r--r--sys/compat/linuxkpi/common/include/linux/completion.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/container_of.h46
-rw-r--r--sys/compat/linuxkpi/common/include/linux/cpu.h6
-rw-r--r--sys/compat/linuxkpi/common/include/linux/crc32.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dcache.h7
-rw-r--r--sys/compat/linuxkpi/common/include/linux/debugfs.h85
-rw-r--r--sys/compat/linuxkpi/common/include/linux/delay.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/devcoredump.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/device.h115
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dma-attrs.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dma-buf-map.h91
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dma-mapping.h53
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dmapool.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dmi.h15
-rw-r--r--sys/compat/linuxkpi/common/include/linux/dynamic_debug.h8
-rw-r--r--sys/compat/linuxkpi/common/include/linux/efi.h1
-rw-r--r--sys/compat/linuxkpi/common/include/linux/err.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/errno.h4
-rw-r--r--sys/compat/linuxkpi/common/include/linux/etherdevice.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ethtool.h22
-rw-r--r--sys/compat/linuxkpi/common/include/linux/eventpoll.h45
-rw-r--r--sys/compat/linuxkpi/common/include/linux/export.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/file.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/firmware.h15
-rw-r--r--sys/compat/linuxkpi/common/include/linux/fs.h87
-rw-r--r--sys/compat/linuxkpi/common/include/linux/fwnode.h10
-rw-r--r--sys/compat/linuxkpi/common/include/linux/gcd.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/gfp.h44
-rw-r--r--sys/compat/linuxkpi/common/include/linux/hardirq.h12
-rw-r--r--sys/compat/linuxkpi/common/include/linux/hashtable.h4
-rw-r--r--sys/compat/linuxkpi/common/include/linux/hdmi.h440
-rw-r--r--sys/compat/linuxkpi/common/include/linux/highmem.h31
-rw-r--r--sys/compat/linuxkpi/common/include/linux/hrtimer.h5
-rw-r--r--sys/compat/linuxkpi/common/include/linux/i2c.h29
-rw-r--r--sys/compat/linuxkpi/common/include/linux/idr.h9
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ieee80211.h144
-rw-r--r--sys/compat/linuxkpi/common/include/linux/if_arp.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/if_ether.h9
-rw-r--r--sys/compat/linuxkpi/common/include/linux/if_vlan.h4
-rw-r--r--sys/compat/linuxkpi/common/include/linux/in.h3
-rw-r--r--sys/compat/linuxkpi/common/include/linux/in6.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/interrupt.h49
-rw-r--r--sys/compat/linuxkpi/common/include/linux/interval_tree.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/interval_tree_generic.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/io-64-nonatomic-lo-hi.h65
-rw-r--r--sys/compat/linuxkpi/common/include/linux/io-mapping.h26
-rw-r--r--sys/compat/linuxkpi/common/include/linux/io.h75
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ioctl.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/iommu.h29
-rw-r--r--sys/compat/linuxkpi/common/include/linux/iopoll.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ioport.h57
-rw-r--r--sys/compat/linuxkpi/common/include/linux/iosys-map.h161
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ip.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/irq_work.h9
-rw-r--r--sys/compat/linuxkpi/common/include/linux/irqdomain.h10
-rw-r--r--sys/compat/linuxkpi/common/include/linux/irqreturn.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/jhash.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/jiffies.h4
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kconfig.h76
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kdev_t.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kernel.h199
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kfifo.h89
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kmod.h5
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kobject.h56
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kref.h21
-rw-r--r--sys/compat/linuxkpi/common/include/linux/kthread.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ktime.h18
-rw-r--r--sys/compat/linuxkpi/common/include/linux/leds.h40
-rw-r--r--sys/compat/linuxkpi/common/include/linux/limits.h47
-rw-r--r--sys/compat/linuxkpi/common/include/linux/list.h40
-rw-r--r--sys/compat/linuxkpi/common/include/linux/lockdep.h13
-rw-r--r--sys/compat/linuxkpi/common/include/linux/log2.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/math64.h51
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mhi.h220
-rw-r--r--sys/compat/linuxkpi/common/include/linux/miscdevice.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mm.h104
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mm_types.h3
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mman.h38
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mmu_context.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mmu_notifier.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mmzone.h11
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mod_devicetable.h14
-rw-r--r--sys/compat/linuxkpi/common/include/linux/module.h3
-rw-r--r--sys/compat/linuxkpi/common/include/linux/moduleparam.h11
-rw-r--r--sys/compat/linuxkpi/common/include/linux/mutex.h4
-rw-r--r--sys/compat/linuxkpi/common/include/linux/net.h21
-rw-r--r--sys/compat/linuxkpi/common/include/linux/net_dim.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/netdev_features.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/netdevice.h189
-rw-r--r--sys/compat/linuxkpi/common/include/linux/nl80211.h58
-rw-r--r--sys/compat/linuxkpi/common/include/linux/notifier.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/numa.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/of.h33
-rw-r--r--sys/compat/linuxkpi/common/include/linux/overflow.h394
-rw-r--r--sys/compat/linuxkpi/common/include/linux/page-flags.h34
-rw-r--r--sys/compat/linuxkpi/common/include/linux/page.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pagemap.h9
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pagevec.h4
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pci.h560
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pci_ids.h9
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pfn.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pfn_t.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pid.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/platform_device.h97
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pm.h46
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pm_qos.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/pm_runtime.h6
-rw-r--r--sys/compat/linuxkpi/common/include/linux/poll.h3
-rw-r--r--sys/compat/linuxkpi/common/include/linux/power_supply.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/preempt.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/prefetch.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/printk.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ptp_clock_kernel.h75
-rw-r--r--sys/compat/linuxkpi/common/include/linux/qrtr.h41
-rw-r--r--sys/compat/linuxkpi/common/include/linux/radix-tree.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/random.h47
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rbtree.h28
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rculist.h7
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rcupdate.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/refcount.h13
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rhashtable.h87
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rwlock.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/rwsem.h4
-rw-r--r--sys/compat/linuxkpi/common/include/linux/scatterlist.h78
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sched.h4
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sched/mm.h43
-rw-r--r--sys/compat/linuxkpi/common/include/linux/semaphore.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/seq_file.h28
-rw-r--r--sys/compat/linuxkpi/common/include/linux/seqlock.h57
-rw-r--r--sys/compat/linuxkpi/common/include/linux/shmem_fs.h20
-rw-r--r--sys/compat/linuxkpi/common/include/linux/shrinker.h10
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sizes.h16
-rw-r--r--sys/compat/linuxkpi/common/include/linux/skbuff.h200
-rw-r--r--sys/compat/linuxkpi/common/include/linux/slab.h27
-rw-r--r--sys/compat/linuxkpi/common/include/linux/smp.h4
-rw-r--r--sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h60
-rw-r--r--sys/compat/linuxkpi/common/include/linux/soc/qcom/qmi.h173
-rw-r--r--sys/compat/linuxkpi/common/include/linux/socket.h13
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sort.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/spinlock.h3
-rw-r--r--sys/compat/linuxkpi/common/include/linux/srcu.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/stackdepot.h32
-rw-r--r--sys/compat/linuxkpi/common/include/linux/stdarg.h (renamed from sys/compat/linux/linux_sysproto.h)21
-rw-r--r--sys/compat/linuxkpi/common/include/linux/stddef.h15
-rw-r--r--sys/compat/linuxkpi/common/include/linux/string.h73
-rw-r--r--sys/compat/linuxkpi/common/include/linux/string_helpers.h69
-rw-r--r--sys/compat/linuxkpi/common/include/linux/stringify.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/suspend.h23
-rw-r--r--sys/compat/linuxkpi/common/include/linux/swap.h9
-rw-r--r--sys/compat/linuxkpi/common/include/linux/sysfs.h61
-rw-r--r--sys/compat/linuxkpi/common/include/linux/tcp.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/time.h8
-rw-r--r--sys/compat/linuxkpi/common/include/linux/timer.h4
-rw-r--r--sys/compat/linuxkpi/common/include/linux/tracepoint.h10
-rw-r--r--sys/compat/linuxkpi/common/include/linux/types.h11
-rw-r--r--sys/compat/linuxkpi/common/include/linux/uaccess.h27
-rw-r--r--sys/compat/linuxkpi/common/include/linux/udp.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/usb.h1
-rw-r--r--sys/compat/linuxkpi/common/include/linux/utsname.h49
-rw-r--r--sys/compat/linuxkpi/common/include/linux/uuid.h21
-rw-r--r--sys/compat/linuxkpi/common/include/linux/vgaarb.h281
-rw-r--r--sys/compat/linuxkpi/common/include/linux/vmalloc.h3
-rw-r--r--sys/compat/linuxkpi/common/include/linux/wait.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/wait_bit.h2
-rw-r--r--sys/compat/linuxkpi/common/include/linux/workqueue.h6
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ww_mutex.h9
-rw-r--r--sys/compat/linuxkpi/common/include/linux/xarray.h27
-rw-r--r--sys/compat/linuxkpi/common/include/net/addrconf.h2
-rw-r--r--sys/compat/linuxkpi/common/include/net/cfg80211.h531
-rw-r--r--sys/compat/linuxkpi/common/include/net/ieee80211_radiotap.h2
-rw-r--r--sys/compat/linuxkpi/common/include/net/if_inet6.h2
-rw-r--r--sys/compat/linuxkpi/common/include/net/ip.h2
-rw-r--r--sys/compat/linuxkpi/common/include/net/ipv6.h2
-rw-r--r--sys/compat/linuxkpi/common/include/net/mac80211.h765
-rw-r--r--sys/compat/linuxkpi/common/include/net/netevent.h2
-rw-r--r--sys/compat/linuxkpi/common/include/net/netlink.h53
-rw-r--r--sys/compat/linuxkpi/common/include/net/page_pool.h117
-rw-r--r--sys/compat/linuxkpi/common/include/net/regulatory.h6
-rw-r--r--sys/compat/linuxkpi/common/include/net/tcp.h2
-rw-r--r--sys/compat/linuxkpi/common/include/stdarg.h2
-rw-r--r--sys/compat/linuxkpi/common/include/video/mipi_display.h64
-rw-r--r--sys/compat/linuxkpi/common/include/video/vga.h16
-rw-r--r--sys/compat/linuxkpi/common/include/xen/xen.h37
-rw-r--r--sys/compat/linuxkpi/common/src/linux_80211.c2722
-rw-r--r--sys/compat/linuxkpi/common/src/linux_80211.h210
-rw-r--r--sys/compat/linuxkpi/common/src/linux_80211_macops.c140
-rw-r--r--sys/compat/linuxkpi/common/src/linux_acpi.c88
-rw-r--r--sys/compat/linuxkpi/common/src/linux_compat.c422
-rw-r--r--sys/compat/linuxkpi/common/src/linux_current.c16
-rw-r--r--sys/compat/linuxkpi/common/src/linux_devres.c45
-rw-r--r--sys/compat/linuxkpi/common/src/linux_dmi.c2
-rw-r--r--sys/compat/linuxkpi/common/src/linux_domain.c3
-rw-r--r--sys/compat/linuxkpi/common/src/linux_firmware.c26
-rw-r--r--sys/compat/linuxkpi/common/src/linux_fpu.c32
-rw-r--r--sys/compat/linuxkpi/common/src/linux_hdmi.c1921
-rw-r--r--sys/compat/linuxkpi/common/src/linux_hrtimer.c25
-rw-r--r--sys/compat/linuxkpi/common/src/linux_i2c.c118
-rw-r--r--sys/compat/linuxkpi/common/src/linux_i2cbb.c158
-rw-r--r--sys/compat/linuxkpi/common/src/linux_idr.c8
-rw-r--r--sys/compat/linuxkpi/common/src/linux_interrupt.c21
-rw-r--r--sys/compat/linuxkpi/common/src/linux_kmod.c3
-rw-r--r--sys/compat/linuxkpi/common/src/linux_kobject.c354
-rw-r--r--sys/compat/linuxkpi/common/src/linux_kthread.c2
-rw-r--r--sys/compat/linuxkpi/common/src/linux_lock.c15
-rw-r--r--sys/compat/linuxkpi/common/src/linux_mhi.c89
-rw-r--r--sys/compat/linuxkpi/common/src/linux_netdev.c72
-rw-r--r--sys/compat/linuxkpi/common/src/linux_page.c160
-rw-r--r--sys/compat/linuxkpi/common/src/linux_pci.c551
-rw-r--r--sys/compat/linuxkpi/common/src/linux_radix.c3
-rw-r--r--sys/compat/linuxkpi/common/src/linux_rcu.c3
-rw-r--r--sys/compat/linuxkpi/common/src/linux_schedule.c3
-rw-r--r--sys/compat/linuxkpi/common/src/linux_seq_file.c177
-rw-r--r--sys/compat/linuxkpi/common/src/linux_shmemfs.c5
-rw-r--r--sys/compat/linuxkpi/common/src/linux_shrinker.c14
-rw-r--r--sys/compat/linuxkpi/common/src/linux_simple_attr.c188
-rw-r--r--sys/compat/linuxkpi/common/src/linux_skbuff.c37
-rw-r--r--sys/compat/linuxkpi/common/src/linux_slab.c26
-rw-r--r--sys/compat/linuxkpi/common/src/linux_tasklet.c23
-rw-r--r--sys/compat/linuxkpi/common/src/linux_usb.c1
-rw-r--r--sys/compat/linuxkpi/common/src/linux_work.c76
-rw-r--r--sys/compat/linuxkpi/common/src/linux_xarray.c40
-rw-r--r--sys/compat/linuxkpi/common/src/lkpi_iic_if.m2
-rw-r--r--sys/compat/linuxkpi/dummy/include/acpi/button.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/asm/agp.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/asm/cacheflush.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/asm/div64.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/asm/intel-mid.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/asm/ioctl.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/asm/msr-index.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/asm/tsc.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/aer.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/ascii85.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/async.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/bits.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/bug.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/byteorder/generic.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/component.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/const.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/cpufreq.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/ctype.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/debugobjects.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/dev_printk.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/device/bus.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/dma-direction.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/elf.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/fault-inject.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/fdtable.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/hmm.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/hwmon-sysfs.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/hwmon.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/if.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/init.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/input.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/intel-iommu.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/irq.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/irqflags.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/kgdb.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/kstrtox.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/list_sort.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/mei_aux.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/mem_encrypt.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/mempolicy.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/mfd/core.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/mfd/intel_soc_pmic.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/mmc/card.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/mmc/core.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/mmc/host.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/mmc/mmc.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/mmc/sd.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/mmc/sdio.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/mmc/sdio_func.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/mmc/sdio_ids.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/mount.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/msi.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/nmi.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/nvmem-consumer.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/of_address.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/of_device.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/of_irq.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/oom.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/pci-p2pdma.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/perf_event.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/pgtable.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/pnp.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/prandom.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/property.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/pseudo_fs.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/relay.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/remoteproc.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/rtnetlink.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/sched/clock.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/sched/signal.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/sched/task.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/spinlock_types.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/stacktrace.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/stat.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/stop_machine.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/swiotlb.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/syscalls.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/sysfb.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/sysrq.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/thermal.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/time64.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/timekeeping.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/tty.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/util_macros.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/version.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/vt.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/linux/zlib.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/media/cec-notifier.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/net/gso.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/net/rtnetlink.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/trace/define_trace.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/uapi/linux/if_arp.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/uapi/linux/sched/types.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/video/nomodeset.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/video/of_display_timing.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/video/of_videomode.h0
-rw-r--r--sys/compat/linuxkpi/dummy/include/video/videomode.h0
-rw-r--r--sys/compat/x86bios/x86bios.c6
-rw-r--r--sys/compat/x86bios/x86bios.h2
455 files changed, 18867 insertions, 5793 deletions
diff --git a/sys/compat/freebsd32/Makefile b/sys/compat/freebsd32/Makefile
index b4f72fcc2bca..6d22d5d1ae41 100644
--- a/sys/compat/freebsd32/Makefile
+++ b/sys/compat/freebsd32/Makefile
@@ -1,6 +1,5 @@
# Makefile for syscall tables
#
-# $FreeBSD$
GENERATED_PREFIX= freebsd32_
SYSENT_FILE= ${SYSDIR}/kern/syscalls.master
diff --git a/sys/compat/freebsd32/freebsd32.h b/sys/compat/freebsd32/freebsd32.h
index 96dce0d1afa4..e1bfe282c4b1 100644
--- a/sys/compat/freebsd32/freebsd32.h
+++ b/sys/compat/freebsd32/freebsd32.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 Doug Rabson
* All rights reserved.
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _COMPAT_FREEBSD32_FREEBSD32_H_
@@ -492,10 +490,22 @@ struct timex32 {
int32_t stbcnt;
};
+struct ptrace_sc_ret32 {
+ uint32_t sr_retval[2];
+ int sr_error;
+};
+
struct ptrace_coredump32 {
int pc_fd;
uint32_t pc_flags;
uint32_t pc_limit1, pc_limit2;
};
+struct ptrace_sc_remote32 {
+ struct ptrace_sc_ret32 pscr_ret;
+ u_int pscr_syscall;
+ u_int pscr_nargs;
+ uint32_t pscr_args;
+};
+
#endif /* !_COMPAT_FREEBSD32_FREEBSD32_H_ */
diff --git a/sys/compat/freebsd32/freebsd32_abort2.c b/sys/compat/freebsd32/freebsd32_abort2.c
index 615dd5e95345..47386aa22855 100644
--- a/sys/compat/freebsd32/freebsd32_abort2.c
+++ b/sys/compat/freebsd32/freebsd32_abort2.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2005 Wojciech A. Koszek
* All rights reserved.
@@ -26,9 +26,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/sbuf.h>
diff --git a/sys/compat/freebsd32/freebsd32_capability.c b/sys/compat/freebsd32/freebsd32_capability.c
index ebcd4a6629c7..681e511a59de 100644
--- a/sys/compat/freebsd32/freebsd32_capability.c
+++ b/sys/compat/freebsd32/freebsd32_capability.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2013 The FreeBSD Foundation
*
@@ -29,8 +29,6 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include "opt_capsicum.h"
#include <sys/param.h>
@@ -119,9 +117,10 @@ freebsd32_cap_ioctls_get(struct thread *td,
cmds = fdep->fde_ioctls;
if (cmds32 != NULL && cmds != NULL) {
for (i = 0; i < MIN(fdep->fde_nioctls, maxcmds); i++) {
- error = suword32(&cmds32[i], cmds[i]);
- if (error != 0)
+ if (suword32(&cmds32[i], cmds[i]) != 0) {
+ error = EFAULT;
goto out;
+ }
}
}
if (fdep->fde_nioctls == -1)
diff --git a/sys/compat/freebsd32/freebsd32_ioctl.c b/sys/compat/freebsd32/freebsd32_ioctl.c
index 7f424b63f414..23c24e0b30a0 100644
--- a/sys/compat/freebsd32/freebsd32_ioctl.c
+++ b/sys/compat/freebsd32/freebsd32_ioctl.c
@@ -29,9 +29,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/capsicum.h>
#include <sys/cdio.h>
diff --git a/sys/compat/freebsd32/freebsd32_ioctl.h b/sys/compat/freebsd32/freebsd32_ioctl.h
index 0c0b18496a04..b22cd76cda8d 100644
--- a/sys/compat/freebsd32/freebsd32_ioctl.h
+++ b/sys/compat/freebsd32/freebsd32_ioctl.h
@@ -27,8 +27,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _COMPAT_FREEBSD32_IOCTL_H_
diff --git a/sys/compat/freebsd32/freebsd32_ipc.h b/sys/compat/freebsd32/freebsd32_ipc.h
index e3677d186da9..4ff8af359428 100644
--- a/sys/compat/freebsd32/freebsd32_ipc.h
+++ b/sys/compat/freebsd32/freebsd32_ipc.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Doug Rabson
* All rights reserved.
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _COMPAT_FREEBSD32_FREEBSD32_IPC_H_
@@ -45,8 +43,8 @@ struct semid_ds32 {
struct ipc_perm32 sem_perm;
uint32_t __sem_base;
unsigned short sem_nsems;
- int32_t sem_otime;
- int32_t sem_ctime;
+ time32_t sem_otime;
+ time32_t sem_ctime;
};
#ifdef _KERNEL
@@ -75,9 +73,9 @@ struct msqid_ds32 {
uint32_t msg_qbytes;
pid_t msg_lspid;
pid_t msg_lrpid;
- int32_t msg_stime;
- int32_t msg_rtime;
- int32_t msg_ctime;
+ time32_t msg_stime;
+ time32_t msg_rtime;
+ time32_t msg_ctime;
};
#ifdef _KERNEL
@@ -97,9 +95,9 @@ struct shmid_ds32 {
pid_t shm_lpid;
pid_t shm_cpid;
unsigned int shm_nattch;
- int32_t shm_atime;
- int32_t shm_dtime;
- int32_t shm_ctime;
+ time32_t shm_atime;
+ time32_t shm_dtime;
+ time32_t shm_ctime;
};
#ifdef _KERNEL
@@ -144,9 +142,9 @@ struct semid_ds_old32 {
struct ipc_perm_old32 sem_perm;
uint32_t __sem_base;
unsigned short sem_nsems;
- int32_t sem_otime;
+ time32_t sem_otime;
int32_t sem_pad1;
- int32_t sem_ctime;
+ time32_t sem_ctime;
int32_t sem_pad2;
int32_t sem_pad3[4];
};
@@ -160,11 +158,11 @@ struct msqid_ds_old32 {
uint32_t msg_qbytes;
pid_t msg_lspid;
pid_t msg_lrpid;
- int32_t msg_stime;
+ time32_t msg_stime;
int32_t msg_pad1;
- int32_t msg_rtime;
+ time32_t msg_rtime;
int32_t msg_pad2;
- int32_t msg_ctime;
+ time32_t msg_ctime;
int32_t msg_pad3;
int32_t msg_pad4[4];
};
@@ -175,9 +173,9 @@ struct shmid_ds_old32 {
pid_t shm_lpid;
pid_t shm_cpid;
int16_t shm_nattch;
- int32_t shm_atime;
- int32_t shm_dtime;
- int32_t shm_ctime;
+ time32_t shm_atime;
+ time32_t shm_dtime;
+ time32_t shm_ctime;
uint32_t shm_internal;
};
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index d1c44a4f9952..e6aea3acdecd 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Doug Rabson
* All rights reserved.
@@ -27,8 +27,6 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include "opt_ffclock.h"
#include "opt_inet.h"
#include "opt_inet6.h"
@@ -84,6 +82,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysproto.h>
#include <sys/systm.h>
#include <sys/thr.h>
+#include <sys/timerfd.h>
#include <sys/timex.h>
#include <sys/unistd.h>
#include <sys/ucontext.h>
@@ -124,7 +123,20 @@ __FBSDID("$FreeBSD$");
#include <compat/freebsd32/freebsd32_signal.h>
#include <compat/freebsd32/freebsd32_proto.h>
-FEATURE(compat_freebsd_32bit, "Compatible with 32-bit FreeBSD");
+int compat_freebsd_32bit = 1;
+
+static void
+register_compat32_feature(void *arg)
+{
+ if (!compat_freebsd_32bit)
+ return;
+
+ FEATURE_ADD("compat_freebsd32", "Compatible with 32-bit FreeBSD");
+ FEATURE_ADD("compat_freebsd_32bit",
+ "Compatible with 32-bit FreeBSD (legacy feature name)");
+}
+SYSINIT(freebsd32, SI_SUB_EXEC, SI_ORDER_ANY, register_compat32_feature,
+ NULL);
struct ptrace_io_desc32 {
int piod_op;
@@ -133,11 +145,6 @@ struct ptrace_io_desc32 {
uint32_t piod_len;
};
-struct ptrace_sc_ret32 {
- uint32_t sr_retval[2];
- int sr_error;
-};
-
struct ptrace_vm_entry32 {
int pve_entry;
int pve_timestamp;
@@ -240,7 +247,7 @@ freebsd32_wait6(struct thread *td, struct freebsd32_wait6_args *uap)
{
struct __wrusage32 wru32;
struct __wrusage wru, *wrup;
- struct siginfo32 si32;
+ struct __siginfo32 si32;
struct __siginfo si, *sip;
int error, status;
@@ -517,7 +524,7 @@ freebsd32_mprotect(struct thread *td, struct freebsd32_mprotect_args *uap)
prot |= PROT_EXEC;
#endif
return (kern_mprotect(td, (uintptr_t)PTRIN(uap->addr), uap->len,
- prot));
+ prot, 0));
}
int
@@ -971,6 +978,7 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
struct ptrace_lwpinfo pl;
struct ptrace_vm_entry pve;
struct ptrace_coredump pc;
+ struct ptrace_sc_remote sr;
struct dbreg32 dbreg;
struct fpreg32 fpreg;
struct reg32 reg;
@@ -984,10 +992,13 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
struct ptrace_lwpinfo32 pl;
struct ptrace_vm_entry32 pve;
struct ptrace_coredump32 pc;
+ struct ptrace_sc_remote32 sr;
uint32_t args[nitems(td->td_sa.args)];
struct ptrace_sc_ret32 psr;
struct iovec32 vec;
} r32;
+ syscallarg_t pscr_args[nitems(td->td_sa.args)];
+ u_int pscr_args32[nitems(td->td_sa.args)];
void *addr;
int data, error, i;
@@ -1015,7 +1026,7 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
*/
data = sizeof(r.pl);
if (uap->data < offsetof(struct ptrace_lwpinfo32, pl_siginfo) +
- sizeof(struct siginfo32))
+ sizeof(struct __siginfo32))
data = offsetof(struct ptrace_lwpinfo, pl_siginfo);
break;
case PT_GETREGS:
@@ -1086,6 +1097,28 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
r.pc.pc_limit = PAIR32TO64(off_t, r32.pc.pc_limit);
data = sizeof(r.pc);
break;
+ case PT_SC_REMOTE:
+ if (uap->data != sizeof(r32.sr)) {
+ error = EINVAL;
+ break;
+ }
+ error = copyin(uap->addr, &r32.sr, uap->data);
+ if (error != 0)
+ break;
+ CP(r32.sr, r.sr, pscr_syscall);
+ CP(r32.sr, r.sr, pscr_nargs);
+ if (r.sr.pscr_nargs > nitems(td->td_sa.args)) {
+ error = EINVAL;
+ break;
+ }
+ error = copyin(PTRIN(r32.sr.pscr_args), pscr_args32,
+ sizeof(u_int) * r32.sr.pscr_nargs);
+ if (error != 0)
+ break;
+ for (i = 0; i < r32.sr.pscr_nargs; i++)
+ pscr_args[i] = pscr_args32[i];
+ r.sr.pscr_args = pscr_args;
+ break;
default:
addr = uap->addr;
break;
@@ -1146,43 +1179,46 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
error = copyout(&r32.psr, uap->addr, MIN(uap->data,
sizeof(r32.psr)));
break;
+ case PT_SC_REMOTE:
+ ptrace_sc_ret_to32(&r.sr.pscr_ret, &r32.sr.pscr_ret);
+ error = copyout(&r32.sr.pscr_ret, uap->addr +
+ offsetof(struct ptrace_sc_remote32, pscr_ret),
+ sizeof(r32.psr));
+ break;
}
return (error);
}
int
-freebsd32_copyinuio(struct iovec32 *iovp, u_int iovcnt, struct uio **uiop)
+freebsd32_copyinuio(const struct iovec32 *iovp, u_int iovcnt, struct uio **uiop)
{
struct iovec32 iov32;
struct iovec *iov;
struct uio *uio;
- u_int iovlen;
int error, i;
*uiop = NULL;
if (iovcnt > UIO_MAXIOV)
return (EINVAL);
- iovlen = iovcnt * sizeof(struct iovec);
- uio = malloc(iovlen + sizeof *uio, M_IOV, M_WAITOK);
- iov = (struct iovec *)(uio + 1);
+ uio = allocuio(iovcnt);
+ iov = uio->uio_iov;
for (i = 0; i < iovcnt; i++) {
error = copyin(&iovp[i], &iov32, sizeof(struct iovec32));
if (error) {
- free(uio, M_IOV);
+ freeuio(uio);
return (error);
}
iov[i].iov_base = PTRIN(iov32.iov_base);
iov[i].iov_len = iov32.iov_len;
}
- uio->uio_iov = iov;
uio->uio_iovcnt = iovcnt;
uio->uio_segflg = UIO_USERSPACE;
uio->uio_offset = -1;
uio->uio_resid = 0;
for (i = 0; i < iovcnt; i++) {
if (iov->iov_len > INT_MAX - uio->uio_resid) {
- free(uio, M_IOV);
+ freeuio(uio);
return (EINVAL);
}
uio->uio_resid += iov->iov_len;
@@ -1202,7 +1238,7 @@ freebsd32_readv(struct thread *td, struct freebsd32_readv_args *uap)
if (error)
return (error);
error = kern_readv(td, uap->fd, auio);
- free(auio, M_IOV);
+ freeuio(auio);
return (error);
}
@@ -1216,7 +1252,7 @@ freebsd32_writev(struct thread *td, struct freebsd32_writev_args *uap)
if (error)
return (error);
error = kern_writev(td, uap->fd, auio);
- free(auio, M_IOV);
+ freeuio(auio);
return (error);
}
@@ -1230,7 +1266,7 @@ freebsd32_preadv(struct thread *td, struct freebsd32_preadv_args *uap)
if (error)
return (error);
error = kern_preadv(td, uap->fd, auio, PAIR32TO64(off_t,uap->offset));
- free(auio, M_IOV);
+ freeuio(auio);
return (error);
}
@@ -1244,7 +1280,7 @@ freebsd32_pwritev(struct thread *td, struct freebsd32_pwritev_args *uap)
if (error)
return (error);
error = kern_pwritev(td, uap->fd, auio, PAIR32TO64(off_t,uap->offset));
- free(auio, M_IOV);
+ freeuio(auio);
return (error);
}
@@ -1311,11 +1347,7 @@ freebsd32_copyoutmsghdr(struct msghdr *msg, struct msghdr32 *msg32)
return (error);
}
-#ifndef __mips__
#define FREEBSD32_ALIGNBYTES (sizeof(int) - 1)
-#else
-#define FREEBSD32_ALIGNBYTES (sizeof(long) - 1)
-#endif
#define FREEBSD32_ALIGN(p) \
(((u_long)(p) + FREEBSD32_ALIGNBYTES) & ~FREEBSD32_ALIGNBYTES)
#define FREEBSD32_CMSG_SPACE(l) \
@@ -1535,6 +1567,7 @@ freebsd32_copyin_control(struct mbuf **mp, caddr_t buf, u_int buflen)
u_int msglen, outlen;
int error;
+ /* Enforce the size limit of the native implementation. */
if (buflen > MCLBYTES)
return (EINVAL);
@@ -1555,35 +1588,39 @@ freebsd32_copyin_control(struct mbuf **mp, caddr_t buf, u_int buflen)
break;
}
cm = (struct cmsghdr *)in1;
- if (cm->cmsg_len < FREEBSD32_ALIGN(sizeof(*cm))) {
+ if (cm->cmsg_len < FREEBSD32_ALIGN(sizeof(*cm)) ||
+ cm->cmsg_len > buflen) {
error = EINVAL;
break;
}
msglen = FREEBSD32_ALIGN(cm->cmsg_len);
- if (msglen > buflen || msglen < cm->cmsg_len) {
+ if (msglen < cm->cmsg_len) {
error = EINVAL;
break;
}
+ /* The native ABI permits the final padding to be omitted. */
+ if (msglen > buflen)
+ msglen = buflen;
buflen -= msglen;
in1 = (char *)in1 + msglen;
outlen += CMSG_ALIGN(sizeof(*cm)) +
CMSG_ALIGN(msglen - FREEBSD32_ALIGN(sizeof(*cm)));
}
- if (error == 0 && outlen > MCLBYTES) {
- /*
- * XXXMJ This implies that the upper limit on 32-bit aligned
- * control messages is less than MCLBYTES, and so we are not
- * perfectly compatible. However, there is no platform
- * guarantee that mbuf clusters larger than MCLBYTES can be
- * allocated.
- */
- error = EINVAL;
- }
if (error != 0)
goto out;
+ /*
+ * Allocate up to MJUMPAGESIZE space for the re-aligned and
+ * re-padded control messages. This allows a full MCLBYTES of
+ * 32-bit sized and aligned messages to fit and avoids an ABI
+ * mismatch with the native implementation.
+ */
m = m_get2(outlen, M_WAITOK, MT_CONTROL, 0);
+ if (m == NULL) {
+ error = EINVAL;
+ goto out;
+ }
m->m_len = outlen;
md = mtod(m, void *);
@@ -2155,13 +2192,13 @@ freebsd32_do_sendfile(struct thread *td,
fdrop(fp, td);
if (uap->sbytes != NULL)
- copyout(&sbytes, uap->sbytes, sizeof(off_t));
+ (void)copyout(&sbytes, uap->sbytes, sizeof(off_t));
out:
if (hdr_uio)
- free(hdr_uio, M_IOV);
+ freeuio(hdr_uio);
if (trl_uio)
- free(trl_uio, M_IOV);
+ freeuio(trl_uio);
return (error);
}
@@ -2256,8 +2293,7 @@ ofreebsd32_stat(struct thread *td, struct ofreebsd32_stat_args *uap)
struct ostat32 sb32;
int error;
- error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE,
- &sb, NULL);
+ error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, &sb);
if (error)
return (error);
copy_ostat(&sb, &sb32);
@@ -2306,7 +2342,7 @@ freebsd32_fstatat(struct thread *td, struct freebsd32_fstatat_args *uap)
int error;
error = kern_statat(td, uap->flag, uap->fd, uap->path, UIO_USERSPACE,
- &ub, NULL);
+ &ub);
if (error)
return (error);
copy_stat(&ub, &ub32);
@@ -2323,7 +2359,7 @@ ofreebsd32_lstat(struct thread *td, struct ofreebsd32_lstat_args *uap)
int error;
error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path,
- UIO_USERSPACE, &sb, NULL);
+ UIO_USERSPACE, &sb);
if (error)
return (error);
copy_ostat(&sb, &sb32);
@@ -2441,8 +2477,7 @@ freebsd11_freebsd32_stat(struct thread *td,
struct freebsd11_stat32 sb32;
int error;
- error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE,
- &sb, NULL);
+ error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, &sb);
if (error != 0)
return (error);
error = freebsd11_cvtstat32(&sb, &sb32);
@@ -2477,7 +2512,7 @@ freebsd11_freebsd32_fstatat(struct thread *td,
int error;
error = kern_statat(td, uap->flag, uap->fd, uap->path, UIO_USERSPACE,
- &sb, NULL);
+ &sb);
if (error != 0)
return (error);
error = freebsd11_cvtstat32(&sb, &sb32);
@@ -2495,7 +2530,7 @@ freebsd11_freebsd32_lstat(struct thread *td,
int error;
error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path,
- UIO_USERSPACE, &sb, NULL);
+ UIO_USERSPACE, &sb);
if (error != 0)
return (error);
error = freebsd11_cvtstat32(&sb, &sb32);
@@ -2567,8 +2602,7 @@ freebsd11_freebsd32_nstat(struct thread *td,
struct nstat32 nsb;
int error;
- error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE,
- &sb, NULL);
+ error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, &sb);
if (error != 0)
return (error);
error = freebsd11_cvtnstat32(&sb, &nsb);
@@ -2586,7 +2620,7 @@ freebsd11_freebsd32_nlstat(struct thread *td,
int error;
error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path,
- UIO_USERSPACE, &sb, NULL);
+ UIO_USERSPACE, &sb);
if (error != 0)
return (error);
error = freebsd11_cvtnstat32(&sb, &nsb);
@@ -2638,9 +2672,9 @@ freebsd32___sysctl(struct thread *td, struct freebsd32___sysctl_args *uap)
uap->new, uap->newlen, &j, SCTL_MASK32);
if (error)
return (error);
- if (uap->oldlenp)
- suword32(uap->oldlenp, j);
- return (0);
+ if (uap->oldlenp != NULL && suword32(uap->oldlenp, j) != 0)
+ error = EFAULT;
+ return (error);
}
int
@@ -2663,9 +2697,8 @@ freebsd32___sysctlbyname(struct thread *td,
&oldlen, uap->new, uap->newlen, &rv, SCTL_MASK32, 1);
if (error != 0)
return (error);
- if (uap->oldlenp != NULL)
- error = suword32(uap->oldlenp, rv);
-
+ if (uap->oldlenp != NULL && suword32(uap->oldlenp, rv) != 0)
+ error = EFAULT;
return (error);
}
@@ -2744,7 +2777,7 @@ freebsd32_jail_set(struct thread *td, struct freebsd32_jail_set_args *uap)
if (error)
return (error);
error = kern_jail_set(td, auio, uap->flags);
- free(auio, M_IOV);
+ freeuio(auio);
return (error);
}
@@ -2771,7 +2804,7 @@ freebsd32_jail_get(struct thread *td, struct freebsd32_jail_get_args *uap)
if (error != 0)
break;
}
- free(auio, M_IOV);
+ freeuio(auio);
return (error);
}
@@ -3116,6 +3149,60 @@ freebsd32_ktimer_gettime(struct thread *td,
}
int
+freebsd32_timerfd_gettime(struct thread *td,
+ struct freebsd32_timerfd_gettime_args *uap)
+{
+ struct itimerspec curr_value;
+ struct itimerspec32 curr_value32;
+ int error;
+
+ error = kern_timerfd_gettime(td, uap->fd, &curr_value);
+ if (error == 0) {
+ CP(curr_value, curr_value32, it_value.tv_sec);
+ CP(curr_value, curr_value32, it_value.tv_nsec);
+ CP(curr_value, curr_value32, it_interval.tv_sec);
+ CP(curr_value, curr_value32, it_interval.tv_nsec);
+ error = copyout(&curr_value32, uap->curr_value,
+ sizeof(curr_value32));
+ }
+
+ return (error);
+}
+
+int
+freebsd32_timerfd_settime(struct thread *td,
+ struct freebsd32_timerfd_settime_args *uap)
+{
+ struct itimerspec new_value, old_value;
+ struct itimerspec32 new_value32, old_value32;
+ int error;
+
+ error = copyin(uap->new_value, &new_value32, sizeof(new_value32));
+ if (error != 0)
+ return (error);
+ CP(new_value32, new_value, it_value.tv_sec);
+ CP(new_value32, new_value, it_value.tv_nsec);
+ CP(new_value32, new_value, it_interval.tv_sec);
+ CP(new_value32, new_value, it_interval.tv_nsec);
+ if (uap->old_value == NULL) {
+ error = kern_timerfd_settime(td, uap->fd, uap->flags,
+ &new_value, NULL);
+ } else {
+ error = kern_timerfd_settime(td, uap->fd, uap->flags,
+ &new_value, &old_value);
+ if (error == 0) {
+ CP(old_value, old_value32, it_value.tv_sec);
+ CP(old_value, old_value32, it_value.tv_nsec);
+ CP(old_value, old_value32, it_interval.tv_sec);
+ CP(old_value, old_value32, it_interval.tv_nsec);
+ error = copyout(&old_value32, uap->old_value,
+ sizeof(old_value32));
+ }
+ }
+ return (error);
+}
+
+int
freebsd32_clock_getcpuclockid2(struct thread *td,
struct freebsd32_clock_getcpuclockid2_args *uap)
{
@@ -3184,7 +3271,7 @@ freebsd32_thr_suspend(struct thread *td, struct freebsd32_thr_suspend_args *uap)
}
void
-siginfo_to_siginfo32(const siginfo_t *src, struct siginfo32 *dst)
+siginfo_to_siginfo32(const siginfo_t *src, struct __siginfo32 *dst)
{
bzero(dst, sizeof(*dst));
dst->si_signo = src->si_signo;
@@ -3233,7 +3320,7 @@ freebsd32_sigtimedwait(struct thread *td, struct freebsd32_sigtimedwait_args *ua
struct timespec *timeout;
sigset_t set;
ksiginfo_t ksi;
- struct siginfo32 si32;
+ struct __siginfo32 si32;
int error;
if (uap->timeout) {
@@ -3256,7 +3343,7 @@ freebsd32_sigtimedwait(struct thread *td, struct freebsd32_sigtimedwait_args *ua
if (uap->info) {
siginfo_to_siginfo32(&ksi.ksi_info, &si32);
- error = copyout(&si32, uap->info, sizeof(struct siginfo32));
+ error = copyout(&si32, uap->info, sizeof(struct __siginfo32));
}
if (error == 0)
@@ -3271,7 +3358,7 @@ int
freebsd32_sigwaitinfo(struct thread *td, struct freebsd32_sigwaitinfo_args *uap)
{
ksiginfo_t ksi;
- struct siginfo32 si32;
+ struct __siginfo32 si32;
sigset_t set;
int error;
@@ -3285,7 +3372,7 @@ freebsd32_sigwaitinfo(struct thread *td, struct freebsd32_sigwaitinfo_args *uap)
if (uap->info) {
siginfo_to_siginfo32(&ksi.ksi_info, &si32);
- error = copyout(&si32, uap->info, sizeof(struct siginfo32));
+ error = copyout(&si32, uap->info, sizeof(struct __siginfo32));
}
if (error == 0)
td->td_retval[0] = ksi.ksi_signo;
@@ -3450,7 +3537,7 @@ freebsd32_nmount(struct thread *td,
return (error);
error = vfs_donmount(td, flags, auio);
- free(auio, M_IOV);
+ freeuio(auio);
return error;
}
@@ -3855,7 +3942,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap)
int
freebsd32_fcntl(struct thread *td, struct freebsd32_fcntl_args *uap)
{
- long tmp;
+ intptr_t tmp;
switch (uap->cmd) {
/*
diff --git a/sys/compat/freebsd32/freebsd32_misc.h b/sys/compat/freebsd32/freebsd32_misc.h
index f6f85adc8e72..b39b714183fb 100644
--- a/sys/compat/freebsd32/freebsd32_misc.h
+++ b/sys/compat/freebsd32/freebsd32_misc.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2013 The FreeBSD Foundation
*
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _COMPAT_FREEBSD32_MISC_H_
diff --git a/sys/compat/freebsd32/freebsd32_proto.h b/sys/compat/freebsd32/freebsd32_proto.h
index 4d56055e084d..cbb95f2b835b 100644
--- a/sys/compat/freebsd32/freebsd32_proto.h
+++ b/sys/compat/freebsd32/freebsd32_proto.h
@@ -2,14 +2,13 @@
* System call prototypes.
*
* DO NOT EDIT-- this file is automatically @generated.
- * $FreeBSD$
*/
#ifndef _FREEBSD32_SYSPROTO_H_
#define _FREEBSD32_SYSPROTO_H_
+#include <sys/types.h>
#include <sys/signal.h>
-#include <sys/acl.h>
#include <sys/cpuset.h>
#include <sys/domainset.h>
#include <sys/_ffcounter.h>
@@ -90,7 +89,7 @@ struct freebsd32_getitimer_args {
struct freebsd32_fcntl_args {
char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
char cmd_l_[PADL_(int)]; int cmd; char cmd_r_[PADR_(int)];
- char arg_l_[PADL_(int32_t)]; int32_t arg; char arg_r_[PADR_(int32_t)];
+ char arg_l_[PADL_(intptr_t)]; intptr_t arg; char arg_r_[PADR_(intptr_t)];
};
struct freebsd32_select_args {
char nd_l_[PADL_(int)]; int nd; char nd_r_[PADR_(int)];
@@ -109,12 +108,12 @@ struct freebsd32_getrusage_args {
};
struct freebsd32_readv_args {
char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
- char iovp_l_[PADL_(struct iovec32 *)]; struct iovec32 * iovp; char iovp_r_[PADR_(struct iovec32 *)];
+ char iovp_l_[PADL_(const struct iovec32 *)]; const struct iovec32 * iovp; char iovp_r_[PADR_(const struct iovec32 *)];
char iovcnt_l_[PADL_(u_int)]; u_int iovcnt; char iovcnt_r_[PADR_(u_int)];
};
struct freebsd32_writev_args {
char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
- char iovp_l_[PADL_(struct iovec32 *)]; struct iovec32 * iovp; char iovp_r_[PADR_(struct iovec32 *)];
+ char iovp_l_[PADL_(const struct iovec32 *)]; const struct iovec32 * iovp; char iovp_r_[PADR_(const struct iovec32 *)];
char iovcnt_l_[PADL_(u_int)]; u_int iovcnt; char iovcnt_r_[PADR_(u_int)];
};
struct freebsd32_settimeofday_args {
@@ -295,12 +294,12 @@ struct freebsd32_jail_args {
};
struct freebsd32_sigtimedwait_args {
char set_l_[PADL_(const sigset_t *)]; const sigset_t * set; char set_r_[PADR_(const sigset_t *)];
- char info_l_[PADL_(struct siginfo32 *)]; struct siginfo32 * info; char info_r_[PADR_(struct siginfo32 *)];
+ char info_l_[PADL_(struct __siginfo32 *)]; struct __siginfo32 * info; char info_r_[PADR_(struct __siginfo32 *)];
char timeout_l_[PADL_(const struct timespec32 *)]; const struct timespec32 * timeout; char timeout_r_[PADR_(const struct timespec32 *)];
};
struct freebsd32_sigwaitinfo_args {
char set_l_[PADL_(const sigset_t *)]; const sigset_t * set; char set_r_[PADR_(const sigset_t *)];
- char info_l_[PADL_(struct siginfo32 *)]; struct siginfo32 * info; char info_r_[PADR_(struct siginfo32 *)];
+ char info_l_[PADL_(struct __siginfo32 *)]; struct __siginfo32 * info; char info_r_[PADR_(struct __siginfo32 *)];
};
struct freebsd32_aio_waitcomplete_args {
char aiocbp_l_[PADL_(uint32_t *)]; uint32_t * aiocbp; char aiocbp_r_[PADR_(uint32_t *)];
@@ -575,7 +574,7 @@ struct freebsd32_wait6_args {
char status_l_[PADL_(int *)]; int * status; char status_r_[PADR_(int *)];
char options_l_[PADL_(int)]; int options; char options_r_[PADR_(int)];
char wrusage_l_[PADL_(struct __wrusage32 *)]; struct __wrusage32 * wrusage; char wrusage_r_[PADR_(struct __wrusage32 *)];
- char info_l_[PADL_(struct siginfo32 *)]; struct siginfo32 * info; char info_r_[PADR_(struct siginfo32 *)];
+ char info_l_[PADL_(struct __siginfo32 *)]; struct __siginfo32 * info; char info_r_[PADR_(struct __siginfo32 *)];
};
struct freebsd32_cap_ioctls_limit_args {
char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
@@ -685,6 +684,16 @@ struct freebsd32_aio_writev_args {
struct freebsd32_aio_readv_args {
char aiocbp_l_[PADL_(struct aiocb32 *)]; struct aiocb32 * aiocbp; char aiocbp_r_[PADR_(struct aiocb32 *)];
};
+struct freebsd32_timerfd_gettime_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char curr_value_l_[PADL_(struct itimerspec32 *)]; struct itimerspec32 * curr_value; char curr_value_r_[PADR_(struct itimerspec32 *)];
+};
+struct freebsd32_timerfd_settime_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+ char flags_l_[PADL_(int)]; int flags; char flags_r_[PADR_(int)];
+ char new_value_l_[PADL_(const struct itimerspec32 *)]; const struct itimerspec32 * new_value; char new_value_r_[PADR_(const struct itimerspec32 *)];
+ char old_value_l_[PADL_(struct itimerspec32 *)]; struct itimerspec32 * old_value; char old_value_r_[PADR_(struct itimerspec32 *)];
+};
int freebsd32_wait4(struct thread *, struct freebsd32_wait4_args *);
int freebsd32_ptrace(struct thread *, struct freebsd32_ptrace_args *);
int freebsd32_recvmsg(struct thread *, struct freebsd32_recvmsg_args *);
@@ -800,6 +809,8 @@ int freebsd32_cpuset_setdomain(struct thread *, struct freebsd32_cpuset_setdomai
int freebsd32___sysctlbyname(struct thread *, struct freebsd32___sysctlbyname_args *);
int freebsd32_aio_writev(struct thread *, struct freebsd32_aio_writev_args *);
int freebsd32_aio_readv(struct thread *, struct freebsd32_aio_readv_args *);
+int freebsd32_timerfd_gettime(struct thread *, struct freebsd32_timerfd_gettime_args *);
+int freebsd32_timerfd_settime(struct thread *, struct freebsd32_timerfd_settime_args *);
#ifdef COMPAT_43
@@ -1131,6 +1142,12 @@ int freebsd11_freebsd32_fstatat(struct thread *, struct freebsd11_freebsd32_fsta
#endif /* COMPAT_FREEBSD13 */
+
+#ifdef COMPAT_FREEBSD14
+
+
+#endif /* COMPAT_FREEBSD14 */
+
#define FREEBSD32_SYS_AUE_freebsd32_wait4 AUE_WAIT4
#define FREEBSD32_SYS_AUE_freebsd4_freebsd32_getfsstat AUE_GETFSSTAT
#define FREEBSD32_SYS_AUE_ofreebsd32_lseek AUE_LSEEK
@@ -1293,6 +1310,8 @@ int freebsd11_freebsd32_fstatat(struct thread *, struct freebsd11_freebsd32_fsta
#define FREEBSD32_SYS_AUE_freebsd32___sysctlbyname AUE_SYSCTL
#define FREEBSD32_SYS_AUE_freebsd32_aio_writev AUE_AIO_WRITEV
#define FREEBSD32_SYS_AUE_freebsd32_aio_readv AUE_AIO_READV
+#define FREEBSD32_SYS_AUE_freebsd32_timerfd_gettime AUE_TIMERFD
+#define FREEBSD32_SYS_AUE_freebsd32_timerfd_settime AUE_TIMERFD
#undef PAD_
#undef PADL_
diff --git a/sys/compat/freebsd32/freebsd32_signal.h b/sys/compat/freebsd32/freebsd32_signal.h
index 9cfa4ab6fd75..379387dc3a8b 100644
--- a/sys/compat/freebsd32/freebsd32_signal.h
+++ b/sys/compat/freebsd32/freebsd32_signal.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2006 David Xu <davidxu@freebsd.org>
* All rights reserved.
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _COMPAT_FREEBSD32_SIGNAL_H_
@@ -63,6 +61,6 @@ struct sigevent32 {
struct sigevent;
int convert_sigevent32(struct sigevent32 *sig32, struct sigevent *sig);
-void siginfo_to_siginfo32(const siginfo_t *src, struct siginfo32 *dst);
+void siginfo_to_siginfo32(const siginfo_t *src, struct __siginfo32 *dst);
#endif /* !_COMPAT_FREEBSD32_SIGNAL_H_ */
diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h
index 4e055a27f3c6..662947c330d4 100644
--- a/sys/compat/freebsd32/freebsd32_syscall.h
+++ b/sys/compat/freebsd32/freebsd32_syscall.h
@@ -2,7 +2,6 @@
* System call numbers.
*
* DO NOT EDIT-- this file is automatically @generated.
- * $FreeBSD$
*/
#define FREEBSD32_SYS_syscall 0
@@ -74,8 +73,8 @@
#define FREEBSD32_SYS_vfork 66
/* 67 is obsolete vread */
/* 68 is obsolete vwrite */
-#define FREEBSD32_SYS_sbrk 69
-#define FREEBSD32_SYS_sstk 70
+ /* 69 is obsolete sbrk */
+ /* 70 is obsolete sstk */
/* 71 is old freebsd32_mmap */
#define FREEBSD32_SYS_freebsd11_vadvise 72
#define FREEBSD32_SYS_munmap 73
@@ -141,7 +140,7 @@
#define FREEBSD32_SYS_mkdir 136
#define FREEBSD32_SYS_rmdir 137
#define FREEBSD32_SYS_freebsd32_utimes 138
- /* 139 is obsolete 4.2 sigreturn */
+ /* 139 is obsolete sigreturn */
#define FREEBSD32_SYS_freebsd32_adjtime 140
/* 141 is old getpeername */
/* 142 is old gethostid */
@@ -327,6 +326,7 @@
#define FREEBSD32_SYS_lchflags 391
#define FREEBSD32_SYS_uuidgen 392
#define FREEBSD32_SYS_freebsd32_sendfile 393
+#define FREEBSD32_SYS_mac_syscall 394
#define FREEBSD32_SYS_freebsd11_freebsd32_getfsstat 395
#define FREEBSD32_SYS_freebsd11_statfs 396
#define FREEBSD32_SYS_freebsd11_fstatfs 397
@@ -501,4 +501,10 @@
#define FREEBSD32_SYS_fspacectl 580
#define FREEBSD32_SYS_sched_getcpu 581
#define FREEBSD32_SYS_swapoff 582
-#define FREEBSD32_SYS_MAXSYSCALL 583
+#define FREEBSD32_SYS_kqueuex 583
+#define FREEBSD32_SYS_membarrier 584
+#define FREEBSD32_SYS_timerfd_create 585
+#define FREEBSD32_SYS_freebsd32_timerfd_gettime 586
+#define FREEBSD32_SYS_freebsd32_timerfd_settime 587
+#define FREEBSD32_SYS_kcmp 588
+#define FREEBSD32_SYS_MAXSYSCALL 589
diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c
index d52c197b8f26..b4c41fdbbc12 100644
--- a/sys/compat/freebsd32/freebsd32_syscalls.c
+++ b/sys/compat/freebsd32/freebsd32_syscalls.c
@@ -2,7 +2,6 @@
* System call names.
*
* DO NOT EDIT-- this file is automatically @generated.
- * $FreeBSD$
*/
const char *freebsd32_syscallnames[] = {
@@ -75,8 +74,8 @@ const char *freebsd32_syscallnames[] = {
"vfork", /* 66 = vfork */
"obs_vread", /* 67 = obsolete vread */
"obs_vwrite", /* 68 = obsolete vwrite */
- "sbrk", /* 69 = sbrk */
- "sstk", /* 70 = sstk */
+ "obs_sbrk", /* 69 = obsolete sbrk */
+ "obs_sstk", /* 70 = obsolete sstk */
"compat.freebsd32_mmap", /* 71 = old freebsd32_mmap */
"compat11.vadvise", /* 72 = freebsd11 vadvise */
"munmap", /* 73 = munmap */
@@ -145,7 +144,7 @@ const char *freebsd32_syscallnames[] = {
"mkdir", /* 136 = mkdir */
"rmdir", /* 137 = rmdir */
"freebsd32_utimes", /* 138 = freebsd32_utimes */
- "obs_4.2", /* 139 = obsolete 4.2 sigreturn */
+ "obs_freebsd32_sigreturn", /* 139 = obsolete sigreturn */
"freebsd32_adjtime", /* 140 = freebsd32_adjtime */
"compat.getpeername", /* 141 = old getpeername */
"compat.gethostid", /* 142 = old gethostid */
@@ -400,7 +399,7 @@ const char *freebsd32_syscallnames[] = {
"lchflags", /* 391 = lchflags */
"uuidgen", /* 392 = uuidgen */
"freebsd32_sendfile", /* 393 = freebsd32_sendfile */
- "#394", /* 394 = mac_syscall */
+ "mac_syscall", /* 394 = mac_syscall */
"compat11.freebsd32_getfsstat", /* 395 = freebsd11 freebsd32_getfsstat */
"compat11.statfs", /* 396 = freebsd11 statfs */
"compat11.fstatfs", /* 397 = freebsd11 fstatfs */
@@ -589,4 +588,10 @@ const char *freebsd32_syscallnames[] = {
"fspacectl", /* 580 = fspacectl */
"sched_getcpu", /* 581 = sched_getcpu */
"swapoff", /* 582 = swapoff */
+ "kqueuex", /* 583 = kqueuex */
+ "membarrier", /* 584 = membarrier */
+ "timerfd_create", /* 585 = timerfd_create */
+ "freebsd32_timerfd_gettime", /* 586 = freebsd32_timerfd_gettime */
+ "freebsd32_timerfd_settime", /* 587 = freebsd32_timerfd_settime */
+ "kcmp", /* 588 = kcmp */
};
diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c
index ee9630ff3783..13d80c695169 100644
--- a/sys/compat/freebsd32/freebsd32_sysent.c
+++ b/sys/compat/freebsd32/freebsd32_sysent.c
@@ -2,7 +2,6 @@
* System call switch table.
*
* DO NOT EDIT-- this file is automatically @generated.
- * $FreeBSD$
*/
#include <sys/param.h>
@@ -131,8 +130,8 @@ struct sysent freebsd32_sysent[] = {
{ .sy_narg = 0, .sy_call = (sy_call_t *)sys_vfork, .sy_auevent = AUE_VFORK, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 66 = vfork */
{ .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 67 = obsolete vread */
{ .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 68 = obsolete vwrite */
- { .sy_narg = AS(sbrk_args), .sy_call = (sy_call_t *)sys_sbrk, .sy_auevent = AUE_SBRK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 69 = sbrk */
- { .sy_narg = AS(sstk_args), .sy_call = (sy_call_t *)sys_sstk, .sy_auevent = AUE_SSTK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 70 = sstk */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 69 = obsolete sbrk */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 70 = obsolete sstk */
{ compat(AS(ofreebsd32_mmap_args),freebsd32_mmap), .sy_auevent = AUE_MMAP, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 71 = old freebsd32_mmap */
{ compat11(AS(freebsd11_vadvise_args),vadvise), .sy_auevent = AUE_O_VADVISE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 72 = freebsd11 vadvise */
{ .sy_narg = AS(munmap_args), .sy_call = (sy_call_t *)sys_munmap, .sy_auevent = AUE_MUNMAP, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 73 = munmap */
@@ -201,7 +200,7 @@ struct sysent freebsd32_sysent[] = {
{ .sy_narg = AS(mkdir_args), .sy_call = (sy_call_t *)sys_mkdir, .sy_auevent = AUE_MKDIR, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 136 = mkdir */
{ .sy_narg = AS(rmdir_args), .sy_call = (sy_call_t *)sys_rmdir, .sy_auevent = AUE_RMDIR, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 137 = rmdir */
{ .sy_narg = AS(freebsd32_utimes_args), .sy_call = (sy_call_t *)freebsd32_utimes, .sy_auevent = AUE_UTIMES, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 138 = freebsd32_utimes */
- { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 139 = obsolete 4.2 sigreturn */
+ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 139 = obsolete sigreturn */
{ .sy_narg = AS(freebsd32_adjtime_args), .sy_call = (sy_call_t *)freebsd32_adjtime, .sy_auevent = AUE_ADJTIME, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 140 = freebsd32_adjtime */
{ compat(AS(ogetpeername_args),getpeername), .sy_auevent = AUE_GETPEERNAME, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 141 = old getpeername */
{ compat(0,gethostid), .sy_auevent = AUE_SYSCTL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 142 = old gethostid */
@@ -456,7 +455,7 @@ struct sysent freebsd32_sysent[] = {
{ .sy_narg = AS(lchflags_args), .sy_call = (sy_call_t *)sys_lchflags, .sy_auevent = AUE_LCHFLAGS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 391 = lchflags */
{ .sy_narg = AS(uuidgen_args), .sy_call = (sy_call_t *)sys_uuidgen, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 392 = uuidgen */
{ .sy_narg = AS(freebsd32_sendfile_args), .sy_call = (sy_call_t *)freebsd32_sendfile, .sy_auevent = AUE_SENDFILE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 393 = freebsd32_sendfile */
- { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 394 = mac_syscall */
+ { .sy_narg = AS(mac_syscall_args), .sy_call = (sy_call_t *)sys_mac_syscall, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 394 = mac_syscall */
{ compat11(AS(freebsd11_freebsd32_getfsstat_args),freebsd32_getfsstat), .sy_auevent = AUE_GETFSSTAT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 395 = freebsd11 freebsd32_getfsstat */
{ compat11(AS(freebsd11_statfs_args),statfs), .sy_auevent = AUE_STATFS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 396 = freebsd11 statfs */
{ compat11(AS(freebsd11_fstatfs_args),fstatfs), .sy_auevent = AUE_FSTATFS, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 397 = freebsd11 fstatfs */
@@ -645,4 +644,10 @@ struct sysent freebsd32_sysent[] = {
{ .sy_narg = AS(fspacectl_args), .sy_call = (sy_call_t *)sys_fspacectl, .sy_auevent = AUE_FSPACECTL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 580 = fspacectl */
{ .sy_narg = 0, .sy_call = (sy_call_t *)sys_sched_getcpu, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 581 = sched_getcpu */
{ .sy_narg = AS(swapoff_args), .sy_call = (sy_call_t *)sys_swapoff, .sy_auevent = AUE_SWAPOFF, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 582 = swapoff */
+ { .sy_narg = AS(kqueuex_args), .sy_call = (sy_call_t *)sys_kqueuex, .sy_auevent = AUE_KQUEUE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 583 = kqueuex */
+ { .sy_narg = AS(membarrier_args), .sy_call = (sy_call_t *)sys_membarrier, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 584 = membarrier */
+ { .sy_narg = AS(timerfd_create_args), .sy_call = (sy_call_t *)sys_timerfd_create, .sy_auevent = AUE_TIMERFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 585 = timerfd_create */
+ { .sy_narg = AS(freebsd32_timerfd_gettime_args), .sy_call = (sy_call_t *)freebsd32_timerfd_gettime, .sy_auevent = AUE_TIMERFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 586 = freebsd32_timerfd_gettime */
+ { .sy_narg = AS(freebsd32_timerfd_settime_args), .sy_call = (sy_call_t *)freebsd32_timerfd_settime, .sy_auevent = AUE_TIMERFD, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 587 = freebsd32_timerfd_settime */
+ { .sy_narg = AS(kcmp_args), .sy_call = (sy_call_t *)sys_kcmp, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 588 = kcmp */
};
diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c
index 92ea09104a26..bfcf9a46b485 100644
--- a/sys/compat/freebsd32/freebsd32_systrace_args.c
+++ b/sys/compat/freebsd32/freebsd32_systrace_args.c
@@ -5,7 +5,6 @@
* System call argument to DTrace register array converstion.
*
* DO NOT EDIT-- this file is automatically @generated.
- * $FreeBSD$
* This file is part of the DTrace syscall provider.
*/
@@ -422,20 +421,6 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
*n_args = 0;
break;
}
- /* sbrk */
- case 69: {
- struct sbrk_args *p = params;
- iarg[a++] = p->incr; /* int */
- *n_args = 1;
- break;
- }
- /* sstk */
- case 70: {
- struct sstk_args *p = params;
- iarg[a++] = p->incr; /* int */
- *n_args = 1;
- break;
- }
/* munmap */
case 73: {
struct munmap_args *p = params;
@@ -542,7 +527,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
struct freebsd32_fcntl_args *p = params;
iarg[a++] = p->fd; /* int */
iarg[a++] = p->cmd; /* int */
- iarg[a++] = p->arg; /* int32_t */
+ uarg[a++] = (intptr_t)p->arg; /* intptr_t */
*n_args = 3;
break;
}
@@ -658,7 +643,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 120: {
struct freebsd32_readv_args *p = params;
iarg[a++] = p->fd; /* int */
- uarg[a++] = (intptr_t)p->iovp; /* struct iovec32 * */
+ uarg[a++] = (intptr_t)p->iovp; /* const struct iovec32 * */
uarg[a++] = p->iovcnt; /* u_int */
*n_args = 3;
break;
@@ -667,7 +652,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 121: {
struct freebsd32_writev_args *p = params;
iarg[a++] = p->fd; /* int */
- uarg[a++] = (intptr_t)p->iovp; /* struct iovec32 * */
+ uarg[a++] = (intptr_t)p->iovp; /* const struct iovec32 * */
uarg[a++] = p->iovcnt; /* u_int */
*n_args = 3;
break;
@@ -1598,7 +1583,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 345: {
struct freebsd32_sigtimedwait_args *p = params;
uarg[a++] = (intptr_t)p->set; /* const sigset_t * */
- uarg[a++] = (intptr_t)p->info; /* struct siginfo32 * */
+ uarg[a++] = (intptr_t)p->info; /* struct __siginfo32 * */
uarg[a++] = (intptr_t)p->timeout; /* const struct timespec32 * */
*n_args = 3;
break;
@@ -1607,7 +1592,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 346: {
struct freebsd32_sigwaitinfo_args *p = params;
uarg[a++] = (intptr_t)p->set; /* const sigset_t * */
- uarg[a++] = (intptr_t)p->info; /* struct siginfo32 * */
+ uarg[a++] = (intptr_t)p->info; /* struct __siginfo32 * */
*n_args = 2;
break;
}
@@ -1615,7 +1600,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 347: {
struct __acl_get_file_args *p = params;
uarg[a++] = (intptr_t)p->path; /* const char * */
- iarg[a++] = p->type; /* acl_type_t */
+ iarg[a++] = p->type; /* __acl_type_t */
uarg[a++] = (intptr_t)p->aclp; /* struct acl * */
*n_args = 3;
break;
@@ -1624,7 +1609,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 348: {
struct __acl_set_file_args *p = params;
uarg[a++] = (intptr_t)p->path; /* const char * */
- iarg[a++] = p->type; /* acl_type_t */
+ iarg[a++] = p->type; /* __acl_type_t */
uarg[a++] = (intptr_t)p->aclp; /* struct acl * */
*n_args = 3;
break;
@@ -1633,7 +1618,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 349: {
struct __acl_get_fd_args *p = params;
iarg[a++] = p->filedes; /* int */
- iarg[a++] = p->type; /* acl_type_t */
+ iarg[a++] = p->type; /* __acl_type_t */
uarg[a++] = (intptr_t)p->aclp; /* struct acl * */
*n_args = 3;
break;
@@ -1642,7 +1627,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 350: {
struct __acl_set_fd_args *p = params;
iarg[a++] = p->filedes; /* int */
- iarg[a++] = p->type; /* acl_type_t */
+ iarg[a++] = p->type; /* __acl_type_t */
uarg[a++] = (intptr_t)p->aclp; /* struct acl * */
*n_args = 3;
break;
@@ -1651,7 +1636,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 351: {
struct __acl_delete_file_args *p = params;
uarg[a++] = (intptr_t)p->path; /* const char * */
- iarg[a++] = p->type; /* acl_type_t */
+ iarg[a++] = p->type; /* __acl_type_t */
*n_args = 2;
break;
}
@@ -1659,7 +1644,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 352: {
struct __acl_delete_fd_args *p = params;
iarg[a++] = p->filedes; /* int */
- iarg[a++] = p->type; /* acl_type_t */
+ iarg[a++] = p->type; /* __acl_type_t */
*n_args = 2;
break;
}
@@ -1667,7 +1652,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 353: {
struct __acl_aclcheck_file_args *p = params;
uarg[a++] = (intptr_t)p->path; /* const char * */
- iarg[a++] = p->type; /* acl_type_t */
+ iarg[a++] = p->type; /* __acl_type_t */
uarg[a++] = (intptr_t)p->aclp; /* struct acl * */
*n_args = 3;
break;
@@ -1676,7 +1661,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 354: {
struct __acl_aclcheck_fd_args *p = params;
iarg[a++] = p->filedes; /* int */
- iarg[a++] = p->type; /* acl_type_t */
+ iarg[a++] = p->type; /* __acl_type_t */
uarg[a++] = (intptr_t)p->aclp; /* struct acl * */
*n_args = 3;
break;
@@ -1849,6 +1834,15 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
*n_args = 8;
break;
}
+ /* mac_syscall */
+ case 394: {
+ struct mac_syscall_args *p = params;
+ uarg[a++] = (intptr_t)p->policy; /* const char * */
+ iarg[a++] = p->call; /* int */
+ uarg[a++] = (intptr_t)p->arg; /* void * */
+ *n_args = 3;
+ break;
+ }
/* ksem_close */
case 400: {
struct ksem_close_args *p = params;
@@ -1991,7 +1985,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 425: {
struct __acl_get_link_args *p = params;
uarg[a++] = (intptr_t)p->path; /* const char * */
- iarg[a++] = p->type; /* acl_type_t */
+ iarg[a++] = p->type; /* __acl_type_t */
uarg[a++] = (intptr_t)p->aclp; /* struct acl * */
*n_args = 3;
break;
@@ -2000,7 +1994,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 426: {
struct __acl_set_link_args *p = params;
uarg[a++] = (intptr_t)p->path; /* const char * */
- iarg[a++] = p->type; /* acl_type_t */
+ iarg[a++] = p->type; /* __acl_type_t */
uarg[a++] = (intptr_t)p->aclp; /* struct acl * */
*n_args = 3;
break;
@@ -2009,7 +2003,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 427: {
struct __acl_delete_link_args *p = params;
uarg[a++] = (intptr_t)p->path; /* const char * */
- iarg[a++] = p->type; /* acl_type_t */
+ iarg[a++] = p->type; /* __acl_type_t */
*n_args = 2;
break;
}
@@ -2017,7 +2011,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 428: {
struct __acl_aclcheck_link_args *p = params;
uarg[a++] = (intptr_t)p->path; /* const char * */
- iarg[a++] = p->type; /* acl_type_t */
+ iarg[a++] = p->type; /* __acl_type_t */
uarg[a++] = (intptr_t)p->aclp; /* struct acl * */
*n_args = 3;
break;
@@ -2868,7 +2862,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
uarg[a++] = (intptr_t)p->status; /* int * */
iarg[a++] = p->options; /* int */
uarg[a++] = (intptr_t)p->wrusage; /* struct __wrusage32 * */
- uarg[a++] = (intptr_t)p->info; /* struct siginfo32 * */
+ uarg[a++] = (intptr_t)p->info; /* struct __siginfo32 * */
*n_args = 8;
break;
}
@@ -3242,7 +3236,7 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
case 573: {
struct sigfastblock_args *p = params;
iarg[a++] = p->cmd; /* int */
- uarg[a++] = (intptr_t)p->ptr; /* uint32_t * */
+ uarg[a++] = (intptr_t)p->ptr; /* void * */
*n_args = 2;
break;
}
@@ -3321,6 +3315,59 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
*n_args = 2;
break;
}
+ /* kqueuex */
+ case 583: {
+ struct kqueuex_args *p = params;
+ uarg[a++] = p->flags; /* u_int */
+ *n_args = 1;
+ break;
+ }
+ /* membarrier */
+ case 584: {
+ struct membarrier_args *p = params;
+ iarg[a++] = p->cmd; /* int */
+ uarg[a++] = p->flags; /* unsigned */
+ iarg[a++] = p->cpu_id; /* int */
+ *n_args = 3;
+ break;
+ }
+ /* timerfd_create */
+ case 585: {
+ struct timerfd_create_args *p = params;
+ iarg[a++] = p->clockid; /* int */
+ iarg[a++] = p->flags; /* int */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_timerfd_gettime */
+ case 586: {
+ struct freebsd32_timerfd_gettime_args *p = params;
+ iarg[a++] = p->fd; /* int */
+ uarg[a++] = (intptr_t)p->curr_value; /* struct itimerspec32 * */
+ *n_args = 2;
+ break;
+ }
+ /* freebsd32_timerfd_settime */
+ case 587: {
+ struct freebsd32_timerfd_settime_args *p = params;
+ iarg[a++] = p->fd; /* int */
+ iarg[a++] = p->flags; /* int */
+ uarg[a++] = (intptr_t)p->new_value; /* const struct itimerspec32 * */
+ uarg[a++] = (intptr_t)p->old_value; /* struct itimerspec32 * */
+ *n_args = 4;
+ break;
+ }
+ /* kcmp */
+ case 588: {
+ struct kcmp_args *p = params;
+ iarg[a++] = p->pid1; /* pid_t */
+ iarg[a++] = p->pid2; /* pid_t */
+ iarg[a++] = p->type; /* int */
+ uarg[a++] = (intptr_t)p->idx1; /* uintptr_t */
+ uarg[a++] = (intptr_t)p->idx2; /* uintptr_t */
+ *n_args = 5;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -3959,26 +4006,6 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
/* vfork */
case 66:
break;
- /* sbrk */
- case 69:
- switch (ndx) {
- case 0:
- p = "int";
- break;
- default:
- break;
- };
- break;
- /* sstk */
- case 70:
- switch (ndx) {
- case 0:
- p = "int";
- break;
- default:
- break;
- };
- break;
/* munmap */
case 73:
switch (ndx) {
@@ -4147,7 +4174,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "int";
break;
case 2:
- p = "int32_t";
+ p = "intptr_t";
break;
default:
break;
@@ -4352,7 +4379,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "int";
break;
case 1:
- p = "userland struct iovec32 *";
+ p = "userland const struct iovec32 *";
break;
case 2:
p = "u_int";
@@ -4368,7 +4395,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "int";
break;
case 1:
- p = "userland struct iovec32 *";
+ p = "userland const struct iovec32 *";
break;
case 2:
p = "u_int";
@@ -5838,7 +5865,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "userland const sigset_t *";
break;
case 1:
- p = "userland struct siginfo32 *";
+ p = "userland struct __siginfo32 *";
break;
case 2:
p = "userland const struct timespec32 *";
@@ -5854,7 +5881,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "userland const sigset_t *";
break;
case 1:
- p = "userland struct siginfo32 *";
+ p = "userland struct __siginfo32 *";
break;
default:
break;
@@ -5867,7 +5894,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "userland const char *";
break;
case 1:
- p = "acl_type_t";
+ p = "__acl_type_t";
break;
case 2:
p = "userland struct acl *";
@@ -5883,7 +5910,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "userland const char *";
break;
case 1:
- p = "acl_type_t";
+ p = "__acl_type_t";
break;
case 2:
p = "userland struct acl *";
@@ -5899,7 +5926,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "int";
break;
case 1:
- p = "acl_type_t";
+ p = "__acl_type_t";
break;
case 2:
p = "userland struct acl *";
@@ -5915,7 +5942,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "int";
break;
case 1:
- p = "acl_type_t";
+ p = "__acl_type_t";
break;
case 2:
p = "userland struct acl *";
@@ -5931,7 +5958,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "userland const char *";
break;
case 1:
- p = "acl_type_t";
+ p = "__acl_type_t";
break;
default:
break;
@@ -5944,7 +5971,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "int";
break;
case 1:
- p = "acl_type_t";
+ p = "__acl_type_t";
break;
default:
break;
@@ -5957,7 +5984,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "userland const char *";
break;
case 1:
- p = "acl_type_t";
+ p = "__acl_type_t";
break;
case 2:
p = "userland struct acl *";
@@ -5973,7 +6000,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "int";
break;
case 1:
- p = "acl_type_t";
+ p = "__acl_type_t";
break;
case 2:
p = "userland struct acl *";
@@ -6287,6 +6314,22 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
};
break;
+ /* mac_syscall */
+ case 394:
+ switch (ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland void *";
+ break;
+ default:
+ break;
+ };
+ break;
/* ksem_close */
case 400:
switch (ndx) {
@@ -6521,7 +6564,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "userland const char *";
break;
case 1:
- p = "acl_type_t";
+ p = "__acl_type_t";
break;
case 2:
p = "userland struct acl *";
@@ -6537,7 +6580,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "userland const char *";
break;
case 1:
- p = "acl_type_t";
+ p = "__acl_type_t";
break;
case 2:
p = "userland struct acl *";
@@ -6553,7 +6596,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "userland const char *";
break;
case 1:
- p = "acl_type_t";
+ p = "__acl_type_t";
break;
default:
break;
@@ -6566,7 +6609,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "userland const char *";
break;
case 1:
- p = "acl_type_t";
+ p = "__acl_type_t";
break;
case 2:
p = "userland struct acl *";
@@ -8136,7 +8179,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "userland struct __wrusage32 *";
break;
case 7 - _P_:
- p = "userland struct siginfo32 *";
+ p = "userland struct __siginfo32 *";
break;
default:
break;
@@ -8833,7 +8876,7 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
p = "int";
break;
case 1:
- p = "userland uint32_t *";
+ p = "userland void *";
break;
default:
break;
@@ -8964,6 +9007,99 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
};
break;
+ /* kqueuex */
+ case 583:
+ switch (ndx) {
+ case 0:
+ p = "u_int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* membarrier */
+ case 584:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "unsigned";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* timerfd_create */
+ case 585:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_timerfd_gettime */
+ case 586:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "userland struct itimerspec32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* freebsd32_timerfd_settime */
+ case 587:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ case 1:
+ p = "int";
+ break;
+ case 2:
+ p = "userland const struct itimerspec32 *";
+ break;
+ case 3:
+ p = "userland struct itimerspec32 *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* kcmp */
+ case 588:
+ switch (ndx) {
+ case 0:
+ p = "pid_t";
+ break;
+ case 1:
+ p = "pid_t";
+ break;
+ case 2:
+ p = "int";
+ break;
+ case 3:
+ p = "uintptr_t";
+ break;
+ case 4:
+ p = "uintptr_t";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -9210,16 +9346,6 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
/* vfork */
case 66:
- /* sbrk */
- case 69:
- if (ndx == 0 || ndx == 1)
- p = "int";
- break;
- /* sstk */
- case 70:
- if (ndx == 0 || ndx == 1)
- p = "int";
- break;
/* munmap */
case 73:
if (ndx == 0 || ndx == 1)
@@ -10033,6 +10159,11 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* mac_syscall */
+ case 394:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
/* ksem_close */
case 400:
if (ndx == 0 || ndx == 1)
@@ -10822,6 +10953,36 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* kqueuex */
+ case 583:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* membarrier */
+ case 584:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* timerfd_create */
+ case 585:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_timerfd_gettime */
+ case 586:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* freebsd32_timerfd_settime */
+ case 587:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* kcmp */
+ case 588:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
diff --git a/sys/compat/freebsd32/freebsd32_util.h b/sys/compat/freebsd32/freebsd32_util.h
index 74fd48f0bd77..dca61da714f0 100644
--- a/sys/compat/freebsd32/freebsd32_util.h
+++ b/sys/compat/freebsd32/freebsd32_util.h
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _COMPAT_FREEBSD32_FREEBSD32_UTIL_H_
@@ -116,7 +114,7 @@ int freebsd32_copyout_strings(struct image_params *imgp,
uintptr_t *stack_base);
int freebsd32_copyiniov(struct iovec32 *iovp, u_int iovcnt,
struct iovec **iov, int error);
-int freebsd32_copyinuio(struct iovec32 *iovp, u_int iovcnt,
+int freebsd32_copyinuio(const struct iovec32 *iovp, u_int iovcnt,
struct uio **uiop);
void freebsd32_rusage_out(const struct rusage *s, struct rusage32 *s32);
@@ -124,4 +122,6 @@ struct image_args;
int freebsd32_exec_copyin_args(struct image_args *args, const char *fname,
enum uio_seg segflg, uint32_t *argv, uint32_t *envv);
+extern int compat_freebsd_32bit;
+
#endif /* !_COMPAT_FREEBSD32_FREEBSD32_UTIL_H_ */
diff --git a/sys/compat/freebsd32/syscalls.conf b/sys/compat/freebsd32/syscalls.conf
index 6b80018165df..055a041cf72a 100644
--- a/sys/compat/freebsd32/syscalls.conf
+++ b/sys/compat/freebsd32/syscalls.conf
@@ -1,10 +1,8 @@
-# $FreeBSD$
sysnames="freebsd32_syscalls.c"
sysproto="freebsd32_proto.h"
sysproto_h=_FREEBSD32_SYSPROTO_H_
syshdr="freebsd32_syscall.h"
syssw="freebsd32_sysent.c"
-sysmk="/dev/null"
syscallprefix="FREEBSD32_SYS_"
switchname="freebsd32_sysent"
namesname="freebsd32_syscallnames"
@@ -48,7 +46,7 @@ syscall_no_abi_change="aio_cancel thr_exit thr_kill thr_kill2 thr_self thr_set_n
obsol="getkerninfo"
# Syscalls without implementations:
-# *mac_* - should be implemented
+# __mac_* - should be implemented
# afs3_syscall - requires significant porting, probably doesn't make sense
# kldsym - can't be implemented (kernel virtual addresses can't fit in 32-bits)
# lgetfh - should be implemented
@@ -56,4 +54,4 @@ obsol="getkerninfo"
# nnpfs_syscall - requires significant porting, probably doesn't make sense
# ntp_gettime - should be implemented
# thr_create - was unimplemented and appears to be unnecessicary
-unimpl="afs3_syscall kldsym __mac_get_proc __mac_set_proc __mac_get_fd __mac_get_file __mac_set_fd __mac_set_file __mac_get_pid __mac_get_link __mac_set_link __mac_execve mac_syscall nfssvc nlm_syscall ntp_gettime lgetfh nnpfs_syscall thr_create"
+unimpl="afs3_syscall kldsym __mac_get_proc __mac_set_proc __mac_get_fd __mac_get_file __mac_set_fd __mac_set_file __mac_get_pid __mac_get_link __mac_set_link __mac_execve nfssvc nlm_syscall ntp_gettime lgetfh nnpfs_syscall thr_create"
diff --git a/sys/compat/ia32/ia32_genassym.c b/sys/compat/ia32/ia32_genassym.c
index 2b46500c95cc..cc0b1e4e8ca5 100644
--- a/sys/compat/ia32/ia32_genassym.c
+++ b/sys/compat/ia32/ia32_genassym.c
@@ -1,6 +1,4 @@
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/assym.h>
#include <sys/systm.h>
diff --git a/sys/compat/ia32/ia32_signal.h b/sys/compat/ia32/ia32_signal.h
index 630ac0ff4a2d..fbb50c4ef1f2 100644
--- a/sys/compat/ia32/ia32_signal.h
+++ b/sys/compat/ia32/ia32_signal.h
@@ -27,8 +27,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _COMPAT_IA32_IA32_SIGNAL_H
@@ -156,7 +154,7 @@ struct ia32_freebsd4_sigframe {
uint32_t sf_addr; /* undocumented 4th arg */
uint32_t sf_ah; /* action/handler pointer */
struct ia32_freebsd4_ucontext sf_uc; /* = *sf_ucontext */
- struct siginfo32 sf_si; /* = *sf_siginfo (SA_SIGINFO case) */
+ struct __siginfo32 sf_si; /* = *sf_siginfo (SA_SIGINFO case) */
};
struct ia32_sigframe {
@@ -167,7 +165,7 @@ struct ia32_sigframe {
uint32_t sf_ah; /* action/handler pointer */
/* Beware, hole due to ucontext being 16 byte aligned! */
struct ia32_ucontext sf_uc; /* = *sf_ucontext */
- struct siginfo32 sf_si; /* = *sf_siginfo (SA_SIGINFO case) */
+ struct __siginfo32 sf_si; /* = *sf_siginfo (SA_SIGINFO case) */
};
struct ia32_osiginfo {
diff --git a/sys/compat/ia32/ia32_sysvec.c b/sys/compat/ia32/ia32_sysvec.c
index 8d4f316349bb..5174438bc40a 100644
--- a/sys/compat/ia32/ia32_sysvec.c
+++ b/sys/compat/ia32/ia32_sysvec.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Doug Rabson
* Copyright (c) 2003 Peter Wemm
@@ -28,8 +28,6 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#define __ELF_WORD_SIZE 32
#include <sys/param.h>
@@ -78,7 +76,7 @@ __FBSDID("$FreeBSD$");
CTASSERT(sizeof(struct ia32_mcontext) == 640);
CTASSERT(sizeof(struct ia32_ucontext) == 704);
CTASSERT(sizeof(struct ia32_sigframe) == 800);
-CTASSERT(sizeof(struct siginfo32) == 64);
+CTASSERT(sizeof(struct __siginfo32) == 64);
#ifdef COMPAT_FREEBSD4
CTASSERT(sizeof(struct ia32_freebsd4_mcontext) == 260);
CTASSERT(sizeof(struct ia32_freebsd4_ucontext) == 324);
@@ -116,7 +114,6 @@ struct sysentvec ia32_freebsd_sysvec = {
.sv_elf_core_osabi = ELFOSABI_FREEBSD,
.sv_elf_core_abi_vendor = FREEBSD_ABI_VENDOR,
.sv_elf_core_prepare_notes = elf32_prepare_notes,
- .sv_imgact_try = NULL,
.sv_minsigstksz = MINSIGSTKSZ,
.sv_minuser = FREEBSD32_MINUSER,
.sv_maxuser = FREEBSD32_MAXUSER,
@@ -130,7 +127,8 @@ struct sysentvec ia32_freebsd_sysvec = {
.sv_fixlimit = ia32_fixlimit,
.sv_maxssiz = &ia32_maxssiz,
.sv_flags = SV_ABI_FREEBSD | SV_ASLR | SV_IA32 | SV_ILP32 |
- SV_SHP | SV_TIMEKEEP | SV_RNG_SEED_VER | SV_DSO_SIG,
+ SV_SHP | SV_TIMEKEEP | SV_RNG_SEED_VER |
+ SV_DSO_SIG | SV_SIGSYS,
.sv_set_syscall_retval = ia32_set_syscall_retval,
.sv_fetch_syscall_args = ia32_fetch_syscall_args,
.sv_syscallnames = freebsd32_syscallnames,
@@ -151,7 +149,6 @@ static Elf32_Brandinfo ia32_brand_info = {
.brand = ELFOSABI_FREEBSD,
.machine = EM_386,
.compat_3_brand = "FreeBSD",
- .emul_path = NULL,
.interp_path = "/libexec/ld-elf.so.1",
.sysvec = &ia32_freebsd_sysvec,
.interp_newpath = "/libexec/ld-elf32.so.1",
@@ -167,7 +164,6 @@ static Elf32_Brandinfo ia32_brand_oinfo = {
.brand = ELFOSABI_FREEBSD,
.machine = EM_386,
.compat_3_brand = "FreeBSD",
- .emul_path = NULL,
.interp_path = "/usr/libexec/ld-elf.so.1",
.sysvec = &ia32_freebsd_sysvec,
.interp_newpath = "/libexec/ld-elf32.so.1",
@@ -183,7 +179,6 @@ static Elf32_Brandinfo kia32_brand_info = {
.brand = ELFOSABI_FREEBSD,
.machine = EM_386,
.compat_3_brand = "FreeBSD",
- .emul_path = NULL,
.interp_path = "/lib/ld.so.1",
.sysvec = &ia32_freebsd_sysvec,
.brand_note = &elf32_kfreebsd_brandnote,
diff --git a/sys/compat/ia32/ia32_util.h b/sys/compat/ia32/ia32_util.h
index 8a41b90b2afa..ef1ad95f42bb 100644
--- a/sys/compat/ia32/ia32_util.h
+++ b/sys/compat/ia32/ia32_util.h
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _COMPAT_IA32_IA32_UTIL_H
diff --git a/sys/compat/lindebugfs/lindebugfs.c b/sys/compat/lindebugfs/lindebugfs.c
index cbfdfbbce876..e63c31cee1d7 100644
--- a/sys/compat/lindebugfs/lindebugfs.c
+++ b/sys/compat/lindebugfs/lindebugfs.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2016-2018, Matthew Macy <mmacy@freebsd.org>
*
@@ -26,9 +26,6 @@
*
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/queue.h>
@@ -69,9 +66,10 @@ __FBSDID("$FreeBSD$");
#include <compat/linux/linux_util.h>
#include <fs/pseudofs/pseudofs.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
+#include <asm/atomic.h>
#include <linux/compat.h>
+#include <linux/debugfs.h>
+#include <linux/fs.h>
MALLOC_DEFINE(M_DFSINT, "debugfsint", "Linux debugfs internal");
@@ -118,27 +116,17 @@ debugfs_fill(PFS_FILL_ARGS)
{
struct dentry_meta *d;
struct linux_file lf = {};
- struct seq_file *sf;
struct vnode vn;
- void *buf;
+ char *buf;
int rc;
- size_t len;
- off_t off;
-
- d = pn->pn_data;
+ off_t off = 0;
if ((rc = linux_set_current_flags(curthread, M_NOWAIT)))
return (rc);
+
+ d = pn->pn_data;
vn.v_data = d->dm_data;
- if (uio->uio_rw == UIO_READ) {
- buf = uio->uio_iov[0].iov_base;
- len = min(uio->uio_iov[0].iov_len, uio->uio_resid);
- } else {
- sbuf_finish(sb);
- buf = sbuf_data(sb);
- len = sbuf_len(sb);
- }
- off = 0;
+
rc = d->dm_fops->open(&vn, &lf);
if (rc < 0) {
#ifdef INVARIANTS
@@ -146,19 +134,23 @@ debugfs_fill(PFS_FILL_ARGS)
#endif
return (-rc);
}
- sf = lf.private_data;
- sf->buf = sb;
- if (uio->uio_rw == UIO_READ) {
- if (d->dm_fops->read)
- rc = d->dm_fops->read(&lf, NULL, len, &off);
- else
- rc = -ENODEV;
- } else {
- if (d->dm_fops->write)
- rc = d->dm_fops->write(&lf, buf, len, &off);
- else
- rc = -ENODEV;
+
+ rc = -ENODEV;
+ if (uio->uio_rw == UIO_READ && d->dm_fops->read) {
+ rc = -ENOMEM;
+ buf = (char *) malloc(sb->s_size, M_DFSINT, M_ZERO | M_NOWAIT);
+ if (buf != NULL) {
+ rc = d->dm_fops->read(&lf, buf, sb->s_size, &off);
+ if (rc > 0)
+ sbuf_bcpy(sb, buf, strlen(buf));
+
+ free(buf, M_DFSINT);
+ }
+ } else if (uio->uio_rw == UIO_WRITE && d->dm_fops->write) {
+ sbuf_finish(sb);
+ rc = d->dm_fops->write(&lf, sbuf_data(sb), sbuf_len(sb), &off);
}
+
if (d->dm_fops->release)
d->dm_fops->release(&vn, &lf);
else
@@ -185,8 +177,8 @@ debugfs_fill_data(PFS_FILL_ARGS)
struct dentry *
debugfs_create_file(const char *name, umode_t mode,
- struct dentry *parent, void *data,
- const struct file_operations *fops)
+ struct dentry *parent, void *data,
+ const struct file_operations *fops)
{
struct dentry_meta *dm;
struct dentry *dnode;
@@ -219,6 +211,54 @@ debugfs_create_file(const char *name, umode_t mode,
}
struct dentry *
+debugfs_create_file_size(const char *name, umode_t mode,
+ struct dentry *parent, void *data,
+ const struct file_operations *fops,
+ loff_t file_size __unused)
+{
+
+ return debugfs_create_file(name, mode, parent, data, fops);
+}
+
+/*
+ * NOTE: Files created with the _unsafe moniker will not be protected from
+ * debugfs core file removals. It is the responsibility of @fops to protect
+ * its file using debugfs_file_get() and debugfs_file_put().
+ *
+ * FreeBSD's LinuxKPI lindebugfs does not perform file removals at the time
+ * of writing. Therefore there is no difference between functions with _unsafe
+ * and functions without _unsafe when using lindebugfs. Functions with _unsafe
+ * exist only for Linux compatibility.
+ */
+struct dentry *
+debugfs_create_file_unsafe(const char *name, umode_t mode,
+ struct dentry *parent, void *data,
+ const struct file_operations *fops)
+{
+
+ return (debugfs_create_file(name, mode, parent, data, fops));
+}
+
+struct dentry *
+debugfs_create_mode_unsafe(const char *name, umode_t mode,
+ struct dentry *parent, void *data,
+ const struct file_operations *fops,
+ const struct file_operations *fops_ro,
+ const struct file_operations *fops_wo)
+{
+ umode_t read = mode & S_IRUGO;
+ umode_t write = mode & S_IWUGO;
+
+ if (read && !write)
+ return (debugfs_create_file_unsafe(name, mode, parent, data, fops_ro));
+
+ if (write && !read)
+ return (debugfs_create_file_unsafe(name, mode, parent, data, fops_wo));
+
+ return (debugfs_create_file_unsafe(name, mode, parent, data, fops));
+}
+
+struct dentry *
debugfs_create_dir(const char *name, struct dentry *parent)
{
struct dentry_meta *dm;
@@ -247,7 +287,7 @@ debugfs_create_dir(const char *name, struct dentry *parent)
struct dentry *
debugfs_create_symlink(const char *name, struct dentry *parent,
- const char *dest)
+ const char *dest)
{
struct dentry_meta *dm;
struct dentry *dnode;
@@ -300,7 +340,305 @@ debugfs_remove_recursive(struct dentry *dnode)
}
static int
-debugfs_init(PFS_INIT_ARGS)
+debugfs_bool_get(void *data, uint64_t *ullval)
+{
+ bool *bval = data;
+
+ if (*bval)
+ *ullval = 1;
+ else
+ *ullval = 0;
+
+ return (0);
+}
+
+static int
+debugfs_bool_set(void *data, uint64_t ullval)
+{
+ bool *bval = data;
+
+ if (ullval)
+ *bval = 1;
+ else
+ *bval = 0;
+
+ return (0);
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_bool, debugfs_bool_get, debugfs_bool_set, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_bool_ro, debugfs_bool_get, NULL, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_bool_wo, NULL, debugfs_bool_set, "%llu\n");
+
+void
+debugfs_create_bool(const char *name, umode_t mode, struct dentry *parent, bool *value)
+{
+
+ debugfs_create_mode_unsafe(name, mode, parent, value, &fops_bool,
+ &fops_bool_ro, &fops_bool_wo);
+}
+
+
+static int
+debugfs_u8_get(void *data, uint64_t *value)
+{
+ uint8_t *u8data = data;
+ *value = *u8data;
+ return (0);
+}
+
+static int
+debugfs_u8_set(void *data, uint64_t value)
+{
+ uint8_t *u8data = data;
+ *u8data = (uint8_t)value;
+ return (0);
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%u\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%u\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%u\n");
+
+void
+debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent, uint8_t *value)
+{
+
+ debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u8,
+ &fops_u8_ro, &fops_u8_wo);
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%016llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_ro, debugfs_u8_get, NULL, "0x%016llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x8_wo, NULL, debugfs_u8_set, "0x%016llx\n");
+
+void
+debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent, uint8_t *value)
+{
+
+ debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x8,
+ &fops_x8_ro, &fops_x8_wo);
+}
+
+
+static int
+debugfs_u16_get(void *data, uint64_t *value)
+{
+ uint16_t *u16data = data;
+ *value = *u16data;
+ return (0);
+}
+
+static int
+debugfs_u16_set(void *data, uint64_t value)
+{
+ uint16_t *u16data = data;
+ *u16data = (uint16_t)value;
+ return (0);
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%u\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_ro, debugfs_u16_get, NULL, "%u\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%u\n");
+
+void
+debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent, uint16_t *value)
+{
+
+ debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u16,
+ &fops_u16_ro, &fops_u16_wo);
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%016llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_ro, debugfs_u16_get, NULL, "0x%016llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x16_wo, NULL, debugfs_u16_set, "0x%016llx\n");
+
+void
+debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent, uint16_t *value)
+{
+
+ debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x16,
+ &fops_x16_ro, &fops_x16_wo);
+}
+
+
+static int
+debugfs_u32_get(void *data, uint64_t *value)
+{
+ uint32_t *u32data = data;
+ *value = *u32data;
+ return (0);
+}
+
+static int
+debugfs_u32_set(void *data, uint64_t value)
+{
+ uint32_t *u32data = data;
+ *u32data = (uint32_t)value;
+ return (0);
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%u\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, "%u\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%u\n");
+
+void
+debugfs_create_u32(const char *name, umode_t mode, struct dentry *parent, uint32_t *value)
+{
+
+ debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u32,
+ &fops_u32_ro, &fops_u32_wo);
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%016llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%016llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%016llx\n");
+
+void
+debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent, uint32_t *value)
+{
+
+ debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x32,
+ &fops_x32_ro, &fops_x32_wo);
+}
+
+
+static int
+debugfs_u64_get(void *data, uint64_t *value)
+{
+ uint64_t *u64data = data;
+ *value = *u64data;
+ return (0);
+}
+
+static int
+debugfs_u64_set(void *data, uint64_t value)
+{
+ uint64_t *u64data = data;
+ *u64data = (uint64_t)value;
+ return (0);
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%u\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_ro, debugfs_u64_get, NULL, "%u\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%u\n");
+
+void
+debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent, uint64_t *value)
+{
+
+ debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u64,
+ &fops_u64_ro, &fops_u64_wo);
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x64, debugfs_u64_get, debugfs_u64_set, "0x%016llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_ro, debugfs_u64_get, NULL, "0x%016llx\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_x64_wo, NULL, debugfs_u64_set, "0x%016llx\n");
+
+void
+debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent, uint64_t *value)
+{
+
+ debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x64,
+ &fops_x64_ro, &fops_x64_wo);
+}
+
+
+static int
+debugfs_ulong_get(void *data, uint64_t *value)
+{
+ uint64_t *uldata = data;
+ *value = *uldata;
+ return (0);
+}
+
+static int
+debugfs_ulong_set(void *data, uint64_t value)
+{
+ uint64_t *uldata = data;
+ *uldata = value;
+ return (0);
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong, debugfs_ulong_get, debugfs_ulong_set, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_ro, debugfs_ulong_get, NULL, "%llu\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_ulong_wo, NULL, debugfs_ulong_set, "%llu\n");
+
+void
+debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent, unsigned long *value)
+{
+
+ debugfs_create_mode_unsafe(name, mode, parent, value, &fops_ulong,
+ &fops_ulong_ro, &fops_ulong_wo);
+}
+
+
+static int
+debugfs_atomic_t_get(void *data, uint64_t *value)
+{
+ atomic_t *atomic_data = data;
+ *value = atomic_read(atomic_data);
+ return (0);
+}
+
+static int
+debugfs_atomic_t_set(void *data, uint64_t value)
+{
+ atomic_t *atomic_data = data;
+ atomic_set(atomic_data, (int)value);
+ return (0);
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t, debugfs_atomic_t_get, debugfs_atomic_t_set, "%d\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_ro, debugfs_atomic_t_get, NULL, "%d\n");
+DEFINE_DEBUGFS_ATTRIBUTE(fops_atomic_t_wo, NULL, debugfs_atomic_t_set, "%d\n");
+
+void
+debugfs_create_atomic_t(const char *name, umode_t mode, struct dentry *parent, atomic_t *value)
+{
+
+ debugfs_create_mode_unsafe(name, mode, parent, value, &fops_atomic_t,
+ &fops_atomic_t_ro, &fops_atomic_t_wo);
+}
+
+
+static ssize_t
+fops_blob_read(struct file *filp, char __user *ubuf, size_t read_size, loff_t *ppos)
+{
+ struct debugfs_blob_wrapper *blob;
+
+ blob = filp->private_data;
+ if (blob == NULL)
+ return (-EINVAL);
+ if (blob->size == 0 || blob->data == NULL)
+ return (-EINVAL);
+
+ return (simple_read_from_buffer(ubuf, read_size, ppos, blob->data, blob->size));
+}
+
+static int
+fops_blob_open(struct inode *inode, struct file *filp)
+{
+
+ return (simple_open(inode, filp));
+}
+
+static const struct file_operations __fops_blob_ro = {
+ .owner = THIS_MODULE,
+ .open = fops_blob_open,
+ .read = fops_blob_read,
+ .llseek = no_llseek
+};
+
+struct dentry *
+debugfs_create_blob(const char *name, umode_t mode, struct dentry *parent,
+ struct debugfs_blob_wrapper *value)
+{
+ /* Blobs are read-only. */
+ return (debugfs_create_file(name, mode & 0444, parent, value, &__fops_blob_ro));
+}
+
+
+static int
+lindebugfs_init(PFS_INIT_ARGS)
{
debugfs_root = pi->pi_root;
@@ -311,14 +649,11 @@ debugfs_init(PFS_INIT_ARGS)
}
static int
-debugfs_uninit(PFS_INIT_ARGS)
+lindebugfs_uninit(PFS_INIT_ARGS)
{
+
return (0);
}
-#ifdef PR_ALLOW_MOUNT_LINSYSFS
-PSEUDOFS(debugfs, 1, PR_ALLOW_MOUNT_LINSYSFS);
-#else
-PSEUDOFS(debugfs, 1, VFCF_JAIL);
-#endif
+PSEUDOFS(lindebugfs, 1, VFCF_JAIL);
MODULE_DEPEND(lindebugfs, linuxkpi, 1, 1, 1);
diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c
index 23e407771fcc..391d5f679ee5 100644
--- a/sys/compat/linprocfs/linprocfs.c
+++ b/sys/compat/linprocfs/linprocfs.c
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-4-Clause
*
- * Copyright (c) 2000 Dag-Erling Coïdan Smørgrav
+ * Copyright (c) 2000 Dag-Erling Smørgrav
* Copyright (c) 1999 Pierre Beyssac
* Copyright (c) 1993 Jan-Simon Pendry
* Copyright (c) 1993
@@ -37,15 +37,12 @@
* 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.
- *
- * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+#include "opt_inet.h"
#include <sys/param.h>
-#include <sys/queue.h>
+#include <sys/systm.h>
#include <sys/blist.h>
#include <sys/conf.h>
#include <sys/exec.h>
@@ -62,6 +59,7 @@ __FBSDID("$FreeBSD$");
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/ptrace.h>
+#include <sys/queue.h>
#include <sys/resourcevar.h>
#include <sys/resource.h>
#include <sys/sbuf.h>
@@ -72,7 +70,6 @@ __FBSDID("$FreeBSD$");
#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
#include <sys/sysent.h>
-#include <sys/systm.h>
#include <sys/time.h>
#include <sys/tty.h>
#include <sys/user.h>
@@ -86,6 +83,10 @@ __FBSDID("$FreeBSD$");
#include <net/if_var.h>
#include <net/if_types.h>
+#include <net/route.h>
+#include <net/route/nhop.h>
+#include <net/route/route_ctl.h>
+
#include <vm/vm.h>
#include <vm/vm_extern.h>
#include <vm/pmap.h>
@@ -105,6 +106,7 @@ __FBSDID("$FreeBSD$");
#endif /* __i386__ || __amd64__ */
#include <compat/linux/linux.h>
+#include <compat/linux/linux_common.h>
#include <compat/linux/linux_emul.h>
#include <compat/linux/linux_mib.h>
#include <compat/linux/linux_misc.h>
@@ -197,10 +199,7 @@ linprocfs_domeminfo(PFS_FILL_ARGS)
static int
linprocfs_docpuinfo(PFS_FILL_ARGS)
{
- int hw_model[2];
- char model[128];
uint64_t freq;
- size_t size;
u_int cache_size[4];
u_int regs[4] = { 0 };
int fqmhz, fqkhz;
@@ -300,12 +299,6 @@ linprocfs_docpuinfo(PFS_FILL_ARGS)
"acc_power",
};
- hw_model[0] = CTL_HW;
- hw_model[1] = HW_MODEL;
- model[0] = '\0';
- size = sizeof(model);
- if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
- strcpy(model, "unknown");
#ifdef __i386__
switch (cpu_vendor_id) {
case CPU_VENDOR_AMD:
@@ -349,7 +342,7 @@ linprocfs_docpuinfo(PFS_FILL_ARGS)
"cpuid level\t: %d\n"
"wp\t\t: %s\n",
i, cpu_vendor, CPUID_TO_FAMILY(cpu_id),
- CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING,
+ CPUID_TO_MODEL(cpu_id), cpu_model, cpu_id & CPUID_STEPPING,
fqmhz, fqkhz,
(cache_size[2] >> 16), 0, mp_ncpus, i, mp_ncpus,
i, i, /*cpu_id & CPUID_LOCAL_APIC_ID ??*/
@@ -519,29 +512,26 @@ _sbuf_mntoptions_helper(struct sbuf *sb, uint64_t f_flags)
static int
linprocfs_domtab(PFS_FILL_ARGS)
{
- struct nameidata nd;
- const char *lep, *mntto, *mntfrom, *fstype;
+ const char *mntto, *mntfrom, *fstype;
char *dlep, *flep;
+ struct vnode *vp;
+ struct pwd *pwd;
size_t lep_len;
int error;
struct statfs *buf, *sp;
size_t count;
- /* resolve symlinks etc. in the emulation tree prefix */
/*
- * Ideally, this would use the current chroot rather than some
- * hardcoded path.
+ * Resolve emulation tree prefix
*/
- NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path);
flep = NULL;
- error = namei(&nd);
- lep = linux_emul_path;
- if (error == 0) {
- if (vn_fullpath(nd.ni_vp, &dlep, &flep) == 0)
- lep = dlep;
- vrele(nd.ni_vp);
- }
- lep_len = strlen(lep);
+ pwd = pwd_hold(td);
+ vp = pwd->pwd_adir;
+ error = vn_fullpath_global(vp, &dlep, &flep);
+ pwd_drop(pwd);
+ if (error != 0)
+ return (error);
+ lep_len = strlen(dlep);
buf = NULL;
error = kern_getfsstat(td, &buf, SIZE_T_MAX, &count,
@@ -560,7 +550,7 @@ linprocfs_domtab(PFS_FILL_ARGS)
}
/* determine mount point */
- if (strncmp(mntto, lep, lep_len) == 0 && mntto[lep_len] == '/')
+ if (strncmp(mntto, dlep, lep_len) == 0 && mntto[lep_len] == '/')
mntto += lep_len;
sbuf_printf(sb, "%s %s %s ", mntfrom, mntto, fstype);
@@ -577,28 +567,25 @@ linprocfs_domtab(PFS_FILL_ARGS)
static int
linprocfs_doprocmountinfo(PFS_FILL_ARGS)
{
- struct nameidata nd;
const char *mntfrom, *mntto, *fstype;
- const char *lep;
char *dlep, *flep;
struct statfs *buf, *sp;
size_t count, lep_len;
+ struct vnode *vp;
+ struct pwd *pwd;
int error;
/*
- * Ideally, this would use the current chroot rather than some
- * hardcoded path.
+ * Resolve emulation tree prefix
*/
- NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path);
flep = NULL;
- error = namei(&nd);
- lep = linux_emul_path;
- if (error == 0) {
- if (vn_fullpath(nd.ni_vp, &dlep, &flep) == 0)
- lep = dlep;
- vrele(nd.ni_vp);
- }
- lep_len = strlen(lep);
+ pwd = pwd_hold(td);
+ vp = pwd->pwd_adir;
+ error = vn_fullpath_global(vp, &dlep, &flep);
+ pwd_drop(pwd);
+ if (error != 0)
+ return (error);
+ lep_len = strlen(dlep);
buf = NULL;
error = kern_getfsstat(td, &buf, SIZE_T_MAX, &count,
@@ -613,7 +600,7 @@ linprocfs_doprocmountinfo(PFS_FILL_ARGS)
continue;
}
- if (strncmp(mntto, lep, lep_len) == 0 && mntto[lep_len] == '/')
+ if (strncmp(mntto, dlep, lep_len) == 0 && mntto[lep_len] == '/')
mntto += lep_len;
#if 0
/*
@@ -1016,7 +1003,7 @@ linprocfs_doprocstat(PFS_FILL_ARGS)
PS_ADD("0", "%d", 0); /* removed field */
PS_ADD("itrealvalue", "%d", 0); /* XXX */
PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime));
- PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size));
+ PS_ADD("vsize", "%ju", (uintmax_t)kp.ki_size);
PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize);
PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss);
PS_ADD("startcode", "%ju", (uintmax_t)startcode);
@@ -1468,38 +1455,52 @@ linprocfs_doprocmem(PFS_FILL_ARGS)
return (error);
}
+/*
+ * Filler function for proc/net/dev
+ */
static int
-linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
+linprocfs_donetdev_cb(if_t ifp, void *arg)
{
- struct ifnet *ifscan;
- int ethno;
-
- IFNET_RLOCK_ASSERT();
-
- /* Short-circuit non ethernet interfaces */
- if (linux_use_real_ifname(ifp))
- return (strlcpy(buffer, ifp->if_xname, buflen));
-
- /* Determine the (relative) unit number for ethernet interfaces */
- ethno = 0;
- CK_STAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
- if (ifscan == ifp)
- return (snprintf(buffer, buflen, "eth%d", ethno));
- if (!linux_use_real_ifname(ifscan))
- ethno++;
- }
-
+ char ifname[LINUX_IFNAMSIZ];
+ struct sbuf *sb = arg;
+
+ if (ifname_bsd_to_linux_ifp(ifp, ifname, sizeof(ifname)) <= 0)
+ return (ENODEV);
+
+ sbuf_printf(sb, "%6.6s: ", ifname);
+ sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
+ (uintmax_t)if_getcounter(ifp, IFCOUNTER_IBYTES),
+ (uintmax_t)if_getcounter(ifp, IFCOUNTER_IPACKETS),
+ (uintmax_t)if_getcounter(ifp, IFCOUNTER_IERRORS),
+ (uintmax_t)if_getcounter(ifp, IFCOUNTER_IQDROPS),
+ /* rx_missed_errors */
+ 0UL, /* rx_fifo_errors */
+ 0UL, /* rx_length_errors +
+ * rx_over_errors +
+ * rx_crc_errors +
+ * rx_frame_errors */
+ 0UL, /* rx_compressed */
+ (uintmax_t)if_getcounter(ifp, IFCOUNTER_IMCASTS));
+ /* XXX-BZ rx only? */
+ sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
+ (uintmax_t)if_getcounter(ifp, IFCOUNTER_OBYTES),
+ (uintmax_t)if_getcounter(ifp, IFCOUNTER_OPACKETS),
+ (uintmax_t)if_getcounter(ifp, IFCOUNTER_OERRORS),
+ (uintmax_t)if_getcounter(ifp, IFCOUNTER_OQDROPS),
+ 0UL, /* tx_fifo_errors */
+ (uintmax_t)if_getcounter(ifp, IFCOUNTER_COLLISIONS),
+ 0UL, /* tx_carrier_errors +
+ * tx_aborted_errors +
+ * tx_window_errors +
+ * tx_heartbeat_errors*/
+ 0UL); /* tx_compressed */
return (0);
}
-/*
- * Filler function for proc/net/dev
- */
static int
linprocfs_donetdev(PFS_FILL_ARGS)
{
- char ifname[16]; /* XXX LINUX_IFNAMSIZ */
- struct ifnet *ifp;
+ struct epoch_tracker et;
sbuf_printf(sb, "%6s|%58s|%s\n"
"%6s|%58s|%58s\n",
@@ -1509,38 +1510,82 @@ linprocfs_donetdev(PFS_FILL_ARGS)
"bytes packets errs drop fifo colls carrier compressed");
CURVNET_SET(TD_TO_VNET(curthread));
- IFNET_RLOCK();
- CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
- linux_ifname(ifp, ifname, sizeof ifname);
- sbuf_printf(sb, "%6.6s: ", ifname);
- sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
- (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IBYTES),
- (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS),
- (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IERRORS),
- (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS),
- /* rx_missed_errors */
- 0UL, /* rx_fifo_errors */
- 0UL, /* rx_length_errors +
- * rx_over_errors +
- * rx_crc_errors +
- * rx_frame_errors */
- 0UL, /* rx_compressed */
- (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS));
- /* XXX-BZ rx only? */
- sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
- (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OBYTES),
- (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS),
- (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OERRORS),
- (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS),
- 0UL, /* tx_fifo_errors */
- (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS),
- 0UL, /* tx_carrier_errors +
- * tx_aborted_errors +
- * tx_window_errors +
- * tx_heartbeat_errors*/
- 0UL); /* tx_compressed */
- }
- IFNET_RUNLOCK();
+ NET_EPOCH_ENTER(et);
+ if_foreach(linprocfs_donetdev_cb, sb);
+ NET_EPOCH_EXIT(et);
+ CURVNET_RESTORE();
+
+ return (0);
+}
+
+struct walkarg {
+ struct sbuf *sb;
+};
+
+static int
+linux_route_print(struct rtentry *rt, void *vw)
+{
+#ifdef INET
+ struct walkarg *w = vw;
+ struct route_nhop_data rnd;
+ struct in_addr dst, mask;
+ struct nhop_object *nh;
+ char ifname[16];
+ uint32_t scopeid = 0;
+ uint32_t gw = 0;
+ uint32_t linux_flags = 0;
+
+ rt_get_inet_prefix_pmask(rt, &dst, &mask, &scopeid);
+
+ rt_get_rnd(rt, &rnd);
+
+ /* select only first route in case of multipath */
+ nh = nhop_select_func(rnd.rnd_nhop, 0);
+
+ if (ifname_bsd_to_linux_ifp(nh->nh_ifp, ifname, sizeof(ifname)) <= 0)
+ return (ENODEV);
+
+ gw = (nh->nh_flags & NHF_GATEWAY)
+ ? nh->gw4_sa.sin_addr.s_addr : 0;
+
+ linux_flags = RTF_UP |
+ (nhop_get_rtflags(nh) & (RTF_GATEWAY | RTF_HOST));
+
+ sbuf_printf(w->sb,
+ "%s\t"
+ "%08X\t%08X\t%04X\t"
+ "%d\t%u\t%d\t"
+ "%08X\t%d\t%u\t%u",
+ ifname,
+ dst.s_addr, gw, linux_flags,
+ 0, 0, rnd.rnd_weight,
+ mask.s_addr, nh->nh_mtu, 0, 0);
+
+ sbuf_printf(w->sb, "\n\n");
+#endif
+ return (0);
+}
+
+/*
+ * Filler function for proc/net/route
+ */
+static int
+linprocfs_donetroute(PFS_FILL_ARGS)
+{
+ struct epoch_tracker et;
+ struct walkarg w = {
+ .sb = sb
+ };
+ uint32_t fibnum = curthread->td_proc->p_fibnum;
+
+ sbuf_printf(w.sb, "%-127s\n", "Iface\tDestination\tGateway "
+ "\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU"
+ "\tWindow\tIRTT");
+
+ CURVNET_SET(TD_TO_VNET(curthread));
+ NET_EPOCH_ENTER(et);
+ rib_walk(fibnum, AF_INET, false, linux_route_print, &w);
+ NET_EPOCH_EXIT(et);
CURVNET_RESTORE();
return (0);
@@ -2100,6 +2145,8 @@ linprocfs_init(PFS_INIT_ARGS)
dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
pfs_create_file(dir, "dev", &linprocfs_donetdev,
NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, "route", &linprocfs_donetroute,
+ NULL, NULL, NULL, PFS_RD);
/* /proc/<pid>/... */
dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
diff --git a/sys/compat/linsysfs/linsysfs.c b/sys/compat/linsysfs/linsysfs.c
index 9ec066ac34c4..7f70221b420d 100644
--- a/sys/compat/linsysfs/linsysfs.c
+++ b/sys/compat/linsysfs/linsysfs.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2006 IronPort Systems
* All rights reserved.
@@ -26,9 +26,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/ctype.h>
@@ -37,22 +34,19 @@ __FBSDID("$FreeBSD$");
#include <sys/mount.h>
#include <sys/sbuf.h>
#include <sys/smp.h>
-#include <sys/socket.h>
#include <sys/bus.h>
#include <sys/pciio.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
-#include <net/if.h>
-#include <net/if_var.h>
-#include <net/if_dl.h>
-
-#include <compat/linux/linux.h>
-#include <compat/linux/linux_common.h>
#include <compat/linux/linux_util.h>
#include <fs/pseudofs/pseudofs.h>
+#include <compat/linsysfs/linsysfs.h>
+
+MALLOC_DEFINE(M_LINSYSFS, "linsysfs", "Linsysfs structures");
+
struct scsi_host_queue {
TAILQ_ENTRY(scsi_host_queue) scsi_host_next;
char *path;
@@ -69,146 +63,6 @@ atoi(const char *str)
return (int)strtol(str, (char **)NULL, 10);
}
-static int
-linsysfs_ifnet_addr(PFS_FILL_ARGS)
-{
- struct l_sockaddr lsa;
- struct ifnet *ifp;
-
- ifp = ifname_linux_to_bsd(td, pn->pn_parent->pn_name, NULL);
- if (ifp == NULL)
- return (ENOENT);
- if (linux_ifhwaddr(ifp, &lsa) != 0)
- return (ENOENT);
- sbuf_printf(sb, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
- lsa.sa_data[0], lsa.sa_data[1], lsa.sa_data[2],
- lsa.sa_data[3], lsa.sa_data[4], lsa.sa_data[5]);
- return (0);
-}
-
-static int
-linsysfs_ifnet_addrlen(PFS_FILL_ARGS)
-{
-
- sbuf_printf(sb, "%d\n", LINUX_IFHWADDRLEN);
- return (0);
-}
-
-static int
-linsysfs_ifnet_flags(PFS_FILL_ARGS)
-{
- struct ifnet *ifp;
- unsigned short flags;
-
- ifp = ifname_linux_to_bsd(td, pn->pn_parent->pn_name, NULL);
- if (ifp == NULL)
- return (ENOENT);
- linux_ifflags(ifp, &flags);
- sbuf_printf(sb, "0x%x\n", flags);
- return (0);
-}
-
-static int
-linsysfs_ifnet_ifindex(PFS_FILL_ARGS)
-{
- struct ifnet *ifp;
-
- ifp = ifname_linux_to_bsd(td, pn->pn_parent->pn_name, NULL);
- if (ifp == NULL)
- return (ENOENT);
- sbuf_printf(sb, "%u\n", ifp->if_index);
- return (0);
-}
-
-static int
-linsysfs_ifnet_mtu(PFS_FILL_ARGS)
-{
- struct ifnet *ifp;
-
- ifp = ifname_linux_to_bsd(td, pn->pn_parent->pn_name, NULL);
- if (ifp == NULL)
- return (ENOENT);
- sbuf_printf(sb, "%u\n", ifp->if_mtu);
- return (0);
-}
-
-static int
-linsysfs_ifnet_tx_queue_len(PFS_FILL_ARGS)
-{
-
- /* XXX */
- sbuf_printf(sb, "1000\n");
- return (0);
-}
-
-static int
-linsysfs_ifnet_type(PFS_FILL_ARGS)
-{
- struct l_sockaddr lsa;
- struct ifnet *ifp;
-
- ifp = ifname_linux_to_bsd(td, pn->pn_parent->pn_name, NULL);
- if (ifp == NULL)
- return (ENOENT);
- if (linux_ifhwaddr(ifp, &lsa) != 0)
- return (ENOENT);
- sbuf_printf(sb, "%d\n", lsa.sa_family);
- return (0);
-}
-
-static void
-linsysfs_listnics(struct pfs_node *dir)
-{
- struct pfs_node *nic;
- struct pfs_node *lo;
-
- nic = pfs_create_dir(dir, "eth0", NULL, NULL, NULL, 0);
-
- pfs_create_file(nic, "address", &linsysfs_ifnet_addr,
- NULL, NULL, NULL, PFS_RD);
-
- pfs_create_file(nic, "addr_len", &linsysfs_ifnet_addrlen,
- NULL, NULL, NULL, PFS_RD);
-
- pfs_create_file(nic, "flags", &linsysfs_ifnet_flags,
- NULL, NULL, NULL, PFS_RD);
-
- pfs_create_file(nic, "ifindex", &linsysfs_ifnet_ifindex,
- NULL, NULL, NULL, PFS_RD);
-
- pfs_create_file(nic, "mtu", &linsysfs_ifnet_mtu,
- NULL, NULL, NULL, PFS_RD);
-
- pfs_create_file(nic, "tx_queue_len", &linsysfs_ifnet_tx_queue_len,
- NULL, NULL, NULL, PFS_RD);
-
- pfs_create_file(nic, "type", &linsysfs_ifnet_type,
- NULL, NULL, NULL, PFS_RD);
-
- lo = pfs_create_dir(dir, "lo", NULL, NULL, NULL, 0);
-
- pfs_create_file(lo, "address", &linsysfs_ifnet_addr,
- NULL, NULL, NULL, PFS_RD);
-
- pfs_create_file(lo, "addr_len", &linsysfs_ifnet_addrlen,
- NULL, NULL, NULL, PFS_RD);
-
- pfs_create_file(lo, "flags", &linsysfs_ifnet_flags,
- NULL, NULL, NULL, PFS_RD);
-
- pfs_create_file(lo, "ifindex", &linsysfs_ifnet_ifindex,
- NULL, NULL, NULL, PFS_RD);
-
- pfs_create_file(lo, "mtu", &linsysfs_ifnet_mtu,
- NULL, NULL, NULL, PFS_RD);
-
- pfs_create_file(lo, "tx_queue_len", &linsysfs_ifnet_tx_queue_len,
- NULL, NULL, NULL, PFS_RD);
-
- pfs_create_file(lo, "type", &linsysfs_ifnet_type,
- NULL, NULL, NULL, PFS_RD);
-}
-
/*
* Filler function for proc_name
*/
@@ -621,7 +475,6 @@ linsysfs_init(PFS_INIT_ARGS)
struct pfs_node *drm;
struct pfs_node *pci;
struct pfs_node *scsi;
- struct pfs_node *net;
struct pfs_node *devdir, *chardev;
struct pfs_node *kernel;
devclass_t devclass;
@@ -673,15 +526,13 @@ linsysfs_init(PFS_INIT_ARGS)
NULL, NULL, NULL, PFS_RD);
linsysfs_listcpus(cpu);
- linsysfs_listnics(net);
/* /sys/kernel */
kernel = pfs_create_dir(root, "kernel", NULL, NULL, NULL, 0);
/* /sys/kernel/debug, mountpoint for lindebugfs. */
pfs_create_dir(kernel, "debug", NULL, NULL, NULL, 0);
- /* /sys/subsystem/... */
- dir = pfs_create_dir(root, "subsystem", NULL, NULL, NULL, 0);
+ linsysfs_net_init();
return (0);
}
@@ -701,6 +552,8 @@ linsysfs_uninit(PFS_INIT_ARGS)
free(scsi_host, M_TEMP);
}
+ linsysfs_net_uninit();
+
return (0);
}
diff --git a/sys/compat/linsysfs/linsysfs.h b/sys/compat/linsysfs/linsysfs.h
new file mode 100644
index 000000000000..97b368ff711c
--- /dev/null
+++ b/sys/compat/linsysfs/linsysfs.h
@@ -0,0 +1,38 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Dmitry Chagin <dchagin@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 _COMPAT_LINSYSFS_LINSYSFS_H_
+#define _COMPAT_LINSYSFS_LINSYSFS_H_
+
+MALLOC_DECLARE(M_LINSYSFS);
+
+extern struct pfs_node *net;
+
+void linsysfs_net_init(void);
+void linsysfs_net_uninit(void);
+
+#endif /* _COMPAT_LINSYSFS_LINSYSFS_H_ */
diff --git a/sys/compat/linsysfs/linsysfs_net.c b/sys/compat/linsysfs/linsysfs_net.c
new file mode 100644
index 000000000000..73602b0132a4
--- /dev/null
+++ b/sys/compat/linsysfs/linsysfs_net.c
@@ -0,0 +1,353 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Dmitry Chagin <dchagin@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.
+ */
+
+#include <sys/param.h>
+#include <sys/eventhandler.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/sbuf.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/vnet.h>
+
+#include <compat/linux/linux.h>
+#include <compat/linux/linux_common.h>
+#include <fs/pseudofs/pseudofs.h>
+
+#include <compat/linsysfs/linsysfs.h>
+
+struct pfs_node *net;
+static eventhandler_tag if_arrival_tag, if_departure_tag;
+
+static uint32_t net_latch_count = 0;
+static struct mtx net_latch_mtx;
+MTX_SYSINIT(net_latch_mtx, &net_latch_mtx, "lsfnet", MTX_DEF);
+
+struct ifp_nodes_queue {
+ TAILQ_ENTRY(ifp_nodes_queue) ifp_nodes_next;
+ if_t ifp;
+ struct vnet *vnet;
+ struct pfs_node *pn;
+};
+TAILQ_HEAD(,ifp_nodes_queue) ifp_nodes_q;
+
+static void
+linsysfs_net_latch_hold(void)
+{
+
+ mtx_lock(&net_latch_mtx);
+ if (net_latch_count++ > 0)
+ mtx_sleep(&net_latch_count, &net_latch_mtx, PDROP, "lsfnet", 0);
+ else
+ mtx_unlock(&net_latch_mtx);
+}
+
+static void
+linsysfs_net_latch_rele(void)
+{
+
+ mtx_lock(&net_latch_mtx);
+ if (--net_latch_count > 0)
+ wakeup_one(&net_latch_count);
+ mtx_unlock(&net_latch_mtx);
+}
+
+static int
+linsysfs_if_addr(PFS_FILL_ARGS)
+{
+ struct epoch_tracker et;
+ struct l_sockaddr lsa;
+ if_t ifp;
+ int error;
+
+ CURVNET_SET(TD_TO_VNET(td));
+ NET_EPOCH_ENTER(et);
+ ifp = ifname_linux_to_ifp(td, pn->pn_parent->pn_name);
+ if (ifp != NULL && (error = linux_ifhwaddr(ifp, &lsa)) == 0)
+ error = sbuf_printf(sb, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n",
+ lsa.sa_data[0], lsa.sa_data[1], lsa.sa_data[2],
+ lsa.sa_data[3], lsa.sa_data[4], lsa.sa_data[5]);
+ else
+ error = ENOENT;
+ NET_EPOCH_EXIT(et);
+ CURVNET_RESTORE();
+ return (error == -1 ? ERANGE : error);
+}
+
+static int
+linsysfs_if_addrlen(PFS_FILL_ARGS)
+{
+
+ sbuf_printf(sb, "%d\n", LINUX_IFHWADDRLEN);
+ return (0);
+}
+
+static int
+linsysfs_if_flags(PFS_FILL_ARGS)
+{
+ struct epoch_tracker et;
+ if_t ifp;
+ int error;
+
+ CURVNET_SET(TD_TO_VNET(td));
+ NET_EPOCH_ENTER(et);
+ ifp = ifname_linux_to_ifp(td, pn->pn_parent->pn_name);
+ if (ifp != NULL)
+ error = sbuf_printf(sb, "0x%x\n", linux_ifflags(ifp));
+ else
+ error = ENOENT;
+ NET_EPOCH_EXIT(et);
+ CURVNET_RESTORE();
+ return (error == -1 ? ERANGE : error);
+}
+
+static int
+linsysfs_if_ifindex(PFS_FILL_ARGS)
+{
+ struct epoch_tracker et;
+ if_t ifp;
+ int error;
+
+ CURVNET_SET(TD_TO_VNET(td));
+ NET_EPOCH_ENTER(et);
+ ifp = ifname_linux_to_ifp(td, pn->pn_parent->pn_name);
+ if (ifp != NULL)
+ error = sbuf_printf(sb, "%u\n", if_getindex(ifp));
+ else
+ error = ENOENT;
+ NET_EPOCH_EXIT(et);
+ CURVNET_RESTORE();
+ return (error == -1 ? ERANGE : error);
+}
+
+static int
+linsysfs_if_mtu(PFS_FILL_ARGS)
+{
+ struct epoch_tracker et;
+ if_t ifp;
+ int error;
+
+ CURVNET_SET(TD_TO_VNET(td));
+ NET_EPOCH_ENTER(et);
+ ifp = ifname_linux_to_ifp(td, pn->pn_parent->pn_name);
+ if (ifp != NULL)
+ error = sbuf_printf(sb, "%u\n", if_getmtu(ifp));
+ else
+ error = ENOENT;
+ NET_EPOCH_EXIT(et);
+ CURVNET_RESTORE();
+ return (error == -1 ? ERANGE : error);
+}
+
+static int
+linsysfs_if_txq_len(PFS_FILL_ARGS)
+{
+
+ /* XXX */
+ sbuf_printf(sb, "1000\n");
+ return (0);
+}
+
+static int
+linsysfs_if_type(PFS_FILL_ARGS)
+{
+ struct epoch_tracker et;
+ struct l_sockaddr lsa;
+ if_t ifp;
+ int error;
+
+ CURVNET_SET(TD_TO_VNET(td));
+ NET_EPOCH_ENTER(et);
+ ifp = ifname_linux_to_ifp(td, pn->pn_parent->pn_name);
+ if (ifp != NULL && (error = linux_ifhwaddr(ifp, &lsa)) == 0)
+ error = sbuf_printf(sb, "%d\n", lsa.sa_family);
+ else
+ error = ENOENT;
+ NET_EPOCH_EXIT(et);
+ CURVNET_RESTORE();
+ return (error == -1 ? ERANGE : error);
+}
+
+static int
+linsysfs_if_visible(PFS_VIS_ARGS)
+{
+ struct ifp_nodes_queue *nq, *nq_tmp;
+ struct epoch_tracker et;
+ if_t ifp;
+ int visible;
+
+ visible = 0;
+ CURVNET_SET(TD_TO_VNET(td));
+ NET_EPOCH_ENTER(et);
+ ifp = ifname_linux_to_ifp(td, pn->pn_name);
+ if (ifp != NULL) {
+ TAILQ_FOREACH_SAFE(nq, &ifp_nodes_q, ifp_nodes_next, nq_tmp) {
+ if (nq->ifp == ifp && nq->vnet == curvnet) {
+ visible = 1;
+ break;
+ }
+ }
+ }
+ NET_EPOCH_EXIT(et);
+ CURVNET_RESTORE();
+ return (visible);
+}
+
+static int
+linsysfs_net_addif(if_t ifp, void *arg)
+{
+ struct ifp_nodes_queue *nq, *nq_tmp;
+ struct pfs_node *nic, *dir = arg;
+ char ifname[LINUX_IFNAMSIZ];
+ struct epoch_tracker et;
+ int ret __diagused;
+
+ NET_EPOCH_ENTER(et);
+ ret = ifname_bsd_to_linux_ifp(ifp, ifname, sizeof(ifname));
+ NET_EPOCH_EXIT(et);
+ KASSERT(ret > 0, ("Interface (%s) is not converted", if_name(ifp)));
+
+ nic = pfs_find_node(dir, ifname);
+ if (nic == NULL) {
+ nic = pfs_create_dir(dir, ifname, NULL, linsysfs_if_visible,
+ NULL, 0);
+ pfs_create_file(nic, "address", &linsysfs_if_addr,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(nic, "addr_len", &linsysfs_if_addrlen,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(nic, "flags", &linsysfs_if_flags,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(nic, "ifindex", &linsysfs_if_ifindex,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(nic, "mtu", &linsysfs_if_mtu,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(nic, "tx_queue_len", &linsysfs_if_txq_len,
+ NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(nic, "type", &linsysfs_if_type,
+ NULL, NULL, NULL, PFS_RD);
+ }
+ /*
+ * There is a small window between registering the if_arrival
+ * eventhandler and creating a list of interfaces.
+ */
+ TAILQ_FOREACH_SAFE(nq, &ifp_nodes_q, ifp_nodes_next, nq_tmp) {
+ if (nq->ifp == ifp && nq->vnet == curvnet)
+ return (0);
+ }
+ nq = malloc(sizeof(*nq), M_LINSYSFS, M_WAITOK);
+ nq->pn = nic;
+ nq->ifp = ifp;
+ nq->vnet = curvnet;
+ TAILQ_INSERT_TAIL(&ifp_nodes_q, nq, ifp_nodes_next);
+ return (0);
+}
+
+static void
+linsysfs_net_delif(if_t ifp)
+{
+ struct ifp_nodes_queue *nq, *nq_tmp;
+ struct pfs_node *pn;
+
+ pn = NULL;
+ TAILQ_FOREACH_SAFE(nq, &ifp_nodes_q, ifp_nodes_next, nq_tmp) {
+ if (nq->ifp == ifp && nq->vnet == curvnet) {
+ TAILQ_REMOVE(&ifp_nodes_q, nq, ifp_nodes_next);
+ pn = nq->pn;
+ free(nq, M_LINSYSFS);
+ break;
+ }
+ }
+ if (pn == NULL)
+ return;
+ TAILQ_FOREACH_SAFE(nq, &ifp_nodes_q, ifp_nodes_next, nq_tmp) {
+ if (nq->pn == pn)
+ return;
+ }
+ pfs_destroy(pn);
+}
+
+static void
+linsysfs_if_arrival(void *arg __unused, if_t ifp)
+{
+
+ linsysfs_net_latch_hold();
+ (void)linsysfs_net_addif(ifp, net);
+ linsysfs_net_latch_rele();
+}
+
+static void
+linsysfs_if_departure(void *arg __unused, if_t ifp)
+{
+
+ linsysfs_net_latch_hold();
+ linsysfs_net_delif(ifp);
+ linsysfs_net_latch_rele();
+}
+
+void
+linsysfs_net_init(void)
+{
+ VNET_ITERATOR_DECL(vnet_iter);
+
+ MPASS(net != NULL);
+ TAILQ_INIT(&ifp_nodes_q);
+
+ if_arrival_tag = EVENTHANDLER_REGISTER(ifnet_arrival_event,
+ linsysfs_if_arrival, NULL, EVENTHANDLER_PRI_ANY);
+ if_departure_tag = EVENTHANDLER_REGISTER(ifnet_departure_event,
+ linsysfs_if_departure, NULL, EVENTHANDLER_PRI_ANY);
+
+ linsysfs_net_latch_hold();
+ VNET_LIST_RLOCK();
+ VNET_FOREACH(vnet_iter) {
+ CURVNET_SET(vnet_iter);
+ if_foreach_sleep(NULL, NULL, linsysfs_net_addif, net);
+ CURVNET_RESTORE();
+ }
+ VNET_LIST_RUNLOCK();
+ linsysfs_net_latch_rele();
+}
+
+void
+linsysfs_net_uninit(void)
+{
+ struct ifp_nodes_queue *nq, *nq_tmp;
+
+ EVENTHANDLER_DEREGISTER(ifnet_arrival_event, if_arrival_tag);
+ EVENTHANDLER_DEREGISTER(ifnet_departure_event, if_departure_tag);
+
+ linsysfs_net_latch_hold();
+ TAILQ_FOREACH_SAFE(nq, &ifp_nodes_q, ifp_nodes_next, nq_tmp) {
+ TAILQ_REMOVE(&ifp_nodes_q, nq, ifp_nodes_next);
+ free(nq, M_LINSYSFS);
+ }
+ linsysfs_net_latch_rele();
+}
diff --git a/sys/compat/linux/check_error.d b/sys/compat/linux/check_error.d
index 8ed87a397863..6d922454b1f0 100644
--- a/sys/compat/linux/check_error.d
+++ b/sys/compat/linux/check_error.d
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
diff --git a/sys/compat/linux/check_internal_locks.d b/sys/compat/linux/check_internal_locks.d
index d3032c06c512..ceed81b3b0f8 100644
--- a/sys/compat/linux/check_internal_locks.d
+++ b/sys/compat/linux/check_internal_locks.d
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
/**
diff --git a/sys/compat/linux/linux.c b/sys/compat/linux/linux.c
index 340fdb37e2a2..61b207070963 100644
--- a/sys/compat/linux/linux.c
+++ b/sys/compat/linux/linux.c
@@ -23,13 +23,9 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <opt_inet6.h>
+#include "opt_inet6.h"
#include <sys/param.h>
-#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/ctype.h>
#include <sys/file.h>
@@ -47,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_types.h>
+#include <netlink/netlink.h>
#include <sys/un.h>
#include <netinet/in.h>
@@ -56,7 +53,16 @@ __FBSDID("$FreeBSD$");
#include <compat/linux/linux_mib.h>
#include <compat/linux/linux_util.h>
-CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ);
+_Static_assert(LINUX_IFNAMSIZ == IFNAMSIZ, "Linux IFNAMSIZ");
+_Static_assert(sizeof(struct sockaddr) == sizeof(struct l_sockaddr),
+ "Linux struct sockaddr size");
+_Static_assert(offsetof(struct sockaddr, sa_data) ==
+ offsetof(struct l_sockaddr, sa_data), "Linux struct sockaddr layout");
+
+static bool use_real_ifnames = false;
+SYSCTL_BOOL(_compat_linux, OID_AUTO, use_real_ifnames, CTLFLAG_RWTUN,
+ &use_real_ifnames, 0,
+ "Use FreeBSD interface names instead of generating ethN aliases");
static int bsd_to_linux_sigtbl[LINUX_SIGTBLSZ] = {
LINUX_SIGHUP, /* SIGHUP */
@@ -237,116 +243,266 @@ bsd_to_linux_sigset(sigset_t *bss, l_sigset_t *lss)
}
/*
+ * Translate a FreeBSD interface name to a Linux interface name
+ * by interface name, and return the number of bytes copied to lxname.
+ */
+int
+ifname_bsd_to_linux_name(const char *bsdname, char *lxname, size_t len)
+{
+ struct epoch_tracker et;
+ struct ifnet *ifp;
+ int ret;
+
+ CURVNET_ASSERT_SET();
+
+ ret = 0;
+ NET_EPOCH_ENTER(et);
+ ifp = ifunit(bsdname);
+ if (ifp != NULL)
+ ret = ifname_bsd_to_linux_ifp(ifp, lxname, len);
+ NET_EPOCH_EXIT(et);
+ return (ret);
+}
+
+/*
+ * Translate a FreeBSD interface name to a Linux interface name
+ * by interface index, and return the number of bytes copied to lxname.
+ */
+int
+ifname_bsd_to_linux_idx(u_int idx, char *lxname, size_t len)
+{
+ struct epoch_tracker et;
+ struct ifnet *ifp;
+ int ret;
+
+ ret = 0;
+ CURVNET_SET(TD_TO_VNET(curthread));
+ NET_EPOCH_ENTER(et);
+ ifp = ifnet_byindex(idx);
+ if (ifp != NULL)
+ ret = ifname_bsd_to_linux_ifp(ifp, lxname, len);
+ NET_EPOCH_EXIT(et);
+ CURVNET_RESTORE();
+ return (ret);
+}
+
+/*
+ * Translate a FreeBSD interface name to a Linux interface name,
+ * and return the number of bytes copied to lxname, 0 if interface
+ * not found, -1 on error.
+ */
+struct ifname_bsd_to_linux_ifp_cb_s {
+ struct ifnet *ifp;
+ int ethno;
+ char *lxname;
+ size_t len;
+};
+
+static int
+ifname_bsd_to_linux_ifp_cb(if_t ifp, void *arg)
+{
+ struct ifname_bsd_to_linux_ifp_cb_s *cbs = arg;
+
+ if (ifp == cbs->ifp)
+ return (snprintf(cbs->lxname, cbs->len, "eth%d", cbs->ethno));
+ if (IFP_IS_ETH(ifp))
+ cbs->ethno++;
+ return (0);
+}
+
+int
+ifname_bsd_to_linux_ifp(struct ifnet *ifp, char *lxname, size_t len)
+{
+ struct ifname_bsd_to_linux_ifp_cb_s arg = {
+ .ifp = ifp,
+ .ethno = 0,
+ .lxname = lxname,
+ .len = len,
+ };
+
+ NET_EPOCH_ASSERT();
+
+ /*
+ * Linux loopback interface name is lo (not lo0),
+ * we translate lo to lo0, loX to loX.
+ */
+ if (IFP_IS_LOOP(ifp) && strncmp(if_name(ifp), "lo0", IFNAMSIZ) == 0)
+ return (strlcpy(lxname, "lo", len));
+
+ /* Short-circuit non ethernet interfaces. */
+ if (!IFP_IS_ETH(ifp) || linux_use_real_ifname(ifp))
+ return (strlcpy(lxname, if_name(ifp), len));
+
+ /* Determine the (relative) unit number for ethernet interfaces. */
+ return (if_foreach(ifname_bsd_to_linux_ifp_cb, &arg));
+}
+
+/*
* Translate a Linux interface name to a FreeBSD interface name,
* and return the associated ifnet structure
* bsdname and lxname need to be least IFNAMSIZ bytes long, but
* can point to the same buffer.
*/
+struct ifname_linux_to_ifp_cb_s {
+ bool is_lo;
+ bool is_eth;
+ int ethno;
+ int unit;
+ const char *lxname;
+ if_t ifp;
+};
+
+static int
+ifname_linux_to_ifp_cb(if_t ifp, void *arg)
+{
+ struct ifname_linux_to_ifp_cb_s *cbs = arg;
+
+ NET_EPOCH_ASSERT();
+
+ /*
+ * Allow Linux programs to use FreeBSD names. Don't presume
+ * we never have an interface named "eth", so don't make
+ * the test optional based on is_eth.
+ */
+ if (strncmp(if_name(ifp), cbs->lxname, LINUX_IFNAMSIZ) == 0)
+ goto out;
+ if (cbs->is_eth && IFP_IS_ETH(ifp) && cbs->unit == cbs->ethno)
+ goto out;
+ if (cbs->is_lo && IFP_IS_LOOP(ifp))
+ goto out;
+ if (IFP_IS_ETH(ifp))
+ cbs->ethno++;
+ return (0);
+
+out:
+ cbs->ifp = ifp;
+ return (1);
+}
+
struct ifnet *
-ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname)
+ifname_linux_to_ifp(struct thread *td, const char *lxname)
{
- struct ifnet *ifp;
- int len, unit;
+ struct ifname_linux_to_ifp_cb_s arg = {
+ .ethno = 0,
+ .lxname = lxname,
+ .ifp = NULL,
+ };
+ int len;
char *ep;
- int index;
- bool is_eth, is_lo;
+
+ NET_EPOCH_ASSERT();
for (len = 0; len < LINUX_IFNAMSIZ; ++len)
if (!isalpha(lxname[len]) || lxname[len] == '\0')
break;
if (len == 0 || len == LINUX_IFNAMSIZ)
return (NULL);
- /* Linux loopback interface name is lo (not lo0) */
- is_lo = (len == 2 && strncmp(lxname, "lo", len) == 0);
- unit = (int)strtoul(lxname + len, &ep, 10);
+ /*
+ * Linux loopback interface name is lo (not lo0),
+ * we translate lo to lo0, loX to loX.
+ */
+ arg.is_lo = (len == 2 && strncmp(lxname, "lo", LINUX_IFNAMSIZ) == 0);
+ arg.unit = (int)strtoul(lxname + len, &ep, 10);
if ((ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ) &&
- is_lo == 0)
+ arg.is_lo == 0)
return (NULL);
- index = 0;
- is_eth = (len == 3 && strncmp(lxname, "eth", len) == 0);
+ arg.is_eth = (len == 3 && strncmp(lxname, "eth", len) == 0);
+
+ if_foreach(ifname_linux_to_ifp_cb, &arg);
+ return (arg.ifp);
+}
+
+int
+ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname)
+{
+ struct epoch_tracker et;
+ struct ifnet *ifp;
CURVNET_SET(TD_TO_VNET(td));
- IFNET_RLOCK();
- CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
- /*
- * Allow Linux programs to use FreeBSD names. Don't presume
- * we never have an interface named "eth", so don't make
- * the test optional based on is_eth.
- */
- if (strncmp(ifp->if_xname, lxname, LINUX_IFNAMSIZ) == 0)
- break;
- if (is_eth && IFP_IS_ETH(ifp) && unit == index++)
- break;
- if (is_lo && IFP_IS_LOOP(ifp))
- break;
- }
- IFNET_RUNLOCK();
- CURVNET_RESTORE();
+ NET_EPOCH_ENTER(et);
+ ifp = ifname_linux_to_ifp(td, lxname);
if (ifp != NULL && bsdname != NULL)
- strlcpy(bsdname, ifp->if_xname, IFNAMSIZ);
- return (ifp);
+ strlcpy(bsdname, if_name(ifp), IFNAMSIZ);
+ NET_EPOCH_EXIT(et);
+ CURVNET_RESTORE();
+ return (ifp != NULL ? 0 : EINVAL);
}
-void
-linux_ifflags(struct ifnet *ifp, short *flags)
+unsigned short
+linux_ifflags(struct ifnet *ifp)
{
- unsigned short fl;
+ unsigned short flags;
+
+ NET_EPOCH_ASSERT();
+
+ flags = if_getflags(ifp) | if_getdrvflags(ifp);
+ return (bsd_to_linux_ifflags(flags));
+}
+
+unsigned short
+bsd_to_linux_ifflags(int fl)
+{
+ unsigned short flags = 0;
- fl = (ifp->if_flags | ifp->if_drv_flags) & 0xffff;
- *flags = 0;
if (fl & IFF_UP)
- *flags |= LINUX_IFF_UP;
+ flags |= LINUX_IFF_UP;
if (fl & IFF_BROADCAST)
- *flags |= LINUX_IFF_BROADCAST;
+ flags |= LINUX_IFF_BROADCAST;
if (fl & IFF_DEBUG)
- *flags |= LINUX_IFF_DEBUG;
+ flags |= LINUX_IFF_DEBUG;
if (fl & IFF_LOOPBACK)
- *flags |= LINUX_IFF_LOOPBACK;
+ flags |= LINUX_IFF_LOOPBACK;
if (fl & IFF_POINTOPOINT)
- *flags |= LINUX_IFF_POINTOPOINT;
+ flags |= LINUX_IFF_POINTOPOINT;
if (fl & IFF_DRV_RUNNING)
- *flags |= LINUX_IFF_RUNNING;
+ flags |= LINUX_IFF_RUNNING;
if (fl & IFF_NOARP)
- *flags |= LINUX_IFF_NOARP;
+ flags |= LINUX_IFF_NOARP;
if (fl & IFF_PROMISC)
- *flags |= LINUX_IFF_PROMISC;
+ flags |= LINUX_IFF_PROMISC;
if (fl & IFF_ALLMULTI)
- *flags |= LINUX_IFF_ALLMULTI;
+ flags |= LINUX_IFF_ALLMULTI;
if (fl & IFF_MULTICAST)
- *flags |= LINUX_IFF_MULTICAST;
+ flags |= LINUX_IFF_MULTICAST;
+ return (flags);
+}
+
+static u_int
+linux_ifhwaddr_cb(void *arg, struct ifaddr *ifa, u_int count)
+{
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ struct l_sockaddr *lsa = arg;
+
+ if (count > 0)
+ return (0);
+ if (sdl->sdl_type != IFT_ETHER)
+ return (0);
+ bzero(lsa, sizeof(*lsa));
+ lsa->sa_family = LINUX_ARPHRD_ETHER;
+ bcopy(LLADDR(sdl), lsa->sa_data, LINUX_IFHWADDRLEN);
+ return (1);
}
int
linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa)
{
- struct ifaddr *ifa;
- struct sockaddr_dl *sdl;
+
+ NET_EPOCH_ASSERT();
if (IFP_IS_LOOP(ifp)) {
bzero(lsa, sizeof(*lsa));
lsa->sa_family = LINUX_ARPHRD_LOOPBACK;
return (0);
}
-
if (!IFP_IS_ETH(ifp))
return (ENOENT);
-
- CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
- sdl = (struct sockaddr_dl*)ifa->ifa_addr;
- if (sdl != NULL && (sdl->sdl_family == AF_LINK) &&
- (sdl->sdl_type == IFT_ETHER)) {
- bzero(lsa, sizeof(*lsa));
- lsa->sa_family = LINUX_ARPHRD_ETHER;
- bcopy(LLADDR(sdl), lsa->sa_data, LINUX_IFHWADDRLEN);
- return (0);
- }
- }
-
+ if (if_foreach_addr_type(ifp, AF_LINK, linux_ifhwaddr_cb, lsa) > 0)
+ return (0);
return (ENOENT);
}
-int
-linux_to_bsd_domain(int domain)
+sa_family_t
+linux_to_bsd_domain(sa_family_t domain)
{
switch (domain) {
@@ -364,12 +520,14 @@ linux_to_bsd_domain(int domain)
return (AF_IPX);
case LINUX_AF_APPLETALK:
return (AF_APPLETALK);
+ case LINUX_AF_NETLINK:
+ return (AF_NETLINK);
}
- return (-1);
+ return (AF_UNKNOWN);
}
-int
-bsd_to_linux_domain(int domain)
+sa_family_t
+bsd_to_linux_domain(sa_family_t domain)
{
switch (domain) {
@@ -387,8 +545,10 @@ bsd_to_linux_domain(int domain)
return (LINUX_AF_IPX);
case AF_APPLETALK:
return (LINUX_AF_APPLETALK);
+ case AF_NETLINK:
+ return (LINUX_AF_NETLINK);
}
- return (-1);
+ return (AF_UNKNOWN);
}
/*
@@ -402,13 +562,13 @@ bsd_to_linux_sockaddr(const struct sockaddr *sa, struct l_sockaddr **lsa,
socklen_t len)
{
struct l_sockaddr *kosa;
- int bdom;
+ sa_family_t bdom;
*lsa = NULL;
if (len < 2 || len > UCHAR_MAX)
return (EINVAL);
bdom = bsd_to_linux_domain(sa->sa_family);
- if (bdom == -1)
+ if (bdom == AF_UNKNOWN)
return (EAFNOSUPPORT);
kosa = malloc(len, M_LINUX, M_WAITOK);
@@ -455,7 +615,7 @@ linux_to_bsd_sockaddr(const struct l_sockaddr *osa, struct sockaddr **sap,
goto out;
bdom = linux_to_bsd_domain(kosa->sa_family);
- if (bdom == -1) {
+ if (bdom == AF_UNKNOWN) {
error = EAFNOSUPPORT;
goto out;
}
@@ -514,6 +674,14 @@ linux_to_bsd_sockaddr(const struct l_sockaddr *osa, struct sockaddr **sap,
}
}
+ if (bdom == AF_NETLINK) {
+ if (salen < sizeof(struct sockaddr_nl)) {
+ error = EINVAL;
+ goto out;
+ }
+ salen = sizeof(struct sockaddr_nl);
+ }
+
sa = (struct sockaddr *)kosa;
sa->sa_family = bdom;
sa->sa_len = salen;
@@ -710,3 +878,10 @@ bsd_to_linux_poll_events(short bev, short *lev)
*lev = bits;
}
+
+bool
+linux_use_real_ifname(const struct ifnet *ifp)
+{
+
+ return (use_real_ifnames);
+}
diff --git a/sys/compat/linux/linux.h b/sys/compat/linux/linux.h
index 72bcb25bd05a..5a0d6e0b68c5 100644
--- a/sys/compat/linux/linux.h
+++ b/sys/compat/linux/linux.h
@@ -1,4 +1,6 @@
/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
* Copyright (c) 2015 Dmitry Chagin <dchagin@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -21,14 +23,83 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUX_MI_H_
#define _LINUX_MI_H_
-#include <sys/queue.h>
+/*
+ * Machine independent set of types for the Linux types.
+ */
+typedef uint32_t l_dev_t;
+
+/*
+ * Linux dev_t conversion routines.
+ *
+ * As of version 2.6.0 of the Linux kernel, dev_t is a 32-bit quantity
+ * with 12 bits set asaid for the major number and 20 for the minor number.
+ * The in-kernel dev_t encoded as MMMmmmmm, where M is a hex digit of the
+ * major number and m is a hex digit of the minor number.
+ * The user-space dev_t encoded as mmmM MMmm, where M and m is the major
+ * and minor numbers accordingly. This is downward compatible with legacy
+ * systems where dev_t is 16 bits wide, encoded as MMmm.
+ * In glibc dev_t is a 64-bit quantity, with 32-bit major and minor numbers,
+ * encoded as MMMM Mmmm mmmM MMmm. This is downward compatible with the Linux
+ * kernel and with legacy systems where dev_t is 16 bits wide.
+ *
+ * In the FreeBSD dev_t is a 64-bit quantity. The major and minor numbers
+ * are encoded as MMMmmmMm, therefore conversion of the device numbers between
+ * Linux user-space and FreeBSD kernel required.
+ */
+static __inline l_dev_t
+linux_encode_dev(int _major, int _minor)
+{
+
+ return ((_minor & 0xff) | ((_major & 0xfff) << 8) |
+ (((_minor & ~0xff) << 12) & 0xfff00000));
+}
+
+static __inline l_dev_t
+linux_new_encode_dev(dev_t _dev)
+{
+
+ return (_dev == NODEV ? 0 : linux_encode_dev(major(_dev), minor(_dev)));
+}
+
+static __inline int
+linux_encode_major(dev_t _dev)
+{
+
+ return (_dev == NODEV ? 0 : major(_dev) & 0xfff);
+}
+
+static __inline int
+linux_encode_minor(dev_t _dev)
+{
+
+ return (_dev == NODEV ? 0 : minor(_dev) & 0xfffff);
+}
+
+static __inline int
+linux_decode_major(l_dev_t _dev)
+{
+
+ return ((_dev & 0xfff00) >> 8);
+}
+
+static __inline int
+linux_decode_minor(l_dev_t _dev)
+{
+
+ return ((_dev & 0xff) | ((_dev & 0xfff00000) >> 12));
+}
+
+static __inline dev_t
+linux_decode_dev(l_dev_t _dev)
+{
+
+ return (makedev(linux_decode_major(_dev), linux_decode_minor(_dev)));
+}
/*
* Private Brandinfo flags
@@ -264,6 +335,21 @@ struct l_statx {
uint64_t __spare2[13];
};
+/*
+ * statfs f_flags
+ */
+#define LINUX_ST_RDONLY 0x0001
+#define LINUX_ST_NOSUID 0x0002
+#define LINUX_ST_NODEV 0x0004 /* No native analogue */
+#define LINUX_ST_NOEXEC 0x0008
+#define LINUX_ST_SYNCHRONOUS 0x0010
+#define LINUX_ST_VALID 0x0020
+#define LINUX_ST_MANDLOCK 0x0040 /* No native analogue */
+#define LINUX_ST_NOATIME 0x0400
+#define LINUX_ST_NODIRATIME 0x0800 /* No native analogue */
+#define LINUX_ST_RELATIME 0x1000 /* No native analogue */
+#define LINUX_ST_NOSYMFOLLOW 0x2000
+
#define lower_32_bits(n) ((uint32_t)((n) & 0xffffffff))
#ifdef KTRACE
@@ -271,4 +357,17 @@ struct l_statx {
ktrstruct("l_sigset_t", (s), l)
#endif
+/*
+ * Criteria for interface name translation
+ */
+#define IFP_IS_ETH(ifp) (if_gettype(ifp) == IFT_ETHER)
+#define IFP_IS_LOOP(ifp) (if_gettype(ifp) == IFT_LOOP)
+
+struct ifnet;
+
+bool linux_use_real_ifname(const struct ifnet *);
+
+void linux_netlink_register(void);
+void linux_netlink_deregister(void);
+
#endif /* _LINUX_MI_H_ */
diff --git a/sys/compat/linux/linux_common.c b/sys/compat/linux/linux_common.c
index 0009d9d26164..e22e29ff2b24 100644
--- a/sys/compat/linux/linux_common.c
+++ b/sys/compat/linux/linux_common.c
@@ -24,21 +24,14 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
-#include <sys/systm.h>
#include <sys/exec.h>
#include <sys/imgact.h>
-#include <sys/imgact_elf.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/sx.h>
#include <compat/linux/linux.h>
-#include <compat/linux/linux_emul.h>
-#include <compat/linux/linux_ioctl.h>
#include <compat/linux/linux_mib.h>
#include <compat/linux/linux_util.h>
@@ -63,12 +56,14 @@ linux_common_modevent(module_t mod, int type, void *data)
linux_osd_jail_register();
SET_FOREACH(ldhp, linux_device_handler_set)
linux_device_register_handler(*ldhp);
+ linux_netlink_register();
break;
case MOD_UNLOAD:
linux_dev_shm_destroy();
linux_osd_jail_deregister();
SET_FOREACH(ldhp, linux_device_handler_set)
linux_device_unregister_handler(*ldhp);
+ linux_netlink_deregister();
break;
default:
return (EOPNOTSUPP);
@@ -84,3 +79,4 @@ static moduledata_t linux_common_mod = {
DECLARE_MODULE(linux_common, linux_common_mod, SI_SUB_EXEC, SI_ORDER_ANY);
MODULE_VERSION(linux_common, 1);
+MODULE_DEPEND(linux_common, netlink, 1, 1, 1);
diff --git a/sys/compat/linux/linux_common.h b/sys/compat/linux/linux_common.h
index 0eb302bfcd17..97f5a259f300 100644
--- a/sys/compat/linux/linux_common.h
+++ b/sys/compat/linux/linux_common.h
@@ -23,20 +23,24 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUX_COMMON_H_
#define _LINUX_COMMON_H_
-struct ifnet *ifname_linux_to_bsd(struct thread *td,
- const char *lxname, char *bsdname);
-void linux_ifflags(struct ifnet *ifp, short *flags);
+int ifname_bsd_to_linux_ifp(struct ifnet *, char *, size_t);
+int ifname_bsd_to_linux_idx(u_int, char *, size_t);
+int ifname_bsd_to_linux_name(const char *, char *, size_t);
+struct ifnet *ifname_linux_to_ifp(struct thread *, const char *);
+int ifname_linux_to_bsd(struct thread *, const char *, char *);
+
+unsigned short linux_ifflags(struct ifnet *);
int linux_ifhwaddr(struct ifnet *ifp, struct l_sockaddr *lsa);
-int linux_to_bsd_domain(int domain);
-int bsd_to_linux_domain(int domain);
+unsigned short bsd_to_linux_ifflags(int);
+sa_family_t linux_to_bsd_domain(sa_family_t domain);
+sa_family_t bsd_to_linux_domain(sa_family_t domain);
+#define AF_UNKNOWN UINT8_MAX
int bsd_to_linux_sockaddr(const struct sockaddr *sa,
struct l_sockaddr **lsa, socklen_t len);
int linux_to_bsd_sockaddr(const struct l_sockaddr *lsa,
diff --git a/sys/compat/linux/linux_dtrace.h b/sys/compat/linux/linux_dtrace.h
index 0bf42f43bac1..2e4c1315aa3d 100644
--- a/sys/compat/linux/linux_dtrace.h
+++ b/sys/compat/linux/linux_dtrace.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2008-2012 Alexander Leidinger <netchild@FreeBSD.org>
* All rights reserved.
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUX_DTRACE_H_
diff --git a/sys/compat/linux/linux_dummy.c b/sys/compat/linux/linux_dummy.c
index 6bfeeaf5c298..35d6debe0da9 100644
--- a/sys/compat/linux/linux_dummy.c
+++ b/sys/compat/linux/linux_dummy.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2013 Dmitry Chagin <dchagin@FreeBSD.org>
*
@@ -25,13 +25,9 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/sdt.h>
#include <sys/systm.h>
+#include <sys/sdt.h>
#include <sys/proc.h>
/*
@@ -79,8 +75,6 @@ DUMMY(add_key);
DUMMY(request_key);
DUMMY(keyctl);
/* Linux 2.6.13: */
-DUMMY(ioprio_set);
-DUMMY(ioprio_get);
DUMMY(inotify_add_watch);
DUMMY(inotify_rm_watch);
/* Linux 2.6.16: */
@@ -129,43 +123,42 @@ DUMMY(pwritev2);
DUMMY(pkey_mprotect);
DUMMY(pkey_alloc);
DUMMY(pkey_free);
+/* Linux 4.18: */
+DUMMY(io_pgetevents);
+/* Linux 5.1: */
+DUMMY(pidfd_send_signal);
+DUMMY(io_uring_setup);
+DUMMY(io_uring_enter);
+DUMMY(io_uring_register);
+/* Linux 5.2: */
DUMMY(open_tree);
DUMMY(move_mount);
DUMMY(fsopen);
DUMMY(fsconfig);
DUMMY(fsmount);
DUMMY(fspick);
+/* Linux 5.3: */
DUMMY(pidfd_open);
-DUMMY(close_range);
+/* Linux 5.6: */
DUMMY(openat2);
DUMMY(pidfd_getfd);
+/* Linux 5.10: */
DUMMY(process_madvise);
+/* Linux 5.12: */
DUMMY(mount_setattr);
-/* Linux 4.18: */
-DUMMY(io_pgetevents);
-/* Linux 5.0: */
-DUMMY(pidfd_send_signal);
-DUMMY(io_uring_setup);
-DUMMY(io_uring_enter);
-DUMMY(io_uring_register);
-
-#define DUMMY_XATTR(s) \
-int \
-linux_ ## s ## xattr( \
- struct thread *td, struct linux_ ## s ## xattr_args *arg) \
-{ \
- \
- return (EOPNOTSUPP); \
-}
-DUMMY_XATTR(set);
-DUMMY_XATTR(lset);
-DUMMY_XATTR(fset);
-DUMMY_XATTR(get);
-DUMMY_XATTR(lget);
-DUMMY_XATTR(fget);
-DUMMY_XATTR(list);
-DUMMY_XATTR(llist);
-DUMMY_XATTR(flist);
-DUMMY_XATTR(remove);
-DUMMY_XATTR(lremove);
-DUMMY_XATTR(fremove);
+/* Linux 5.13: */
+DUMMY(landlock_create_ruleset);
+DUMMY(landlock_add_rule);
+DUMMY(landlock_restrict_self);
+/* Linux 5.14: */
+DUMMY(memfd_secret);
+DUMMY(quotactl_fd);
+/* Linux 5.15: */
+DUMMY(process_mrelease);
+/* Linux 5.16: */
+DUMMY(futex_waitv);
+DUMMY(set_mempolicy_home_node);
+/* Linux 6.5: */
+DUMMY(cachestat);
+/* Linux 6.6: */
+DUMMY(fchmodat2);
diff --git a/sys/compat/linux/linux_elf.c b/sys/compat/linux/linux_elf.c
index b02b6e2cc777..c9eb6aea8373 100644
--- a/sys/compat/linux/linux_elf.c
+++ b/sys/compat/linux/linux_elf.c
@@ -37,10 +37,8 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
+#include <sys/exec.h>
#include <sys/imgact.h>
#include <sys/imgact_elf.h>
#include <sys/lock.h>
@@ -50,10 +48,15 @@ __FBSDID("$FreeBSD$");
#include <sys/procfs.h>
#include <sys/reg.h>
#include <sys/sbuf.h>
+#include <sys/sysent.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <vm/vm_map.h>
#include <machine/elf.h>
-#if __ELF_WORD_SIZE == 32
+#ifdef COMPAT_LINUX32
#define linux_pt_regset linux_pt_regset32
#define bsd_to_linux_regset bsd_to_linux_regset32
#include <machine/../linux32/linux.h>
@@ -61,11 +64,33 @@ __FBSDID("$FreeBSD$");
#include <machine/../linux/linux.h>
#endif
#include <compat/linux/linux_elf.h>
-#include <compat/linux/linux_emul.h>
+#include <compat/linux/linux_mib.h>
#include <compat/linux/linux_misc.h>
-/* This adds "linux32_" and "linux64_" prefixes. */
-#define __linuxN(x) __CONCAT(__CONCAT(__CONCAT(linux,__ELF_WORD_SIZE),_),x)
+struct l_elf_siginfo {
+ l_int si_signo;
+ l_int si_code;
+ l_int si_errno;
+};
+
+typedef struct linux_pt_regset l_elf_gregset_t;
+
+struct linux_elf_prstatus {
+ struct l_elf_siginfo pr_info;
+ l_short pr_cursig;
+ l_ulong pr_sigpend;
+ l_ulong pr_sighold;
+ l_pid_t pr_pid;
+ l_pid_t pr_ppid;
+ l_pid_t pr_pgrp;
+ l_pid_t pr_sid;
+ l_timeval pr_utime;
+ l_timeval pr_stime;
+ l_timeval pr_cutime;
+ l_timeval pr_cstime;
+ l_elf_gregset_t pr_reg;
+ l_int pr_fpvalid;
+};
#define LINUX_NT_AUXV 6
@@ -115,7 +140,7 @@ __linuxN(prepare_notes)(struct thread *td, struct note_info_list *list,
}
typedef struct linux_elf_prstatus linux_elf_prstatus_t;
-#if __ELF_WORD_SIZE == 32
+#ifdef COMPAT_LINUX32
typedef struct prpsinfo32 linux_elf_prpsinfo_t;
typedef struct fpreg32 linux_elf_prfpregset_t;
#else
@@ -192,7 +217,7 @@ __linuxN(note_prstatus)(void *arg, struct sbuf *sb, size_t *sizep)
{
struct thread *td;
linux_elf_prstatus_t *status;
-#if __ELF_WORD_SIZE == 32
+#ifdef COMPAT_LINUX32
struct reg32 pr_reg;
#else
struct reg pr_reg;
@@ -209,7 +234,7 @@ __linuxN(note_prstatus)(void *arg, struct sbuf *sb, size_t *sizep)
status->pr_cursig = td->td_proc->p_sig;
status->pr_pid = td->td_tid;
-#if __ELF_WORD_SIZE == 32
+#ifdef COMPAT_LINUX32
fill_regs32(td, &pr_reg);
#else
fill_regs(td, &pr_reg);
@@ -231,7 +256,7 @@ __linuxN(note_fpregset)(void *arg, struct sbuf *sb, size_t *sizep)
if (sb != NULL) {
KASSERT(*sizep == sizeof(*fpregset), ("invalid size"));
fpregset = malloc(sizeof(*fpregset), M_TEMP, M_ZERO | M_WAITOK);
-#if __ELF_WORD_SIZE == 32
+#ifdef COMPAT_LINUX32
fill_fpregs32(td, fpregset);
#else
fill_fpregs(td, fpregset);
@@ -292,3 +317,229 @@ __linuxN(note_nt_auxv)(void *arg, struct sbuf *sb, size_t *sizep)
PRELE(p);
}
}
+
+/*
+ * Copy strings out to the new process address space, constructing new arg
+ * and env vector tables. Return a pointer to the base so that it can be used
+ * as the initial stack pointer.
+ */
+int
+__linuxN(copyout_strings)(struct image_params *imgp, uintptr_t *stack_base)
+{
+ char canary[LINUX_AT_RANDOM_LEN];
+ char **vectp;
+ char *stringp;
+ uintptr_t destp, ustringp;
+ struct ps_strings *arginfo;
+ struct proc *p;
+ size_t execpath_len;
+ int argc, envc;
+ int error;
+
+ p = imgp->proc;
+ destp = PROC_PS_STRINGS(p);
+ arginfo = imgp->ps_strings = (void *)destp;
+
+ /*
+ * Copy the image path for the rtld.
+ */
+ if (imgp->execpath != NULL && imgp->auxargs != NULL) {
+ execpath_len = strlen(imgp->execpath) + 1;
+ destp -= execpath_len;
+ destp = rounddown2(destp, sizeof(void *));
+ imgp->execpathp = (void *)destp;
+ error = copyout(imgp->execpath, imgp->execpathp, execpath_len);
+ if (error != 0)
+ return (error);
+ }
+
+ /*
+ * Prepare the canary for SSP.
+ */
+ arc4rand(canary, sizeof(canary), 0);
+ destp -= sizeof(canary);
+ imgp->canary = (void *)destp;
+ error = copyout(canary, imgp->canary, sizeof(canary));
+ if (error != 0)
+ return (error);
+ imgp->canarylen = sizeof(canary);
+
+ /*
+ * Allocate room for the argument and environment strings.
+ */
+ destp -= ARG_MAX - imgp->args->stringspace;
+ destp = rounddown2(destp, sizeof(void *));
+ ustringp = destp;
+
+ if (imgp->auxargs) {
+ /*
+ * Allocate room on the stack for the ELF auxargs
+ * array. It has up to LINUX_AT_COUNT entries.
+ */
+ destp -= LINUX_AT_COUNT * sizeof(Elf_Auxinfo);
+ destp = rounddown2(destp, sizeof(void *));
+ }
+
+ vectp = (char **)destp;
+
+ /*
+ * Allocate room for the argv[] and env vectors including the
+ * terminating NULL pointers.
+ */
+ vectp -= imgp->args->argc + 1 + imgp->args->envc + 1;
+
+ /*
+ * Starting with 2.24, glibc depends on a 16-byte stack alignment.
+ */
+ vectp = (char **)((((uintptr_t)vectp + 8) & ~0xF) - 8);
+
+ /*
+ * vectp also becomes our initial stack base
+ */
+ *stack_base = (uintptr_t)vectp;
+
+ stringp = imgp->args->begin_argv;
+ argc = imgp->args->argc;
+ envc = imgp->args->envc;
+
+ /*
+ * Copy out strings - arguments and environment.
+ */
+ error = copyout(stringp, (void *)ustringp,
+ ARG_MAX - imgp->args->stringspace);
+ if (error != 0)
+ return (error);
+
+ /*
+ * Fill in "ps_strings" struct for ps, w, etc.
+ */
+ imgp->argv = vectp;
+ if (suword(&arginfo->ps_argvstr, (long)(intptr_t)vectp) != 0 ||
+ suword32(&arginfo->ps_nargvstr, argc) != 0)
+ return (EFAULT);
+
+ /*
+ * Fill in argument portion of vector table.
+ */
+ for (; argc > 0; --argc) {
+ if (suword(vectp++, ustringp) != 0)
+ return (EFAULT);
+ while (*stringp++ != 0)
+ ustringp++;
+ ustringp++;
+ }
+
+ /* a null vector table pointer separates the argp's from the envp's */
+ if (suword(vectp++, 0) != 0)
+ return (EFAULT);
+
+ imgp->envv = vectp;
+ if (suword(&arginfo->ps_envstr, (long)(intptr_t)vectp) != 0 ||
+ suword32(&arginfo->ps_nenvstr, envc) != 0)
+ return (EFAULT);
+
+ /*
+ * Fill in environment portion of vector table.
+ */
+ for (; envc > 0; --envc) {
+ if (suword(vectp++, ustringp) != 0)
+ return (EFAULT);
+ while (*stringp++ != 0)
+ ustringp++;
+ ustringp++;
+ }
+
+ /* end of vector table is a null pointer */
+ if (suword(vectp, 0) != 0)
+ return (EFAULT);
+
+ if (imgp->auxargs) {
+ vectp++;
+ error = imgp->sysent->sv_copyout_auxargs(imgp,
+ (uintptr_t)vectp);
+ if (error != 0)
+ return (error);
+ }
+
+ return (0);
+}
+
+bool
+linux_trans_osrel(const Elf_Note *note, int32_t *osrel)
+{
+ const Elf32_Word *desc;
+ uintptr_t p;
+
+ p = (uintptr_t)(note + 1);
+ p += roundup2(note->n_namesz, sizeof(Elf32_Addr));
+
+ desc = (const Elf32_Word *)p;
+ if (desc[0] != GNU_ABI_LINUX)
+ return (false);
+ /*
+ * For Linux we encode osrel using the Linux convention of
+ * (version << 16) | (major << 8) | (minor)
+ * See macro in linux_mib.h
+ */
+ *osrel = LINUX_KERNVER(desc[1], desc[2], desc[3]);
+
+ return (true);
+}
+
+int
+__linuxN(copyout_auxargs)(struct image_params *imgp, uintptr_t base)
+{
+ struct thread *td = curthread;
+ Elf_Auxargs *args;
+ Elf_Auxinfo *aarray, *pos;
+ struct proc *p;
+ int error, issetugid;
+
+ p = imgp->proc;
+ issetugid = p->p_flag & P_SUGID ? 1 : 0;
+ args = imgp->auxargs;
+ aarray = pos = malloc(LINUX_AT_COUNT * sizeof(*pos), M_TEMP,
+ M_WAITOK | M_ZERO);
+
+ __linuxN(arch_copyout_auxargs)(imgp, &pos);
+ /*
+ * Do not export AT_CLKTCK when emulating Linux kernel prior to 2.4.0,
+ * as it has appeared in the 2.4.0-rc7 first time.
+ * Being exported, AT_CLKTCK is returned by sysconf(_SC_CLK_TCK),
+ * glibc falls back to the hard-coded CLK_TCK value when aux entry
+ * is not present.
+ * Also see linux_times() implementation.
+ */
+ if (linux_kernver(td) >= LINUX_KERNVER(2,4,0))
+ AUXARGS_ENTRY(pos, LINUX_AT_CLKTCK, stclohz);
+ AUXARGS_ENTRY(pos, AT_PAGESZ, args->pagesz);
+ AUXARGS_ENTRY(pos, AT_PHDR, args->phdr);
+ AUXARGS_ENTRY(pos, AT_PHENT, args->phent);
+ AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum);
+ AUXARGS_ENTRY(pos, AT_BASE, args->base);
+ AUXARGS_ENTRY(pos, AT_FLAGS, args->flags);
+ AUXARGS_ENTRY(pos, AT_ENTRY, args->entry);
+ AUXARGS_ENTRY(pos, AT_UID, imgp->proc->p_ucred->cr_ruid);
+ AUXARGS_ENTRY(pos, AT_EUID, imgp->proc->p_ucred->cr_svuid);
+ AUXARGS_ENTRY(pos, AT_GID, imgp->proc->p_ucred->cr_rgid);
+ AUXARGS_ENTRY(pos, AT_EGID, imgp->proc->p_ucred->cr_svgid);
+ AUXARGS_ENTRY(pos, LINUX_AT_SECURE, issetugid);
+ if (linux_kernver(td) >= LINUX_KERNVER(2,6,30))
+ AUXARGS_ENTRY_PTR(pos, LINUX_AT_RANDOM, imgp->canary);
+ if (linux_kernver(td) >= LINUX_KERNVER(2,6,26) && imgp->execpathp != 0)
+ AUXARGS_ENTRY(pos, LINUX_AT_EXECFN, PTROUT(imgp->execpathp));
+ if (args->execfd != -1)
+ AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd);
+ if (linux_kernver(td) >= LINUX_KERNVER(5,13,0))
+ AUXARGS_ENTRY(pos, LINUX_AT_MINSIGSTKSZ,
+ imgp->sysent->sv_minsigstksz);
+ AUXARGS_ENTRY(pos, AT_NULL, 0);
+
+ free(imgp->auxargs, M_TEMP);
+ imgp->auxargs = NULL;
+ KASSERT(pos - aarray <= LINUX_AT_COUNT, ("Too many auxargs"));
+
+ error = copyout(aarray, PTRIN(base), sizeof(*aarray) * LINUX_AT_COUNT);
+ free(aarray, M_TEMP);
+ return (error);
+}
diff --git a/sys/compat/linux/linux_elf.h b/sys/compat/linux/linux_elf.h
index 4bb9318e360b..2584a8a990c0 100644
--- a/sys/compat/linux/linux_elf.h
+++ b/sys/compat/linux/linux_elf.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2018 Chuck Tuffli
*
@@ -28,29 +28,23 @@
#ifndef _COMPAT_LINUX_ELF_H_
#define _COMPAT_LINUX_ELF_H_
-struct l_elf_siginfo {
- l_int si_signo;
- l_int si_code;
- l_int si_errno;
-};
+struct note_info_list;
-typedef struct linux_pt_regset l_elf_gregset_t;
+/* Linux core notes are labeled "CORE" */
+#define LINUX_ABI_VENDOR "CORE"
-struct linux_elf_prstatus {
- struct l_elf_siginfo pr_info;
- l_short pr_cursig;
- l_ulong pr_sigpend;
- l_ulong pr_sighold;
- l_pid_t pr_pid;
- l_pid_t pr_ppid;
- l_pid_t pr_pgrp;
- l_pid_t pr_sid;
- l_timeval pr_utime;
- l_timeval pr_stime;
- l_timeval pr_cutime;
- l_timeval pr_cstime;
- l_elf_gregset_t pr_reg;
- l_int pr_fpvalid;
-};
+/* Elf notes */
+#define GNU_ABI_VENDOR "GNU"
+#define GNU_ABI_LINUX 0
+
+/* This adds "linux32_" and "linux64_" prefixes. */
+#define __linuxN(x) __CONCAT(__CONCAT(__CONCAT(linux,__ELF_WORD_SIZE),_),x)
+
+void __linuxN(prepare_notes)(struct thread *, struct note_info_list *,
+ size_t *);
+void __linuxN(arch_copyout_auxargs)(struct image_params *, Elf_Auxinfo **);
+int __linuxN(copyout_auxargs)(struct image_params *, uintptr_t);
+int __linuxN(copyout_strings)(struct image_params *, uintptr_t *);
+bool linux_trans_osrel(const Elf_Note *note, int32_t *osrel);
#endif
diff --git a/sys/compat/linux/linux_elf32.c b/sys/compat/linux/linux_elf32.c
index 17ee4b6baa0a..6bd4b141af85 100644
--- a/sys/compat/linux/linux_elf32.c
+++ b/sys/compat/linux/linux_elf32.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Edward Tomasz Napierala <trasz@FreeBSD.org>
* Copyright (c) 2002 Doug Rabson
@@ -31,8 +31,5 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#define __ELF_WORD_SIZE 32
#include <compat/linux/linux_elf.c>
diff --git a/sys/compat/linux/linux_elf64.c b/sys/compat/linux/linux_elf64.c
index 2e283d763bbc..397bcf741fae 100644
--- a/sys/compat/linux/linux_elf64.c
+++ b/sys/compat/linux/linux_elf64.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Edward Tomasz Napierala <trasz@FreeBSD.org>
* Copyright (c) 2002 Doug Rabson
@@ -31,8 +31,5 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#define __ELF_WORD_SIZE 64
#include <compat/linux/linux_elf.c>
diff --git a/sys/compat/linux/linux_emul.c b/sys/compat/linux/linux_emul.c
index 08510fc29a3f..e5ab51802468 100644
--- a/sys/compat/linux/linux_emul.c
+++ b/sys/compat/linux/linux_emul.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1994-1996 Søren Schmidt
* Copyright (c) 2006 Roman Divacky
@@ -28,21 +28,16 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
-#include <sys/systm.h>
#include <sys/fcntl.h>
#include <sys/imgact.h>
-#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
-#include <sys/sx.h>
#include <sys/proc.h>
#include <sys/resourcevar.h>
+#include <sys/sx.h>
#include <sys/syscallsubr.h>
#include <sys/sysent.h>
@@ -149,7 +144,7 @@ linux_proc_init(struct thread *td, struct thread *newtd, bool init_thread)
p = newtd->td_proc;
/* non-exec call */
- em = malloc(sizeof(*em), M_TEMP, M_WAITOK | M_ZERO);
+ em = malloc(sizeof(*em), M_LINUX, M_WAITOK | M_ZERO);
if (init_thread) {
LINUX_CTR1(proc_init, "thread newtd(%d)",
newtd->td_tid);
@@ -213,41 +208,6 @@ linux_on_exit(struct proc *p)
free(pem, M_LINUX);
}
-/*
- * If a Linux binary is exec'ing something, try this image activator
- * first. We override standard shell script execution in order to
- * be able to modify the interpreter path. We only do this if a Linux
- * binary is doing the exec, so we do not create an EXEC module for it.
- */
-int
-linux_exec_imgact_try(struct image_params *imgp)
-{
- const char *head = (const char *)imgp->image_header;
- char *rpath;
- int error = -1;
-
- /*
- * The interpreter for shell scripts run from a Linux binary needs
- * to be located in /compat/linux if possible in order to recursively
- * maintain Linux path emulation.
- */
- if (((const short *)head)[0] == SHELLMAGIC) {
- /*
- * Run our normal shell image activator. If it succeeds attempt
- * to use the alternate path for the interpreter. If an
- * alternate path is found, use our stringspace to store it.
- */
- if ((error = exec_shell_imgact(imgp)) == 0) {
- linux_emul_convpath(imgp->interpreter_name, UIO_SYSSPACE,
- &rpath, 0, AT_FDCWD);
- if (rpath != NULL)
- imgp->args->fname_buf =
- imgp->interpreter_name = rpath;
- }
- }
- return (error);
-}
-
int
linux_common_execve(struct thread *td, struct image_args *eargs)
{
@@ -273,6 +233,10 @@ linux_common_execve(struct thread *td, struct image_args *eargs)
* FreeBSD binary we destroy Linux emuldata thread & proc entries.
*/
if (SV_CURPROC_ABI() != SV_ABI_LINUX) {
+
+ /* Clear ABI root directory if set. */
+ linux_pwd_onexec_native(td);
+
PROC_LOCK(p);
em = em_find(td);
KASSERT(em != NULL, ("proc_exec: thread emuldata not found.\n"));
@@ -283,13 +247,13 @@ linux_common_execve(struct thread *td, struct image_args *eargs)
p->p_emuldata = NULL;
PROC_UNLOCK(p);
- free(em, M_TEMP);
+ free(em, M_LINUX);
free(pem, M_LINUX);
}
return (EJUSTRETURN);
}
-void
+int
linux_on_exec(struct proc *p, struct image_params *imgp)
{
struct thread *td;
@@ -297,6 +261,7 @@ linux_on_exec(struct proc *p, struct image_params *imgp)
#if defined(__amd64__)
struct linux_pemuldata *pem;
#endif
+ int error;
td = curthread;
MPASS((imgp->sysent->sv_flags & SV_ABI_MASK) == SV_ABI_LINUX);
@@ -329,6 +294,10 @@ linux_on_exec(struct proc *p, struct image_params *imgp)
continue;
linux_proc_init(td, othertd, true);
}
+
+ /* Set ABI root directory. */
+ if ((error = linux_pwd_onexec(td)) != 0)
+ return (error);
}
#if defined(__amd64__)
/*
@@ -341,6 +310,7 @@ linux_on_exec(struct proc *p, struct image_params *imgp)
pem->persona |= LINUX_READ_IMPLIES_EXEC;
}
#endif
+ return (0);
}
void
@@ -355,7 +325,7 @@ linux_thread_dtor(struct thread *td)
LINUX_CTR1(thread_dtor, "thread(%d)", em->em_tid);
- free(em, M_TEMP);
+ free(em, M_LINUX);
}
void
diff --git a/sys/compat/linux/linux_emul.h b/sys/compat/linux/linux_emul.h
index 9b552ab9c720..6dfa31f6edf7 100644
--- a/sys/compat/linux/linux_emul.h
+++ b/sys/compat/linux/linux_emul.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2006 Roman Divacky
* All rights reserved.
@@ -25,18 +25,12 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUX_EMUL_H_
#define _LINUX_EMUL_H_
struct image_params;
-struct note_info_list;
-
-/* Linux core notes are labeled "CORE" */
-#define LINUX_ABI_VENDOR "CORE"
/*
* modeled after similar structure in NetBSD
@@ -54,15 +48,12 @@ struct linux_emuldata {
struct linux_emuldata *em_find(struct thread *);
-int linux_exec_imgact_try(struct image_params *);
void linux_proc_init(struct thread *, struct thread *, bool);
void linux_on_exit(struct proc *);
void linux_schedtail(struct thread *);
-void linux_on_exec(struct proc *, struct image_params *);
+int linux_on_exec(struct proc *, struct image_params *);
void linux_thread_dtor(struct thread *);
int linux_common_execve(struct thread *, struct image_args *);
-void linux32_prepare_notes(struct thread *, struct note_info_list *, size_t *);
-void linux64_prepare_notes(struct thread *, struct note_info_list *, size_t *);
/* process emuldata flags */
#define LINUX_XDEPR_REQUEUEOP 0x00000001 /* uses deprecated
diff --git a/sys/compat/linux/linux_errno.c b/sys/compat/linux/linux_errno.c
index 69880db86319..f04f694e5bec 100644
--- a/sys/compat/linux/linux_errno.c
+++ b/sys/compat/linux/linux_errno.c
@@ -1,11 +1,7 @@
-/* $FreeBSD$ */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
#include <sys/param.h>
-#include <sys/errno.h>
#include <sys/systm.h>
+#include <sys/errno.h>
#include <compat/linux/linux.h>
#include <compat/linux/linux_errno.h>
diff --git a/sys/compat/linux/linux_errno.h b/sys/compat/linux/linux_errno.h
index 0eae6684ce44..22c52272bae6 100644
--- a/sys/compat/linux/linux_errno.h
+++ b/sys/compat/linux/linux_errno.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 The FreeBSD Foundation
*
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUX_ERRNO_H_
diff --git a/sys/compat/linux/linux_errno.inc b/sys/compat/linux/linux_errno.inc
index 37d83962fe44..9e051db495d8 100644
--- a/sys/compat/linux/linux_errno.inc
+++ b/sys/compat/linux/linux_errno.inc
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1994-1996 Søren Schmidt
* All rights reserved.
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
diff --git a/sys/compat/linux/linux_event.c b/sys/compat/linux/linux_event.c
index 002987ed3c0e..e88791659f1f 100644
--- a/sys/compat/linux/linux_event.c
+++ b/sys/compat/linux/linux_event.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2007 Roman Divacky
* Copyright (c) 2014 Dmitry Chagin <dchagin@FreeBSD.org>
@@ -26,35 +26,27 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_compat.h"
-
#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/imgact.h>
-#include <sys/kernel.h>
-#include <sys/limits.h>
-#include <sys/lock.h>
-#include <sys/mutex.h>
#include <sys/callout.h>
#include <sys/capsicum.h>
-#include <sys/types.h>
-#include <sys/user.h>
+#include <sys/errno.h>
+#include <sys/event.h>
+#include <sys/eventfd.h>
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/filio.h>
-#include <sys/errno.h>
-#include <sys/event.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
#include <sys/poll.h>
#include <sys/proc.h>
#include <sys/selinfo.h>
#include <sys/specialfd.h>
#include <sys/sx.h>
#include <sys/syscallsubr.h>
+#include <sys/timerfd.h>
#include <sys/timespec.h>
-#include <sys/eventfd.h>
+#include <sys/user.h>
#ifdef COMPAT_LINUX32
#include <machine/../linux32/linux.h>
@@ -68,7 +60,7 @@ __FBSDID("$FreeBSD$");
#include <compat/linux/linux_event.h>
#include <compat/linux/linux_file.h>
#include <compat/linux/linux_signal.h>
-#include <compat/linux/linux_timer.h>
+#include <compat/linux/linux_time.h>
#include <compat/linux/linux_util.h>
typedef uint64_t epoll_udata_t;
@@ -108,55 +100,6 @@ struct epoll_copyout_args {
int error;
};
-/* timerfd */
-typedef uint64_t timerfd_t;
-
-static fo_rdwr_t timerfd_read;
-static fo_ioctl_t timerfd_ioctl;
-static fo_poll_t timerfd_poll;
-static fo_kqfilter_t timerfd_kqfilter;
-static fo_stat_t timerfd_stat;
-static fo_close_t timerfd_close;
-static fo_fill_kinfo_t timerfd_fill_kinfo;
-
-static struct fileops timerfdops = {
- .fo_read = timerfd_read,
- .fo_write = invfo_rdwr,
- .fo_truncate = invfo_truncate,
- .fo_ioctl = timerfd_ioctl,
- .fo_poll = timerfd_poll,
- .fo_kqfilter = timerfd_kqfilter,
- .fo_stat = timerfd_stat,
- .fo_close = timerfd_close,
- .fo_chmod = invfo_chmod,
- .fo_chown = invfo_chown,
- .fo_sendfile = invfo_sendfile,
- .fo_fill_kinfo = timerfd_fill_kinfo,
- .fo_flags = DFLAG_PASSABLE
-};
-
-static void filt_timerfddetach(struct knote *kn);
-static int filt_timerfdread(struct knote *kn, long hint);
-
-static struct filterops timerfd_rfiltops = {
- .f_isfd = 1,
- .f_detach = filt_timerfddetach,
- .f_event = filt_timerfdread
-};
-
-struct timerfd {
- clockid_t tfd_clockid;
- struct itimerspec tfd_time;
- struct callout tfd_callout;
- timerfd_t tfd_count;
- bool tfd_canceled;
- struct selinfo tfd_sel;
- struct mtx tfd_lock;
-};
-
-static void linux_timerfd_expire(void *);
-static void linux_timerfd_curval(struct timerfd *, struct itimerspec *);
-
static int
epoll_create_common(struct thread *td, int flags)
{
@@ -667,255 +610,19 @@ linux_eventfd2(struct thread *td, struct linux_eventfd2_args *args)
int
linux_timerfd_create(struct thread *td, struct linux_timerfd_create_args *args)
{
- struct timerfd *tfd;
- struct file *fp;
clockid_t clockid;
- int fflags, fd, error;
-
- if ((args->flags & ~LINUX_TFD_CREATE_FLAGS) != 0)
- return (EINVAL);
+ int error, flags;
error = linux_to_native_clockid(&clockid, args->clockid);
if (error != 0)
return (error);
- if (clockid != CLOCK_REALTIME && clockid != CLOCK_MONOTONIC)
- return (EINVAL);
-
- fflags = 0;
+ flags = 0;
if ((args->flags & LINUX_TFD_CLOEXEC) != 0)
- fflags |= O_CLOEXEC;
-
- error = falloc(td, &fp, &fd, fflags);
- if (error != 0)
- return (error);
-
- tfd = malloc(sizeof(*tfd), M_EPOLL, M_WAITOK | M_ZERO);
- tfd->tfd_clockid = clockid;
- mtx_init(&tfd->tfd_lock, "timerfd", NULL, MTX_DEF);
-
- callout_init_mtx(&tfd->tfd_callout, &tfd->tfd_lock, 0);
- knlist_init_mtx(&tfd->tfd_sel.si_note, &tfd->tfd_lock);
-
- fflags = FREAD;
- if ((args->flags & LINUX_O_NONBLOCK) != 0)
- fflags |= FNONBLOCK;
-
- finit(fp, fflags, DTYPE_LINUXTFD, tfd, &timerfdops);
- fdrop(fp, td);
-
- td->td_retval[0] = fd;
- return (error);
-}
-
-static int
-timerfd_close(struct file *fp, struct thread *td)
-{
- struct timerfd *tfd;
-
- tfd = fp->f_data;
- if (fp->f_type != DTYPE_LINUXTFD || tfd == NULL)
- return (EINVAL);
-
- timespecclear(&tfd->tfd_time.it_value);
- timespecclear(&tfd->tfd_time.it_interval);
-
- callout_drain(&tfd->tfd_callout);
-
- seldrain(&tfd->tfd_sel);
- knlist_destroy(&tfd->tfd_sel.si_note);
-
- fp->f_ops = &badfileops;
- mtx_destroy(&tfd->tfd_lock);
- free(tfd, M_EPOLL);
-
- return (0);
-}
-
-static int
-timerfd_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
- int flags, struct thread *td)
-{
- struct timerfd *tfd;
- timerfd_t count;
- int error;
-
- tfd = fp->f_data;
- if (fp->f_type != DTYPE_LINUXTFD || tfd == NULL)
- return (EINVAL);
-
- if (uio->uio_resid < sizeof(timerfd_t))
- return (EINVAL);
-
- error = 0;
- mtx_lock(&tfd->tfd_lock);
-retry:
- if (tfd->tfd_canceled) {
- tfd->tfd_count = 0;
- mtx_unlock(&tfd->tfd_lock);
- return (ECANCELED);
- }
- if (tfd->tfd_count == 0) {
- if ((fp->f_flag & FNONBLOCK) != 0) {
- mtx_unlock(&tfd->tfd_lock);
- return (EAGAIN);
- }
- error = mtx_sleep(&tfd->tfd_count, &tfd->tfd_lock, PCATCH, "ltfdrd", 0);
- if (error == 0)
- goto retry;
- }
- if (error == 0) {
- count = tfd->tfd_count;
- tfd->tfd_count = 0;
- mtx_unlock(&tfd->tfd_lock);
- error = uiomove(&count, sizeof(timerfd_t), uio);
- } else
- mtx_unlock(&tfd->tfd_lock);
-
- return (error);
-}
-
-static int
-timerfd_poll(struct file *fp, int events, struct ucred *active_cred,
- struct thread *td)
-{
- struct timerfd *tfd;
- int revents = 0;
-
- tfd = fp->f_data;
- if (fp->f_type != DTYPE_LINUXTFD || tfd == NULL)
- return (POLLERR);
-
- mtx_lock(&tfd->tfd_lock);
- if ((events & (POLLIN|POLLRDNORM)) && tfd->tfd_count > 0)
- revents |= events & (POLLIN|POLLRDNORM);
- if (revents == 0)
- selrecord(td, &tfd->tfd_sel);
- mtx_unlock(&tfd->tfd_lock);
-
- return (revents);
-}
-
-static int
-timerfd_kqfilter(struct file *fp, struct knote *kn)
-{
- struct timerfd *tfd;
-
- tfd = fp->f_data;
- if (fp->f_type != DTYPE_LINUXTFD || tfd == NULL)
- return (EINVAL);
-
- if (kn->kn_filter == EVFILT_READ)
- kn->kn_fop = &timerfd_rfiltops;
- else
- return (EINVAL);
-
- kn->kn_hook = tfd;
- knlist_add(&tfd->tfd_sel.si_note, kn, 0);
-
- return (0);
-}
-
-static void
-filt_timerfddetach(struct knote *kn)
-{
- struct timerfd *tfd = kn->kn_hook;
-
- mtx_lock(&tfd->tfd_lock);
- knlist_remove(&tfd->tfd_sel.si_note, kn, 1);
- mtx_unlock(&tfd->tfd_lock);
-}
-
-static int
-filt_timerfdread(struct knote *kn, long hint)
-{
- struct timerfd *tfd = kn->kn_hook;
-
- return (tfd->tfd_count > 0);
-}
-
-static int
-timerfd_ioctl(struct file *fp, u_long cmd, void *data,
- struct ucred *active_cred, struct thread *td)
-{
-
- if (fp->f_data == NULL || fp->f_type != DTYPE_LINUXTFD)
- return (EINVAL);
-
- switch (cmd) {
- case FIONBIO:
- case FIOASYNC:
- return (0);
- }
-
- return (ENOTTY);
-}
-
-static int
-timerfd_stat(struct file *fp, struct stat *st, struct ucred *active_cred)
-{
-
- return (ENXIO);
-}
-
-static int
-timerfd_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp)
-{
-
- kif->kf_type = KF_TYPE_UNKNOWN;
- return (0);
-}
-
-static void
-linux_timerfd_clocktime(struct timerfd *tfd, struct timespec *ts)
-{
-
- if (tfd->tfd_clockid == CLOCK_REALTIME)
- getnanotime(ts);
- else /* CLOCK_MONOTONIC */
- getnanouptime(ts);
-}
-
-static void
-linux_timerfd_curval(struct timerfd *tfd, struct itimerspec *ots)
-{
- struct timespec cts;
-
- linux_timerfd_clocktime(tfd, &cts);
- *ots = tfd->tfd_time;
- if (ots->it_value.tv_sec != 0 || ots->it_value.tv_nsec != 0) {
- timespecsub(&ots->it_value, &cts, &ots->it_value);
- if (ots->it_value.tv_sec < 0 ||
- (ots->it_value.tv_sec == 0 &&
- ots->it_value.tv_nsec == 0)) {
- ots->it_value.tv_sec = 0;
- ots->it_value.tv_nsec = 1;
- }
- }
-}
-
-static int
-linux_timerfd_gettime_common(struct thread *td, int fd, struct itimerspec *ots)
-{
- struct timerfd *tfd;
- struct file *fp;
- int error;
-
- error = fget(td, fd, &cap_read_rights, &fp);
- if (error != 0)
- return (error);
- tfd = fp->f_data;
- if (fp->f_type != DTYPE_LINUXTFD || tfd == NULL) {
- error = EINVAL;
- goto out;
- }
-
- mtx_lock(&tfd->tfd_lock);
- linux_timerfd_curval(tfd, ots);
- mtx_unlock(&tfd->tfd_lock);
+ flags |= O_CLOEXEC;
+ if ((args->flags & LINUX_TFD_NONBLOCK) != 0)
+ flags |= TFD_NONBLOCK;
-out:
- fdrop(fp, td);
- return (error);
+ return (kern_timerfd_create(td, clockid, flags));
}
int
@@ -925,84 +632,14 @@ linux_timerfd_gettime(struct thread *td, struct linux_timerfd_gettime_args *args
struct itimerspec ots;
int error;
- error = linux_timerfd_gettime_common(td, args->fd, &ots);
+ error = kern_timerfd_gettime(td, args->fd, &ots);
if (error != 0)
return (error);
- error = native_to_linux_itimerspec(&lots, &ots);
- if (error == 0)
- error = copyout(&lots, args->old_value, sizeof(lots));
- return (error);
-}
-#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
-int
-linux_timerfd_gettime64(struct thread *td, struct linux_timerfd_gettime64_args *args)
-{
- struct l_itimerspec64 lots;
- struct itimerspec ots;
- int error;
-
- error = linux_timerfd_gettime_common(td, args->fd, &ots);
- if (error != 0)
- return (error);
- error = native_to_linux_itimerspec64(&lots, &ots);
+ error = native_to_linux_itimerspec(&lots, &ots);
if (error == 0)
error = copyout(&lots, args->old_value, sizeof(lots));
- return (error);
-}
-#endif
-
-static int
-linux_timerfd_settime_common(struct thread *td, int fd, int flags,
- struct itimerspec *nts, struct itimerspec *oval)
-{
- struct timespec cts, ts;
- struct timerfd *tfd;
- struct timeval tv;
- struct file *fp;
- int error;
-
- if ((flags & ~LINUX_TFD_SETTIME_FLAGS) != 0)
- return (EINVAL);
- error = fget(td, fd, &cap_write_rights, &fp);
- if (error != 0)
- return (error);
- tfd = fp->f_data;
- if (fp->f_type != DTYPE_LINUXTFD || tfd == NULL) {
- error = EINVAL;
- goto out;
- }
-
- mtx_lock(&tfd->tfd_lock);
- if (!timespecisset(&nts->it_value))
- timespecclear(&nts->it_interval);
- if (oval != NULL)
- linux_timerfd_curval(tfd, oval);
-
- bcopy(nts, &tfd->tfd_time, sizeof(*nts));
- tfd->tfd_count = 0;
- if (timespecisset(&nts->it_value)) {
- linux_timerfd_clocktime(tfd, &cts);
- ts = nts->it_value;
- if ((flags & LINUX_TFD_TIMER_ABSTIME) == 0) {
- timespecadd(&tfd->tfd_time.it_value, &cts,
- &tfd->tfd_time.it_value);
- } else {
- timespecsub(&ts, &cts, &ts);
- }
- TIMESPEC_TO_TIMEVAL(&tv, &ts);
- callout_reset(&tfd->tfd_callout, tvtohz(&tv),
- linux_timerfd_expire, tfd);
- tfd->tfd_canceled = false;
- } else {
- tfd->tfd_canceled = true;
- callout_stop(&tfd->tfd_callout);
- }
- mtx_unlock(&tfd->tfd_lock);
-
-out:
- fdrop(fp, td);
return (error);
}
@@ -1010,7 +647,7 @@ int
linux_timerfd_settime(struct thread *td, struct linux_timerfd_settime_args *args)
{
struct l_itimerspec lots;
- struct itimerspec nts, ots, *pots;
+ struct itimerspec nts, ots;
int error;
error = copyin(args->new_value, &lots, sizeof(lots));
@@ -1019,23 +656,43 @@ linux_timerfd_settime(struct thread *td, struct linux_timerfd_settime_args *args
error = linux_to_native_itimerspec(&nts, &lots);
if (error != 0)
return (error);
- pots = (args->old_value != NULL ? &ots : NULL);
- error = linux_timerfd_settime_common(td, args->fd, args->flags,
- &nts, pots);
+ if (args->old_value == NULL)
+ error = kern_timerfd_settime(td, args->fd, args->flags, &nts, NULL);
+ else
+ error = kern_timerfd_settime(td, args->fd, args->flags, &nts, &ots);
if (error == 0 && args->old_value != NULL) {
error = native_to_linux_itimerspec(&lots, &ots);
if (error == 0)
error = copyout(&lots, args->old_value, sizeof(lots));
}
+
return (error);
}
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
int
+linux_timerfd_gettime64(struct thread *td, struct linux_timerfd_gettime64_args *args)
+{
+ struct l_itimerspec64 lots;
+ struct itimerspec ots;
+ int error;
+
+ error = kern_timerfd_gettime(td, args->fd, &ots);
+ if (error != 0)
+ return (error);
+
+ error = native_to_linux_itimerspec64(&lots, &ots);
+ if (error == 0)
+ error = copyout(&lots, args->old_value, sizeof(lots));
+
+ return (error);
+}
+
+int
linux_timerfd_settime64(struct thread *td, struct linux_timerfd_settime64_args *args)
{
struct l_itimerspec64 lots;
- struct itimerspec nts, ots, *pots;
+ struct itimerspec nts, ots;
int error;
error = copyin(args->new_value, &lots, sizeof(lots));
@@ -1044,50 +701,16 @@ linux_timerfd_settime64(struct thread *td, struct linux_timerfd_settime64_args *
error = linux_to_native_itimerspec64(&nts, &lots);
if (error != 0)
return (error);
- pots = (args->old_value != NULL ? &ots : NULL);
- error = linux_timerfd_settime_common(td, args->fd, args->flags,
- &nts, pots);
+ if (args->old_value == NULL)
+ error = kern_timerfd_settime(td, args->fd, args->flags, &nts, NULL);
+ else
+ error = kern_timerfd_settime(td, args->fd, args->flags, &nts, &ots);
if (error == 0 && args->old_value != NULL) {
error = native_to_linux_itimerspec64(&lots, &ots);
if (error == 0)
error = copyout(&lots, args->old_value, sizeof(lots));
}
+
return (error);
}
#endif
-
-static void
-linux_timerfd_expire(void *arg)
-{
- struct timespec cts, ts;
- struct timeval tv;
- struct timerfd *tfd;
-
- tfd = (struct timerfd *)arg;
-
- linux_timerfd_clocktime(tfd, &cts);
- if (timespeccmp(&cts, &tfd->tfd_time.it_value, >=)) {
- if (timespecisset(&tfd->tfd_time.it_interval))
- timespecadd(&tfd->tfd_time.it_value,
- &tfd->tfd_time.it_interval,
- &tfd->tfd_time.it_value);
- else
- /* single shot timer */
- timespecclear(&tfd->tfd_time.it_value);
- if (timespecisset(&tfd->tfd_time.it_value)) {
- timespecsub(&tfd->tfd_time.it_value, &cts, &ts);
- TIMESPEC_TO_TIMEVAL(&tv, &ts);
- callout_reset(&tfd->tfd_callout, tvtohz(&tv),
- linux_timerfd_expire, tfd);
- }
- tfd->tfd_count++;
- KNOTE_LOCKED(&tfd->tfd_sel.si_note, 0);
- selwakeup(&tfd->tfd_sel);
- wakeup(&tfd->tfd_count);
- } else if (timespecisset(&tfd->tfd_time.it_value)) {
- timespecsub(&tfd->tfd_time.it_value, &cts, &ts);
- TIMESPEC_TO_TIMEVAL(&tv, &ts);
- callout_reset(&tfd->tfd_callout, tvtohz(&tv),
- linux_timerfd_expire, tfd);
- }
-}
diff --git a/sys/compat/linux/linux_event.h b/sys/compat/linux/linux_event.h
index 445564da4150..8c6758fefcc9 100644
--- a/sys/compat/linux/linux_event.h
+++ b/sys/compat/linux/linux_event.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUX_EVENT_H_
@@ -56,15 +54,7 @@
#define LINUX_EFD_SEMAPHORE (1 << 0)
-#define LINUX_TFD_TIMER_ABSTIME (1 << 0)
-#define LINUX_TFD_TIMER_CANCEL_ON_SET (1 << 1)
#define LINUX_TFD_CLOEXEC LINUX_O_CLOEXEC
#define LINUX_TFD_NONBLOCK LINUX_O_NONBLOCK
-#define LINUX_TFD_SHARED_FCNTL_FLAGS (LINUX_TFD_CLOEXEC \
- |LINUX_TFD_NONBLOCK)
-#define LINUX_TFD_CREATE_FLAGS LINUX_TFD_SHARED_FCNTL_FLAGS
-#define LINUX_TFD_SETTIME_FLAGS (LINUX_TFD_TIMER_ABSTIME \
- |LINUX_TFD_TIMER_CANCEL_ON_SET)
-
#endif /* !_LINUX_EVENT_H_ */
diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c
index 3b712cf71e60..1279490ae8be 100644
--- a/sys/compat/linux/linux_file.c
+++ b/sys/compat/linux/linux_file.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1994-1995 Søren Schmidt
* All rights reserved.
@@ -26,25 +26,14 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_compat.h"
-
#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/capsicum.h>
-#include <sys/conf.h>
#include <sys/dirent.h>
#include <sys/fcntl.h>
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/lock.h>
-#include <sys/malloc.h>
#include <sys/mman.h>
-#include <sys/mount.h>
-#include <sys/mutex.h>
-#include <sys/namei.h>
#include <sys/selinfo.h>
#include <sys/pipe.h>
#include <sys/proc.h>
@@ -58,6 +47,7 @@ __FBSDID("$FreeBSD$");
#ifdef COMPAT_LINUX32
#include <compat/freebsd32/freebsd32_misc.h>
+#include <compat/freebsd32/freebsd32_util.h>
#include <machine/../linux32/linux.h>
#include <machine/../linux32/linux32_proto.h>
#else
@@ -108,18 +98,9 @@ static struct bsd_to_linux_bitmap mfd_bitmap[] = {
int
linux_creat(struct thread *td, struct linux_creat_args *args)
{
- char *path;
- int error;
- if (!LUSECONVPATH(td)) {
- return (kern_openat(td, AT_FDCWD, args->path, UIO_USERSPACE,
- O_WRONLY | O_CREAT | O_TRUNC, args->mode));
- }
- LCONVPATHEXIST(args->path, &path);
- error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE,
- O_WRONLY | O_CREAT | O_TRUNC, args->mode);
- LFREEPATH(path);
- return (error);
+ return (kern_openat(td, AT_FDCWD, args->path, UIO_USERSPACE,
+ O_WRONLY | O_CREAT | O_TRUNC, args->mode));
}
#endif
@@ -225,45 +206,20 @@ done:
int
linux_openat(struct thread *td, struct linux_openat_args *args)
{
- char *path;
- int dfd, error;
+ int dfd;
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
- if (!LUSECONVPATH(td)) {
- return (linux_common_open(td, dfd, args->filename, args->flags,
- args->mode, UIO_USERSPACE));
- }
- if (args->flags & LINUX_O_CREAT)
- LCONVPATH_AT(args->filename, &path, 1, dfd);
- else
- LCONVPATH_AT(args->filename, &path, 0, dfd);
-
- error = linux_common_open(td, dfd, path, args->flags, args->mode,
- UIO_SYSSPACE);
- LFREEPATH(path);
- return (error);
+ return (linux_common_open(td, dfd, args->filename, args->flags,
+ args->mode, UIO_USERSPACE));
}
#ifdef LINUX_LEGACY_SYSCALLS
int
linux_open(struct thread *td, struct linux_open_args *args)
{
- char *path;
- int error;
-
- if (!LUSECONVPATH(td)) {
- return (linux_common_open(td, AT_FDCWD, args->path, args->flags,
- args->mode, UIO_USERSPACE));
- }
- if (args->flags & LINUX_O_CREAT)
- LCONVPATHCREAT(args->path, &path);
- else
- LCONVPATHEXIST(args->path, &path);
- error = linux_common_open(td, AT_FDCWD, path, args->flags, args->mode,
- UIO_SYSSPACE);
- LFREEPATH(path);
- return (error);
+ return (linux_common_open(td, AT_FDCWD, args->path, args->flags,
+ args->mode, UIO_USERSPACE));
}
#endif
@@ -293,17 +249,8 @@ linux_name_to_handle_at(struct thread *td,
if ((args->flags & LINUX_AT_EMPTY_PATH) != 0)
bsd_flags |= AT_EMPTY_PATH;
- if (!LUSECONVPATH(td)) {
- error = kern_getfhat(td, bsd_flags, fd, args->name,
- UIO_USERSPACE, &fh, UIO_SYSSPACE);
- } else {
- char *path;
-
- LCONVPATH_AT(args->name, &path, 0, fd);
- error = kern_getfhat(td, bsd_flags, fd, path, UIO_SYSSPACE,
- &fh, UIO_SYSSPACE);
- LFREEPATH(path);
- }
+ error = kern_getfhat(td, bsd_flags, fd, args->name,
+ UIO_USERSPACE, &fh, UIO_SYSSPACE);
if (error != 0)
return (error);
@@ -465,7 +412,7 @@ linux_getdents(struct thread *td, struct linux_getdents_args *args)
size_t retval;
buflen = min(args->count, MAXBSIZE);
- buf = malloc(buflen, M_TEMP, M_WAITOK);
+ buf = malloc(buflen, M_LINUX, M_WAITOK);
error = kern_getdirentries(td, args->fd, buf, buflen,
&base, NULL, UIO_SYSSPACE);
@@ -474,7 +421,7 @@ linux_getdents(struct thread *td, struct linux_getdents_args *args)
goto out1;
}
- lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO);
+ lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_LINUX, M_WAITOK | M_ZERO);
len = td->td_retval[0];
inp = buf;
@@ -520,9 +467,9 @@ linux_getdents(struct thread *td, struct linux_getdents_args *args)
td->td_retval[0] = retval;
out:
- free(lbuf, M_TEMP);
+ free(lbuf, M_LINUX);
out1:
- free(buf, M_TEMP);
+ free(buf, M_LINUX);
return (error);
}
#endif
@@ -535,14 +482,13 @@ linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
int len, reclen; /* BSD-format */
caddr_t outp; /* Linux-format */
int resid, linuxreclen; /* Linux-format */
- caddr_t lbuf; /* Linux-format */
off_t base;
struct l_dirent64 *linux_dirent64;
int buflen, error;
size_t retval;
buflen = min(args->count, MAXBSIZE);
- buf = malloc(buflen, M_TEMP, M_WAITOK);
+ buf = malloc(buflen, M_LINUX, M_WAITOK);
error = kern_getdirentries(td, args->fd, buf, buflen,
&base, NULL, UIO_SYSSPACE);
@@ -551,7 +497,8 @@ linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
goto out1;
}
- lbuf = malloc(LINUX_RECLEN64(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO);
+ linux_dirent64 = malloc(LINUX_RECLEN64(LINUX_NAME_MAX), M_LINUX,
+ M_WAITOK | M_ZERO);
len = td->td_retval[0];
inp = buf;
@@ -572,7 +519,6 @@ linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
goto out;
}
- linux_dirent64 = (struct l_dirent64*)lbuf;
linux_dirent64->d_ino = bdp->d_fileno;
linux_dirent64->d_off = bdp->d_off;
linux_dirent64->d_reclen = linuxreclen;
@@ -594,9 +540,9 @@ linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
td->td_retval[0] = retval;
out:
- free(lbuf, M_TEMP);
+ free(linux_dirent64, M_LINUX);
out1:
- free(buf, M_TEMP);
+ free(buf, M_LINUX);
return (error);
}
@@ -607,13 +553,12 @@ linux_readdir(struct thread *td, struct linux_readdir_args *args)
struct dirent *bdp;
caddr_t buf; /* BSD-format */
int linuxreclen; /* Linux-format */
- caddr_t lbuf; /* Linux-format */
off_t base;
- struct l_dirent *linux_dirent;
+ struct l_dirent *linux_dirent; /* Linux-format */
int buflen, error;
- buflen = LINUX_RECLEN(LINUX_NAME_MAX);
- buf = malloc(buflen, M_TEMP, M_WAITOK);
+ buflen = sizeof(*bdp);
+ buf = malloc(buflen, M_LINUX, M_WAITOK);
error = kern_getdirentries(td, args->fd, buf, buflen,
&base, NULL, UIO_SYSSPACE);
@@ -624,12 +569,12 @@ linux_readdir(struct thread *td, struct linux_readdir_args *args)
if (td->td_retval[0] == 0)
goto out;
- lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_TEMP, M_WAITOK | M_ZERO);
+ linux_dirent = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_LINUX,
+ M_WAITOK | M_ZERO);
bdp = (struct dirent *) buf;
linuxreclen = LINUX_RECLEN(bdp->d_namlen);
- linux_dirent = (struct l_dirent*)lbuf;
linux_dirent->d_ino = bdp->d_fileno;
linux_dirent->d_off = bdp->d_off;
linux_dirent->d_reclen = bdp->d_namlen;
@@ -639,9 +584,9 @@ linux_readdir(struct thread *td, struct linux_readdir_args *args)
if (error == 0)
td->td_retval[0] = linuxreclen;
- free(lbuf, M_TEMP);
+ free(linux_dirent, M_LINUX);
out:
- free(buf, M_TEMP);
+ free(buf, M_LINUX);
return (error);
}
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
@@ -654,24 +599,13 @@ out:
int
linux_access(struct thread *td, struct linux_access_args *args)
{
- char *path;
- int error;
/* Linux convention. */
if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
return (EINVAL);
- if (!LUSECONVPATH(td)) {
- error = kern_accessat(td, AT_FDCWD, args->path, UIO_USERSPACE, 0,
- args->amode);
- } else {
- LCONVPATHEXIST(args->path, &path);
- error = kern_accessat(td, AT_FDCWD, path, UIO_SYSSPACE, 0,
- args->amode);
- LFREEPATH(path);
- }
-
- return (error);
+ return (kern_accessat(td, AT_FDCWD, args->path, UIO_USERSPACE, 0,
+ args->amode));
}
#endif
@@ -679,23 +613,14 @@ static int
linux_do_accessat(struct thread *td, int ldfd, const char *filename,
int amode, int flags)
{
- char *path;
- int error, dfd;
+ int dfd;
/* Linux convention. */
if (amode & ~(F_OK | X_OK | W_OK | R_OK))
return (EINVAL);
dfd = (ldfd == LINUX_AT_FDCWD) ? AT_FDCWD : ldfd;
- if (!LUSECONVPATH(td)) {
- error = kern_accessat(td, dfd, filename, UIO_USERSPACE, flags, amode);
- } else {
- LCONVPATHEXIST_AT(filename, &path, dfd);
- error = kern_accessat(td, dfd, path, UIO_SYSSPACE, flags, amode);
- LFREEPATH(path);
- }
-
- return (error);
+ return (kern_accessat(td, dfd, filename, UIO_USERSPACE, flags, amode));
}
int
@@ -731,33 +656,18 @@ linux_faccessat2(struct thread *td, struct linux_faccessat2_args *args)
int
linux_unlink(struct thread *td, struct linux_unlink_args *args)
{
- char *path;
int error;
struct stat st;
- if (!LUSECONVPATH(td)) {
- error = kern_funlinkat(td, AT_FDCWD, args->path, FD_NONE,
- UIO_USERSPACE, 0, 0);
- if (error == EPERM) {
- /* Introduce POSIX noncompliant behaviour of Linux */
- if (kern_statat(td, 0, AT_FDCWD, args->path,
- UIO_USERSPACE, &st, NULL) == 0) {
- if (S_ISDIR(st.st_mode))
- error = EISDIR;
- }
- }
- } else {
- LCONVPATHEXIST(args->path, &path);
- error = kern_funlinkat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0, 0);
- if (error == EPERM) {
- /* Introduce POSIX noncompliant behaviour of Linux */
- if (kern_statat(td, 0, AT_FDCWD, path, UIO_SYSSPACE, &st,
- NULL) == 0) {
- if (S_ISDIR(st.st_mode))
- error = EISDIR;
- }
+ error = kern_funlinkat(td, AT_FDCWD, args->path, FD_NONE,
+ UIO_USERSPACE, 0, 0);
+ if (error == EPERM) {
+ /* Introduce POSIX noncompliant behaviour of Linux */
+ if (kern_statat(td, 0, AT_FDCWD, args->path,
+ UIO_USERSPACE, &st) == 0) {
+ if (S_ISDIR(st.st_mode))
+ error = EISDIR;
}
- LFREEPATH(path);
}
return (error);
@@ -778,7 +688,7 @@ linux_unlinkat_impl(struct thread *td, enum uio_seg pathseg, const char *path,
if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) {
/* Introduce POSIX noncompliant behaviour of Linux */
if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path,
- pathseg, &st, NULL) == 0 && S_ISDIR(st.st_mode))
+ pathseg, &st) == 0 && S_ISDIR(st.st_mode))
error = EISDIR;
}
return (error);
@@ -787,142 +697,75 @@ linux_unlinkat_impl(struct thread *td, enum uio_seg pathseg, const char *path,
int
linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
{
- char *path;
- int error, dfd;
+ int dfd;
if (args->flag & ~LINUX_AT_REMOVEDIR)
return (EINVAL);
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
- if (!LUSECONVPATH(td)) {
- return (linux_unlinkat_impl(td, UIO_USERSPACE, args->pathname,
- dfd, args));
- }
- LCONVPATHEXIST_AT(args->pathname, &path, dfd);
- error = linux_unlinkat_impl(td, UIO_SYSSPACE, path, dfd, args);
- LFREEPATH(path);
- return (error);
+ return (linux_unlinkat_impl(td, UIO_USERSPACE, args->pathname,
+ dfd, args));
}
+
int
linux_chdir(struct thread *td, struct linux_chdir_args *args)
{
- char *path;
- int error;
- if (!LUSECONVPATH(td)) {
- return (kern_chdir(td, args->path, UIO_USERSPACE));
- }
- LCONVPATHEXIST(args->path, &path);
- error = kern_chdir(td, path, UIO_SYSSPACE);
- LFREEPATH(path);
- return (error);
+ return (kern_chdir(td, args->path, UIO_USERSPACE));
}
#ifdef LINUX_LEGACY_SYSCALLS
int
linux_chmod(struct thread *td, struct linux_chmod_args *args)
{
- char *path;
- int error;
- if (!LUSECONVPATH(td)) {
- return (kern_fchmodat(td, AT_FDCWD, args->path, UIO_USERSPACE,
- args->mode, 0));
- }
- LCONVPATHEXIST(args->path, &path);
- error = kern_fchmodat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode, 0);
- LFREEPATH(path);
- return (error);
+ return (kern_fchmodat(td, AT_FDCWD, args->path, UIO_USERSPACE,
+ args->mode, 0));
}
#endif
int
linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args)
{
- char *path;
- int error, dfd;
+ int dfd;
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
- if (!LUSECONVPATH(td)) {
- return (kern_fchmodat(td, dfd, args->filename, UIO_USERSPACE,
- args->mode, 0));
- }
- LCONVPATHEXIST_AT(args->filename, &path, dfd);
- error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0);
- LFREEPATH(path);
- return (error);
+ return (kern_fchmodat(td, dfd, args->filename, UIO_USERSPACE,
+ args->mode, 0));
}
#ifdef LINUX_LEGACY_SYSCALLS
int
linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
{
- char *path;
- int error;
- if (!LUSECONVPATH(td)) {
- return (kern_mkdirat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->mode));
- }
- LCONVPATHCREAT(args->path, &path);
- error = kern_mkdirat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode);
- LFREEPATH(path);
- return (error);
+ return (kern_mkdirat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->mode));
}
#endif
int
linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args)
{
- char *path;
- int error, dfd;
+ int dfd;
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
- if (!LUSECONVPATH(td)) {
- return (kern_mkdirat(td, dfd, args->pathname, UIO_USERSPACE, args->mode));
- }
- LCONVPATHCREAT_AT(args->pathname, &path, dfd);
- error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode);
- LFREEPATH(path);
- return (error);
+ return (kern_mkdirat(td, dfd, args->pathname, UIO_USERSPACE, args->mode));
}
#ifdef LINUX_LEGACY_SYSCALLS
int
linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
{
- char *path;
- int error;
- if (!LUSECONVPATH(td)) {
- return (kern_frmdirat(td, AT_FDCWD, args->path, FD_NONE,
- UIO_USERSPACE, 0));
- }
- LCONVPATHEXIST(args->path, &path);
- error = kern_frmdirat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0);
- LFREEPATH(path);
- return (error);
+ return (kern_frmdirat(td, AT_FDCWD, args->path, FD_NONE,
+ UIO_USERSPACE, 0));
}
int
linux_rename(struct thread *td, struct linux_rename_args *args)
{
- char *from, *to;
- int error;
- if (!LUSECONVPATH(td)) {
- return (kern_renameat(td, AT_FDCWD, args->from, AT_FDCWD,
- args->to, UIO_USERSPACE));
- }
- LCONVPATHEXIST(args->from, &from);
- /* Expand LCONVPATHCREATE so that `from' can be freed on errors */
- error = linux_emul_convpath(args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
- if (to == NULL) {
- LFREEPATH(from);
- return (error);
- }
- error = kern_renameat(td, AT_FDCWD, from, AT_FDCWD, to, UIO_SYSSPACE);
- LFREEPATH(from);
- LFREEPATH(to);
- return (error);
+ return (kern_renameat(td, AT_FDCWD, args->from, AT_FDCWD,
+ args->to, UIO_USERSPACE));
}
#endif
@@ -943,8 +786,7 @@ linux_renameat(struct thread *td, struct linux_renameat_args *args)
int
linux_renameat2(struct thread *td, struct linux_renameat2_args *args)
{
- char *from, *to;
- int error, olddfd, newdfd;
+ int olddfd, newdfd;
if (args->flags != 0) {
if (args->flags & ~(LINUX_RENAME_EXCHANGE |
@@ -969,137 +811,68 @@ linux_renameat2(struct thread *td, struct linux_renameat2_args *args)
olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
- if (!LUSECONVPATH(td)) {
- return (kern_renameat(td, olddfd, args->oldname, newdfd,
- args->newname, UIO_USERSPACE));
- }
- LCONVPATHEXIST_AT(args->oldname, &from, olddfd);
- /* Expand LCONVPATHCREATE so that `from' can be freed on errors */
- error = linux_emul_convpath(args->newname, UIO_USERSPACE, &to, 1, newdfd);
- if (to == NULL) {
- LFREEPATH(from);
- return (error);
- }
- error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE);
- LFREEPATH(from);
- LFREEPATH(to);
- return (error);
+ return (kern_renameat(td, olddfd, args->oldname, newdfd,
+ args->newname, UIO_USERSPACE));
}
#ifdef LINUX_LEGACY_SYSCALLS
int
linux_symlink(struct thread *td, struct linux_symlink_args *args)
{
- char *path, *to;
- int error;
- if (!LUSECONVPATH(td)) {
- return (kern_symlinkat(td, args->path, AT_FDCWD, args->to,
- UIO_USERSPACE));
- }
- LCONVPATHEXIST(args->path, &path);
- /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
- error = linux_emul_convpath(args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
- if (to == NULL) {
- LFREEPATH(path);
- return (error);
- }
- error = kern_symlinkat(td, path, AT_FDCWD, to, UIO_SYSSPACE);
- LFREEPATH(path);
- LFREEPATH(to);
- return (error);
+ return (kern_symlinkat(td, args->path, AT_FDCWD, args->to,
+ UIO_USERSPACE));
}
#endif
int
linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
{
- char *path, *to;
- int error, dfd;
+ int dfd;
dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
- if (!LUSECONVPATH(td)) {
- return (kern_symlinkat(td, args->oldname, dfd, args->newname,
- UIO_USERSPACE));
- }
- LCONVPATHEXIST(args->oldname, &path);
- /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
- error = linux_emul_convpath(args->newname, UIO_USERSPACE, &to, 1, dfd);
- if (to == NULL) {
- LFREEPATH(path);
- return (error);
- }
- error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE);
- LFREEPATH(path);
- LFREEPATH(to);
- return (error);
+ return (kern_symlinkat(td, args->oldname, dfd, args->newname,
+ UIO_USERSPACE));
}
#ifdef LINUX_LEGACY_SYSCALLS
int
linux_readlink(struct thread *td, struct linux_readlink_args *args)
{
- char *name;
- int error;
if (args->count <= 0)
return (EINVAL);
- if (!LUSECONVPATH(td)) {
- return (kern_readlinkat(td, AT_FDCWD, args->name, UIO_USERSPACE,
- args->buf, UIO_USERSPACE, args->count));
- }
- LCONVPATHEXIST(args->name, &name);
- error = kern_readlinkat(td, AT_FDCWD, name, UIO_SYSSPACE,
- args->buf, UIO_USERSPACE, args->count);
- LFREEPATH(name);
- return (error);
+ return (kern_readlinkat(td, AT_FDCWD, args->name, UIO_USERSPACE,
+ args->buf, UIO_USERSPACE, args->count));
}
#endif
int
linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
{
- char *name;
- int error, dfd;
+ int dfd;
if (args->bufsiz <= 0)
return (EINVAL);
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
- if (!LUSECONVPATH(td)) {
- return (kern_readlinkat(td, dfd, args->path, UIO_USERSPACE,
- args->buf, UIO_USERSPACE, args->bufsiz));
- }
- LCONVPATHEXIST_AT(args->path, &name, dfd);
- error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf,
- UIO_USERSPACE, args->bufsiz);
- LFREEPATH(name);
- return (error);
+ return (kern_readlinkat(td, dfd, args->path, UIO_USERSPACE,
+ args->buf, UIO_USERSPACE, args->bufsiz));
}
int
linux_truncate(struct thread *td, struct linux_truncate_args *args)
{
- char *path;
- int error;
- if (!LUSECONVPATH(td)) {
- return (kern_truncate(td, args->path, UIO_USERSPACE, args->length));
- }
- LCONVPATHEXIST(args->path, &path);
- error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
- LFREEPATH(path);
- return (error);
+ return (kern_truncate(td, args->path, UIO_USERSPACE, args->length));
}
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
int
linux_truncate64(struct thread *td, struct linux_truncate64_args *args)
{
- char *path;
off_t length;
- int error;
#if defined(__amd64__) && defined(COMPAT_LINUX32)
length = PAIR32TO64(off_t, args->length);
@@ -1107,13 +880,7 @@ linux_truncate64(struct thread *td, struct linux_truncate64_args *args)
length = args->length;
#endif
- if (!LUSECONVPATH(td)) {
- return (kern_truncate(td, args->path, UIO_USERSPACE, length));
- }
- LCONVPATHEXIST(args->path, &path);
- error = kern_truncate(td, path, UIO_SYSSPACE, length);
- LFREEPATH(path);
- return (error);
+ return (kern_truncate(td, args->path, UIO_USERSPACE, length));
}
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
@@ -1144,33 +911,16 @@ linux_ftruncate64(struct thread *td, struct linux_ftruncate64_args *args)
int
linux_link(struct thread *td, struct linux_link_args *args)
{
- char *path, *to;
- int error;
- if (!LUSECONVPATH(td)) {
- return (kern_linkat(td, AT_FDCWD, AT_FDCWD, args->path, args->to,
- UIO_USERSPACE, AT_SYMLINK_FOLLOW));
- }
- LCONVPATHEXIST(args->path, &path);
- /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
- error = linux_emul_convpath(args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
- if (to == NULL) {
- LFREEPATH(path);
- return (error);
- }
- error = kern_linkat(td, AT_FDCWD, AT_FDCWD, path, to, UIO_SYSSPACE,
- AT_SYMLINK_FOLLOW);
- LFREEPATH(path);
- LFREEPATH(to);
- return (error);
+ return (kern_linkat(td, AT_FDCWD, AT_FDCWD, args->path, args->to,
+ UIO_USERSPACE, AT_SYMLINK_FOLLOW));
}
#endif
int
linux_linkat(struct thread *td, struct linux_linkat_args *args)
{
- char *path, *to;
- int error, olddfd, newdfd, flag;
+ int olddfd, newdfd, flag;
if (args->flag & ~(LINUX_AT_SYMLINK_FOLLOW | LINUX_AT_EMPTY_PATH))
return (EINVAL);
@@ -1181,21 +931,8 @@ linux_linkat(struct thread *td, struct linux_linkat_args *args)
olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
- if (!LUSECONVPATH(td)) {
- return (kern_linkat(td, olddfd, newdfd, args->oldname,
- args->newname, UIO_USERSPACE, flag));
- }
- LCONVPATHEXIST_AT(args->oldname, &path, olddfd);
- /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
- error = linux_emul_convpath(args->newname, UIO_USERSPACE, &to, 1, newdfd);
- if (to == NULL) {
- LFREEPATH(path);
- return (error);
- }
- error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, flag);
- LFREEPATH(path);
- LFREEPATH(to);
- return (error);
+ return (kern_linkat(td, olddfd, newdfd, args->oldname,
+ args->newname, UIO_USERSPACE, flag));
}
int
@@ -1265,7 +1002,8 @@ linux_pwrite(struct thread *td, struct linux_pwrite_args *uap)
offset = uap->offset;
#endif
- return (kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, offset));
+ return (linux_enobufs2eagain(td, uap->fd,
+ kern_pwrite(td, uap->fd, uap->buf, uap->nbyte, offset)));
}
#define HALF_LONG_BITS ((sizeof(l_long) * NBBY / 2))
@@ -1293,14 +1031,14 @@ linux_preadv(struct thread *td, struct linux_preadv_args *uap)
if (offset < 0)
return (EINVAL);
#ifdef COMPAT_LINUX32
- error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
+ error = freebsd32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
#else
error = copyinuio(uap->vec, uap->vlen, &auio);
#endif
if (error != 0)
return (error);
error = kern_preadv(td, uap->fd, auio, offset);
- free(auio, M_IOV);
+ freeuio(auio);
return (error);
}
@@ -1320,15 +1058,15 @@ linux_pwritev(struct thread *td, struct linux_pwritev_args *uap)
if (offset < 0)
return (EINVAL);
#ifdef COMPAT_LINUX32
- error = linux32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
+ error = freebsd32_copyinuio(PTRIN(uap->vec), uap->vlen, &auio);
#else
error = copyinuio(uap->vec, uap->vlen, &auio);
#endif
if (error != 0)
return (error);
error = kern_pwritev(td, uap->fd, auio, offset);
- free(auio, M_IOV);
- return (error);
+ freeuio(auio);
+ return (linux_enobufs2eagain(td, uap->fd, error));
}
int
@@ -1781,26 +1519,16 @@ linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
int
linux_chown(struct thread *td, struct linux_chown_args *args)
{
- char *path;
- int error;
- if (!LUSECONVPATH(td)) {
- return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE,
- args->uid, args->gid, 0));
- }
- LCONVPATHEXIST(args->path, &path);
- error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid,
- args->gid, 0);
- LFREEPATH(path);
- return (error);
+ return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE,
+ args->uid, args->gid, 0));
}
#endif
int
linux_fchownat(struct thread *td, struct linux_fchownat_args *args)
{
- char *path;
- int error, dfd, flag, unsupported;
+ int dfd, flag, unsupported;
unsupported = args->flag & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH);
if (unsupported != 0) {
@@ -1814,33 +1542,17 @@ linux_fchownat(struct thread *td, struct linux_fchownat_args *args)
AT_EMPTY_PATH;
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
- if (!LUSECONVPATH(td)) {
- return (kern_fchownat(td, dfd, args->filename, UIO_USERSPACE,
- args->uid, args->gid, flag));
- }
- LCONVPATHEXIST_AT(args->filename, &path, dfd);
- error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid,
- flag);
- LFREEPATH(path);
- return (error);
+ return (kern_fchownat(td, dfd, args->filename, UIO_USERSPACE,
+ args->uid, args->gid, flag));
}
#ifdef LINUX_LEGACY_SYSCALLS
int
linux_lchown(struct thread *td, struct linux_lchown_args *args)
{
- char *path;
- int error;
- if (!LUSECONVPATH(td)) {
- return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->uid,
- args->gid, AT_SYMLINK_NOFOLLOW));
- }
- LCONVPATHEXIST(args->path, &path);
- error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid, args->gid,
- AT_SYMLINK_NOFOLLOW);
- LFREEPATH(path);
- return (error);
+ return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->uid,
+ args->gid, AT_SYMLINK_NOFOLLOW));
}
#endif
@@ -2092,3 +1804,74 @@ linux_splice(struct thread *td, struct linux_splice_args *args)
*/
return (EINVAL);
}
+
+int
+linux_close_range(struct thread *td, struct linux_close_range_args *args)
+{
+ u_int flags = 0;
+
+ /*
+ * Implementing close_range(CLOSE_RANGE_UNSHARE) allows Linux to
+ * unshare filedesc table of the calling thread from others threads
+ * in a thread group (i.e., process in the FreeBSD) or others processes,
+ * which shares the same table, before closing the files. FreeBSD does
+ * not have compatible unsharing mechanism due to the fact that sharing
+ * process resources, including filedesc table, is at thread level in the
+ * Linux, while in the FreeBSD it is at the process level.
+ * Return EINVAL for now if the CLOSE_RANGE_UNSHARE flag is specified
+ * until this new Linux API stabilizes.
+ */
+
+ if ((args->flags & ~(LINUX_CLOSE_RANGE_CLOEXEC)) != 0)
+ return (EINVAL);
+ if (args->first > args->last)
+ return (EINVAL);
+ if ((args->flags & LINUX_CLOSE_RANGE_CLOEXEC) != 0)
+ flags |= CLOSE_RANGE_CLOEXEC;
+ return (kern_close_range(td, flags, args->first, args->last));
+}
+
+int
+linux_enobufs2eagain(struct thread *td, int fd, int error)
+{
+ struct file *fp;
+
+ if (error != ENOBUFS)
+ return (error);
+ if (fget(td, fd, &cap_no_rights, &fp) != 0)
+ return (error);
+ if (fp->f_type == DTYPE_SOCKET && (fp->f_flag & FNONBLOCK) != 0)
+ error = EAGAIN;
+ fdrop(fp, td);
+ return (error);
+}
+
+int
+linux_write(struct thread *td, struct linux_write_args *args)
+{
+ struct write_args bargs = {
+ .fd = args->fd,
+ .buf = args->buf,
+ .nbyte = args->nbyte,
+ };
+
+ return (linux_enobufs2eagain(td, args->fd, sys_write(td, &bargs)));
+}
+
+int
+linux_writev(struct thread *td, struct linux_writev_args *args)
+{
+ struct uio *auio;
+ int error;
+
+#ifdef COMPAT_LINUX32
+ error = freebsd32_copyinuio(PTRIN(args->iovp), args->iovcnt, &auio);
+#else
+ error = copyinuio(args->iovp, args->iovcnt, &auio);
+#endif
+ if (error != 0)
+ return (error);
+ error = kern_writev(td, args->fd, auio);
+ freeuio(auio);
+ return (linux_enobufs2eagain(td, args->fd, error));
+}
diff --git a/sys/compat/linux/linux_file.h b/sys/compat/linux/linux_file.h
index 3f885f915411..ce9feca154ed 100644
--- a/sys/compat/linux/linux_file.h
+++ b/sys/compat/linux/linux_file.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2007 Roman Divacky
* All rights reserved.
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUX_FILE_H_
@@ -191,10 +189,21 @@
#define LINUX_HUGETLB_FLAG_ENCODE_2GB (31 << LINUX_HUGETLB_FLAG_ENCODE_SHIFT)
#define LINUX_HUGETLB_FLAG_ENCODE_16GB (34U << LINUX_HUGETLB_FLAG_ENCODE_SHIFT)
+#if defined(_KERNEL)
struct l_file_handle {
l_uint handle_bytes;
l_int handle_type;
unsigned char f_handle[0];
};
+int linux_enobufs2eagain(struct thread *, int, int);
+#endif
+
+/*
+ * Look at linux_close_range() for an explanation.
+ *
+ * #define LINUX_CLOSE_RANGE_UNSHARE (1U << 1)
+ */
+#define LINUX_CLOSE_RANGE_CLOEXEC (1U << 2)
+
#endif /* !_LINUX_FILE_H_ */
diff --git a/sys/compat/linux/linux_fork.c b/sys/compat/linux/linux_fork.c
index 7654e447f878..4ce3bc192b4e 100644
--- a/sys/compat/linux/linux_fork.c
+++ b/sys/compat/linux/linux_fork.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2004 Tim J. Robbins
* Copyright (c) 2002 Doug Rabson
@@ -28,14 +28,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_compat.h"
-
#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/imgact.h>
#include <sys/ktr.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@@ -47,7 +40,6 @@ __FBSDID("$FreeBSD$");
#include <sys/sx.h>
#include <sys/umtxvar.h>
#include <sys/unistd.h>
-#include <sys/wait.h>
#include <vm/vm.h>
#include <vm/pmap.h>
diff --git a/sys/compat/linux/linux_fork.h b/sys/compat/linux/linux_fork.h
index bdc201bce57e..6e2d204a81ea 100644
--- a/sys/compat/linux/linux_fork.h
+++ b/sys/compat/linux/linux_fork.h
@@ -1,4 +1,6 @@
/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
* Copyright (c) 2021 Dmitry Chagin <dchagin@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -21,8 +23,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUX_FORK_H_
@@ -62,6 +62,7 @@
#define LINUX_CSIGNAL 0x000000ff
+#if defined(_KERNEL)
/*
* User-space clone3 args layout.
*/
@@ -97,5 +98,6 @@ struct l_clone_args {
int linux_set_upcall(struct thread *, register_t);
int linux_set_cloned_tls(struct thread *, void *);
void linux_thread_detach(struct thread *);
+#endif /* defined(_KERNEL) */
#endif /* _LINUX_FORK_H_ */
diff --git a/sys/compat/linux/linux_futex.c b/sys/compat/linux/linux_futex.c
index eb3ce3421465..ab2760859e16 100644
--- a/sys/compat/linux/linux_futex.c
+++ b/sys/compat/linux/linux_futex.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2009-2021 Dmitry Chagin <dchagin@FreeBSD.org>
* Copyright (c) 2008 Roman Divacky
@@ -26,20 +26,17 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_compat.h"
-
#include <sys/param.h>
-#include <sys/systm.h>
#include <sys/imgact.h>
#include <sys/imgact_elf.h>
#include <sys/ktr.h>
+#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/sched.h>
+#include <sys/sysent.h>
+#include <sys/vnode.h>
#include <sys/umtxvar.h>
#ifdef COMPAT_LINUX32
@@ -52,7 +49,7 @@ __FBSDID("$FreeBSD$");
#include <compat/linux/linux_emul.h>
#include <compat/linux/linux_futex.h>
#include <compat/linux/linux_misc.h>
-#include <compat/linux/linux_timer.h>
+#include <compat/linux/linux_time.h>
#include <compat/linux/linux_util.h>
#define FUTEX_SHARED 0x8 /* shared futex */
@@ -786,6 +783,8 @@ linux_futex_wait(struct thread *td, struct linux_futex_args *args)
}
umtxq_unlock(&uq->uq_key);
umtx_key_release(&uq->uq_key);
+ if (error == ERESTART)
+ error = EINTR;
return (error);
}
@@ -931,7 +930,7 @@ linux_get_robust_list(struct thread *td, struct linux_get_robust_list_args *args
if (error != 0)
return (EFAULT);
- return (copyout(&head, args->head, sizeof(head)));
+ return (copyout(&head, args->head, sizeof(l_uintptr_t)));
}
static int
diff --git a/sys/compat/linux/linux_futex.h b/sys/compat/linux/linux_futex.h
index 189db4e17c4f..b6b6b0c98573 100644
--- a/sys/compat/linux/linux_futex.h
+++ b/sys/compat/linux/linux_futex.h
@@ -31,8 +31,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUX_FUTEX_H
@@ -79,6 +77,17 @@
#define FUTEX_TID_MASK 0x3fffffff
#define FUTEX_BITSET_MATCH_ANY 0xffffffff
+/* robust futexes */
+struct linux_robust_list {
+ l_uintptr_t next;
+};
+
+struct linux_robust_list_head {
+ struct linux_robust_list list;
+ l_long futex_offset;
+ l_uintptr_t pending_list;
+};
+
int futex_xchgl(int oparg, uint32_t *uaddr, int *oldval);
int futex_addl(int oparg, uint32_t *uaddr, int *oldval);
int futex_orl(int oparg, uint32_t *uaddr, int *oldval);
diff --git a/sys/compat/linux/linux_getcwd.c b/sys/compat/linux/linux_getcwd.c
index 4917641be5e5..e11b47aff178 100644
--- a/sys/compat/linux/linux_getcwd.c
+++ b/sys/compat/linux/linux_getcwd.c
@@ -1,7 +1,7 @@
/* $OpenBSD: linux_getcwd.c,v 1.2 2001/05/16 12:50:21 ho Exp $ */
/* $NetBSD: vfs_getcwd.c,v 1.3.2.3 1999/07/11 10:24:09 sommerfeld Exp $ */
/*-
- * SPDX-License-Identifier: BSD-2-Clause-NetBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* Copyright (c) 2015 The FreeBSD Foundation
@@ -35,16 +35,10 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_compat.h"
-
#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/vnode.h>
-#include <sys/proc.h>
#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
#ifdef COMPAT_LINUX32
#include <machine/../linux32/linux.h>
@@ -54,7 +48,6 @@ __FBSDID("$FreeBSD$");
#include <machine/../linux/linux_proto.h>
#endif
#include <compat/linux/linux_misc.h>
-#include <compat/linux/linux_util.h>
/*
* Find pathname of process's current directory.
diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c
index ea391e56cd9a..41c43f1ef8e6 100644
--- a/sys/compat/linux/linux_ioctl.c
+++ b/sys/compat/linux/linux_ioctl.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1994-1995 Søren Schmidt
* All rights reserved.
@@ -26,27 +26,13 @@
* SUCH DAMAGE.
*/
-#include "opt_compat.h"
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/sysproto.h>
-#ifdef COMPAT_LINUX32
-#include <sys/abi_compat.h>
-#endif
#include <sys/capsicum.h>
#include <sys/cdio.h>
-#include <sys/dvdio.h>
-#include <sys/conf.h>
-#include <sys/disk.h>
#include <sys/consio.h>
-#include <sys/ctype.h>
+#include <sys/disk.h>
+#include <sys/dvdio.h>
#include <sys/fcntl.h>
-#include <sys/file.h>
-#include <sys/filedesc.h>
#include <sys/filio.h>
#include <sys/jail.h>
#include <sys/kbio.h>
@@ -55,19 +41,16 @@ __FBSDID("$FreeBSD$");
#include <sys/linker_set.h>
#include <sys/lock.h>
#include <sys/malloc.h>
+#include <sys/mman.h>
#include <sys/proc.h>
#include <sys/sbuf.h>
-#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/soundcard.h>
-#include <sys/stdint.h>
-#include <sys/sx.h>
+#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
+#include <sys/sysproto.h>
+#include <sys/sx.h>
#include <sys/tty.h>
-#include <sys/uio.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <sys/resourcevar.h>
#include <net/if.h>
#include <net/if_var.h>
@@ -89,7 +72,7 @@ __FBSDID("$FreeBSD$");
#include <compat/linux/linux_ioctl.h>
#include <compat/linux/linux_mib.h>
#include <compat/linux/linux_socket.h>
-#include <compat/linux/linux_timer.h>
+#include <compat/linux/linux_time.h>
#include <compat/linux/linux_util.h>
#include <contrib/v4l/videodev.h>
@@ -100,8 +83,6 @@ __FBSDID("$FreeBSD$");
#include <cam/scsi/scsi_sg.h>
-CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ);
-
#define DEFINE_LINUX_IOCTL_SET(shortname, SHORTNAME) \
static linux_ioctl_function_t linux_ioctl_ ## shortname; \
static struct linux_ioctl_handler shortname ## _handler = { \
@@ -285,7 +266,7 @@ linux_ioctl_disk(struct thread *td, struct linux_ioctl_args *args)
fdrop(fp, td);
if (error)
return (error);
- blksize64 = mediasize;;
+ blksize64 = mediasize;
return (copyout(&blksize64, (void *)args->arg,
sizeof(blksize64)));
case LINUX_BLKSSZGET:
@@ -1025,8 +1006,12 @@ linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
error = ENOIOCTL;
break;
case LINUX_TIOCSPTLCK:
- /* Our unlockpt() does nothing. */
- error = 0;
+ /*
+ * Our unlockpt() does nothing. Check that fd refers
+ * to a pseudo-terminal master device.
+ */
+ args->cmd = TIOCPTMASTER;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
break;
default:
error = ENOIOCTL;
@@ -1464,7 +1449,7 @@ linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
if (!error) {
lth.cdth_trk0 = th.starting_track;
lth.cdth_trk1 = th.ending_track;
- copyout(&lth, (void *)args->arg, sizeof(lth));
+ error = copyout(&lth, (void *)args->arg, sizeof(lth));
}
break;
}
@@ -1626,7 +1611,8 @@ linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
if (error) {
if (lda.type == LINUX_DVD_HOST_SEND_KEY2) {
lda.type = LINUX_DVD_AUTH_FAILURE;
- copyout(&lda, (void *)args->arg, sizeof(lda));
+ (void)copyout(&lda, (void *)args->arg,
+ sizeof(lda));
}
break;
}
@@ -1786,9 +1772,10 @@ linux_ioctl_sound(struct thread *td, struct linux_ioctl_args *args)
struct linux_old_mixer_info info;
bzero(&info, sizeof(info));
strncpy(info.id, "OSS", sizeof(info.id) - 1);
- strncpy(info.name, "FreeBSD OSS Mixer", sizeof(info.name) - 1);
- copyout(&info, (void *)args->arg, sizeof(info));
- return (0);
+ strncpy(info.name, "FreeBSD OSS Mixer",
+ sizeof(info.name) - 1);
+ return (copyout(&info, (void *)args->arg,
+ sizeof(info)));
}
default:
return (ENOIOCTL);
@@ -2107,195 +2094,273 @@ static int
linux_ioctl_ifname(struct thread *td, struct l_ifreq *uifr)
{
struct l_ifreq ifr;
- struct ifnet *ifp;
- int error, ethno, index;
+ int error, ret;
error = copyin(uifr, &ifr, sizeof(ifr));
if (error != 0)
return (error);
-
- CURVNET_SET(TD_TO_VNET(curthread));
- IFNET_RLOCK();
- index = 1; /* ifr.ifr_ifindex starts from 1 */
- ethno = 0;
- error = ENODEV;
- CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
- if (ifr.ifr_ifindex == index) {
- if (!linux_use_real_ifname(ifp))
- snprintf(ifr.ifr_name, LINUX_IFNAMSIZ,
- "eth%d", ethno);
- else
- strlcpy(ifr.ifr_name, ifp->if_xname,
- LINUX_IFNAMSIZ);
- error = 0;
- break;
- }
- if (!linux_use_real_ifname(ifp))
- ethno++;
- index++;
- }
- IFNET_RUNLOCK();
- if (error == 0)
- error = copyout(&ifr, uifr, sizeof(ifr));
- CURVNET_RESTORE();
-
- return (error);
+ ret = ifname_bsd_to_linux_idx(ifr.ifr_index, ifr.ifr_name,
+ LINUX_IFNAMSIZ);
+ if (ret > 0)
+ return (copyout(&ifr, uifr, sizeof(ifr)));
+ else
+ return (ENODEV);
}
/*
* Implement the SIOCGIFCONF ioctl
*/
+static u_int
+linux_ifconf_ifaddr_cb(void *arg, struct ifaddr *ifa, u_int count)
+{
+#ifdef COMPAT_LINUX32
+ struct l_ifconf *ifc;
+#else
+ struct ifconf *ifc;
+#endif
+
+ ifc = arg;
+ ifc->ifc_len += sizeof(struct l_ifreq);
+ return (1);
+}
+
+static int
+linux_ifconf_ifnet_cb(if_t ifp, void *arg)
+{
+
+ if_foreach_addr_type(ifp, AF_INET, linux_ifconf_ifaddr_cb, arg);
+ return (0);
+}
+
+struct linux_ifconfig_ifaddr_cb2_s {
+ struct l_ifreq ifr;
+ struct sbuf *sb;
+ size_t max_len;
+ size_t valid_len;
+};
+
+static u_int
+linux_ifconf_ifaddr_cb2(void *arg, struct ifaddr *ifa, u_int len)
+{
+ struct linux_ifconfig_ifaddr_cb2_s *cbs = arg;
+ struct sockaddr *sa = ifa->ifa_addr;
+
+ cbs->ifr.ifr_addr.sa_family = LINUX_AF_INET;
+ memcpy(cbs->ifr.ifr_addr.sa_data, sa->sa_data,
+ sizeof(cbs->ifr.ifr_addr.sa_data));
+ sbuf_bcat(cbs->sb, &cbs->ifr, sizeof(cbs->ifr));
+ cbs->max_len += sizeof(cbs->ifr);
+
+ if (sbuf_error(cbs->sb) == 0)
+ cbs->valid_len = sbuf_len(cbs->sb);
+ return (1);
+}
+
+static int
+linux_ifconf_ifnet_cb2(if_t ifp, void *arg)
+{
+ struct linux_ifconfig_ifaddr_cb2_s *cbs = arg;
+
+ bzero(&cbs->ifr, sizeof(cbs->ifr));
+ ifname_bsd_to_linux_ifp(ifp, cbs->ifr.ifr_name,
+ sizeof(cbs->ifr.ifr_name));
+
+ /* Walk the address list */
+ if_foreach_addr_type(ifp, AF_INET, linux_ifconf_ifaddr_cb2, cbs);
+ return (0);
+}
static int
linux_ifconf(struct thread *td, struct ifconf *uifc)
{
+ struct linux_ifconfig_ifaddr_cb2_s cbs;
+ struct epoch_tracker et;
#ifdef COMPAT_LINUX32
struct l_ifconf ifc;
#else
struct ifconf ifc;
#endif
- struct l_ifreq ifr;
- struct ifnet *ifp;
- struct ifaddr *ifa;
struct sbuf *sb;
- int error, ethno, full = 0, valid_len, max_len;
+ int error, full;
error = copyin(uifc, &ifc, sizeof(ifc));
if (error != 0)
return (error);
- max_len = maxphys - 1;
-
- CURVNET_SET(TD_TO_VNET(td));
/* handle the 'request buffer size' case */
- if ((l_uintptr_t)ifc.ifc_buf == PTROUT(NULL)) {
+ if (PTRIN(ifc.ifc_buf) == NULL) {
ifc.ifc_len = 0;
- IFNET_RLOCK();
- CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
- CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
- struct sockaddr *sa = ifa->ifa_addr;
- if (sa->sa_family == AF_INET)
- ifc.ifc_len += sizeof(ifr);
- }
- }
- IFNET_RUNLOCK();
- error = copyout(&ifc, uifc, sizeof(ifc));
- CURVNET_RESTORE();
- return (error);
+ NET_EPOCH_ENTER(et);
+ if_foreach(linux_ifconf_ifnet_cb, &ifc);
+ NET_EPOCH_EXIT(et);
+ return (copyout(&ifc, uifc, sizeof(ifc)));
}
-
- if (ifc.ifc_len <= 0) {
- CURVNET_RESTORE();
+ if (ifc.ifc_len <= 0)
return (EINVAL);
- }
+
+ full = 0;
+ cbs.max_len = maxphys - 1;
again:
- /* Keep track of eth interfaces */
- ethno = 0;
- if (ifc.ifc_len <= max_len) {
- max_len = ifc.ifc_len;
+ if (ifc.ifc_len <= cbs.max_len) {
+ cbs.max_len = ifc.ifc_len;
full = 1;
}
- sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN);
- max_len = 0;
- valid_len = 0;
+ cbs.sb = sb = sbuf_new(NULL, NULL, cbs.max_len + 1, SBUF_FIXEDLEN);
+ cbs.max_len = 0;
+ cbs.valid_len = 0;
/* Return all AF_INET addresses of all interfaces */
- IFNET_RLOCK();
- CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
- int addrs = 0;
-
- bzero(&ifr, sizeof(ifr));
- if (IFP_IS_ETH(ifp))
- snprintf(ifr.ifr_name, LINUX_IFNAMSIZ, "eth%d",
- ethno++);
- else
- strlcpy(ifr.ifr_name, ifp->if_xname, LINUX_IFNAMSIZ);
-
- /* Walk the address list */
- CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
- struct sockaddr *sa = ifa->ifa_addr;
-
- if (sa->sa_family == AF_INET) {
- ifr.ifr_addr.sa_family = LINUX_AF_INET;
- memcpy(ifr.ifr_addr.sa_data, sa->sa_data,
- sizeof(ifr.ifr_addr.sa_data));
- sbuf_bcat(sb, &ifr, sizeof(ifr));
- max_len += sizeof(ifr);
- addrs++;
- }
-
- if (sbuf_error(sb) == 0)
- valid_len = sbuf_len(sb);
- }
- if (addrs == 0) {
- bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
- sbuf_bcat(sb, &ifr, sizeof(ifr));
- max_len += sizeof(ifr);
+ NET_EPOCH_ENTER(et);
+ if_foreach(linux_ifconf_ifnet_cb2, &cbs);
+ NET_EPOCH_EXIT(et);
- if (sbuf_error(sb) == 0)
- valid_len = sbuf_len(sb);
- }
- }
- IFNET_RUNLOCK();
-
- if (valid_len != max_len && !full) {
+ if (cbs.valid_len != cbs.max_len && !full) {
sbuf_delete(sb);
goto again;
}
- ifc.ifc_len = valid_len;
+ ifc.ifc_len = cbs.valid_len;
sbuf_finish(sb);
error = copyout(sbuf_data(sb), PTRIN(ifc.ifc_buf), ifc.ifc_len);
if (error == 0)
error = copyout(&ifc, uifc, sizeof(ifc));
sbuf_delete(sb);
- CURVNET_RESTORE();
return (error);
}
static int
-linux_gifflags(struct thread *td, struct ifnet *ifp, struct l_ifreq *ifr)
-{
- l_short flags;
-
- linux_ifflags(ifp, &flags);
-
- return (copyout(&flags, &ifr->ifr_flags, sizeof(flags)));
-}
-
-static int
-linux_gifhwaddr(struct ifnet *ifp, struct l_ifreq *ifr)
+linux_ioctl_socket_ifreq(struct thread *td, int fd, u_int cmd,
+ struct l_ifreq *uifr)
{
- struct l_sockaddr lsa;
+ struct l_ifreq lifr;
+ struct ifreq bifr;
+ size_t ifrusiz;
+ int error, temp_flags;
- if (linux_ifhwaddr(ifp, &lsa) != 0)
- return (ENOENT);
+ switch (cmd) {
+ case LINUX_SIOCGIFINDEX:
+ cmd = SIOCGIFINDEX;
+ break;
+ case LINUX_SIOCGIFFLAGS:
+ cmd = SIOCGIFFLAGS;
+ break;
+ case LINUX_SIOCGIFADDR:
+ cmd = SIOCGIFADDR;
+ break;
+ case LINUX_SIOCSIFADDR:
+ cmd = SIOCSIFADDR;
+ break;
+ case LINUX_SIOCGIFDSTADDR:
+ cmd = SIOCGIFDSTADDR;
+ break;
+ case LINUX_SIOCGIFBRDADDR:
+ cmd = SIOCGIFBRDADDR;
+ break;
+ case LINUX_SIOCGIFNETMASK:
+ cmd = SIOCGIFNETMASK;
+ break;
+ case LINUX_SIOCSIFNETMASK:
+ cmd = SIOCSIFNETMASK;
+ break;
+ case LINUX_SIOCGIFMTU:
+ cmd = SIOCGIFMTU;
+ break;
+ case LINUX_SIOCSIFMTU:
+ cmd = SIOCSIFMTU;
+ break;
+ case LINUX_SIOCGIFHWADDR:
+ cmd = SIOCGHWADDR;
+ break;
+ case LINUX_SIOCGIFMETRIC:
+ cmd = SIOCGIFMETRIC;
+ break;
+ case LINUX_SIOCSIFMETRIC:
+ cmd = SIOCSIFMETRIC;
+ break;
+ /*
+ * XXX This is slightly bogus, but these ioctls are currently
+ * XXX only used by the aironet (if_an) network driver.
+ */
+ case LINUX_SIOCDEVPRIVATE:
+ cmd = SIOCGPRIVATE_0;
+ break;
+ case LINUX_SIOCDEVPRIVATE+1:
+ cmd = SIOCGPRIVATE_1;
+ break;
+ default:
+ LINUX_RATELIMIT_MSG_OPT2(
+ "ioctl_socket_ifreq fd=%d, cmd=0x%x is not implemented",
+ fd, cmd);
+ return (ENOIOCTL);
+ }
- return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof(lsa)));
-}
+ error = copyin(uifr, &lifr, sizeof(lifr));
+ if (error != 0)
+ return (error);
+ bzero(&bifr, sizeof(bifr));
- /*
-* If we fault in bsd_to_linux_ifreq() then we will fault when we call
-* the native ioctl(). Thus, we don't really need to check the return
-* value of this function.
-*/
-static int
-bsd_to_linux_ifreq(struct ifreq *arg)
-{
- struct ifreq ifr;
- size_t ifr_len = sizeof(struct ifreq);
- int error;
+ /*
+ * The size of Linux enum ifr_ifru is bigger than
+ * the FreeBSD size due to the struct ifmap.
+ */
+ ifrusiz = (sizeof(lifr) > sizeof(bifr) ? sizeof(bifr) :
+ sizeof(lifr)) - offsetof(struct l_ifreq, ifr_ifru);
+ bcopy(&lifr.ifr_ifru, &bifr.ifr_ifru, ifrusiz);
- if ((error = copyin(arg, &ifr, ifr_len)))
+ error = ifname_linux_to_bsd(td, lifr.ifr_name, bifr.ifr_name);
+ if (error != 0)
return (error);
- *(u_short *)&ifr.ifr_addr = ifr.ifr_addr.sa_family;
+ /* Translate in values. */
+ switch (cmd) {
+ case SIOCGIFINDEX:
+ bifr.ifr_index = lifr.ifr_index;
+ break;
+ case SIOCSIFADDR:
+ case SIOCSIFNETMASK:
+ bifr.ifr_addr.sa_len = sizeof(struct sockaddr);
+ bifr.ifr_addr.sa_family =
+ linux_to_bsd_domain(lifr.ifr_addr.sa_family);
+ break;
+ default:
+ break;
+ }
- error = copyout(&ifr, arg, ifr_len);
+ error = kern_ioctl(td, fd, cmd, (caddr_t)&bifr);
+ if (error != 0)
+ return (error);
+ bzero(&lifr.ifr_ifru, sizeof(lifr.ifr_ifru));
+
+ /* Translate out values. */
+ switch (cmd) {
+ case SIOCGIFINDEX:
+ lifr.ifr_index = bifr.ifr_index;
+ break;
+ case SIOCGIFFLAGS:
+ temp_flags = bifr.ifr_flags | (bifr.ifr_flagshigh << 16);
+ lifr.ifr_flags = bsd_to_linux_ifflags(temp_flags);
+ break;
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ case SIOCGIFDSTADDR:
+ case SIOCGIFBRDADDR:
+ case SIOCGIFNETMASK:
+ bcopy(&bifr.ifr_addr, &lifr.ifr_addr, sizeof(bifr.ifr_addr));
+ lifr.ifr_addr.sa_family =
+ bsd_to_linux_domain(bifr.ifr_addr.sa_family);
+ break;
+ case SIOCGHWADDR:
+ bcopy(&bifr.ifr_addr, &lifr.ifr_hwaddr, sizeof(bifr.ifr_addr));
+ lifr.ifr_hwaddr.sa_family = LINUX_ARPHRD_ETHER;
+ break;
+ default:
+ bcopy(&bifr.ifr_ifru, &lifr.ifr_ifru, ifrusiz);
+ break;
+ }
- return (error);
+ return (copyout(&lifr, uifr, sizeof(lifr)));
}
/*
@@ -2305,84 +2370,34 @@ bsd_to_linux_ifreq(struct ifreq *arg)
static int
linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
{
- char lifname[LINUX_IFNAMSIZ], ifname[IFNAMSIZ];
- struct ifnet *ifp;
struct file *fp;
int error, type;
- ifp = NULL;
- error = 0;
-
error = fget(td, args->fd, &cap_ioctl_rights, &fp);
if (error != 0)
return (error);
type = fp->f_type;
fdrop(fp, td);
+
+ CURVNET_SET(TD_TO_VNET(td));
+
if (type != DTYPE_SOCKET) {
/* not a socket - probably a tap / vmnet device */
switch (args->cmd) {
case LINUX_SIOCGIFADDR:
case LINUX_SIOCSIFADDR:
case LINUX_SIOCGIFFLAGS:
- return (linux_ioctl_special(td, args));
+ error = linux_ioctl_special(td, args);
+ break;
default:
- return (ENOIOCTL);
+ error = ENOIOCTL;
+ break;
}
+ CURVNET_RESTORE();
+ return (error);
}
- switch (args->cmd & 0xffff) {
- case LINUX_FIOGETOWN:
- case LINUX_FIOSETOWN:
- case LINUX_SIOCADDMULTI:
- case LINUX_SIOCATMARK:
- case LINUX_SIOCDELMULTI:
- case LINUX_SIOCGIFNAME:
- case LINUX_SIOCGIFCONF:
- case LINUX_SIOCGPGRP:
- case LINUX_SIOCSPGRP:
- case LINUX_SIOCGIFCOUNT:
- /* these ioctls don't take an interface name */
- break;
-
- case LINUX_SIOCGIFFLAGS:
- case LINUX_SIOCGIFADDR:
- case LINUX_SIOCSIFADDR:
- case LINUX_SIOCGIFDSTADDR:
- case LINUX_SIOCGIFBRDADDR:
- case LINUX_SIOCGIFNETMASK:
- case LINUX_SIOCSIFNETMASK:
- case LINUX_SIOCGIFMTU:
- case LINUX_SIOCSIFMTU:
- case LINUX_SIOCSIFNAME:
- case LINUX_SIOCGIFHWADDR:
- case LINUX_SIOCSIFHWADDR:
- case LINUX_SIOCDEVPRIVATE:
- case LINUX_SIOCDEVPRIVATE+1:
- case LINUX_SIOCGIFINDEX:
- /* copy in the interface name and translate it. */
- error = copyin((void *)args->arg, lifname, LINUX_IFNAMSIZ);
- if (error != 0)
- return (error);
- memset(ifname, 0, sizeof(ifname));
- ifp = ifname_linux_to_bsd(td, lifname, ifname);
- if (ifp == NULL)
- return (EINVAL);
- /*
- * We need to copy it back out in case we pass the
- * request on to our native ioctl(), which will expect
- * the ifreq to be in user space and have the correct
- * interface name.
- */
- error = copyout(ifname, (void *)args->arg, IFNAMSIZ);
- if (error != 0)
- return (error);
- break;
-
- default:
- return (ENOIOCTL);
- }
-
- switch (args->cmd & 0xffff) {
+ switch (args->cmd) {
case LINUX_FIOSETOWN:
args->cmd = FIOSETOWN;
error = sys_ioctl(td, (struct ioctl_args *)args);
@@ -2418,67 +2433,6 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
error = linux_ifconf(td, (struct ifconf *)args->arg);
break;
- case LINUX_SIOCGIFFLAGS:
- args->cmd = SIOCGIFFLAGS;
- error = linux_gifflags(td, ifp, (struct l_ifreq *)args->arg);
- break;
-
- case LINUX_SIOCGIFADDR:
- args->cmd = SIOCGIFADDR;
- error = sys_ioctl(td, (struct ioctl_args *)args);
- bsd_to_linux_ifreq((struct ifreq *)args->arg);
- break;
-
- case LINUX_SIOCSIFADDR:
- /* XXX probably doesn't work, included for completeness */
- args->cmd = SIOCSIFADDR;
- error = sys_ioctl(td, (struct ioctl_args *)args);
- break;
-
- case LINUX_SIOCGIFDSTADDR:
- args->cmd = SIOCGIFDSTADDR;
- error = sys_ioctl(td, (struct ioctl_args *)args);
- bsd_to_linux_ifreq((struct ifreq *)args->arg);
- break;
-
- case LINUX_SIOCGIFBRDADDR:
- args->cmd = SIOCGIFBRDADDR;
- error = sys_ioctl(td, (struct ioctl_args *)args);
- bsd_to_linux_ifreq((struct ifreq *)args->arg);
- break;
-
- case LINUX_SIOCGIFNETMASK:
- args->cmd = SIOCGIFNETMASK;
- error = sys_ioctl(td, (struct ioctl_args *)args);
- bsd_to_linux_ifreq((struct ifreq *)args->arg);
- break;
-
- case LINUX_SIOCSIFNETMASK:
- error = ENOIOCTL;
- break;
-
- case LINUX_SIOCGIFMTU:
- args->cmd = SIOCGIFMTU;
- error = sys_ioctl(td, (struct ioctl_args *)args);
- break;
-
- case LINUX_SIOCSIFMTU:
- args->cmd = SIOCSIFMTU;
- error = sys_ioctl(td, (struct ioctl_args *)args);
- break;
-
- case LINUX_SIOCSIFNAME:
- error = ENOIOCTL;
- break;
-
- case LINUX_SIOCGIFHWADDR:
- error = linux_gifhwaddr(ifp, (struct l_ifreq *)args->arg);
- break;
-
- case LINUX_SIOCSIFHWADDR:
- error = ENOIOCTL;
- break;
-
case LINUX_SIOCADDMULTI:
args->cmd = SIOCADDMULTI;
error = sys_ioctl(td, (struct ioctl_args *)args);
@@ -2489,34 +2443,17 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
error = sys_ioctl(td, (struct ioctl_args *)args);
break;
- case LINUX_SIOCGIFINDEX:
- args->cmd = SIOCGIFINDEX;
- error = sys_ioctl(td, (struct ioctl_args *)args);
- break;
-
case LINUX_SIOCGIFCOUNT:
error = 0;
break;
- /*
- * XXX This is slightly bogus, but these ioctls are currently
- * XXX only used by the aironet (if_an) network driver.
- */
- case LINUX_SIOCDEVPRIVATE:
- args->cmd = SIOCGPRIVATE_0;
- error = sys_ioctl(td, (struct ioctl_args *)args);
- break;
-
- case LINUX_SIOCDEVPRIVATE+1:
- args->cmd = SIOCGPRIVATE_1;
- error = sys_ioctl(td, (struct ioctl_args *)args);
+ default:
+ error = linux_ioctl_socket_ifreq(td, args->fd, args->cmd,
+ PTRIN(args->arg));
break;
}
- if (ifp != NULL)
- /* restore the original interface name */
- copyout(lifname, (void *)args->arg, LINUX_IFNAMSIZ);
-
+ CURVNET_RESTORE();
return (error);
}
@@ -3279,7 +3216,9 @@ linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args)
error = fo_ioctl(fp, VIDIOC_TRY_FMT, &vformat,
td->td_ucred, td);
bsd_to_linux_v4l2_format(&vformat, &l_vformat);
- copyout(&l_vformat, (void *)args->arg, sizeof(l_vformat));
+ if (error == 0)
+ error = copyout(&l_vformat, (void *)args->arg,
+ sizeof(l_vformat));
fdrop(fp, td);
return (error);
@@ -3348,7 +3287,9 @@ linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args)
error = fo_ioctl(fp, VIDIOC_DQBUF, &vbuf,
td->td_ucred, td);
bsd_to_linux_v4l2_buffer(&vbuf, &l_vbuf);
- copyout(&l_vbuf, (void *)args->arg, sizeof(l_vbuf));
+ if (error == 0)
+ error = copyout(&l_vbuf, (void *)args->arg,
+ sizeof(l_vbuf));
fdrop(fp, td);
return (error);
diff --git a/sys/compat/linux/linux_ioctl.h b/sys/compat/linux/linux_ioctl.h
index 3e2078780d39..8a56e35d10c6 100644
--- a/sys/compat/linux/linux_ioctl.h
+++ b/sys/compat/linux/linux_ioctl.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999 Marcel Moolenaar
* All rights reserved.
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUX_IOCTL_H_
@@ -237,6 +235,8 @@
#define LINUX_SIOCGIFBRDADDR 0x8919
#define LINUX_SIOCGIFNETMASK 0x891b
#define LINUX_SIOCSIFNETMASK 0x891c
+#define LINUX_SIOCGIFMETRIC 0x891d
+#define LINUX_SIOCSIFMETRIC 0x891e
#define LINUX_SIOCGIFMTU 0x8921
#define LINUX_SIOCSIFMTU 0x8922
#define LINUX_SIOCSIFNAME 0x8923
diff --git a/sys/compat/linux/linux_ipc.c b/sys/compat/linux/linux_ipc.c
index 258917e6a969..5b6a28b20774 100644
--- a/sys/compat/linux/linux_ipc.c
+++ b/sys/compat/linux/linux_ipc.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1994-1995 Søren Schmidt
* All rights reserved.
@@ -26,21 +26,16 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/syscallsubr.h>
-#include <sys/sysproto.h>
-#include <sys/proc.h>
#include <sys/limits.h>
#include <sys/msg.h>
+#include <sys/proc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/stat.h>
-
-#include "opt_compat.h"
+#include <sys/syscallsubr.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
#ifdef COMPAT_LINUX32
#include <machine/../linux32/linux.h>
@@ -51,7 +46,7 @@ __FBSDID("$FreeBSD$");
#endif
#include <compat/linux/linux_ipc.h>
#include <compat/linux/linux_ipc64.h>
-#include <compat/linux/linux_timer.h>
+#include <compat/linux/linux_time.h>
#include <compat/linux/linux_util.h>
/*
@@ -305,22 +300,20 @@ linux_msqid_pullup(l_int ver, struct l_msqid64_ds *linux_msqid64, caddr_t uaddr)
if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
return (copyin(uaddr, linux_msqid64, sizeof(*linux_msqid64)));
- else {
- error = copyin(uaddr, &linux_msqid, sizeof(linux_msqid));
- if (error != 0)
- return (error);
- bzero(linux_msqid64, sizeof(*linux_msqid64));
+ error = copyin(uaddr, &linux_msqid, sizeof(linux_msqid));
+ if (error != 0)
+ return (error);
- linux_msqid64->msg_perm.uid = linux_msqid.msg_perm.uid;
- linux_msqid64->msg_perm.gid = linux_msqid.msg_perm.gid;
- linux_msqid64->msg_perm.mode = linux_msqid.msg_perm.mode;
- if (linux_msqid.msg_qbytes == 0)
- linux_msqid64->msg_qbytes = linux_msqid.msg_lqbytes;
- else
- linux_msqid64->msg_qbytes = linux_msqid.msg_qbytes;
- return (0);
- }
+ bzero(linux_msqid64, sizeof(*linux_msqid64));
+ linux_msqid64->msg_perm.uid = linux_msqid.msg_perm.uid;
+ linux_msqid64->msg_perm.gid = linux_msqid.msg_perm.gid;
+ linux_msqid64->msg_perm.mode = linux_msqid.msg_perm.mode;
+ if (linux_msqid.msg_qbytes == 0)
+ linux_msqid64->msg_qbytes = linux_msqid.msg_lqbytes;
+ else
+ linux_msqid64->msg_qbytes = linux_msqid.msg_qbytes;
+ return (0);
}
static int
@@ -331,43 +324,40 @@ linux_msqid_pushdown(l_int ver, struct l_msqid64_ds *linux_msqid64, caddr_t uadd
if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
return (copyout(linux_msqid64, uaddr, sizeof(*linux_msqid64)));
- else {
- bzero(&linux_msqid, sizeof(linux_msqid));
- error = linux_ipc64_perm_to_ipc_perm(&linux_msqid64->msg_perm,
- &linux_msqid.msg_perm);
- if (error != 0)
- return (error);
+ bzero(&linux_msqid, sizeof(linux_msqid));
+ error = linux_ipc64_perm_to_ipc_perm(&linux_msqid64->msg_perm,
+ &linux_msqid.msg_perm);
+ if (error != 0)
+ return (error);
- linux_msqid.msg_stime = linux_msqid64->msg_stime;
- linux_msqid.msg_rtime = linux_msqid64->msg_rtime;
- linux_msqid.msg_ctime = linux_msqid64->msg_ctime;
-
- if (linux_msqid64->msg_cbytes > USHRT_MAX)
- linux_msqid.msg_cbytes = USHRT_MAX;
- else
- linux_msqid.msg_cbytes = linux_msqid64->msg_cbytes;
- linux_msqid.msg_lcbytes = linux_msqid64->msg_cbytes;
- if (linux_msqid64->msg_qnum > USHRT_MAX)
- linux_msqid.msg_qnum = USHRT_MAX;
- else
- linux_msqid.msg_qnum = linux_msqid64->msg_qnum;
- if (linux_msqid64->msg_qbytes > USHRT_MAX)
- linux_msqid.msg_qbytes = USHRT_MAX;
- else
- linux_msqid.msg_qbytes = linux_msqid64->msg_qbytes;
- linux_msqid.msg_lqbytes = linux_msqid64->msg_qbytes;
- linux_msqid.msg_lspid = linux_msqid64->msg_lspid;
- linux_msqid.msg_lrpid = linux_msqid64->msg_lrpid;
-
- /* Linux does not check overflow */
- if (linux_msqid.msg_stime != linux_msqid64->msg_stime ||
- linux_msqid.msg_rtime != linux_msqid64->msg_rtime ||
- linux_msqid.msg_ctime != linux_msqid64->msg_ctime)
- return (EOVERFLOW);
-
- return (copyout(&linux_msqid, uaddr, sizeof(linux_msqid)));
- }
+ linux_msqid.msg_stime = linux_msqid64->msg_stime;
+ linux_msqid.msg_rtime = linux_msqid64->msg_rtime;
+ linux_msqid.msg_ctime = linux_msqid64->msg_ctime;
+
+ if (linux_msqid64->msg_cbytes > USHRT_MAX)
+ linux_msqid.msg_cbytes = USHRT_MAX;
+ else
+ linux_msqid.msg_cbytes = linux_msqid64->msg_cbytes;
+ linux_msqid.msg_lcbytes = linux_msqid64->msg_cbytes;
+ if (linux_msqid64->msg_qnum > USHRT_MAX)
+ linux_msqid.msg_qnum = USHRT_MAX;
+ else
+ linux_msqid.msg_qnum = linux_msqid64->msg_qnum;
+ if (linux_msqid64->msg_qbytes > USHRT_MAX)
+ linux_msqid.msg_qbytes = USHRT_MAX;
+ else
+ linux_msqid.msg_qbytes = linux_msqid64->msg_qbytes;
+ linux_msqid.msg_lqbytes = linux_msqid64->msg_qbytes;
+ linux_msqid.msg_lspid = linux_msqid64->msg_lspid;
+ linux_msqid.msg_lrpid = linux_msqid64->msg_lrpid;
+
+ /* Linux does not check overflow */
+ if (linux_msqid.msg_stime != linux_msqid64->msg_stime ||
+ linux_msqid.msg_rtime != linux_msqid64->msg_rtime ||
+ linux_msqid.msg_ctime != linux_msqid64->msg_ctime)
+ return (EOVERFLOW);
+ return (copyout(&linux_msqid, uaddr, sizeof(linux_msqid)));
}
static int
@@ -378,18 +368,15 @@ linux_semid_pullup(l_int ver, struct l_semid64_ds *linux_semid64, caddr_t uaddr)
if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
return (copyin(uaddr, linux_semid64, sizeof(*linux_semid64)));
- else {
- error = copyin(uaddr, &linux_semid, sizeof(linux_semid));
- if (error != 0)
- return (error);
-
- bzero(linux_semid64, sizeof(*linux_semid64));
+ error = copyin(uaddr, &linux_semid, sizeof(linux_semid));
+ if (error != 0)
+ return (error);
- linux_semid64->sem_perm.uid = linux_semid.sem_perm.uid;
- linux_semid64->sem_perm.gid = linux_semid.sem_perm.gid;
- linux_semid64->sem_perm.mode = linux_semid.sem_perm.mode;
- return (0);
- }
+ bzero(linux_semid64, sizeof(*linux_semid64));
+ linux_semid64->sem_perm.uid = linux_semid.sem_perm.uid;
+ linux_semid64->sem_perm.gid = linux_semid.sem_perm.gid;
+ linux_semid64->sem_perm.mode = linux_semid.sem_perm.mode;
+ return (0);
}
static int
@@ -400,26 +387,23 @@ linux_semid_pushdown(l_int ver, struct l_semid64_ds *linux_semid64, caddr_t uadd
if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
return (copyout(linux_semid64, uaddr, sizeof(*linux_semid64)));
- else {
- bzero(&linux_semid, sizeof(linux_semid));
+ bzero(&linux_semid, sizeof(linux_semid));
error = linux_ipc64_perm_to_ipc_perm(&linux_semid64->sem_perm,
- &linux_semid.sem_perm);
- if (error != 0)
- return (error);
-
- linux_semid.sem_otime = linux_semid64->sem_otime;
- linux_semid.sem_ctime = linux_semid64->sem_ctime;
- linux_semid.sem_nsems = linux_semid64->sem_nsems;
+ &linux_semid.sem_perm);
+ if (error != 0)
+ return (error);
- /* Linux does not check overflow */
- if (linux_semid.sem_otime != linux_semid64->sem_otime ||
- linux_semid.sem_ctime != linux_semid64->sem_ctime ||
- linux_semid.sem_nsems != linux_semid64->sem_nsems)
- return (EOVERFLOW);
+ linux_semid.sem_otime = linux_semid64->sem_otime;
+ linux_semid.sem_ctime = linux_semid64->sem_ctime;
+ linux_semid.sem_nsems = linux_semid64->sem_nsems;
- return (copyout(&linux_semid, uaddr, sizeof(linux_semid)));
- }
+ /* Linux does not check overflow */
+ if (linux_semid.sem_otime != linux_semid64->sem_otime ||
+ linux_semid.sem_ctime != linux_semid64->sem_ctime ||
+ linux_semid.sem_nsems != linux_semid64->sem_nsems)
+ return (EOVERFLOW);
+ return (copyout(&linux_semid, uaddr, sizeof(linux_semid)));
}
static int
@@ -430,18 +414,16 @@ linux_shmid_pullup(l_int ver, struct l_shmid64_ds *linux_shmid64, caddr_t uaddr)
if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
return (copyin(uaddr, linux_shmid64, sizeof(*linux_shmid64)));
- else {
- error = copyin(uaddr, &linux_shmid, sizeof(linux_shmid));
- if (error != 0)
- return (error);
- bzero(linux_shmid64, sizeof(*linux_shmid64));
+ error = copyin(uaddr, &linux_shmid, sizeof(linux_shmid));
+ if (error != 0)
+ return (error);
- linux_shmid64->shm_perm.uid = linux_shmid.shm_perm.uid;
- linux_shmid64->shm_perm.gid = linux_shmid.shm_perm.gid;
- linux_shmid64->shm_perm.mode = linux_shmid.shm_perm.mode;
- return (0);
- }
+ bzero(linux_shmid64, sizeof(*linux_shmid64));
+ linux_shmid64->shm_perm.uid = linux_shmid.shm_perm.uid;
+ linux_shmid64->shm_perm.gid = linux_shmid.shm_perm.gid;
+ linux_shmid64->shm_perm.mode = linux_shmid.shm_perm.mode;
+ return (0);
}
static int
@@ -452,34 +434,31 @@ linux_shmid_pushdown(l_int ver, struct l_shmid64_ds *linux_shmid64, caddr_t uadd
if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
return (copyout(linux_shmid64, uaddr, sizeof(*linux_shmid64)));
- else {
- bzero(&linux_shmid, sizeof(linux_shmid));
- error = linux_ipc64_perm_to_ipc_perm(&linux_shmid64->shm_perm,
- &linux_shmid.shm_perm);
- if (error != 0)
- return (error);
+ bzero(&linux_shmid, sizeof(linux_shmid));
+ error = linux_ipc64_perm_to_ipc_perm(&linux_shmid64->shm_perm,
+ &linux_shmid.shm_perm);
+ if (error != 0)
+ return (error);
- linux_shmid.shm_segsz = linux_shmid64->shm_segsz;
- linux_shmid.shm_atime = linux_shmid64->shm_atime;
- linux_shmid.shm_dtime = linux_shmid64->shm_dtime;
- linux_shmid.shm_ctime = linux_shmid64->shm_ctime;
- linux_shmid.shm_cpid = linux_shmid64->shm_cpid;
- linux_shmid.shm_lpid = linux_shmid64->shm_lpid;
- linux_shmid.shm_nattch = linux_shmid64->shm_nattch;
-
- /* Linux does not check overflow */
- if (linux_shmid.shm_segsz != linux_shmid64->shm_segsz ||
- linux_shmid.shm_atime != linux_shmid64->shm_atime ||
- linux_shmid.shm_dtime != linux_shmid64->shm_dtime ||
- linux_shmid.shm_ctime != linux_shmid64->shm_ctime ||
- linux_shmid.shm_cpid != linux_shmid64->shm_cpid ||
- linux_shmid.shm_lpid != linux_shmid64->shm_lpid ||
- linux_shmid.shm_nattch != linux_shmid64->shm_nattch)
- return (EOVERFLOW);
-
- return (copyout(&linux_shmid, uaddr, sizeof(linux_shmid)));
- }
+ linux_shmid.shm_segsz = linux_shmid64->shm_segsz;
+ linux_shmid.shm_atime = linux_shmid64->shm_atime;
+ linux_shmid.shm_dtime = linux_shmid64->shm_dtime;
+ linux_shmid.shm_ctime = linux_shmid64->shm_ctime;
+ linux_shmid.shm_cpid = linux_shmid64->shm_cpid;
+ linux_shmid.shm_lpid = linux_shmid64->shm_lpid;
+ linux_shmid.shm_nattch = linux_shmid64->shm_nattch;
+
+ /* Linux does not check overflow */
+ if (linux_shmid.shm_segsz != linux_shmid64->shm_segsz ||
+ linux_shmid.shm_atime != linux_shmid64->shm_atime ||
+ linux_shmid.shm_dtime != linux_shmid64->shm_dtime ||
+ linux_shmid.shm_ctime != linux_shmid64->shm_ctime ||
+ linux_shmid.shm_cpid != linux_shmid64->shm_cpid ||
+ linux_shmid.shm_lpid != linux_shmid64->shm_lpid ||
+ linux_shmid.shm_nattch != linux_shmid64->shm_nattch)
+ return (EOVERFLOW);
+ return (copyout(&linux_shmid, uaddr, sizeof(linux_shmid)));
}
static int
@@ -491,18 +470,14 @@ linux_shminfo_pushdown(l_int ver, struct l_shminfo64 *linux_shminfo64,
if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
return (copyout(linux_shminfo64, uaddr,
sizeof(*linux_shminfo64)));
- else {
- bzero(&linux_shminfo, sizeof(linux_shminfo));
-
- linux_shminfo.shmmax = linux_shminfo64->shmmax;
- linux_shminfo.shmmin = linux_shminfo64->shmmin;
- linux_shminfo.shmmni = linux_shminfo64->shmmni;
- linux_shminfo.shmseg = linux_shminfo64->shmseg;
- linux_shminfo.shmall = linux_shminfo64->shmall;
- return (copyout(&linux_shminfo, uaddr,
- sizeof(linux_shminfo)));
- }
+ bzero(&linux_shminfo, sizeof(linux_shminfo));
+ linux_shminfo.shmmax = linux_shminfo64->shmmax;
+ linux_shminfo.shmmin = linux_shminfo64->shmmin;
+ linux_shminfo.shmmni = linux_shminfo64->shmmni;
+ linux_shminfo.shmseg = linux_shminfo64->shmseg;
+ linux_shminfo.shmall = linux_shminfo64->shmall;
+ return (copyout(&linux_shminfo, uaddr, sizeof(linux_shminfo)));
}
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
@@ -546,17 +521,14 @@ linux_semtimedop(struct thread *td, struct linux_semtimedop_args *args)
int
linux_semget(struct thread *td, struct linux_semget_args *args)
{
- struct semget_args /* {
- key_t key;
- int nsems;
- int semflg;
- } */ bsd_args;
+ struct semget_args bsd_args = {
+ .key = args->key,
+ .nsems = args->nsems,
+ .semflg = args->semflg
+ };
if (args->nsems < 0)
return (EINVAL);
- bsd_args.key = args->key;
- bsd_args.nsems = args->nsems;
- bsd_args.semflg = args->semflg;
return (sys_semget(td, &bsd_args));
}
@@ -710,13 +682,11 @@ linux_msgrcv(struct thread *td, struct linux_msgrcv_args *args)
int
linux_msgget(struct thread *td, struct linux_msgget_args *args)
{
- struct msgget_args /* {
- key_t key;
- int msgflg;
- } */ bsd_args;
+ struct msgget_args bsd_args = {
+ .key = args->key,
+ .msgflg = args->msgflg
+ };
- bsd_args.key = args->key;
- bsd_args.msgflg = args->msgflg;
return (sys_msgget(td, &bsd_args));
}
@@ -802,41 +772,34 @@ linux_msgctl(struct thread *td, struct linux_msgctl_args *args)
int
linux_shmat(struct thread *td, struct linux_shmat_args *args)
{
- struct shmat_args /* {
- int shmid;
- void *shmaddr;
- int shmflg;
- } */ bsd_args;
-
- bsd_args.shmid = args->shmid;
- bsd_args.shmaddr = PTRIN(args->shmaddr);
- bsd_args.shmflg = args->shmflg;
+ struct shmat_args bsd_args = {
+ .shmid = args->shmid,
+ .shmaddr = PTRIN(args->shmaddr),
+ .shmflg = args->shmflg
+ };
+
return (sys_shmat(td, &bsd_args));
}
int
linux_shmdt(struct thread *td, struct linux_shmdt_args *args)
{
- struct shmdt_args /* {
- void *shmaddr;
- } */ bsd_args;
+ struct shmdt_args bsd_args = {
+ .shmaddr = PTRIN(args->shmaddr)
+ };
- bsd_args.shmaddr = PTRIN(args->shmaddr);
return (sys_shmdt(td, &bsd_args));
}
int
linux_shmget(struct thread *td, struct linux_shmget_args *args)
{
- struct shmget_args /* {
- key_t key;
- int size;
- int shmflg;
- } */ bsd_args;
-
- bsd_args.key = args->key;
- bsd_args.size = args->size;
- bsd_args.shmflg = args->shmflg;
+ struct shmget_args bsd_args = {
+ .key = args->key,
+ .size = args->size,
+ .shmflg = args->shmflg
+ };
+
return (sys_shmget(td, &bsd_args));
}
diff --git a/sys/compat/linux/linux_ipc.h b/sys/compat/linux/linux_ipc.h
index a148814b8273..c7a512516444 100644
--- a/sys/compat/linux/linux_ipc.h
+++ b/sys/compat/linux/linux_ipc.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2000 Marcel Moolenaar
* All rights reserved.
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUX_IPC_H_
diff --git a/sys/compat/linux/linux_ipc64.h b/sys/compat/linux/linux_ipc64.h
index f0aa5618dff1..e3834b909bfc 100644
--- a/sys/compat/linux/linux_ipc64.h
+++ b/sys/compat/linux/linux_ipc64.h
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUX_IPC64_H_
@@ -103,9 +101,13 @@ struct l_msqid64_ds {
struct l_semid64_ds {
struct l_ipc64_perm sem_perm; /* permissions */
l_time_t sem_otime; /* last semop time */
+#if defined(__amd64__) || defined(__i386__)
l_ulong __unused1;
+#endif
l_time_t sem_ctime; /* last change time */
+#if defined(__amd64__) || defined(__i386__)
l_ulong __unused2;
+#endif
l_ulong sem_nsems; /* no. of semaphores in array */
l_ulong __unused3;
l_ulong __unused4;
diff --git a/sys/compat/linux/linux_mib.c b/sys/compat/linux/linux_mib.c
index ed1bdc528278..9e1c4ed9df57 100644
--- a/sys/compat/linux/linux_mib.c
+++ b/sys/compat/linux/linux_mib.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999 Marcel Moolenaar
* All rights reserved.
@@ -26,19 +26,12 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/sdt.h>
-#include <sys/systm.h>
-#include <sys/sysctl.h>
-#include <sys/proc.h>
+#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/jail.h>
-#include <sys/lock.h>
+#include <sys/proc.h>
#include <sys/sx.h>
#include <compat/linux/linux_mib.h>
@@ -95,10 +88,6 @@ SYSCTL_BOOL(_compat_linux, OID_AUTO, map_sched_prio, CTLFLAG_RDTUN,
&linux_map_sched_prio, 0, "Map scheduler priorities to Linux priorities "
"(not POSIX compliant)");
-int linux_use_emul_path = 1;
-SYSCTL_INT(_compat_linux, OID_AUTO, use_emul_path, CTLFLAG_RWTUN,
- &linux_use_emul_path, 0, "Use linux.compat.emul_path");
-
static bool linux_setid_allowed = true;
SYSCTL_BOOL(_compat_linux, OID_AUTO, setid_allowed, CTLFLAG_RWTUN,
&linux_setid_allowed, 0,
diff --git a/sys/compat/linux/linux_mib.h b/sys/compat/linux/linux_mib.h
index 615439b4d107..1372f4a0f5cf 100644
--- a/sys/compat/linux/linux_mib.h
+++ b/sys/compat/linux/linux_mib.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999 Marcel Moolenaar
* All rights reserved.
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUX_MIB_H_
@@ -46,8 +44,8 @@ int linux_get_oss_version(struct thread *td);
int linux_kernver(struct thread *td);
-#define LINUX_KVERSION 4
-#define LINUX_KPATCHLEVEL 4
+#define LINUX_KVERSION 5
+#define LINUX_KPATCHLEVEL 15
#define LINUX_KSUBLEVEL 0
#define LINUX_KERNVER(a,b,c) (((a) << 16) + ((b) << 8) + (c))
@@ -57,13 +55,6 @@ int linux_kernver(struct thread *td);
#define LINUX_XKERNVERSTR(x) LINUX_KERNVERSTR(x)
#define LINUX_VERSION_STR LINUX_XKERNVERSTR(LINUX_KVERSION.LINUX_KPATCHLEVEL.LINUX_KSUBLEVEL)
-#define LINUX_KERNVER_2004000 LINUX_KERNVER(2,4,0)
-#define LINUX_KERNVER_2006039 LINUX_KERNVER(2,6,39)
-#define LINUX_KERNVER_5004000 LINUX_KERNVER(5,4,0)
-
-#define linux_use54(t) (linux_kernver(t) >= LINUX_KERNVER_5004000)
-
-extern int linux_debug;
extern int linux_default_openfiles;
extern int linux_default_stacksize;
extern int linux_dummy_rlimits;
diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
index 9c4aa1c26f9c..cb62b0e70c0d 100644
--- a/sys/compat/linux/linux_misc.c
+++ b/sys/compat/linux/linux_misc.c
@@ -29,60 +29,38 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_compat.h"
-
#include <sys/param.h>
-#include <sys/blist.h>
#include <sys/fcntl.h>
-#if defined(__i386__)
-#include <sys/imgact_aout.h>
-#endif
#include <sys/jail.h>
#include <sys/imgact.h>
-#include <sys/kernel.h>
#include <sys/limits.h>
#include <sys/lock.h>
-#include <sys/malloc.h>
-#include <sys/mman.h>
-#include <sys/mount.h>
#include <sys/msgbuf.h>
#include <sys/mutex.h>
-#include <sys/namei.h>
#include <sys/poll.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/procctl.h>
#include <sys/reboot.h>
-#include <sys/racct.h>
#include <sys/random.h>
#include <sys/resourcevar.h>
+#include <sys/rtprio.h>
#include <sys/sched.h>
-#include <sys/sdt.h>
-#include <sys/signalvar.h>
#include <sys/smp.h>
#include <sys/stat.h>
#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
+#include <sys/sysent.h>
#include <sys/sysproto.h>
-#include <sys/systm.h>
#include <sys/time.h>
#include <sys/vmmeter.h>
#include <sys/vnode.h>
-#include <sys/wait.h>
-#include <sys/cpuset.h>
-#include <sys/uio.h>
#include <security/audit/audit.h>
#include <security/mac/mac_framework.h>
-#include <vm/vm.h>
#include <vm/pmap.h>
-#include <vm/vm_kern.h>
#include <vm/vm_map.h>
-#include <vm/vm_extern.h>
#include <vm/swap_pager.h>
#ifdef COMPAT_LINUX32
@@ -97,10 +75,10 @@ __FBSDID("$FreeBSD$");
#include <compat/linux/linux_dtrace.h>
#include <compat/linux/linux_file.h>
#include <compat/linux/linux_mib.h>
+#include <compat/linux/linux_mmap.h>
#include <compat/linux/linux_signal.h>
-#include <compat/linux/linux_timer.h>
+#include <compat/linux/linux_time.h>
#include <compat/linux/linux_util.h>
-#include <compat/linux/linux_sysproto.h>
#include <compat/linux/linux_emul.h>
#include <compat/linux/linux_misc.h>
@@ -251,261 +229,6 @@ linux_brk(struct thread *td, struct linux_brk_args *args)
return (0);
}
-#if defined(__i386__)
-/* XXX: what about amd64/linux32? */
-
-int
-linux_uselib(struct thread *td, struct linux_uselib_args *args)
-{
- struct nameidata ni;
- struct vnode *vp;
- struct exec *a_out;
- vm_map_t map;
- vm_map_entry_t entry;
- struct vattr attr;
- vm_offset_t vmaddr;
- unsigned long file_offset;
- unsigned long bss_size;
- char *library;
- ssize_t aresid;
- int error;
- bool locked, opened, textset;
-
- a_out = NULL;
- vp = NULL;
- locked = false;
- textset = false;
- opened = false;
-
- if (!LUSECONVPATH(td)) {
- NDINIT(&ni, LOOKUP, ISOPEN | FOLLOW | LOCKLEAF | AUDITVNODE1,
- UIO_USERSPACE, args->library);
- error = namei(&ni);
- } else {
- LCONVPATHEXIST(args->library, &library);
- NDINIT(&ni, LOOKUP, ISOPEN | FOLLOW | LOCKLEAF | AUDITVNODE1,
- UIO_SYSSPACE, library);
- error = namei(&ni);
- LFREEPATH(library);
- }
- if (error)
- goto cleanup;
-
- vp = ni.ni_vp;
- NDFREE_PNBUF(&ni);
-
- /*
- * From here on down, we have a locked vnode that must be unlocked.
- * XXX: The code below largely duplicates exec_check_permissions().
- */
- locked = true;
-
- /* Executable? */
- error = VOP_GETATTR(vp, &attr, td->td_ucred);
- if (error)
- goto cleanup;
-
- if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
- ((attr.va_mode & 0111) == 0) || (attr.va_type != VREG)) {
- /* EACCESS is what exec(2) returns. */
- error = ENOEXEC;
- goto cleanup;
- }
-
- /* Sensible size? */
- if (attr.va_size == 0) {
- error = ENOEXEC;
- goto cleanup;
- }
-
- /* Can we access it? */
- error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
- if (error)
- goto cleanup;
-
- /*
- * XXX: This should use vn_open() so that it is properly authorized,
- * and to reduce code redundancy all over the place here.
- * XXX: Not really, it duplicates far more of exec_check_permissions()
- * than vn_open().
- */
-#ifdef MAC
- error = mac_vnode_check_open(td->td_ucred, vp, VREAD);
- if (error)
- goto cleanup;
-#endif
- error = VOP_OPEN(vp, FREAD, td->td_ucred, td, NULL);
- if (error)
- goto cleanup;
- opened = true;
-
- /* Pull in executable header into exec_map */
- error = vm_mmap(exec_map, (vm_offset_t *)&a_out, PAGE_SIZE,
- VM_PROT_READ, VM_PROT_READ, 0, OBJT_VNODE, vp, 0);
- if (error)
- goto cleanup;
-
- /* Is it a Linux binary ? */
- if (((a_out->a_magic >> 16) & 0xff) != 0x64) {
- error = ENOEXEC;
- goto cleanup;
- }
-
- /*
- * While we are here, we should REALLY do some more checks
- */
-
- /* Set file/virtual offset based on a.out variant. */
- switch ((int)(a_out->a_magic & 0xffff)) {
- case 0413: /* ZMAGIC */
- file_offset = 1024;
- break;
- case 0314: /* QMAGIC */
- file_offset = 0;
- break;
- default:
- error = ENOEXEC;
- goto cleanup;
- }
-
- bss_size = round_page(a_out->a_bss);
-
- /* Check various fields in header for validity/bounds. */
- if (a_out->a_text & PAGE_MASK || a_out->a_data & PAGE_MASK) {
- error = ENOEXEC;
- goto cleanup;
- }
-
- /* text + data can't exceed file size */
- if (a_out->a_data + a_out->a_text > attr.va_size) {
- error = EFAULT;
- goto cleanup;
- }
-
- /*
- * text/data/bss must not exceed limits
- * XXX - this is not complete. it should check current usage PLUS
- * the resources needed by this library.
- */
- PROC_LOCK(td->td_proc);
- if (a_out->a_text > maxtsiz ||
- a_out->a_data + bss_size > lim_cur_proc(td->td_proc, RLIMIT_DATA) ||
- racct_set(td->td_proc, RACCT_DATA, a_out->a_data +
- bss_size) != 0) {
- PROC_UNLOCK(td->td_proc);
- error = ENOMEM;
- goto cleanup;
- }
- PROC_UNLOCK(td->td_proc);
-
- /*
- * Prevent more writers.
- */
- error = VOP_SET_TEXT(vp);
- if (error != 0)
- goto cleanup;
- textset = true;
-
- /*
- * Lock no longer needed
- */
- locked = false;
- VOP_UNLOCK(vp);
-
- /*
- * Check if file_offset page aligned. Currently we cannot handle
- * misalinged file offsets, and so we read in the entire image
- * (what a waste).
- */
- if (file_offset & PAGE_MASK) {
- /* Map text+data read/write/execute */
-
- /* a_entry is the load address and is page aligned */
- vmaddr = trunc_page(a_out->a_entry);
-
- /* get anon user mapping, read+write+execute */
- error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
- &vmaddr, a_out->a_text + a_out->a_data, 0, VMFS_NO_SPACE,
- VM_PROT_ALL, VM_PROT_ALL, 0);
- if (error)
- goto cleanup;
-
- error = vn_rdwr(UIO_READ, vp, (void *)vmaddr, file_offset,
- a_out->a_text + a_out->a_data, UIO_USERSPACE, 0,
- td->td_ucred, NOCRED, &aresid, td);
- if (error != 0)
- goto cleanup;
- if (aresid != 0) {
- error = ENOEXEC;
- goto cleanup;
- }
- } else {
- /*
- * for QMAGIC, a_entry is 20 bytes beyond the load address
- * to skip the executable header
- */
- vmaddr = trunc_page(a_out->a_entry);
-
- /*
- * Map it all into the process's space as a single
- * copy-on-write "data" segment.
- */
- map = &td->td_proc->p_vmspace->vm_map;
- error = vm_mmap(map, &vmaddr,
- a_out->a_text + a_out->a_data, VM_PROT_ALL, VM_PROT_ALL,
- MAP_PRIVATE | MAP_FIXED, OBJT_VNODE, vp, file_offset);
- if (error)
- goto cleanup;
- vm_map_lock(map);
- if (!vm_map_lookup_entry(map, vmaddr, &entry)) {
- vm_map_unlock(map);
- error = EDOOFUS;
- goto cleanup;
- }
- entry->eflags |= MAP_ENTRY_VN_EXEC;
- vm_map_unlock(map);
- textset = false;
- }
-
- if (bss_size != 0) {
- /* Calculate BSS start address */
- vmaddr = trunc_page(a_out->a_entry) + a_out->a_text +
- a_out->a_data;
-
- /* allocate some 'anon' space */
- error = vm_map_find(&td->td_proc->p_vmspace->vm_map, NULL, 0,
- &vmaddr, bss_size, 0, VMFS_NO_SPACE, VM_PROT_ALL,
- VM_PROT_ALL, 0);
- if (error)
- goto cleanup;
- }
-
-cleanup:
- if (opened) {
- if (locked)
- VOP_UNLOCK(vp);
- locked = false;
- VOP_CLOSE(vp, FREAD, td->td_ucred, td);
- }
- if (textset) {
- if (!locked) {
- locked = true;
- VOP_LOCK(vp, LK_SHARED | LK_RETRY);
- }
- VOP_UNSET_TEXT_CHECKED(vp);
- }
- if (locked)
- VOP_UNLOCK(vp);
-
- /* Release the temporary mapping. */
- if (a_out)
- kmap_free_wakeup(exec_map, (vm_offset_t)a_out, PAGE_SIZE);
-
- return (error);
-}
-
-#endif /* __i386__ */
-
#ifdef LINUX_LEGACY_SYSCALLS
int
linux_select(struct thread *td, struct linux_select_args *args)
@@ -625,6 +348,39 @@ linux_msync(struct thread *td, struct linux_msync_args *args)
args->fl & ~LINUX_MS_SYNC));
}
+int
+linux_mprotect(struct thread *td, struct linux_mprotect_args *uap)
+{
+
+ return (linux_mprotect_common(td, PTROUT(uap->addr), uap->len,
+ uap->prot));
+}
+
+int
+linux_madvise(struct thread *td, struct linux_madvise_args *uap)
+{
+
+ return (linux_madvise_common(td, PTROUT(uap->addr), uap->len,
+ uap->behav));
+}
+
+int
+linux_mmap2(struct thread *td, struct linux_mmap2_args *uap)
+{
+#if defined(LINUX_ARCHWANT_MMAP2PGOFF)
+ /*
+ * For architectures with sizeof (off_t) < sizeof (loff_t) mmap is
+ * implemented with mmap2 syscall and the offset is represented in
+ * multiples of page size.
+ */
+ return (linux_mmap_common(td, PTROUT(uap->addr), uap->len, uap->prot,
+ uap->flags, uap->fd, (uint64_t)(uint32_t)uap->pgoff * PAGE_SIZE));
+#else
+ return (linux_mmap_common(td, PTROUT(uap->addr), uap->len, uap->prot,
+ uap->flags, uap->fd, uap->pgoff));
+#endif
+}
+
#ifdef LINUX_LEGACY_SYSCALLS
int
linux_time(struct thread *td, struct linux_time_args *args)
@@ -659,7 +415,7 @@ struct l_times_argv {
#define CONVOTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
#define CONVNTCK(r) (r.tv_sec * stclohz + r.tv_usec / (1000000 / stclohz))
-#define CONVTCK(r) (linux_kernver(td) >= LINUX_KERNVER_2004000 ? \
+#define CONVTCK(r) (linux_kernver(td) >= LINUX_KERNVER(2,4,0) ? \
CONVNTCK(r) : CONVOTCK(r))
int
@@ -749,7 +505,6 @@ linux_utime(struct thread *td, struct linux_utime_args *args)
{
struct timeval tv[2], *tvp;
struct l_utimbuf lut;
- char *fname;
int error;
if (args->times) {
@@ -763,16 +518,8 @@ linux_utime(struct thread *td, struct linux_utime_args *args)
} else
tvp = NULL;
- if (!LUSECONVPATH(td)) {
- error = kern_utimesat(td, AT_FDCWD, args->fname, UIO_USERSPACE,
- tvp, UIO_SYSSPACE);
- } else {
- LCONVPATHEXIST(args->fname, &fname);
- error = kern_utimesat(td, AT_FDCWD, fname, UIO_SYSSPACE, tvp,
- UIO_SYSSPACE);
- LFREEPATH(fname);
- }
- return (error);
+ return (kern_utimesat(td, AT_FDCWD, args->fname, UIO_USERSPACE,
+ tvp, UIO_SYSSPACE));
}
#endif
@@ -782,7 +529,6 @@ linux_utimes(struct thread *td, struct linux_utimes_args *args)
{
l_timeval ltv[2];
struct timeval tv[2], *tvp = NULL;
- char *fname;
int error;
if (args->tptr != NULL) {
@@ -795,16 +541,8 @@ linux_utimes(struct thread *td, struct linux_utimes_args *args)
tvp = tv;
}
- if (!LUSECONVPATH(td)) {
- error = kern_utimesat(td, AT_FDCWD, args->fname, UIO_USERSPACE,
- tvp, UIO_SYSSPACE);
- } else {
- LCONVPATHEXIST(args->fname, &fname);
- error = kern_utimesat(td, AT_FDCWD, fname, UIO_SYSSPACE,
- tvp, UIO_SYSSPACE);
- LFREEPATH(fname);
- }
- return (error);
+ return (kern_utimesat(td, AT_FDCWD, args->fname, UIO_USERSPACE,
+ tvp, UIO_SYSSPACE));
}
#endif
@@ -837,8 +575,7 @@ static int
linux_common_utimensat(struct thread *td, int ldfd, const char *pathname,
struct timespec *timesp, int lflags)
{
- char *path = NULL;
- int error, dfd, flags = 0;
+ int dfd, flags = 0;
dfd = (ldfd == LINUX_AT_FDCWD) ? AT_FDCWD : ldfd;
@@ -859,27 +596,14 @@ linux_common_utimensat(struct thread *td, int ldfd, const char *pathname,
if (lflags & LINUX_AT_EMPTY_PATH)
flags |= AT_EMPTY_PATH;
- if (!LUSECONVPATH(td)) {
- if (pathname != NULL) {
- return (kern_utimensat(td, dfd, pathname,
- UIO_USERSPACE, timesp, UIO_SYSSPACE, flags));
- }
- }
-
if (pathname != NULL)
- LCONVPATHEXIST_AT(pathname, &path, dfd);
- else if (lflags != 0)
- return (EINVAL);
+ return (kern_utimensat(td, dfd, pathname,
+ UIO_USERSPACE, timesp, UIO_SYSSPACE, flags));
- if (path == NULL)
- error = kern_futimens(td, dfd, timesp, UIO_SYSSPACE);
- else {
- error = kern_utimensat(td, dfd, path, UIO_SYSSPACE, timesp,
- UIO_SYSSPACE, flags);
- LFREEPATH(path);
- }
+ if (lflags != 0)
+ return (EINVAL);
- return (error);
+ return (kern_futimens(td, dfd, timesp, UIO_SYSSPACE));
}
int
@@ -970,7 +694,6 @@ linux_futimesat(struct thread *td, struct linux_futimesat_args *args)
{
l_timeval ltv[2];
struct timeval tv[2], *tvp = NULL;
- char *fname;
int error, dfd;
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
@@ -985,16 +708,8 @@ linux_futimesat(struct thread *td, struct linux_futimesat_args *args)
tvp = tv;
}
- if (!LUSECONVPATH(td)) {
- error = kern_utimesat(td, dfd, args->filename, UIO_USERSPACE,
- tvp, UIO_SYSSPACE);
- } else {
- LCONVPATHEXIST_AT(args->filename, &fname, dfd);
- error = kern_utimesat(td, dfd, fname, UIO_SYSSPACE,
- tvp, UIO_SYSSPACE);
- LFREEPATH(fname);
- }
- return (error);
+ return (kern_utimesat(td, dfd, args->filename, UIO_USERSPACE,
+ tvp, UIO_SYSSPACE));
}
#endif
@@ -1044,12 +759,12 @@ linux_common_wait(struct thread *td, idtype_t idtype, int id, int *statusp,
int
linux_waitpid(struct thread *td, struct linux_waitpid_args *args)
{
- struct linux_wait4_args wait4_args;
-
- wait4_args.pid = args->pid;
- wait4_args.status = args->status;
- wait4_args.options = args->options;
- wait4_args.rusage = NULL;
+ struct linux_wait4_args wait4_args = {
+ .pid = args->pid,
+ .status = args->status,
+ .options = args->options,
+ .rusage = NULL,
+ };
return (linux_wait4(td, &wait4_args));
}
@@ -1125,7 +840,7 @@ linux_waitid(struct thread *td, struct linux_waitid_args *args)
idtype = P_PID;
break;
case LINUX_P_PGID:
- if (linux_use54(td) && args->id == 0) {
+ if (linux_kernver(td) >= LINUX_KERNVER(5,4,0) && args->id == 0) {
p = td->td_proc;
PROC_LOCK(p);
id = p->p_pgid;
@@ -1152,31 +867,19 @@ linux_waitid(struct thread *td, struct linux_waitid_args *args)
int
linux_mknod(struct thread *td, struct linux_mknod_args *args)
{
- char *path;
int error;
- enum uio_seg seg;
- bool convpath;
-
- convpath = LUSECONVPATH(td);
- if (!convpath) {
- path = args->path;
- seg = UIO_USERSPACE;
- } else {
- LCONVPATHCREAT(args->path, &path);
- seg = UIO_SYSSPACE;
- }
switch (args->mode & S_IFMT) {
case S_IFIFO:
case S_IFSOCK:
- error = kern_mkfifoat(td, AT_FDCWD, path, seg,
+ error = kern_mkfifoat(td, AT_FDCWD, args->path, UIO_USERSPACE,
args->mode);
break;
case S_IFCHR:
case S_IFBLK:
- error = kern_mknodat(td, AT_FDCWD, path, seg,
- args->mode, args->dev);
+ error = kern_mknodat(td, AT_FDCWD, args->path, UIO_USERSPACE,
+ args->mode, linux_decode_dev(args->dev));
break;
case S_IFDIR:
@@ -1187,7 +890,7 @@ linux_mknod(struct thread *td, struct linux_mknod_args *args)
args->mode |= S_IFREG;
/* FALLTHROUGH */
case S_IFREG:
- error = kern_openat(td, AT_FDCWD, path, seg,
+ error = kern_openat(td, AT_FDCWD, args->path, UIO_USERSPACE,
O_WRONLY | O_CREAT | O_TRUNC, args->mode);
if (error == 0)
kern_close(td, td->td_retval[0]);
@@ -1197,8 +900,6 @@ linux_mknod(struct thread *td, struct linux_mknod_args *args)
error = EINVAL;
break;
}
- if (convpath)
- LFREEPATH(path);
return (error);
}
#endif
@@ -1206,32 +907,21 @@ linux_mknod(struct thread *td, struct linux_mknod_args *args)
int
linux_mknodat(struct thread *td, struct linux_mknodat_args *args)
{
- char *path;
int error, dfd;
- enum uio_seg seg;
- bool convpath;
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
- convpath = LUSECONVPATH(td);
- if (!convpath) {
- path = __DECONST(char *, args->filename);
- seg = UIO_USERSPACE;
- } else {
- LCONVPATHCREAT_AT(args->filename, &path, dfd);
- seg = UIO_SYSSPACE;
- }
-
switch (args->mode & S_IFMT) {
case S_IFIFO:
case S_IFSOCK:
- error = kern_mkfifoat(td, dfd, path, seg, args->mode);
+ error = kern_mkfifoat(td, dfd, args->filename, UIO_USERSPACE,
+ args->mode);
break;
case S_IFCHR:
case S_IFBLK:
- error = kern_mknodat(td, dfd, path, seg, args->mode,
- args->dev);
+ error = kern_mknodat(td, dfd, args->filename, UIO_USERSPACE,
+ args->mode, linux_decode_dev(args->dev));
break;
case S_IFDIR:
@@ -1242,7 +932,7 @@ linux_mknodat(struct thread *td, struct linux_mknodat_args *args)
args->mode |= S_IFREG;
/* FALLTHROUGH */
case S_IFREG:
- error = kern_openat(td, dfd, path, seg,
+ error = kern_openat(td, dfd, args->filename, UIO_USERSPACE,
O_WRONLY | O_CREAT | O_TRUNC, args->mode);
if (error == 0)
kern_close(td, td->td_retval[0]);
@@ -1252,8 +942,6 @@ linux_mknodat(struct thread *td, struct linux_mknodat_args *args)
error = EINVAL;
break;
}
- if (convpath)
- LFREEPATH(path);
return (error);
}
@@ -1818,13 +1506,6 @@ linux_getsid(struct thread *td, struct linux_getsid_args *args)
}
int
-linux_nosys(struct thread *td, struct nosys_args *ignore)
-{
-
- return (ENOSYS);
-}
-
-int
linux_getpriority(struct thread *td, struct linux_getpriority_args *args)
{
int error;
@@ -2294,7 +1975,7 @@ linux_sched_setaffinity(struct thread *td,
PROC_UNLOCK(tdt->td_proc);
len = min(args->len, sizeof(cpuset_t));
- mask = malloc(sizeof(cpuset_t), M_TEMP, M_WAITOK | M_ZERO);;
+ mask = malloc(sizeof(cpuset_t), M_TEMP, M_WAITOK | M_ZERO);
error = copyin(args->user_mask_ptr, mask, len);
if (error != 0)
goto out;
@@ -2898,28 +2579,370 @@ linux_seccomp(struct thread *td, struct linux_seccomp_args *args)
}
}
-#ifndef COMPAT_LINUX32
+/*
+ * Custom version of exec_copyin_args(), to copy out argument and environment
+ * strings from the old process address space into the temporary string buffer.
+ * Based on freebsd32_exec_copyin_args.
+ */
+static int
+linux_exec_copyin_args(struct image_args *args, const char *fname,
+ enum uio_seg segflg, l_uintptr_t *argv, l_uintptr_t *envv)
+{
+ char *argp, *envp;
+ l_uintptr_t *ptr, arg;
+ int error;
+
+ bzero(args, sizeof(*args));
+ if (argv == NULL)
+ return (EFAULT);
+
+ /*
+ * Allocate demand-paged memory for the file name, argument, and
+ * environment strings.
+ */
+ error = exec_alloc_args(args);
+ if (error != 0)
+ return (error);
+
+ /*
+ * Copy the file name.
+ */
+ error = exec_args_add_fname(args, fname, segflg);
+ if (error != 0)
+ goto err_exit;
+
+ /*
+ * extract arguments first
+ */
+ ptr = argv;
+ for (;;) {
+ error = copyin(ptr++, &arg, sizeof(arg));
+ if (error)
+ goto err_exit;
+ if (arg == 0)
+ break;
+ argp = PTRIN(arg);
+ error = exec_args_add_arg(args, argp, UIO_USERSPACE);
+ if (error != 0)
+ goto err_exit;
+ }
+
+ /*
+ * This comment is from Linux do_execveat_common:
+ * When argv is empty, add an empty string ("") as argv[0] to
+ * ensure confused userspace programs that start processing
+ * from argv[1] won't end up walking envp.
+ */
+ if (args->argc == 0 &&
+ (error = exec_args_add_arg(args, "", UIO_SYSSPACE) != 0))
+ goto err_exit;
+
+ /*
+ * extract environment strings
+ */
+ if (envv) {
+ ptr = envv;
+ for (;;) {
+ error = copyin(ptr++, &arg, sizeof(arg));
+ if (error)
+ goto err_exit;
+ if (arg == 0)
+ break;
+ envp = PTRIN(arg);
+ error = exec_args_add_env(args, envp, UIO_USERSPACE);
+ if (error != 0)
+ goto err_exit;
+ }
+ }
+
+ return (0);
+
+err_exit:
+ exec_free_args(args);
+ return (error);
+}
+
int
linux_execve(struct thread *td, struct linux_execve_args *args)
{
struct image_args eargs;
- char *path;
int error;
LINUX_CTR(execve);
- if (!LUSECONVPATH(td)) {
- error = exec_copyin_args(&eargs, args->path, UIO_USERSPACE,
- args->argp, args->envp);
- } else {
- LCONVPATHEXIST(args->path, &path);
- error = exec_copyin_args(&eargs, path, UIO_SYSSPACE, args->argp,
- args->envp);
- LFREEPATH(path);
- }
+ error = linux_exec_copyin_args(&eargs, args->path, UIO_USERSPACE,
+ args->argp, args->envp);
if (error == 0)
error = linux_common_execve(td, &eargs);
AUDIT_SYSCALL_EXIT(error == EJUSTRETURN ? 0 : error, td);
return (error);
}
-#endif
+
+static void
+linux_up_rtprio_if(struct thread *td1, struct rtprio *rtp)
+{
+ struct rtprio rtp2;
+
+ pri_to_rtp(td1, &rtp2);
+ if (rtp2.type < rtp->type ||
+ (rtp2.type == rtp->type &&
+ rtp2.prio < rtp->prio)) {
+ rtp->type = rtp2.type;
+ rtp->prio = rtp2.prio;
+ }
+}
+
+#define LINUX_PRIO_DIVIDER RTP_PRIO_MAX / LINUX_IOPRIO_MAX
+
+static int
+linux_rtprio2ioprio(struct rtprio *rtp)
+{
+ int ioprio, prio;
+
+ switch (rtp->type) {
+ case RTP_PRIO_IDLE:
+ prio = RTP_PRIO_MIN;
+ ioprio = LINUX_IOPRIO_PRIO(LINUX_IOPRIO_CLASS_IDLE, prio);
+ break;
+ case RTP_PRIO_NORMAL:
+ prio = rtp->prio / LINUX_PRIO_DIVIDER;
+ ioprio = LINUX_IOPRIO_PRIO(LINUX_IOPRIO_CLASS_BE, prio);
+ break;
+ case RTP_PRIO_REALTIME:
+ prio = rtp->prio / LINUX_PRIO_DIVIDER;
+ ioprio = LINUX_IOPRIO_PRIO(LINUX_IOPRIO_CLASS_RT, prio);
+ break;
+ default:
+ prio = RTP_PRIO_MIN;
+ ioprio = LINUX_IOPRIO_PRIO(LINUX_IOPRIO_CLASS_NONE, prio);
+ break;
+ }
+ return (ioprio);
+}
+
+static int
+linux_ioprio2rtprio(int ioprio, struct rtprio *rtp)
+{
+
+ switch (LINUX_IOPRIO_PRIO_CLASS(ioprio)) {
+ case LINUX_IOPRIO_CLASS_IDLE:
+ rtp->prio = RTP_PRIO_MIN;
+ rtp->type = RTP_PRIO_IDLE;
+ break;
+ case LINUX_IOPRIO_CLASS_BE:
+ rtp->prio = LINUX_IOPRIO_PRIO_DATA(ioprio) * LINUX_PRIO_DIVIDER;
+ rtp->type = RTP_PRIO_NORMAL;
+ break;
+ case LINUX_IOPRIO_CLASS_RT:
+ rtp->prio = LINUX_IOPRIO_PRIO_DATA(ioprio) * LINUX_PRIO_DIVIDER;
+ rtp->type = RTP_PRIO_REALTIME;
+ break;
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+#undef LINUX_PRIO_DIVIDER
+
+int
+linux_ioprio_get(struct thread *td, struct linux_ioprio_get_args *args)
+{
+ struct thread *td1;
+ struct rtprio rtp;
+ struct pgrp *pg;
+ struct proc *p;
+ int error, found;
+
+ p = NULL;
+ td1 = NULL;
+ error = 0;
+ found = 0;
+ rtp.type = RTP_PRIO_IDLE;
+ rtp.prio = RTP_PRIO_MAX;
+ switch (args->which) {
+ case LINUX_IOPRIO_WHO_PROCESS:
+ if (args->who == 0) {
+ td1 = td;
+ p = td1->td_proc;
+ PROC_LOCK(p);
+ } else if (args->who > PID_MAX) {
+ td1 = linux_tdfind(td, args->who, -1);
+ if (td1 != NULL)
+ p = td1->td_proc;
+ } else
+ p = pfind(args->who);
+ if (p == NULL)
+ return (ESRCH);
+ if ((error = p_cansee(td, p))) {
+ PROC_UNLOCK(p);
+ break;
+ }
+ if (td1 != NULL) {
+ pri_to_rtp(td1, &rtp);
+ } else {
+ FOREACH_THREAD_IN_PROC(p, td1) {
+ linux_up_rtprio_if(td1, &rtp);
+ }
+ }
+ found++;
+ PROC_UNLOCK(p);
+ break;
+ case LINUX_IOPRIO_WHO_PGRP:
+ sx_slock(&proctree_lock);
+ if (args->who == 0) {
+ pg = td->td_proc->p_pgrp;
+ PGRP_LOCK(pg);
+ } else {
+ pg = pgfind(args->who);
+ if (pg == NULL) {
+ sx_sunlock(&proctree_lock);
+ error = ESRCH;
+ break;
+ }
+ }
+ sx_sunlock(&proctree_lock);
+ LIST_FOREACH(p, &pg->pg_members, p_pglist) {
+ PROC_LOCK(p);
+ if (p->p_state == PRS_NORMAL &&
+ p_cansee(td, p) == 0) {
+ FOREACH_THREAD_IN_PROC(p, td1) {
+ linux_up_rtprio_if(td1, &rtp);
+ found++;
+ }
+ }
+ PROC_UNLOCK(p);
+ }
+ PGRP_UNLOCK(pg);
+ break;
+ case LINUX_IOPRIO_WHO_USER:
+ if (args->who == 0)
+ args->who = td->td_ucred->cr_uid;
+ sx_slock(&allproc_lock);
+ FOREACH_PROC_IN_SYSTEM(p) {
+ PROC_LOCK(p);
+ if (p->p_state == PRS_NORMAL &&
+ p->p_ucred->cr_uid == args->who &&
+ p_cansee(td, p) == 0) {
+ FOREACH_THREAD_IN_PROC(p, td1) {
+ linux_up_rtprio_if(td1, &rtp);
+ found++;
+ }
+ }
+ PROC_UNLOCK(p);
+ }
+ sx_sunlock(&allproc_lock);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ if (error == 0) {
+ if (found != 0)
+ td->td_retval[0] = linux_rtprio2ioprio(&rtp);
+ else
+ error = ESRCH;
+ }
+ return (error);
+}
+
+int
+linux_ioprio_set(struct thread *td, struct linux_ioprio_set_args *args)
+{
+ struct thread *td1;
+ struct rtprio rtp;
+ struct pgrp *pg;
+ struct proc *p;
+ int error;
+
+ if ((error = linux_ioprio2rtprio(args->ioprio, &rtp)) != 0)
+ return (error);
+ /* Attempts to set high priorities (REALTIME) require su privileges. */
+ if (RTP_PRIO_BASE(rtp.type) == RTP_PRIO_REALTIME &&
+ (error = priv_check(td, PRIV_SCHED_RTPRIO)) != 0)
+ return (error);
+
+ p = NULL;
+ td1 = NULL;
+ switch (args->which) {
+ case LINUX_IOPRIO_WHO_PROCESS:
+ if (args->who == 0) {
+ td1 = td;
+ p = td1->td_proc;
+ PROC_LOCK(p);
+ } else if (args->who > PID_MAX) {
+ td1 = linux_tdfind(td, args->who, -1);
+ if (td1 != NULL)
+ p = td1->td_proc;
+ } else
+ p = pfind(args->who);
+ if (p == NULL)
+ return (ESRCH);
+ if ((error = p_cansched(td, p))) {
+ PROC_UNLOCK(p);
+ break;
+ }
+ if (td1 != NULL) {
+ error = rtp_to_pri(&rtp, td1);
+ } else {
+ FOREACH_THREAD_IN_PROC(p, td1) {
+ if ((error = rtp_to_pri(&rtp, td1)) != 0)
+ break;
+ }
+ }
+ PROC_UNLOCK(p);
+ break;
+ case LINUX_IOPRIO_WHO_PGRP:
+ sx_slock(&proctree_lock);
+ if (args->who == 0) {
+ pg = td->td_proc->p_pgrp;
+ PGRP_LOCK(pg);
+ } else {
+ pg = pgfind(args->who);
+ if (pg == NULL) {
+ sx_sunlock(&proctree_lock);
+ error = ESRCH;
+ break;
+ }
+ }
+ sx_sunlock(&proctree_lock);
+ LIST_FOREACH(p, &pg->pg_members, p_pglist) {
+ PROC_LOCK(p);
+ if (p->p_state == PRS_NORMAL &&
+ p_cansched(td, p) == 0) {
+ FOREACH_THREAD_IN_PROC(p, td1) {
+ if ((error = rtp_to_pri(&rtp, td1)) != 0)
+ break;
+ }
+ }
+ PROC_UNLOCK(p);
+ if (error != 0)
+ break;
+ }
+ PGRP_UNLOCK(pg);
+ break;
+ case LINUX_IOPRIO_WHO_USER:
+ if (args->who == 0)
+ args->who = td->td_ucred->cr_uid;
+ sx_slock(&allproc_lock);
+ FOREACH_PROC_IN_SYSTEM(p) {
+ PROC_LOCK(p);
+ if (p->p_state == PRS_NORMAL &&
+ p->p_ucred->cr_uid == args->who &&
+ p_cansched(td, p) == 0) {
+ FOREACH_THREAD_IN_PROC(p, td1) {
+ if ((error = rtp_to_pri(&rtp, td1)) != 0)
+ break;
+ }
+ }
+ PROC_UNLOCK(p);
+ if (error != 0)
+ break;
+ }
+ sx_sunlock(&allproc_lock);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}
diff --git a/sys/compat/linux/linux_misc.h b/sys/compat/linux/linux_misc.h
index 7a8073539e87..cc025f89d5ff 100644
--- a/sys/compat/linux/linux_misc.h
+++ b/sys/compat/linux/linux_misc.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2006 Roman Divacky
* All rights reserved.
@@ -24,15 +24,11 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUX_MISC_H_
#define _LINUX_MISC_H_
-#include <sys/sysctl.h>
-
#define LINUX_MAX_PID_NS_LEVEL 32
/* bits per mask */
@@ -193,4 +189,28 @@ struct syscall_info {
};
};
+/* Linux ioprio set/get syscalls */
+#define LINUX_IOPRIO_CLASS_SHIFT 13
+#define LINUX_IOPRIO_CLASS_MASK 0x07
+#define LINUX_IOPRIO_PRIO_MASK ((1UL << LINUX_IOPRIO_CLASS_SHIFT) - 1)
+
+#define LINUX_IOPRIO_PRIO_CLASS(ioprio) \
+ (((ioprio) >> LINUX_IOPRIO_CLASS_SHIFT) & LINUX_IOPRIO_CLASS_MASK)
+#define LINUX_IOPRIO_PRIO_DATA(ioprio) ((ioprio) & LINUX_IOPRIO_PRIO_MASK)
+#define LINUX_IOPRIO_PRIO(class, data) \
+ ((((class) & LINUX_IOPRIO_CLASS_MASK) << LINUX_IOPRIO_CLASS_SHIFT) | \
+ ((data) & LINUX_IOPRIO_PRIO_MASK))
+
+#define LINUX_IOPRIO_CLASS_NONE 0
+#define LINUX_IOPRIO_CLASS_RT 1
+#define LINUX_IOPRIO_CLASS_BE 2
+#define LINUX_IOPRIO_CLASS_IDLE 3
+
+#define LINUX_IOPRIO_MIN 0
+#define LINUX_IOPRIO_MAX 7
+
+#define LINUX_IOPRIO_WHO_PROCESS 1
+#define LINUX_IOPRIO_WHO_PGRP 2
+#define LINUX_IOPRIO_WHO_USER 3
+
#endif /* _LINUX_MISC_H_ */
diff --git a/sys/compat/linux/linux_mmap.c b/sys/compat/linux/linux_mmap.c
index 4e53f3255b07..a8e790a29da4 100644
--- a/sys/compat/linux/linux_mmap.c
+++ b/sys/compat/linux/linux_mmap.c
@@ -27,18 +27,13 @@
* 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.
- *
- * $FreeBSD$
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/capsicum.h>
+#include <sys/fcntl.h>
#include <sys/file.h>
-#include <sys/imgact.h>
#include <sys/ktr.h>
#include <sys/lock.h>
+#include <sys/malloc.h>
#include <sys/mman.h>
#include <sys/proc.h>
#include <sys/resourcevar.h>
@@ -230,16 +225,22 @@ out:
int
linux_mprotect_common(struct thread *td, uintptr_t addr, size_t len, int prot)
{
+ int flags = 0;
- /* XXX Ignore PROT_GROWSDOWN and PROT_GROWSUP for now. */
- prot &= ~(LINUX_PROT_GROWSDOWN | LINUX_PROT_GROWSUP);
- if ((prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) != 0)
+ /* XXX Ignore PROT_GROWSUP for now. */
+ prot &= ~LINUX_PROT_GROWSUP;
+ if ((prot & ~(LINUX_PROT_GROWSDOWN | PROT_READ | PROT_WRITE |
+ PROT_EXEC)) != 0)
return (EINVAL);
+ if ((prot & LINUX_PROT_GROWSDOWN) != 0) {
+ prot &= ~LINUX_PROT_GROWSDOWN;
+ flags |= VM_MAP_PROTECT_GROWSDOWN;
+ }
#if defined(__amd64__)
linux_fixup_prot(td, &prot);
#endif
- return (kern_mprotect(td, addr, len, prot));
+ return (kern_mprotect(td, addr, len, prot, flags));
}
/*
diff --git a/sys/compat/linux/linux_mmap.h b/sys/compat/linux/linux_mmap.h
index 3bedc2102f5f..043dec9d40b7 100644
--- a/sys/compat/linux/linux_mmap.h
+++ b/sys/compat/linux/linux_mmap.h
@@ -27,8 +27,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUX_MMAP_H_
diff --git a/sys/compat/linux/linux_netlink.c b/sys/compat/linux/linux_netlink.c
new file mode 100644
index 000000000000..8675f830b4ef
--- /dev/null
+++ b/sys/compat/linux/linux_netlink.c
@@ -0,0 +1,622 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Alexander V. Chernikov
+ *
+ * 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.
+ */
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/types.h>
+#include <sys/ck.h>
+#include <sys/lock.h>
+#include <sys/socket.h>
+#include <sys/vnode.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <net/route/nhop.h>
+#include <net/route/route_ctl.h>
+#include <netlink/netlink.h>
+#include <netlink/netlink_ctl.h>
+#include <netlink/netlink_linux.h>
+#include <netlink/netlink_var.h>
+#include <netlink/netlink_route.h>
+
+#include <compat/linux/linux.h>
+#include <compat/linux/linux_common.h>
+#include <compat/linux/linux_util.h>
+
+#define DEBUG_MOD_NAME nl_linux
+#define DEBUG_MAX_LEVEL LOG_DEBUG3
+#include <netlink/netlink_debug.h>
+_DECLARE_DEBUG(LOG_INFO);
+
+static bool
+valid_rta_size(const struct rtattr *rta, int sz)
+{
+ return (NL_RTA_DATA_LEN(rta) == sz);
+}
+
+static bool
+valid_rta_u32(const struct rtattr *rta)
+{
+ return (valid_rta_size(rta, sizeof(uint32_t)));
+}
+
+static uint32_t
+_rta_get_uint32(const struct rtattr *rta)
+{
+ return (*((const uint32_t *)NL_RTA_DATA_CONST(rta)));
+}
+
+static int
+rtnl_neigh_from_linux(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct ndmsg *ndm = (struct ndmsg *)(hdr + 1);
+ sa_family_t f;
+
+ if (hdr->nlmsg_len < sizeof(struct nlmsghdr) + sizeof(struct ndmsg))
+ return (EBADMSG);
+ if ((f = linux_to_bsd_domain(ndm->ndm_family)) == AF_UNKNOWN)
+ return (EPFNOSUPPORT);
+
+ ndm->ndm_family = f;
+
+ return (0);
+}
+
+static int
+rtnl_ifaddr_from_linux(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ struct ifaddrmsg *ifam = (struct ifaddrmsg *)(hdr + 1);
+ sa_family_t f;
+
+ if (hdr->nlmsg_len < sizeof(struct nlmsghdr) + sizeof(struct ifaddrmsg))
+ return (EBADMSG);
+ if ((f = linux_to_bsd_domain(ifam->ifa_family)) == AF_UNKNOWN)
+ return (EPFNOSUPPORT);
+
+ ifam->ifa_family = f;
+
+ return (0);
+}
+
+/*
+ * XXX: in case of error state of hdr is inconsistent.
+ */
+static int
+rtnl_route_from_linux(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+ /* Tweak address families and default fib only */
+ struct rtmsg *rtm = (struct rtmsg *)(hdr + 1);
+ struct nlattr *nla, *nla_head;
+ int attrs_len;
+ sa_family_t f;
+
+ if (hdr->nlmsg_len < sizeof(struct nlmsghdr) + sizeof(struct rtmsg))
+ return (EBADMSG);
+ if ((f = linux_to_bsd_domain(rtm->rtm_family)) == AF_UNKNOWN)
+ return (EPFNOSUPPORT);
+ rtm->rtm_family = f;
+
+ if (rtm->rtm_table == 254)
+ rtm->rtm_table = 0;
+
+ attrs_len = hdr->nlmsg_len - sizeof(struct nlmsghdr);
+ attrs_len -= NETLINK_ALIGN(sizeof(struct rtmsg));
+ nla_head = (struct nlattr *)((char *)rtm + NETLINK_ALIGN(sizeof(struct rtmsg)));
+
+ NLA_FOREACH(nla, nla_head, attrs_len) {
+ RT_LOG(LOG_DEBUG3, "GOT type %d len %d total %d",
+ nla->nla_type, nla->nla_len, attrs_len);
+ struct rtattr *rta = (struct rtattr *)nla;
+ if (rta->rta_len < sizeof(struct rtattr)) {
+ break;
+ }
+ switch (rta->rta_type) {
+ case NL_RTA_TABLE:
+ if (!valid_rta_u32(rta))
+ return (EBADMSG);
+ rtm->rtm_table = 0;
+ uint32_t fibnum = _rta_get_uint32(rta);
+ RT_LOG(LOG_DEBUG3, "GET RTABLE: %u", fibnum);
+ if (fibnum == 254) {
+ *((uint32_t *)NL_RTA_DATA(rta)) = 0;
+ }
+ break;
+ }
+ }
+
+ return (0);
+}
+
+static int
+rtnl_from_linux(struct nlmsghdr *hdr, struct nl_pstate *npt)
+{
+
+ switch (hdr->nlmsg_type) {
+ case NL_RTM_GETROUTE:
+ case NL_RTM_NEWROUTE:
+ case NL_RTM_DELROUTE:
+ return (rtnl_route_from_linux(hdr, npt));
+ case NL_RTM_GETNEIGH:
+ return (rtnl_neigh_from_linux(hdr, npt));
+ case NL_RTM_GETADDR:
+ return (rtnl_ifaddr_from_linux(hdr, npt));
+ /* Silence warning for the messages where no translation is required */
+ case NL_RTM_NEWLINK:
+ case NL_RTM_DELLINK:
+ case NL_RTM_GETLINK:
+ break;
+ default:
+ RT_LOG(LOG_DEBUG, "Passing message type %d untranslated",
+ hdr->nlmsg_type);
+ /* XXXGL: maybe return error? */
+ }
+
+ return (0);
+}
+
+static int
+nlmsg_from_linux(int netlink_family, struct nlmsghdr **hdr,
+ struct nl_pstate *npt)
+{
+ switch (netlink_family) {
+ case NETLINK_ROUTE:
+ return (rtnl_from_linux(*hdr, npt));
+ }
+
+ return (0);
+}
+
+
+/************************************************************
+ * Kernel -> Linux
+ ************************************************************/
+
+static bool
+handle_default_out(struct nlmsghdr *hdr, struct nl_writer *nw)
+{
+ char *out_hdr;
+ out_hdr = nlmsg_reserve_data(nw, NLMSG_ALIGN(hdr->nlmsg_len), char);
+
+ if (out_hdr != NULL) {
+ memcpy(out_hdr, hdr, hdr->nlmsg_len);
+ nw->num_messages++;
+ return (true);
+ }
+ return (false);
+}
+
+static bool
+nlmsg_copy_header(struct nlmsghdr *hdr, struct nl_writer *nw)
+{
+ return (nlmsg_add(nw, hdr->nlmsg_pid, hdr->nlmsg_seq, hdr->nlmsg_type,
+ hdr->nlmsg_flags, 0));
+}
+
+static void *
+_nlmsg_copy_next_header(struct nlmsghdr *hdr, struct nl_writer *nw, int sz)
+{
+ void *next_hdr = nlmsg_reserve_data(nw, sz, void);
+ memcpy(next_hdr, hdr + 1, NLMSG_ALIGN(sz));
+
+ return (next_hdr);
+}
+#define nlmsg_copy_next_header(_hdr, _ns, _t) \
+ ((_t *)(_nlmsg_copy_next_header(_hdr, _ns, sizeof(_t))))
+
+static bool
+nlmsg_copy_nla(const struct nlattr *nla_orig, struct nl_writer *nw)
+{
+ struct nlattr *nla = nlmsg_reserve_data(nw, nla_orig->nla_len, struct nlattr);
+ if (nla != NULL) {
+ memcpy(nla, nla_orig, nla_orig->nla_len);
+ return (true);
+ }
+ return (false);
+}
+
+/*
+ * Translate a FreeBSD interface name to a Linux interface name.
+ */
+static bool
+nlmsg_translate_ifname_nla(struct nlattr *nla, struct nl_writer *nw)
+{
+ char ifname[LINUX_IFNAMSIZ];
+
+ if (ifname_bsd_to_linux_name((char *)(nla + 1), ifname,
+ sizeof(ifname)) <= 0)
+ return (false);
+ return (nlattr_add_string(nw, IFLA_IFNAME, ifname));
+}
+
+#define LINUX_NLA_UNHANDLED -1
+/*
+ * Translate a FreeBSD attribute to a Linux attribute.
+ * Returns LINUX_NLA_UNHANDLED when the attribute is not processed
+ * and the caller must take care of it, otherwise the result is returned.
+ */
+static int
+nlmsg_translate_all_nla(struct nlmsghdr *hdr, struct nlattr *nla,
+ struct nl_writer *nw)
+{
+
+ switch (hdr->nlmsg_type) {
+ case NL_RTM_NEWLINK:
+ case NL_RTM_DELLINK:
+ case NL_RTM_GETLINK:
+ switch (nla->nla_type) {
+ case IFLA_IFNAME:
+ return (nlmsg_translate_ifname_nla(nla, nw));
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+ return (LINUX_NLA_UNHANDLED);
+}
+
+static bool
+nlmsg_copy_all_nla(struct nlmsghdr *hdr, int raw_hdrlen, struct nl_writer *nw)
+{
+ struct nlattr *nla;
+ int ret;
+
+ int hdrlen = NETLINK_ALIGN(raw_hdrlen);
+ int attrs_len = hdr->nlmsg_len - sizeof(struct nlmsghdr) - hdrlen;
+ struct nlattr *nla_head = (struct nlattr *)((char *)(hdr + 1) + hdrlen);
+
+ NLA_FOREACH(nla, nla_head, attrs_len) {
+ RT_LOG(LOG_DEBUG3, "reading attr %d len %d", nla->nla_type, nla->nla_len);
+ if (nla->nla_len < sizeof(struct nlattr)) {
+ return (false);
+ }
+ ret = nlmsg_translate_all_nla(hdr, nla, nw);
+ if (ret == LINUX_NLA_UNHANDLED)
+ ret = nlmsg_copy_nla(nla, nw);
+ if (!ret)
+ return (false);
+ }
+ return (true);
+}
+#undef LINUX_NLA_UNHANDLED
+
+static unsigned int
+rtnl_if_flags_to_linux(unsigned int if_flags)
+{
+ unsigned int result = 0;
+
+ for (int i = 0; i < 31; i++) {
+ unsigned int flag = 1 << i;
+ if (!(flag & if_flags))
+ continue;
+ switch (flag) {
+ case IFF_UP:
+ case IFF_BROADCAST:
+ case IFF_DEBUG:
+ case IFF_LOOPBACK:
+ case IFF_POINTOPOINT:
+ case IFF_DRV_RUNNING:
+ case IFF_NOARP:
+ case IFF_PROMISC:
+ case IFF_ALLMULTI:
+ result |= flag;
+ break;
+ case IFF_NEEDSEPOCH:
+ case IFF_DRV_OACTIVE:
+ case IFF_SIMPLEX:
+ case IFF_LINK0:
+ case IFF_LINK1:
+ case IFF_LINK2:
+ case IFF_CANTCONFIG:
+ case IFF_PPROMISC:
+ case IFF_MONITOR:
+ case IFF_STATICARP:
+ case IFF_STICKYARP:
+ case IFF_DYING:
+ case IFF_RENAMING:
+ /* No Linux analogue */
+ break;
+ case IFF_MULTICAST:
+ result |= 1 << 12;
+ }
+ }
+ return (result);
+}
+
+static bool
+rtnl_newlink_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp,
+ struct nl_writer *nw)
+{
+ if (!nlmsg_copy_header(hdr, nw))
+ return (false);
+
+ struct ifinfomsg *ifinfo;
+ ifinfo = nlmsg_copy_next_header(hdr, nw, struct ifinfomsg);
+
+ ifinfo->ifi_family = bsd_to_linux_domain(ifinfo->ifi_family);
+ /* Convert interface type */
+ switch (ifinfo->ifi_type) {
+ case IFT_ETHER:
+ ifinfo->ifi_type = LINUX_ARPHRD_ETHER;
+ break;
+ }
+ ifinfo->ifi_flags = rtnl_if_flags_to_linux(ifinfo->ifi_flags);
+
+ /* Copy attributes unchanged */
+ if (!nlmsg_copy_all_nla(hdr, sizeof(struct ifinfomsg), nw))
+ return (false);
+
+ /* make ip(8) happy */
+ if (!nlattr_add_string(nw, IFLA_QDISC, "noqueue"))
+ return (false);
+
+ if (!nlattr_add_u32(nw, IFLA_TXQLEN, 1000))
+ return (false);
+
+ nlmsg_end(nw);
+ RT_LOG(LOG_DEBUG2, "done processing nw %p", nw);
+ return (true);
+}
+
+static bool
+rtnl_newaddr_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp,
+ struct nl_writer *nw)
+{
+ if (!nlmsg_copy_header(hdr, nw))
+ return (false);
+
+ struct ifaddrmsg *ifamsg;
+ ifamsg = nlmsg_copy_next_header(hdr, nw, struct ifaddrmsg);
+
+ ifamsg->ifa_family = bsd_to_linux_domain(ifamsg->ifa_family);
+ /* XXX: fake ifa_flags? */
+
+ /* Copy attributes unchanged */
+ if (!nlmsg_copy_all_nla(hdr, sizeof(struct ifaddrmsg), nw))
+ return (false);
+
+ nlmsg_end(nw);
+ RT_LOG(LOG_DEBUG2, "done processing nw %p", nw);
+ return (true);
+}
+
+static bool
+rtnl_newneigh_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp,
+ struct nl_writer *nw)
+{
+ if (!nlmsg_copy_header(hdr, nw))
+ return (false);
+
+ struct ndmsg *ndm;
+ ndm = nlmsg_copy_next_header(hdr, nw, struct ndmsg);
+
+ ndm->ndm_family = bsd_to_linux_domain(ndm->ndm_family);
+
+ /* Copy attributes unchanged */
+ if (!nlmsg_copy_all_nla(hdr, sizeof(struct ndmsg), nw))
+ return (false);
+
+ nlmsg_end(nw);
+ RT_LOG(LOG_DEBUG2, "done processing nw %p", nw);
+ return (true);
+}
+
+static bool
+rtnl_newroute_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp,
+ struct nl_writer *nw)
+{
+ if (!nlmsg_copy_header(hdr, nw))
+ return (false);
+
+ struct rtmsg *rtm;
+ rtm = nlmsg_copy_next_header(hdr, nw, struct rtmsg);
+ rtm->rtm_family = bsd_to_linux_domain(rtm->rtm_family);
+
+ struct nlattr *nla;
+
+ int hdrlen = NETLINK_ALIGN(sizeof(struct rtmsg));
+ int attrs_len = hdr->nlmsg_len - sizeof(struct nlmsghdr) - hdrlen;
+ struct nlattr *nla_head = (struct nlattr *)((char *)(hdr + 1) + hdrlen);
+
+ NLA_FOREACH(nla, nla_head, attrs_len) {
+ struct rtattr *rta = (struct rtattr *)nla;
+ //RT_LOG(LOG_DEBUG, "READING attr %d len %d", nla->nla_type, nla->nla_len);
+ if (rta->rta_len < sizeof(struct rtattr)) {
+ break;
+ }
+
+ switch (rta->rta_type) {
+ case NL_RTA_TABLE:
+ {
+ uint32_t fibnum;
+ fibnum = _rta_get_uint32(rta);
+ if (fibnum == 0)
+ fibnum = 254;
+ RT_LOG(LOG_DEBUG3, "XFIBNUM %u", fibnum);
+ if (!nlattr_add_u32(nw, NL_RTA_TABLE, fibnum))
+ return (false);
+ }
+ break;
+ default:
+ if (!nlmsg_copy_nla(nla, nw))
+ return (false);
+ break;
+ }
+ }
+
+ nlmsg_end(nw);
+ RT_LOG(LOG_DEBUG2, "done processing nw %p", nw);
+ return (true);
+}
+
+static bool
+rtnl_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_writer *nw)
+{
+ RT_LOG(LOG_DEBUG2, "Got message type %d", hdr->nlmsg_type);
+
+ switch (hdr->nlmsg_type) {
+ case NL_RTM_NEWLINK:
+ case NL_RTM_DELLINK:
+ case NL_RTM_GETLINK:
+ return (rtnl_newlink_to_linux(hdr, nlp, nw));
+ case NL_RTM_NEWADDR:
+ case NL_RTM_DELADDR:
+ return (rtnl_newaddr_to_linux(hdr, nlp, nw));
+ case NL_RTM_NEWROUTE:
+ case NL_RTM_DELROUTE:
+ return (rtnl_newroute_to_linux(hdr, nlp, nw));
+ case NL_RTM_NEWNEIGH:
+ case NL_RTM_DELNEIGH:
+ case NL_RTM_GETNEIGH:
+ return (rtnl_newneigh_to_linux(hdr, nlp, nw));
+ default:
+ RT_LOG(LOG_DEBUG, "[WARN] Passing message type %d untranslated",
+ hdr->nlmsg_type);
+ return (handle_default_out(hdr, nw));
+ }
+}
+
+static bool
+nlmsg_error_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_writer *nw)
+{
+ if (!nlmsg_copy_header(hdr, nw))
+ return (false);
+
+ struct nlmsgerr *nlerr;
+ nlerr = nlmsg_copy_next_header(hdr, nw, struct nlmsgerr);
+ nlerr->error = bsd_to_linux_errno(nlerr->error);
+
+ int copied_len = sizeof(struct nlmsghdr) + sizeof(struct nlmsgerr);
+ if (hdr->nlmsg_len == copied_len) {
+ nlmsg_end(nw);
+ return (true);
+ }
+
+ /*
+ * CAP_ACK was not set. Original request needs to be translated.
+ * XXX: implement translation of the original message
+ */
+ RT_LOG(LOG_DEBUG, "[WARN] Passing ack message type %d untranslated",
+ nlerr->msg.nlmsg_type);
+ char *dst_payload, *src_payload;
+ int copy_len = hdr->nlmsg_len - copied_len;
+ dst_payload = nlmsg_reserve_data(nw, NLMSG_ALIGN(copy_len), char);
+
+ src_payload = (char *)hdr + copied_len;
+
+ memcpy(dst_payload, src_payload, copy_len);
+ nlmsg_end(nw);
+
+ return (true);
+}
+
+static bool
+nlmsg_to_linux(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_writer *nw)
+{
+ if (hdr->nlmsg_type < NLMSG_MIN_TYPE) {
+ switch (hdr->nlmsg_type) {
+ case NLMSG_ERROR:
+ return (nlmsg_error_to_linux(hdr, nlp, nw));
+ case NLMSG_NOOP:
+ case NLMSG_DONE:
+ case NLMSG_OVERRUN:
+ return (handle_default_out(hdr, nw));
+ default:
+ RT_LOG(LOG_DEBUG, "[WARN] Passing message type %d untranslated",
+ hdr->nlmsg_type);
+ return (handle_default_out(hdr, nw));
+ }
+ }
+
+ switch (nlp->nl_proto) {
+ case NETLINK_ROUTE:
+ return (rtnl_to_linux(hdr, nlp, nw));
+ default:
+ return (handle_default_out(hdr, nw));
+ }
+}
+
+static bool
+nlmsgs_to_linux(struct nl_writer *nw, struct nlpcb *nlp)
+{
+ struct nl_buf *nb, *orig;
+ u_int offset, msglen, orig_messages;
+
+ RT_LOG(LOG_DEBUG3, "%p: in %u bytes %u messages", __func__,
+ nw->buf->datalen, nw->num_messages);
+
+ orig = nw->buf;
+ nb = nl_buf_alloc(orig->datalen + SCRATCH_BUFFER_SIZE, M_NOWAIT);
+ if (__predict_false(nb == NULL))
+ return (false);
+ nw->buf = nb;
+ orig_messages = nw->num_messages;
+ nw->num_messages = 0;
+
+ /* Assume correct headers. Buffer IS mutable */
+ for (offset = 0;
+ offset + sizeof(struct nlmsghdr) <= orig->datalen;
+ offset += msglen) {
+ struct nlmsghdr *hdr = (struct nlmsghdr *)&orig->data[offset];
+
+ msglen = NLMSG_ALIGN(hdr->nlmsg_len);
+ if (!nlmsg_to_linux(hdr, nlp, nw)) {
+ RT_LOG(LOG_DEBUG, "failed to process msg type %d",
+ hdr->nlmsg_type);
+ nl_buf_free(nb);
+ nw->buf = orig;
+ nw->num_messages = orig_messages;
+ return (false);
+ }
+ }
+
+ MPASS(nw->num_messages == orig_messages);
+ MPASS(nw->buf == nb);
+ nl_buf_free(orig);
+ RT_LOG(LOG_DEBUG3, "%p: out %u bytes", __func__, offset);
+
+ return (true);
+}
+
+static struct linux_netlink_provider linux_netlink_v1 = {
+ .msgs_to_linux = nlmsgs_to_linux,
+ .msg_from_linux = nlmsg_from_linux,
+};
+
+void
+linux_netlink_register(void)
+{
+ linux_netlink_p = &linux_netlink_v1;
+}
+
+void
+linux_netlink_deregister(void)
+{
+ linux_netlink_p = NULL;
+}
diff --git a/sys/compat/linux/linux_persona.h b/sys/compat/linux/linux_persona.h
index 7ae166aeb2cf..18aef6f02d76 100644
--- a/sys/compat/linux/linux_persona.h
+++ b/sys/compat/linux/linux_persona.h
@@ -1,6 +1,3 @@
-/*
- * $FreeBSD$
- */
#ifndef LINUX_PERSONALITY_H
#define LINUX_PERSONALITY_H
diff --git a/sys/compat/linux/linux_ptrace.c b/sys/compat/linux/linux_ptrace.c
index 151355d2bb3f..421760eab2a9 100644
--- a/sys/compat/linux/linux_ptrace.c
+++ b/sys/compat/linux/linux_ptrace.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2017 Edward Tomasz Napierala <trasz@FreeBSD.org>
*
@@ -29,9 +29,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/proc.h>
@@ -100,11 +97,6 @@ __FBSDID("$FreeBSD$");
#define LINUX_PTRACE_SYSCALL_INFO_ENTRY 1
#define LINUX_PTRACE_SYSCALL_INFO_EXIT 2
-#define LINUX_PTRACE_PEEKUSER_ORIG_RAX 120
-#define LINUX_PTRACE_PEEKUSER_RIP 128
-#define LINUX_PTRACE_PEEKUSER_CS 136
-#define LINUX_PTRACE_PEEKUSER_DS 184
-
static int
map_signum(int lsig, int *bsigp)
{
@@ -180,52 +172,6 @@ linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data)
}
static int
-linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data)
-{
- struct reg b_reg;
- uint64_t val;
- int error;
-
- error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
- if (error != 0)
- return (error);
-
- switch ((uintptr_t)addr) {
-#ifdef __amd64__
- case LINUX_PTRACE_PEEKUSER_ORIG_RAX:
- val = b_reg.r_rax;
- break;
- case LINUX_PTRACE_PEEKUSER_RIP:
- val = b_reg.r_rip;
- break;
- case LINUX_PTRACE_PEEKUSER_CS:
- val = b_reg.r_cs;
- break;
- case LINUX_PTRACE_PEEKUSER_DS:
- val = b_reg.r_ds;
- break;
-#endif /* __amd64__ */
- default:
- linux_msg(td, "PTRACE_PEEKUSER offset %ld not implemented; "
- "returning EINVAL", (uintptr_t)addr);
- return (EINVAL);
- }
-
- error = copyout(&val, data, sizeof(val));
- td->td_retval[0] = error;
-
- return (error);
-}
-
-static int
-linux_ptrace_pokeuser(struct thread *td, pid_t pid, void *addr, void *data)
-{
-
- linux_msg(td, "PTRACE_POKEUSER not implemented; returning EINVAL");
- return (EINVAL);
-}
-
-static int
linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data)
{
struct linux_pemuldata *pem;
diff --git a/sys/compat/linux/linux_rseq.c b/sys/compat/linux/linux_rseq.c
index 89bf526a4271..e8de17318d60 100644
--- a/sys/compat/linux/linux_rseq.c
+++ b/sys/compat/linux/linux_rseq.c
@@ -25,9 +25,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/systm.h>
diff --git a/sys/compat/linux/linux_siginfo.h b/sys/compat/linux/linux_siginfo.h
index b0c70e1b745e..f254b6a22bbd 100644
--- a/sys/compat/linux/linux_siginfo.h
+++ b/sys/compat/linux/linux_siginfo.h
@@ -29,8 +29,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUX_SIGINFO_H_
diff --git a/sys/compat/linux/linux_signal.c b/sys/compat/linux/linux_signal.c
index 09bcbcef4427..9a84700b3949 100644
--- a/sys/compat/linux/linux_signal.c
+++ b/sys/compat/linux/linux_signal.c
@@ -26,19 +26,15 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include "opt_ktrace.h"
#include <sys/param.h>
-#include <sys/systm.h>
#include <sys/ktr.h>
#include <sys/lock.h>
#include <sys/mutex.h>
-#include <sys/sx.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
+#include <sys/sx.h>
#include <sys/syscallsubr.h>
#include <sys/sysproto.h>
#ifdef KTRACE
@@ -47,8 +43,6 @@ __FBSDID("$FreeBSD$");
#include <security/audit/audit.h>
-#include "opt_compat.h"
-
#ifdef COMPAT_LINUX32
#include <machine/../linux32/linux.h>
#include <machine/../linux32/linux32_proto.h>
@@ -58,7 +52,7 @@ __FBSDID("$FreeBSD$");
#endif
#include <compat/linux/linux_mib.h>
#include <compat/linux/linux_signal.h>
-#include <compat/linux/linux_timer.h>
+#include <compat/linux/linux_time.h>
#include <compat/linux/linux_util.h>
#include <compat/linux/linux_emul.h>
#include <compat/linux/linux_misc.h>
@@ -176,6 +170,7 @@ linux_do_sigaction(struct thread *td, int linux_sig, l_sigaction_t *linux_nsa,
if (!LINUX_SIG_VALID(linux_sig))
return (EINVAL);
+ sig = linux_to_bsd_signal(linux_sig);
osa = (linux_osa != NULL) ? &oact : NULL;
if (linux_nsa != NULL) {
@@ -186,9 +181,11 @@ linux_do_sigaction(struct thread *td, int linux_sig, l_sigaction_t *linux_nsa,
linux_ktrsigset(&linux_nsa->lsa_mask,
sizeof(linux_nsa->lsa_mask));
#endif
+ if ((sig == SIGKILL || sig == SIGSTOP) &&
+ nsa->sa_handler == SIG_DFL)
+ return (EINVAL);
} else
nsa = NULL;
- sig = linux_to_bsd_signal(linux_sig);
error = kern_sigaction(td, sig, nsa, osa, 0);
if (error != 0)
@@ -772,14 +769,14 @@ siginfo_to_lsiginfo(const siginfo_t *si, l_siginfo_t *lsi, l_int sig)
}
}
-int
+static int
lsiginfo_to_siginfo(struct thread *td, const l_siginfo_t *lsi,
siginfo_t *si, int sig)
{
switch (lsi->lsi_code) {
case LINUX_SI_TKILL:
- if (linux_kernver(td) >= LINUX_KERNVER_2006039) {
+ if (linux_kernver(td) >= LINUX_KERNVER(2,6,39)) {
linux_msg(td, "SI_TKILL forbidden since 2.6.39");
return (EPERM);
}
diff --git a/sys/compat/linux/linux_signal.h b/sys/compat/linux/linux_signal.h
index aa385728efa6..3f3599f4027e 100644
--- a/sys/compat/linux/linux_signal.h
+++ b/sys/compat/linux/linux_signal.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2000 Marcel Moolenaar
* All rights reserved.
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUX_SIGNAL_H_
@@ -33,9 +31,7 @@
int linux_do_sigaction(struct thread *, int, l_sigaction_t *, l_sigaction_t *);
void siginfo_to_lsiginfo(const siginfo_t *si, l_siginfo_t *lsi, l_int sig);
-int lsiginfo_to_siginfo(struct thread *td, const l_siginfo_t *lsi,
- siginfo_t *si, int sig);
int linux_copyin_sigset(struct thread *td, l_sigset_t *, l_size_t, sigset_t *,
- sigset_t **);
+ sigset_t **);
#endif /* _LINUX_SIGNAL_H_ */
diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c
index 9434e40709bb..1e578982fced 100644
--- a/sys/compat/linux/linux_socket.c
+++ b/sys/compat/linux/linux_socket.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1995 Søren Schmidt
* All rights reserved.
@@ -26,32 +26,21 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-/* XXX we use functions that might not exist. */
-#include "opt_compat.h"
#include "opt_inet6.h"
#include <sys/param.h>
-#include <sys/proc.h>
-#include <sys/systm.h>
-#include <sys/sysproto.h>
#include <sys/capsicum.h>
-#include <sys/fcntl.h>
-#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/limits.h>
-#include <sys/lock.h>
#include <sys/malloc.h>
-#include <sys/mutex.h>
#include <sys/mbuf.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/syscallsubr.h>
-#include <sys/uio.h>
-#include <sys/stat.h>
-#include <sys/syslog.h>
+#include <sys/sysproto.h>
+#include <sys/vnode.h>
#include <sys/un.h>
#include <sys/unistd.h>
@@ -60,7 +49,6 @@ __FBSDID("$FreeBSD$");
#include <net/if.h>
#include <net/vnet.h>
#include <netinet/in.h>
-#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#ifdef INET6
@@ -69,6 +57,7 @@ __FBSDID("$FreeBSD$");
#endif
#ifdef COMPAT_LINUX32
+#include <compat/freebsd32/freebsd32_util.h>
#include <machine/../linux32/linux.h>
#include <machine/../linux32/linux32_proto.h>
#else
@@ -80,9 +69,19 @@ __FBSDID("$FreeBSD$");
#include <compat/linux/linux_file.h>
#include <compat/linux/linux_mib.h>
#include <compat/linux/linux_socket.h>
-#include <compat/linux/linux_timer.h>
+#include <compat/linux/linux_time.h>
#include <compat/linux/linux_util.h>
+_Static_assert(offsetof(struct l_ifreq, ifr_ifru) ==
+ offsetof(struct ifreq, ifr_ifru),
+ "Linux ifreq members names should be equal to FreeeBSD");
+_Static_assert(offsetof(struct l_ifreq, ifr_index) ==
+ offsetof(struct ifreq, ifr_index),
+ "Linux ifreq members names should be equal to FreeeBSD");
+_Static_assert(offsetof(struct l_ifreq, ifr_name) ==
+ offsetof(struct ifreq, ifr_name),
+ "Linux ifreq members names should be equal to FreeeBSD");
+
#define SECURITY_CONTEXT_STRING "unconfined"
static int linux_sendmsg_common(struct thread *, l_int, struct l_msghdr *,
@@ -91,6 +90,8 @@ static int linux_recvmsg_common(struct thread *, l_int, struct l_msghdr *,
l_uint, struct msghdr *);
static int linux_set_socket_flags(int, int *);
+#define SOL_NETLINK 270
+
static int
linux_to_bsd_sockopt_level(int level)
{
@@ -869,7 +870,8 @@ static const char *linux_netlink_names[] = {
int
linux_socket(struct thread *td, struct linux_socket_args *args)
{
- int domain, retval_socket, type;
+ int retval_socket, type;
+ sa_family_t domain;
type = args->type & LINUX_SOCK_TYPE_MASK;
if (type < 0 || type > LINUX_SOCK_MAX)
@@ -879,7 +881,7 @@ linux_socket(struct thread *td, struct linux_socket_args *args)
if (retval_socket != 0)
return (retval_socket);
domain = linux_to_bsd_domain(args->domain);
- if (domain == -1) {
+ if (domain == AF_UNKNOWN) {
/* Mask off SOCK_NONBLOCK / CLOEXEC for error messages. */
type = args->type & LINUX_SOCK_TYPE_MASK;
if (args->domain == LINUX_AF_NETLINK &&
@@ -970,7 +972,6 @@ linux_connect(struct thread *td, struct linux_connect_args *args)
struct socket *so;
struct sockaddr *sa;
struct file *fp;
- u_int fflag;
int error;
error = linux_to_bsd_sockaddr(PTRIN(args->name), &sa,
@@ -988,14 +989,13 @@ linux_connect(struct thread *td, struct linux_connect_args *args)
* when on a non-blocking socket. Instead it returns the
* error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
*/
- error = getsock_cap(td, args->s, &cap_connect_rights,
- &fp, &fflag, NULL);
+ error = getsock(td, args->s, &cap_connect_rights, &fp);
if (error != 0)
return (error);
error = EISCONN;
so = fp->f_data;
- if (fflag & FNONBLOCK) {
+ if (atomic_load_int(&fp->f_flag) & FNONBLOCK) {
SOCK_LOCK(so);
if (so->so_emuldata == 0)
error = so->so_error;
@@ -1018,31 +1018,29 @@ static int
linux_accept_common(struct thread *td, int s, l_uintptr_t addr,
l_uintptr_t namelen, int flags)
{
- struct sockaddr *sa;
+ struct sockaddr_storage ss = { .ss_len = sizeof(ss) };
struct file *fp, *fp1;
- int bflags, len;
struct socket *so;
- int error, error1;
+ socklen_t len;
+ int bflags, error, error1;
bflags = 0;
fp = NULL;
- sa = NULL;
error = linux_set_socket_flags(flags, &bflags);
if (error != 0)
return (error);
- if (PTRIN(addr) == NULL) {
- len = 0;
- error = kern_accept4(td, s, NULL, NULL, bflags, NULL);
- } else {
+ if (PTRIN(addr) != NULL) {
error = copyin(PTRIN(namelen), &len, sizeof(len));
if (error != 0)
return (error);
if (len < 0)
return (EINVAL);
- error = kern_accept4(td, s, &sa, &len, bflags, &fp);
- }
+ } else
+ len = 0;
+
+ error = kern_accept4(td, s, (struct sockaddr *)&ss, bflags, &fp);
/*
* Translate errno values into ones used by Linux.
@@ -1058,7 +1056,7 @@ linux_accept_common(struct thread *td, int s, l_uintptr_t addr,
error = EINVAL;
break;
case EINVAL:
- error1 = getsock_cap(td, s, &cap_accept_rights, &fp1, NULL, NULL);
+ error1 = getsock(td, s, &cap_accept_rights, &fp1);
if (error1 != 0) {
error = error1;
break;
@@ -1072,11 +1070,14 @@ linux_accept_common(struct thread *td, int s, l_uintptr_t addr,
return (error);
}
- if (len != 0) {
- error = linux_copyout_sockaddr(sa, PTRIN(addr), len);
- if (error == 0)
- error = copyout(&len, PTRIN(namelen),
- sizeof(len));
+ if (PTRIN(addr) != NULL) {
+ len = min(ss.ss_len, len);
+ error = linux_copyout_sockaddr((struct sockaddr *)&ss,
+ PTRIN(addr), len);
+ if (error == 0) {
+ len = ss.ss_len;
+ error = copyout(&len, PTRIN(namelen), sizeof(len));
+ }
if (error != 0) {
fdclose(td, fp, td->td_retval[0]);
td->td_retval[0] = 0;
@@ -1084,7 +1085,6 @@ linux_accept_common(struct thread *td, int s, l_uintptr_t addr,
}
if (fp != NULL)
fdrop(fp, td);
- free(sa, M_SONAME);
return (error);
}
@@ -1107,48 +1107,50 @@ linux_accept4(struct thread *td, struct linux_accept4_args *args)
int
linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
{
- struct sockaddr *sa;
- int len, error;
+ struct sockaddr_storage ss = { .ss_len = sizeof(ss) };
+ socklen_t len;
+ int error;
error = copyin(PTRIN(args->namelen), &len, sizeof(len));
if (error != 0)
return (error);
- error = kern_getsockname(td, args->s, &sa, &len);
+ error = kern_getsockname(td, args->s, (struct sockaddr *)&ss);
if (error != 0)
return (error);
- if (len != 0)
- error = linux_copyout_sockaddr(sa, PTRIN(args->addr), len);
-
- free(sa, M_SONAME);
- if (error == 0)
+ len = min(ss.ss_len, len);
+ error = linux_copyout_sockaddr((struct sockaddr *)&ss,
+ PTRIN(args->addr), len);
+ if (error == 0) {
+ len = ss.ss_len;
error = copyout(&len, PTRIN(args->namelen), sizeof(len));
+ }
return (error);
}
int
linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
{
- struct sockaddr *sa;
- int len, error;
+ struct sockaddr_storage ss = { .ss_len = sizeof(ss) };
+ socklen_t len;
+ int error;
error = copyin(PTRIN(args->namelen), &len, sizeof(len));
if (error != 0)
return (error);
- if (len < 0)
- return (EINVAL);
- error = kern_getpeername(td, args->s, &sa, &len);
+ error = kern_getpeername(td, args->s, (struct sockaddr *)&ss);
if (error != 0)
return (error);
- if (len != 0)
- error = linux_copyout_sockaddr(sa, PTRIN(args->addr), len);
-
- free(sa, M_SONAME);
- if (error == 0)
+ len = min(ss.ss_len, len);
+ error = linux_copyout_sockaddr((struct sockaddr *)&ss,
+ PTRIN(args->addr), len);
+ if (error == 0) {
+ len = ss.ss_len;
error = copyout(&len, PTRIN(args->namelen), sizeof(len));
+ }
return (error);
}
@@ -1207,7 +1209,7 @@ linux_send(struct thread *td, struct linux_send_args *args)
int tolen;
} */ bsd_args;
struct file *fp;
- int error, fflag;
+ int error;
bsd_args.s = args->s;
bsd_args.buf = (caddr_t)PTRIN(args->msg);
@@ -1221,10 +1223,9 @@ linux_send(struct thread *td, struct linux_send_args *args)
* Linux doesn't return ENOTCONN for non-blocking sockets.
* Instead it returns the EAGAIN.
*/
- error = getsock_cap(td, args->s, &cap_send_rights, &fp,
- &fflag, NULL);
+ error = getsock(td, args->s, &cap_send_rights, &fp);
if (error == 0) {
- if (fflag & FNONBLOCK)
+ if (atomic_load_int(&fp->f_flag) & FNONBLOCK)
error = EAGAIN;
fdrop(fp, td);
}
@@ -1275,8 +1276,7 @@ linux_sendto(struct thread *td, struct linux_sendto_args *args)
return (linux_sendto_hdrincl(td, args));
bzero(&msg, sizeof(msg));
- error = getsock_cap(td, args->s, &cap_send_connect_rights,
- &fp, NULL, NULL);
+ error = getsock(td, args->s, &cap_send_connect_rights, &fp);
if (error != 0)
return (error);
so = fp->f_data;
@@ -1351,6 +1351,7 @@ static int
linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
l_uint flags)
{
+ struct sockaddr_storage ss = { .ss_len = sizeof(ss) };
struct cmsghdr *cmsg;
struct mbuf *control;
struct msghdr msg;
@@ -1359,14 +1360,13 @@ linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
struct l_msghdr linux_msghdr;
struct iovec *iov;
socklen_t datalen;
- struct sockaddr *sa;
struct socket *so;
sa_family_t sa_family;
struct file *fp;
void *data;
l_size_t len;
l_size_t clen;
- int error, fflag;
+ int error;
error = copyin(msghdr, &linux_msghdr, sizeof(linux_msghdr));
if (error != 0)
@@ -1388,7 +1388,7 @@ linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
return (error);
#ifdef COMPAT_LINUX32
- error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
+ error = freebsd32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
&iov, EMSGSIZE);
#else
error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
@@ -1398,19 +1398,17 @@ linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
control = NULL;
- error = kern_getsockname(td, s, &sa, &datalen);
+ error = kern_getsockname(td, s, (struct sockaddr *)&ss);
if (error != 0)
goto bad;
- sa_family = sa->sa_family;
- free(sa, M_SONAME);
+ sa_family = ss.ss_family;
if (flags & LINUX_MSG_OOB) {
error = EOPNOTSUPP;
if (sa_family == AF_UNIX)
goto bad;
- error = getsock_cap(td, s, &cap_send_rights, &fp,
- &fflag, NULL);
+ error = getsock(td, s, &cap_send_rights, &fp);
if (error != 0)
goto bad;
so = fp->f_data;
@@ -1704,6 +1702,39 @@ _Static_assert(sizeof(struct bintime) >= sizeof(struct timespec),
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
static int
+recvmsg_scm_sol_socket(struct thread *td, l_int msg_type, l_int lmsg_type,
+ l_uint flags, socklen_t *datalen, void **data, void **udata)
+{
+ int error;
+
+ error = 0;
+ switch (msg_type) {
+ case SCM_RIGHTS:
+ error = recvmsg_scm_rights(td, flags, datalen,
+ data, udata);
+ break;
+ case SCM_CREDS:
+ error = recvmsg_scm_creds(datalen, data, udata);
+ break;
+ case SCM_CREDS2:
+ error = recvmsg_scm_creds2(datalen, data, udata);
+ break;
+ case SCM_TIMESTAMP:
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+ error = recvmsg_scm_timestamp(lmsg_type, datalen,
+ data, udata);
+#endif
+ break;
+ case SCM_BINTIME:
+ error = recvmsg_scm_timestampns(lmsg_type, datalen,
+ data, udata);
+ break;
+ }
+
+ return (error);
+}
+
+static int
recvmsg_scm_ip_origdstaddr(socklen_t *datalen, void **data, void **udata)
{
struct l_sockaddr *lsa;
@@ -1718,6 +1749,23 @@ recvmsg_scm_ip_origdstaddr(socklen_t *datalen, void **data, void **udata)
}
static int
+recvmsg_scm_ipproto_ip(l_int msg_type, l_int lmsg_type, socklen_t *datalen,
+ void **data, void **udata)
+{
+ int error;
+
+ error = 0;
+ switch (msg_type) {
+ case IP_ORIGDSTADDR:
+ error = recvmsg_scm_ip_origdstaddr(datalen, data,
+ udata);
+ break;
+ }
+
+ return (error);
+}
+
+static int
linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
l_uint flags, struct msghdr *msg)
{
@@ -1732,7 +1780,7 @@ linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
struct sockaddr *sa;
caddr_t outbuf;
void *data, *udata;
- int error;
+ int error, skiped;
error = copyin(msghdr, &l_msghdr, sizeof(l_msghdr));
if (error != 0)
@@ -1749,7 +1797,7 @@ linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
return (error);
#ifdef COMPAT_LINUX32
- error = linux32_copyiniov(PTRIN(msg->msg_iov), msg->msg_iovlen,
+ error = freebsd32_copyiniov(PTRIN(msg->msg_iov), msg->msg_iovlen,
&iov, EMSGSIZE);
#else
error = copyiniov(msg->msg_iov, msg->msg_iovlen, &iov, EMSGSIZE);
@@ -1789,8 +1837,8 @@ linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
if (error != 0)
goto bad;
+ skiped = outlen = 0;
maxlen = l_msghdr.msg_controllen;
- l_msghdr.msg_controllen = 0;
if (control == NULL)
goto out;
@@ -1798,61 +1846,38 @@ linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
msg->msg_control = mtod(control, struct cmsghdr *);
msg->msg_controllen = control->m_len;
outbuf = PTRIN(l_msghdr.msg_control);
- outlen = 0;
for (m = control; m != NULL; m = m->m_next) {
cm = mtod(m, struct cmsghdr *);
lcm->cmsg_type = bsd_to_linux_cmsg_type(p, cm->cmsg_type,
cm->cmsg_level);
lcm->cmsg_level = bsd_to_linux_sockopt_level(cm->cmsg_level);
- data = CMSG_DATA(cm);
- datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
- udata = NULL;
- error = 0;
-
- /* Process non SOL_SOCKET types. */
- if (cm->cmsg_level == IPPROTO_IP &&
- lcm->cmsg_type == LINUX_IP_ORIGDSTADDR) {
- error = recvmsg_scm_ip_origdstaddr(&datalen, &data, &udata);
- goto cont;
- }
-
if (lcm->cmsg_type == -1 ||
- cm->cmsg_level != SOL_SOCKET) {
+ cm->cmsg_level == -1) {
LINUX_RATELIMIT_MSG_OPT2(
"unsupported recvmsg cmsg level %d type %d",
cm->cmsg_level, cm->cmsg_type);
- error = EINVAL;
- goto bad;
- }
-
-
- switch (cm->cmsg_type) {
- case SCM_RIGHTS:
- error = recvmsg_scm_rights(td, flags,
- &datalen, &data, &udata);
- break;
- case SCM_CREDS:
- error = recvmsg_scm_creds(&datalen,
- &data, &udata);
- break;
- case SCM_CREDS2:
- error = recvmsg_scm_creds2(&datalen,
- &data, &udata);
- break;
- case SCM_TIMESTAMP:
-#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
- error = recvmsg_scm_timestamp(lcm->cmsg_type,
- &datalen, &data, &udata);
-#endif
- break;
- case SCM_BINTIME:
- error = recvmsg_scm_timestampns(lcm->cmsg_type,
- &datalen, &data, &udata);
- break;
+ /* Skip unsupported messages */
+ skiped++;
+ continue;
}
+ data = CMSG_DATA(cm);
+ datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
+ udata = NULL;
+ error = 0;
-cont:
+ switch (cm->cmsg_level) {
+ case IPPROTO_IP:
+ error = recvmsg_scm_ipproto_ip(cm->cmsg_type,
+ lcm->cmsg_type, &datalen, &data, &udata);
+ break;
+ case SOL_SOCKET:
+ error = recvmsg_scm_sol_socket(td, cm->cmsg_type,
+ lcm->cmsg_type, flags, &datalen, &data, &udata);
+ break;
+ }
+
+ /* The recvmsg_scm_ is responsible to free udata on error. */
if (error != 0)
goto bad;
@@ -1871,11 +1896,10 @@ cont:
lcm->cmsg_len = LINUX_CMSG_LEN(datalen);
error = copyout(lcm, outbuf, L_CMSG_HDRSZ);
if (error == 0) {
- outbuf += L_CMSG_HDRSZ;
- error = copyout(data, outbuf, datalen);
+ error = copyout(data, LINUX_CMSG_DATA(outbuf), datalen);
if (error == 0) {
- outbuf += LINUX_CMSG_ALIGN(datalen);
- outlen += LINUX_CMSG_LEN(datalen);
+ outbuf += LINUX_CMSG_SPACE(datalen);
+ outlen += LINUX_CMSG_SPACE(datalen);
}
}
err:
@@ -1883,9 +1907,13 @@ err:
if (error != 0)
goto bad;
}
- l_msghdr.msg_controllen = outlen;
+ if (outlen == 0 && skiped > 0) {
+ error = EINVAL;
+ goto bad;
+ }
out:
+ l_msghdr.msg_controllen = outlen;
error = copyout(&l_msghdr, msghdr, sizeof(l_msghdr));
bad:
@@ -1908,8 +1936,7 @@ linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
struct file *fp;
int error;
- error = getsock_cap(td, args->s, &cap_recv_rights,
- &fp, NULL, NULL);
+ error = getsock(td, args->s, &cap_recv_rights, &fp);
if (error != 0)
return (error);
fdrop(fp, td);
@@ -1927,8 +1954,7 @@ linux_recvmmsg_common(struct thread *td, l_int s, struct l_mmsghdr *msg,
l_uint retval;
int error, datagrams;
- error = getsock_cap(td, s, &cap_recv_rights,
- &fp, NULL, NULL);
+ error = getsock(td, s, &cap_recv_rights, &fp);
if (error != 0)
return (error);
datagrams = 0;
@@ -2091,6 +2117,9 @@ linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
case IPPROTO_TCP:
name = linux_to_bsd_tcp_sockopt(args->optname);
break;
+ case SOL_NETLINK:
+ name = args->optname;
+ break;
default:
name = -1;
break;
@@ -2281,8 +2310,8 @@ linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
name, &newval, UIO_SYSSPACE, &len);
if (error != 0)
return (error);
- newval = bsd_to_linux_domain(newval);
- if (newval == -1)
+ newval = bsd_to_linux_domain((sa_family_t)newval);
+ if (newval == AF_UNKNOWN)
return (ENOPROTOOPT);
return (linux_sockopt_copyout(td, &newval,
len, args));
@@ -2348,57 +2377,210 @@ out:
return (error);
}
+/*
+ * Based on sendfile_getsock from kern_sendfile.c
+ * Determines whether an fd is a stream socket that can be used
+ * with FreeBSD sendfile.
+ */
+static bool
+is_sendfile(struct file *fp, struct file *ofp)
+{
+ struct socket *so;
+
+ /*
+ * FreeBSD sendfile() system call sends a regular file or
+ * shared memory object out a stream socket.
+ */
+ if ((fp->f_type != DTYPE_SHM && fp->f_type != DTYPE_VNODE) ||
+ (fp->f_type == DTYPE_VNODE &&
+ (fp->f_vnode == NULL || fp->f_vnode->v_type != VREG)))
+ return (false);
+ /*
+ * The socket must be a stream socket and connected.
+ */
+ if (ofp->f_type != DTYPE_SOCKET)
+ return (false);
+ so = ofp->f_data;
+ if (so->so_type != SOCK_STREAM)
+ return (false);
+ /*
+ * SCTP one-to-one style sockets currently don't work with
+ * sendfile().
+ */
+ if (so->so_proto->pr_protocol == IPPROTO_SCTP)
+ return (false);
+ return (!SOLISTENING(so));
+}
+
+static bool
+is_regular_file(struct file *fp)
+{
+
+ return (fp->f_type == DTYPE_VNODE && fp->f_vnode != NULL &&
+ fp->f_vnode->v_type == VREG);
+}
+
static int
-linux_sendfile_common(struct thread *td, l_int out, l_int in,
- l_loff_t *offset, l_size_t count)
+sendfile_fallback(struct thread *td, struct file *fp, l_int out,
+ off_t *offset, l_size_t count, off_t *sbytes)
{
- off_t bytes_read;
- int error;
- l_loff_t current_offset;
- struct file *fp;
+ off_t current_offset, out_offset, to_send;
+ l_size_t bytes_sent, n_read;
+ struct file *ofp;
+ struct iovec aiov;
+ struct uio auio;
+ bool seekable;
+ size_t bufsz;
+ void *buf;
+ int flags, error;
- AUDIT_ARG_FD(in);
- error = fget_read(td, in, &cap_pread_rights, &fp);
+ if (offset == NULL) {
+ if ((error = fo_seek(fp, 0, SEEK_CUR, td)) != 0)
+ return (error);
+ current_offset = td->td_uretoff.tdu_off;
+ } else {
+ if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0)
+ return (ESPIPE);
+ current_offset = *offset;
+ }
+ error = fget_write(td, out, &cap_pwrite_rights, &ofp);
if (error != 0)
return (error);
-
- if (offset != NULL) {
- current_offset = *offset;
- } else {
- error = (fp->f_ops->fo_flags & DFLAG_SEEKABLE) != 0 ?
- fo_seek(fp, 0, SEEK_CUR, td) : ESPIPE;
- if (error != 0)
+ seekable = (ofp->f_ops->fo_flags & DFLAG_SEEKABLE) != 0;
+ if (seekable) {
+ if ((error = fo_seek(ofp, 0, SEEK_CUR, td)) != 0)
goto drop;
+ out_offset = td->td_uretoff.tdu_off;
+ } else
+ out_offset = 0;
+
+ flags = FOF_OFFSET | FOF_NOUPDATE;
+ bufsz = min(count, MAXPHYS);
+ buf = malloc(bufsz, M_LINUX, M_WAITOK);
+ bytes_sent = 0;
+ while (bytes_sent < count) {
+ to_send = min(count - bytes_sent, bufsz);
+ aiov.iov_base = buf;
+ aiov.iov_len = bufsz;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_segflg = UIO_SYSSPACE;
+ auio.uio_td = td;
+ auio.uio_rw = UIO_READ;
+ auio.uio_offset = current_offset;
+ auio.uio_resid = to_send;
+ error = fo_read(fp, &auio, fp->f_cred, flags, td);
+ if (error != 0)
+ break;
+ n_read = to_send - auio.uio_resid;
+ if (n_read == 0)
+ break;
+ aiov.iov_base = buf;
+ aiov.iov_len = bufsz;
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_segflg = UIO_SYSSPACE;
+ auio.uio_td = td;
+ auio.uio_rw = UIO_WRITE;
+ auio.uio_offset = (seekable) ? out_offset : 0;
+ auio.uio_resid = n_read;
+ error = fo_write(ofp, &auio, ofp->f_cred, flags, td);
+ if (error != 0)
+ break;
+ bytes_sent += n_read;
+ current_offset += n_read;
+ out_offset += n_read;
+ }
+ free(buf, M_LINUX);
+
+ if (error == 0) {
+ *sbytes = bytes_sent;
+ if (offset != NULL)
+ *offset = current_offset;
+ else
+ error = fo_seek(fp, current_offset, SEEK_SET, td);
+ }
+ if (error == 0 && seekable)
+ error = fo_seek(ofp, out_offset, SEEK_SET, td);
+
+drop:
+ fdrop(ofp, td);
+ return (error);
+}
+
+static int
+sendfile_sendfile(struct thread *td, struct file *fp, l_int out,
+ off_t *offset, l_size_t count, off_t *sbytes)
+{
+ off_t current_offset;
+ int error;
+
+ if (offset == NULL) {
+ if ((fp->f_ops->fo_flags & DFLAG_SEEKABLE) == 0)
+ return (ESPIPE);
+ if ((error = fo_seek(fp, 0, SEEK_CUR, td)) != 0)
+ return (error);
current_offset = td->td_uretoff.tdu_off;
+ } else
+ current_offset = *offset;
+ error = fo_sendfile(fp, out, NULL, NULL, current_offset, count,
+ sbytes, 0, td);
+ if (error == 0) {
+ current_offset += *sbytes;
+ if (offset != NULL)
+ *offset = current_offset;
+ else
+ error = fo_seek(fp, current_offset, SEEK_SET, td);
}
+ return (error);
+}
- bytes_read = 0;
+static int
+linux_sendfile_common(struct thread *td, l_int out, l_int in,
+ off_t *offset, l_size_t count)
+{
+ struct file *fp, *ofp;
+ off_t sbytes;
+ int error;
/* Linux cannot have 0 count. */
- if (count <= 0 || current_offset < 0) {
+ if (count <= 0 || (offset != NULL && *offset < 0))
+ return (EINVAL);
+
+ AUDIT_ARG_FD(in);
+ error = fget_read(td, in, &cap_pread_rights, &fp);
+ if (error != 0)
+ return (error);
+ if ((fp->f_type != DTYPE_SHM && fp->f_type != DTYPE_VNODE) ||
+ (fp->f_type == DTYPE_VNODE &&
+ (fp->f_vnode == NULL || fp->f_vnode->v_type != VREG))) {
error = EINVAL;
goto drop;
}
-
- error = fo_sendfile(fp, out, NULL, NULL, current_offset, count,
- &bytes_read, 0, td);
+ error = fget_unlocked(td, out, &cap_no_rights, &ofp);
if (error != 0)
goto drop;
- current_offset += bytes_read;
- if (offset != NULL) {
- *offset = current_offset;
+ if (is_regular_file(fp) && is_regular_file(ofp)) {
+ error = kern_copy_file_range(td, in, offset, out, NULL, count,
+ 0);
} else {
- error = fo_seek(fp, current_offset, SEEK_SET, td);
- if (error != 0)
- goto drop;
+ sbytes = 0;
+ if (is_sendfile(fp, ofp))
+ error = sendfile_sendfile(td, fp, out, offset, count,
+ &sbytes);
+ else
+ error = sendfile_fallback(td, fp, out, offset, count,
+ &sbytes);
+ if (error == ENOBUFS && (ofp->f_flag & FNONBLOCK) != 0)
+ error = EAGAIN;
+ if (error == 0)
+ td->td_retval[0] = sbytes;
}
+ fdrop(ofp, td);
- td->td_retval[0] = (ssize_t)bytes_read;
drop:
fdrop(fp, td);
- if (error == ENOTSOCK)
- error = EINVAL;
return (error);
}
@@ -2408,10 +2590,10 @@ linux_sendfile(struct thread *td, struct linux_sendfile_args *arg)
/*
* Differences between FreeBSD and Linux sendfile:
* - Linux doesn't send anything when count is 0 (FreeBSD uses 0 to
- * mean send the whole file.) In linux_sendfile given fds are still
- * checked for validity when the count is 0.
+ * mean send the whole file).
* - Linux can send to any fd whereas FreeBSD only supports sockets.
- * The same restriction follows for linux_sendfile.
+ * We therefore use FreeBSD sendfile where possible for performance,
+ * but fall back on a manual copy (sendfile_fallback).
* - Linux doesn't have an equivalent for FreeBSD's flags and sf_hdtr.
* - Linux takes an offset pointer and updates it to the read location.
* FreeBSD takes in an offset and a 'bytes read' parameter which is
@@ -2421,44 +2603,37 @@ linux_sendfile(struct thread *td, struct linux_sendfile_args *arg)
* returns 0. We use the 'bytes read' parameter to get this value.
*/
- l_loff_t offset64;
- l_long offset;
- int ret;
+ off_t offset64;
+ l_off_t offset;
int error;
if (arg->offset != NULL) {
error = copyin(arg->offset, &offset, sizeof(offset));
if (error != 0)
return (error);
- offset64 = (l_loff_t)offset;
+ offset64 = offset;
}
- ret = linux_sendfile_common(td, arg->out, arg->in,
+ error = linux_sendfile_common(td, arg->out, arg->in,
arg->offset != NULL ? &offset64 : NULL, arg->count);
- if (arg->offset != NULL) {
-#if defined(__i386__) || defined(__arm__) || \
- (defined(__amd64__) && defined(COMPAT_LINUX32))
+ if (error == 0 && arg->offset != NULL) {
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
if (offset64 > INT32_MAX)
return (EOVERFLOW);
#endif
- offset = (l_long)offset64;
+ offset = (l_off_t)offset64;
error = copyout(&offset, arg->offset, sizeof(offset));
- if (error != 0)
- return (error);
}
- return (ret);
+ return (error);
}
-#if defined(__i386__) || defined(__arm__) || \
- (defined(__amd64__) && defined(COMPAT_LINUX32))
-
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
int
linux_sendfile64(struct thread *td, struct linux_sendfile64_args *arg)
{
- l_loff_t offset;
- int ret;
+ off_t offset;
int error;
if (arg->offset != NULL) {
@@ -2467,16 +2642,13 @@ linux_sendfile64(struct thread *td, struct linux_sendfile64_args *arg)
return (error);
}
- ret = linux_sendfile_common(td, arg->out, arg->in,
+ error = linux_sendfile_common(td, arg->out, arg->in,
arg->offset != NULL ? &offset : NULL, arg->count);
- if (arg->offset != NULL) {
+ if (error == 0 && arg->offset != NULL)
error = copyout(&offset, arg->offset, sizeof(offset));
- if (error != 0)
- return (error);
- }
- return (ret);
+ return (error);
}
/* Argument list sizes for linux_socketcall */
@@ -2567,4 +2739,4 @@ linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
linux_msg(td, "socket type %d not implemented", args->what);
return (ENOSYS);
}
-#endif /* __i386__ || __arm__ || (__amd64__ && COMPAT_LINUX32) */
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
diff --git a/sys/compat/linux/linux_socket.h b/sys/compat/linux/linux_socket.h
index 74b96fbb9c11..68176c3cc401 100644
--- a/sys/compat/linux/linux_socket.h
+++ b/sys/compat/linux/linux_socket.h
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUX_SOCKET_H_
@@ -126,8 +124,7 @@ struct l_ucred {
uint32_t gid;
};
-#if defined(__i386__) || defined(__arm__) || \
- (defined(__amd64__) && defined(COMPAT_LINUX32))
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
struct linux_accept_args {
register_t s;
@@ -160,7 +157,7 @@ int linux_accept(struct thread *td, struct linux_accept_args *args);
#define LINUX_SENDMMSG 20
#define LINUX_SENDFILE 21
-#endif /* __i386__ || __arm__ || (__amd64__ && COMPAT_LINUX32) */
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
/* Socket defines */
#define LINUX_SOL_SOCKET 1
@@ -326,4 +323,42 @@ int linux_accept(struct thread *td, struct linux_accept_args *args);
#define LINUX_TCP_INFO 11
#define LINUX_TCP_MD5SIG 14
+struct l_ifmap {
+ l_ulong mem_start;
+ l_ulong mem_end;
+ l_ushort base_addr;
+ u_char irq;
+ u_char dma;
+ u_char port;
+ /* 3 bytes spare */
+};
+
+/*
+ * Careful changing the declaration of this structure.
+ * To use FreeBSD names to access the struct l_ifreq members the
+ * member names of struct l_ifreq should be equal to the FreeBSD.
+ */
+struct l_ifreq {
+ char ifr_name[LINUX_IFNAMSIZ];
+ union {
+ struct l_sockaddr ifru_addr;
+ struct l_sockaddr ifru_dstaddr;
+ struct l_sockaddr ifru_broadaddr;
+ struct l_sockaddr ifru_netmask;
+ struct l_sockaddr ifru_hwaddr;
+ l_short ifru_flags[1];
+ l_int ifru_index;
+ l_int ifru_mtu;
+ struct l_ifmap ifru_map;
+ char ifru_slave[LINUX_IFNAMSIZ];
+ char ifru_newname[LINUX_IFNAMSIZ];
+ l_uintptr_t ifru_data;
+ } ifr_ifru;
+};
+
+/*
+ * Define here members which are not exists in the FreeBSD struct ifreq.
+ */
+#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
+
#endif /* _LINUX_SOCKET_H_ */
diff --git a/sys/compat/linux/linux_stats.c b/sys/compat/linux/linux_stats.c
index fb2dd2fe01ef..6c032cc569f8 100644
--- a/sys/compat/linux/linux_stats.c
+++ b/sys/compat/linux/linux_stats.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1994-1995 Søren Schmidt
* All rights reserved.
@@ -26,27 +26,25 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_compat.h"
+#include "opt_ktrace.h"
#include <sys/param.h>
#include <sys/capsicum.h>
#include <sys/dirent.h>
-#include <sys/file.h>
-#include <sys/filedesc.h>
-#include <sys/proc.h>
+#include <sys/lock.h>
#include <sys/malloc.h>
-#include <sys/mount.h>
+#include <sys/mutex.h>
#include <sys/namei.h>
+#include <sys/proc.h>
#include <sys/stat.h>
#include <sys/syscallsubr.h>
-#include <sys/systm.h>
#include <sys/tty.h>
#include <sys/vnode.h>
-#include <sys/conf.h>
-#include <sys/fcntl.h>
+#ifdef KTRACE
+#include <sys/ktrace.h>
+#endif
+
+#include <security/audit/audit.h>
#ifdef COMPAT_LINUX32
#include <machine/../linux32/linux.h>
@@ -56,41 +54,68 @@ __FBSDID("$FreeBSD$");
#include <machine/../linux/linux_proto.h>
#endif
-#include <compat/linux/linux_util.h>
+#include <compat/linux/linux.h>
#include <compat/linux/linux_file.h>
+#include <compat/linux/linux_util.h>
-static void
-translate_vnhook_major_minor(struct vnode *vp, struct stat *sb)
+
+static int
+linux_kern_fstat(struct thread *td, int fd, struct stat *sbp)
{
- int major, minor;
+ struct vnode *vp;
+ struct file *fp;
+ int error;
- if (vn_isdisk(vp)) {
- sb->st_mode &= ~S_IFMT;
- sb->st_mode |= S_IFBLK;
- }
+ AUDIT_ARG_FD(fd);
- /*
- * Return the same st_dev for every devfs instance. The reason
- * for this is to work around an idiosyncrasy of glibc getttynam()
- * implementation: it checks whether st_dev returned for fd 0
- * is the same as st_dev returned for the target of /proc/self/fd/0
- * symlink, and with linux chroots having their own devfs instance,
- * the check will fail if you chroot into it.
- */
- if (rootdevmp != NULL && vp->v_mount->mnt_vfc == rootdevmp->mnt_vfc)
- sb->st_dev = rootdevmp->mnt_stat.f_fsid.val[0];
+ error = fget(td, fd, &cap_fstat_rights, &fp);
+ if (__predict_false(error != 0))
+ return (error);
- if (linux_vn_get_major_minor(vp, &major, &minor) == 0)
- sb->st_rdev = (major << 8 | minor);
+ AUDIT_ARG_FILE(td->td_proc, fp);
+
+ error = fo_stat(fp, sbp, td->td_ucred);
+ if (error == 0 && (vp = fp->f_vnode) != NULL)
+ translate_vnhook_major_minor(vp, sbp);
+ fdrop(fp, td);
+#ifdef KTRACE
+ if (KTRPOINT(td, KTR_STRUCT))
+ ktrstat_error(sbp, error);
+#endif
+ return (error);
}
static int
linux_kern_statat(struct thread *td, int flag, int fd, const char *path,
enum uio_seg pathseg, struct stat *sbp)
{
+ struct nameidata nd;
+ int error;
- return (kern_statat(td, flag, fd, path, pathseg, sbp,
- translate_vnhook_major_minor));
+ if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH |
+ AT_EMPTY_PATH)) != 0)
+ return (EINVAL);
+
+ NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_RESOLVE_BENEATH |
+ AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH) | LOCKSHARED | LOCKLEAF |
+ AUDITVNODE1, pathseg, path, fd, &cap_fstat_rights);
+
+ if ((error = namei(&nd)) != 0) {
+ if (error == ENOTDIR &&
+ (nd.ni_resflags & NIRES_EMPTYPATH) != 0)
+ error = linux_kern_fstat(td, fd, sbp);
+ return (error);
+ }
+ error = VOP_STAT(nd.ni_vp, sbp, td->td_ucred, NOCRED);
+ if (error == 0)
+ translate_vnhook_major_minor(nd.ni_vp, sbp);
+ NDFREE_PNBUF(&nd);
+ vput(nd.ni_vp);
+#ifdef KTRACE
+ if (KTRPOINT(td, KTR_STRUCT))
+ ktrstat_error(sbp, error);
+#endif
+ return (error);
}
#ifdef LINUX_LEGACY_SYSCALLS
@@ -112,77 +137,19 @@ linux_kern_lstat(struct thread *td, const char *path, enum uio_seg pathseg,
}
#endif
-static void
-translate_fd_major_minor(struct thread *td, int fd, struct stat *buf)
-{
- struct file *fp;
- struct vnode *vp;
- struct mount *mp;
- int major, minor;
-
- /*
- * No capability rights required here.
- */
- if ((!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode)) ||
- fget(td, fd, &cap_no_rights, &fp) != 0)
- return;
- vp = fp->f_vnode;
- if (vp != NULL && vn_isdisk(vp)) {
- buf->st_mode &= ~S_IFMT;
- buf->st_mode |= S_IFBLK;
- }
- if (vp != NULL && rootdevmp != NULL) {
- mp = vp->v_mount;
- __compiler_membar();
- if (mp != NULL && mp->mnt_vfc == rootdevmp->mnt_vfc)
- buf->st_dev = rootdevmp->mnt_stat.f_fsid.val[0];
- }
- if (linux_vn_get_major_minor(vp, &major, &minor) == 0) {
- buf->st_rdev = (major << 8 | minor);
- } else if (fp->f_type == DTYPE_PTS) {
- struct tty *tp = fp->f_data;
-
- /* Convert the numbers for the slave device. */
- if (linux_driver_get_major_minor(devtoname(tp->t_dev),
- &major, &minor) == 0) {
- buf->st_rdev = (major << 8 | minor);
- }
- }
- fdrop(fp, td);
-}
-
-/*
- * l_dev_t has the same encoding as dev_t in the latter's low 16 bits, so
- * truncation of a dev_t to 16 bits gives the same result as unpacking
- * using major() and minor() and repacking in the l_dev_t format. This
- * detail is hidden in dev_to_ldev(). Overflow in conversions of dev_t's
- * are not checked for, as for other fields.
- *
- * dev_to_ldev() is only used for translating st_dev. When we convert
- * st_rdev for copying it out, it isn't really a dev_t, but has already
- * been translated to an l_dev_t in a nontrivial way. Translating it
- * again would be illogical but would have no effect since the low 16
- * bits have the same encoding.
- *
- * The nontrivial translation for st_rdev renumbers some devices, but not
- * ones that can be mounted on, so it is consistent with the translation
- * for st_dev except when the renumbering or truncation causes conflicts.
- */
-#define dev_to_ldev(d) ((uint16_t)(d))
-
static int
newstat_copyout(struct stat *buf, void *ubuf)
{
struct l_newstat tbuf;
bzero(&tbuf, sizeof(tbuf));
- tbuf.st_dev = dev_to_ldev(buf->st_dev);
+ tbuf.st_dev = linux_new_encode_dev(buf->st_dev);
tbuf.st_ino = buf->st_ino;
tbuf.st_mode = buf->st_mode;
tbuf.st_nlink = buf->st_nlink;
tbuf.st_uid = buf->st_uid;
tbuf.st_gid = buf->st_gid;
- tbuf.st_rdev = buf->st_rdev;
+ tbuf.st_rdev = linux_new_encode_dev(buf->st_rdev);
tbuf.st_size = buf->st_size;
tbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
tbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
@@ -196,55 +163,15 @@ newstat_copyout(struct stat *buf, void *ubuf)
return (copyout(&tbuf, ubuf, sizeof(tbuf)));
}
-static int
-statx_copyout(struct stat *buf, void *ubuf)
-{
- struct l_statx tbuf;
-
- bzero(&tbuf, sizeof(tbuf));
- tbuf.stx_mask = STATX_ALL;
- tbuf.stx_blksize = buf->st_blksize;
- tbuf.stx_attributes = 0;
- tbuf.stx_nlink = buf->st_nlink;
- tbuf.stx_uid = buf->st_uid;
- tbuf.stx_gid = buf->st_gid;
- tbuf.stx_mode = buf->st_mode;
- tbuf.stx_ino = buf->st_ino;
- tbuf.stx_size = buf->st_size;
- tbuf.stx_blocks = buf->st_blocks;
-
- tbuf.stx_atime.tv_sec = buf->st_atim.tv_sec;
- tbuf.stx_atime.tv_nsec = buf->st_atim.tv_nsec;
- tbuf.stx_btime.tv_sec = buf->st_birthtim.tv_sec;
- tbuf.stx_btime.tv_nsec = buf->st_birthtim.tv_nsec;
- tbuf.stx_ctime.tv_sec = buf->st_ctim.tv_sec;
- tbuf.stx_ctime.tv_nsec = buf->st_ctim.tv_nsec;
- tbuf.stx_mtime.tv_sec = buf->st_mtim.tv_sec;
- tbuf.stx_mtime.tv_nsec = buf->st_mtim.tv_nsec;
-
- tbuf.stx_rdev_major = buf->st_rdev >> 8;
- tbuf.stx_rdev_minor = buf->st_rdev & 0xff;
- tbuf.stx_dev_major = buf->st_dev >> 8;
- tbuf.stx_dev_minor = buf->st_dev & 0xff;
-
- return (copyout(&tbuf, ubuf, sizeof(tbuf)));
-}
#ifdef LINUX_LEGACY_SYSCALLS
int
linux_newstat(struct thread *td, struct linux_newstat_args *args)
{
struct stat buf;
- char *path;
int error;
- if (!LUSECONVPATH(td)) {
- error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf);
- } else {
- LCONVPATHEXIST(args->path, &path);
- error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
- LFREEPATH(path);
- }
+ error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf);
if (error)
return (error);
return (newstat_copyout(&buf, args->buf));
@@ -254,16 +181,9 @@ int
linux_newlstat(struct thread *td, struct linux_newlstat_args *args)
{
struct stat sb;
- char *path;
int error;
- if (!LUSECONVPATH(td)) {
- error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &sb);
- } else {
- LCONVPATHEXIST(args->path, &path);
- error = linux_kern_lstat(td, path, UIO_SYSSPACE, &sb);
- LFREEPATH(path);
- }
+ error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &sb);
if (error)
return (error);
return (newstat_copyout(&sb, args->buf));
@@ -276,8 +196,7 @@ linux_newfstat(struct thread *td, struct linux_newfstat_args *args)
struct stat buf;
int error;
- error = kern_fstat(td, args->fd, &buf);
- translate_fd_major_minor(td, args->fd, &buf);
+ error = linux_kern_fstat(td, args->fd, &buf);
if (!error)
error = newstat_copyout(&buf, args->buf);
@@ -285,19 +204,27 @@ linux_newfstat(struct thread *td, struct linux_newfstat_args *args)
}
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+
+static __inline uint16_t
+linux_old_encode_dev(dev_t _dev)
+{
+
+ return (_dev == NODEV ? 0 : linux_encode_dev(major(_dev), minor(_dev)));
+}
+
static int
-stat_copyout(struct stat *buf, void *ubuf)
+old_stat_copyout(struct stat *buf, void *ubuf)
{
- struct l_stat lbuf;
+ struct l_old_stat lbuf;
bzero(&lbuf, sizeof(lbuf));
- lbuf.st_dev = dev_to_ldev(buf->st_dev);
+ lbuf.st_dev = linux_old_encode_dev(buf->st_dev);
lbuf.st_ino = buf->st_ino;
lbuf.st_mode = buf->st_mode;
lbuf.st_nlink = buf->st_nlink;
lbuf.st_uid = buf->st_uid;
lbuf.st_gid = buf->st_gid;
- lbuf.st_rdev = buf->st_rdev;
+ lbuf.st_rdev = linux_old_encode_dev(buf->st_rdev);
lbuf.st_size = MIN(buf->st_size, INT32_MAX);
lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
@@ -317,40 +244,26 @@ int
linux_stat(struct thread *td, struct linux_stat_args *args)
{
struct stat buf;
- char *path;
int error;
- if (!LUSECONVPATH(td)) {
- error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf);
- } else {
- LCONVPATHEXIST(args->path, &path);
- error = linux_kern_stat(td, path, UIO_SYSSPACE, &buf);
- LFREEPATH(path);
- }
+ error = linux_kern_stat(td, args->path, UIO_USERSPACE, &buf);
if (error) {
return (error);
}
- return (stat_copyout(&buf, args->up));
+ return (old_stat_copyout(&buf, args->up));
}
int
linux_lstat(struct thread *td, struct linux_lstat_args *args)
{
struct stat buf;
- char *path;
int error;
- if (!LUSECONVPATH(td)) {
- error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &buf);
- } else {
- LCONVPATHEXIST(args->path, &path);
- error = linux_kern_lstat(td, path, UIO_SYSSPACE, &buf);
- LFREEPATH(path);
- }
+ error = linux_kern_lstat(td, args->path, UIO_USERSPACE, &buf);
if (error) {
return (error);
}
- return (stat_copyout(&buf, args->up));
+ return (old_stat_copyout(&buf, args->up));
}
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
@@ -411,33 +324,50 @@ bsd_to_linux_ftype(const char *fstypename)
}
static int
-bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs)
+bsd_to_linux_mnt_flags(int f_flags)
{
-#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
- uint64_t tmp;
+ int flags = LINUX_ST_VALID;
+
+ if (f_flags & MNT_RDONLY)
+ flags |= LINUX_ST_RDONLY;
+ if (f_flags & MNT_NOEXEC)
+ flags |= LINUX_ST_NOEXEC;
+ if (f_flags & MNT_NOSUID)
+ flags |= LINUX_ST_NOSUID;
+ if (f_flags & MNT_NOATIME)
+ flags |= LINUX_ST_NOATIME;
+ if (f_flags & MNT_NOSYMFOLLOW)
+ flags |= LINUX_ST_NOSYMFOLLOW;
+ if (f_flags & MNT_SYNCHRONOUS)
+ flags |= LINUX_ST_SYNCHRONOUS;
+
+ return (flags);
+}
-#define LINUX_HIBITS 0xffffffff00000000ULL
+static int
+bsd_to_linux_statfs(struct statfs *bsd_statfs, struct l_statfs *linux_statfs)
+{
- tmp = bsd_statfs->f_blocks | bsd_statfs->f_bfree | bsd_statfs->f_files |
- bsd_statfs->f_bsize;
- if ((bsd_statfs->f_bavail != -1 && (bsd_statfs->f_bavail & LINUX_HIBITS)) ||
- (bsd_statfs->f_ffree != -1 && (bsd_statfs->f_ffree & LINUX_HIBITS)) ||
- (tmp & LINUX_HIBITS))
- return (EOVERFLOW);
-#undef LINUX_HIBITS
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+ statfs_scale_blocks(bsd_statfs, INT32_MAX);
#endif
linux_statfs->f_type = bsd_to_linux_ftype(bsd_statfs->f_fstypename);
linux_statfs->f_bsize = bsd_statfs->f_bsize;
linux_statfs->f_blocks = bsd_statfs->f_blocks;
linux_statfs->f_bfree = bsd_statfs->f_bfree;
linux_statfs->f_bavail = bsd_statfs->f_bavail;
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+ linux_statfs->f_ffree = MIN(bsd_statfs->f_ffree, INT32_MAX);
+ linux_statfs->f_files = MIN(bsd_statfs->f_files, INT32_MAX);
+#else
linux_statfs->f_ffree = bsd_statfs->f_ffree;
linux_statfs->f_files = bsd_statfs->f_files;
+#endif
linux_statfs->f_fsid.val[0] = bsd_statfs->f_fsid.val[0];
linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
linux_statfs->f_namelen = MAXNAMLEN;
linux_statfs->f_frsize = bsd_statfs->f_bsize;
- linux_statfs->f_flags = 0;
+ linux_statfs->f_flags = bsd_to_linux_mnt_flags(bsd_statfs->f_flags);
memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
return (0);
@@ -448,18 +378,10 @@ linux_statfs(struct thread *td, struct linux_statfs_args *args)
{
struct l_statfs linux_statfs;
struct statfs *bsd_statfs;
- char *path;
int error;
- if (!LUSECONVPATH(td)) {
- bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
- error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs);
- } else {
- LCONVPATHEXIST(args->path, &path);
- bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
- error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs);
- LFREEPATH(path);
- }
+ bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
+ error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs);
if (error == 0)
error = bsd_to_linux_statfs(bsd_statfs, &linux_statfs);
free(bsd_statfs, M_STATFS);
@@ -484,7 +406,7 @@ bsd_to_linux_statfs64(struct statfs *bsd_statfs, struct l_statfs64 *linux_statfs
linux_statfs->f_fsid.val[1] = bsd_statfs->f_fsid.val[1];
linux_statfs->f_namelen = MAXNAMLEN;
linux_statfs->f_frsize = bsd_statfs->f_bsize;
- linux_statfs->f_flags = 0;
+ linux_statfs->f_flags = bsd_to_linux_mnt_flags(bsd_statfs->f_flags);
memset(linux_statfs->f_spare, 0, sizeof(linux_statfs->f_spare));
}
@@ -493,21 +415,13 @@ linux_statfs64(struct thread *td, struct linux_statfs64_args *args)
{
struct l_statfs64 linux_statfs;
struct statfs *bsd_statfs;
- char *path;
int error;
if (args->bufsize != sizeof(struct l_statfs64))
return (EINVAL);
- if (!LUSECONVPATH(td)) {
- bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
- error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs);
- } else {
- LCONVPATHEXIST(args->path, &path);
- bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
- error = kern_statfs(td, path, UIO_SYSSPACE, bsd_statfs);
- LFREEPATH(path);
- }
+ bsd_statfs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
+ error = kern_statfs(td, args->path, UIO_USERSPACE, bsd_statfs);
if (error == 0)
bsd_to_linux_statfs64(bsd_statfs, &linux_statfs);
free(bsd_statfs, M_STATFS);
@@ -579,13 +493,13 @@ stat64_copyout(struct stat *buf, void *ubuf)
struct l_stat64 lbuf;
bzero(&lbuf, sizeof(lbuf));
- lbuf.st_dev = dev_to_ldev(buf->st_dev);
+ lbuf.st_dev = linux_new_encode_dev(buf->st_dev);
lbuf.st_ino = buf->st_ino;
lbuf.st_mode = buf->st_mode;
lbuf.st_nlink = buf->st_nlink;
lbuf.st_uid = buf->st_uid;
lbuf.st_gid = buf->st_gid;
- lbuf.st_rdev = buf->st_rdev;
+ lbuf.st_rdev = linux_new_encode_dev(buf->st_rdev);
lbuf.st_size = buf->st_size;
lbuf.st_atim.tv_sec = buf->st_atim.tv_sec;
lbuf.st_atim.tv_nsec = buf->st_atim.tv_nsec;
@@ -611,16 +525,9 @@ int
linux_stat64(struct thread *td, struct linux_stat64_args *args)
{
struct stat buf;
- char *filename;
int error;
- if (!LUSECONVPATH(td)) {
- error = linux_kern_stat(td, args->filename, UIO_USERSPACE, &buf);
- } else {
- LCONVPATHEXIST(args->filename, &filename);
- error = linux_kern_stat(td, filename, UIO_SYSSPACE, &buf);
- LFREEPATH(filename);
- }
+ error = linux_kern_stat(td, args->filename, UIO_USERSPACE, &buf);
if (error)
return (error);
return (stat64_copyout(&buf, args->statbuf));
@@ -630,16 +537,9 @@ int
linux_lstat64(struct thread *td, struct linux_lstat64_args *args)
{
struct stat sb;
- char *filename;
int error;
- if (!LUSECONVPATH(td)) {
- error = linux_kern_lstat(td, args->filename, UIO_USERSPACE, &sb);
- } else {
- LCONVPATHEXIST(args->filename, &filename);
- error = linux_kern_lstat(td, filename, UIO_SYSSPACE, &sb);
- LFREEPATH(filename);
- }
+ error = linux_kern_lstat(td, args->filename, UIO_USERSPACE, &sb);
if (error)
return (error);
return (stat64_copyout(&sb, args->statbuf));
@@ -651,8 +551,7 @@ linux_fstat64(struct thread *td, struct linux_fstat64_args *args)
struct stat buf;
int error;
- error = kern_fstat(td, args->fd, &buf);
- translate_fd_major_minor(td, args->fd, &buf);
+ error = linux_kern_fstat(td, args->fd, &buf);
if (!error)
error = stat64_copyout(&buf, args->statbuf);
@@ -662,7 +561,6 @@ linux_fstat64(struct thread *td, struct linux_fstat64_args *args)
int
linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
{
- char *path;
int error, dfd, flag, unsupported;
struct stat buf;
@@ -677,14 +575,8 @@ linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
AT_EMPTY_PATH : 0;
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
- if (!LUSECONVPATH(td)) {
- error = linux_kern_statat(td, flag, dfd, args->pathname,
- UIO_USERSPACE, &buf);
- } else {
- LCONVPATHEXIST_AT(args->pathname, &path, dfd);
- error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
- LFREEPATH(path);
- }
+ error = linux_kern_statat(td, flag, dfd, args->pathname,
+ UIO_USERSPACE, &buf);
if (error == 0)
error = stat64_copyout(&buf, args->statbuf);
@@ -696,7 +588,6 @@ linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
int
linux_newfstatat(struct thread *td, struct linux_newfstatat_args *args)
{
- char *path;
int error, dfd, flag, unsupported;
struct stat buf;
@@ -712,14 +603,8 @@ linux_newfstatat(struct thread *td, struct linux_newfstatat_args *args)
AT_EMPTY_PATH : 0;
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
- if (!LUSECONVPATH(td)) {
- error = linux_kern_statat(td, flag, dfd, args->pathname,
- UIO_USERSPACE, &buf);
- } else {
- LCONVPATHEXIST_AT(args->pathname, &path, dfd);
- error = linux_kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
- LFREEPATH(path);
- }
+ error = linux_kern_statat(td, flag, dfd, args->pathname,
+ UIO_USERSPACE, &buf);
if (error == 0)
error = newstat_copyout(&buf, args->statbuf);
@@ -767,10 +652,42 @@ linux_syncfs(struct thread *td, struct linux_syncfs_args *args)
return (error);
}
+static int
+statx_copyout(struct stat *buf, void *ubuf)
+{
+ struct l_statx tbuf;
+
+ bzero(&tbuf, sizeof(tbuf));
+ tbuf.stx_mask = STATX_ALL;
+ tbuf.stx_blksize = buf->st_blksize;
+ tbuf.stx_attributes = 0;
+ tbuf.stx_nlink = buf->st_nlink;
+ tbuf.stx_uid = buf->st_uid;
+ tbuf.stx_gid = buf->st_gid;
+ tbuf.stx_mode = buf->st_mode;
+ tbuf.stx_ino = buf->st_ino;
+ tbuf.stx_size = buf->st_size;
+ tbuf.stx_blocks = buf->st_blocks;
+
+ tbuf.stx_atime.tv_sec = buf->st_atim.tv_sec;
+ tbuf.stx_atime.tv_nsec = buf->st_atim.tv_nsec;
+ tbuf.stx_btime.tv_sec = buf->st_birthtim.tv_sec;
+ tbuf.stx_btime.tv_nsec = buf->st_birthtim.tv_nsec;
+ tbuf.stx_ctime.tv_sec = buf->st_ctim.tv_sec;
+ tbuf.stx_ctime.tv_nsec = buf->st_ctim.tv_nsec;
+ tbuf.stx_mtime.tv_sec = buf->st_mtim.tv_sec;
+ tbuf.stx_mtime.tv_nsec = buf->st_mtim.tv_nsec;
+ tbuf.stx_rdev_major = linux_encode_major(buf->st_rdev);
+ tbuf.stx_rdev_minor = linux_encode_minor(buf->st_rdev);
+ tbuf.stx_dev_major = linux_encode_major(buf->st_dev);
+ tbuf.stx_dev_minor = linux_encode_minor(buf->st_dev);
+
+ return (copyout(&tbuf, ubuf, sizeof(tbuf)));
+}
+
int
linux_statx(struct thread *td, struct linux_statx_args *args)
{
- char *path;
int error, dirfd, flags, unsupported;
struct stat buf;
@@ -787,14 +704,8 @@ linux_statx(struct thread *td, struct linux_statx_args *args)
AT_EMPTY_PATH : 0;
dirfd = (args->dirfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dirfd;
- if (!LUSECONVPATH(td)) {
- error = linux_kern_statat(td, flags, dirfd, args->pathname,
- UIO_USERSPACE, &buf);
- } else {
- LCONVPATHEXIST_AT(args->pathname, &path, dirfd);
- error = linux_kern_statat(td, flags, dirfd, path, UIO_SYSSPACE, &buf);
- LFREEPATH(path);
- }
+ error = linux_kern_statat(td, flags, dirfd, args->pathname,
+ UIO_USERSPACE, &buf);
if (error == 0)
error = statx_copyout(&buf, args->statxbuf);
diff --git a/sys/compat/linux/linux_sysctl.c b/sys/compat/linux/linux_sysctl.c
index 36f76c088ca3..65c64a7ba563 100644
--- a/sys/compat/linux/linux_sysctl.c
+++ b/sys/compat/linux/linux_sysctl.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 Marcel Moolenaar
* All rights reserved.
@@ -26,21 +26,13 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_compat.h"
-
#include <sys/param.h>
-#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
-#include <sys/proc.h>
-#include <sys/sdt.h>
#include <sys/sysctl.h>
-#include <sys/systm.h>
#include <sys/sbuf.h>
+#include <sys/vnode.h>
#ifdef COMPAT_LINUX32
#include <machine/../linux32/linux.h>
diff --git a/sys/compat/linux/linux_time.c b/sys/compat/linux/linux_time.c
index 32db84a570b9..e9e5cf075210 100644
--- a/sys/compat/linux/linux_time.c
+++ b/sys/compat/linux/linux_time.c
@@ -1,7 +1,7 @@
/* $NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $ */
/*-
- * SPDX-License-Identifier: BSD-2-Clause-NetBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -32,29 +32,18 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
#if 0
__KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $");
#endif
-#include "opt_compat.h"
-
#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/lock.h>
-#include <sys/ucred.h>
#include <sys/limits.h>
-#include <sys/mount.h>
+#include <sys/lock.h>
#include <sys/mutex.h>
+#include <sys/proc.h>
#include <sys/resourcevar.h>
-#include <sys/sdt.h>
-#include <sys/signal.h>
-#include <sys/stdint.h>
#include <sys/syscallsubr.h>
-#include <sys/sysproto.h>
#include <sys/time.h>
-#include <sys/systm.h>
-#include <sys/proc.h>
#ifdef COMPAT_LINUX32
#include <machine/../linux32/linux.h>
@@ -66,7 +55,7 @@ __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp
#include <compat/linux/linux_dtrace.h>
#include <compat/linux/linux_misc.h>
-#include <compat/linux/linux_timer.h>
+#include <compat/linux/linux_time.h>
#include <compat/linux/linux_util.h>
/* DTrace init */
diff --git a/sys/compat/linux/linux_timer.h b/sys/compat/linux/linux_time.h
index b9f877cc83a4..d99684db1cbf 100644
--- a/sys/compat/linux/linux_timer.h
+++ b/sys/compat/linux/linux_time.h
@@ -26,14 +26,10 @@
* 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.
- *
- * $FreeBSD$
*/
-#ifndef _LINUX_TIMER_H
-#define _LINUX_TIMER_H
-
-#include <sys/abi_compat.h>
+#ifndef _LINUX_TIME_H
+#define _LINUX_TIME_H
#ifndef __LINUX_ARCH_SIGEV_PREAMBLE_SIZE
#define __LINUX_ARCH_SIGEV_PREAMBLE_SIZE \
@@ -143,4 +139,4 @@ int linux_to_native_itimerspec64(struct itimerspec *,
int linux_to_native_timerflags(int *, int);
-#endif /* _LINUX_TIMER_H */
+#endif /* _LINUX_TIME_H */
diff --git a/sys/compat/linux/linux_timer.c b/sys/compat/linux/linux_timer.c
index 3e844704f132..2188006ec38f 100644
--- a/sys/compat/linux/linux_timer.c
+++ b/sys/compat/linux/linux_timer.c
@@ -27,18 +27,12 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_compat.h"
#include <sys/param.h>
-#include <sys/errno.h>
+#include <sys/proc.h>
#include <sys/signal.h>
#include <sys/syscallsubr.h>
-#include <sys/systm.h>
#include <sys/time.h>
-#include <sys/types.h>
#ifdef COMPAT_LINUX32
#include <machine/../linux32/linux.h>
@@ -47,7 +41,7 @@ __FBSDID("$FreeBSD$");
#include <machine/../linux/linux.h>
#include <machine/../linux/linux_proto.h>
#endif
-#include <compat/linux/linux_timer.h>
+#include <compat/linux/linux_time.h>
static int
linux_convert_l_sigevent(struct l_sigevent *l_sig, struct sigevent *sig)
diff --git a/sys/compat/linux/linux_uid16.c b/sys/compat/linux/linux_uid16.c
index 4dd4129cfa0b..a0c9f1c39198 100644
--- a/sys/compat/linux/linux_uid16.c
+++ b/sys/compat/linux/linux_uid16.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 The FreeBSD Project
* All rights reserved.
@@ -26,23 +26,15 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_compat.h"
-
-#include <sys/fcntl.h>
#include <sys/param.h>
-#include <sys/kernel.h>
+#include <sys/fcntl.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/priv.h>
#include <sys/proc.h>
-#include <sys/sdt.h>
#include <sys/syscallsubr.h>
#include <sys/sysproto.h>
-#include <sys/systm.h>
#ifdef COMPAT_LINUX32
#include <machine/../linux32/linux.h>
@@ -77,52 +69,17 @@ DUMMY(getresgid16);
int
linux_chown16(struct thread *td, struct linux_chown16_args *args)
{
- char *path;
- int error;
- if (!LUSECONVPATH(td) && !SDT_PROBES_ENABLED()) {
- error = kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE,
- CAST_NOCHG(args->uid), CAST_NOCHG(args->gid), 0);
- } else {
- LCONVPATHEXIST(args->path, &path);
- /*
- * The DTrace probes have to be after the LCONVPATHEXIST, as
- * LCONVPATHEXIST may return on its own and we do not want to
- * have a stray entry without the corresponding return.
- */
- LIN_SDT_PROBE1(uid16, linux_chown16, conv_path, path);
-
- error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE,
- CAST_NOCHG(args->uid), CAST_NOCHG(args->gid), 0);
- LFREEPATH(path);
- }
- return (error);
+ return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE,
+ CAST_NOCHG(args->uid), CAST_NOCHG(args->gid), 0));
}
int
linux_lchown16(struct thread *td, struct linux_lchown16_args *args)
{
- char *path;
- int error;
- if (!LUSECONVPATH(td) && !SDT_PROBES_ENABLED()) {
- error = kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE,
- CAST_NOCHG(args->uid), CAST_NOCHG(args->gid), AT_SYMLINK_NOFOLLOW);
- } else {
- LCONVPATHEXIST(args->path, &path);
-
- /*
- * The DTrace probes have to be after the LCONVPATHEXIST, as
- * LCONVPATHEXIST may return on its own and we do not want to
- * have a stray entry without the corresponding return.
- */
- LIN_SDT_PROBE1(uid16, linux_lchown16, conv_path, path);
-
- error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE,
- CAST_NOCHG(args->uid), CAST_NOCHG(args->gid), AT_SYMLINK_NOFOLLOW);
- LFREEPATH(path);
- }
- return (error);
+ return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE,
+ CAST_NOCHG(args->uid), CAST_NOCHG(args->gid), AT_SYMLINK_NOFOLLOW));
}
int
diff --git a/sys/compat/linux/linux_util.c b/sys/compat/linux/linux_util.c
index 4fa460078597..e0c010cb5e48 100644
--- a/sys/compat/linux/linux_util.c
+++ b/sys/compat/linux/linux_util.c
@@ -31,29 +31,18 @@
* from: svr4_util.c,v 1.5 1995/01/22 23:44:50 christos Exp
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/jail.h>
#include <sys/malloc.h>
-#include <sys/kernel.h>
-#include <sys/linker_set.h>
#include <sys/namei.h>
#include <sys/proc.h>
-#include <sys/sdt.h>
+#include <sys/stat.h>
#include <sys/syscallsubr.h>
-#include <sys/sysctl.h>
-#include <sys/systm.h>
#include <sys/vnode.h>
-#include <net/if.h>
-#include <net/if_var.h>
-#include <net/if_types.h>
-
#include <machine/stdarg.h>
#include <compat/linux/linux_dtrace.h>
@@ -86,28 +75,30 @@ SYSCTL_STRING(_compat_linux, OID_AUTO, emul_path, CTLFLAG_RWTUN,
linux_emul_path, sizeof(linux_emul_path),
"Linux runtime environment path");
-static bool use_real_ifnames = false;
-SYSCTL_BOOL(_compat_linux, OID_AUTO, use_real_ifnames, CTLFLAG_RWTUN,
- &use_real_ifnames, 0,
- "Use FreeBSD interface names instead of generating ethN aliases");
-
-/*
- * Search an alternate path before passing pathname arguments on to
- * system calls. Useful for keeping a separate 'emulation tree'.
- *
- * If cflag is set, we check if an attempt can be made to create the
- * named file, i.e. we check if the directory it should be in exists.
- */
int
-linux_emul_convpath(const char *path, enum uio_seg pathseg,
- char **pbuf, int cflag, int dfd)
+linux_pwd_onexec(struct thread *td)
{
- int retval;
+ struct nameidata nd;
+ int error;
- retval = kern_alternate_path(linux_emul_path, path, pathseg, pbuf,
- cflag, dfd);
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path);
+ error = namei(&nd);
+ if (error != 0) {
+ /* Do not prevent execution if altroot is non-existent. */
+ pwd_altroot(td, NULL);
+ return (0);
+ }
+ NDFREE_PNBUF(&nd);
+ pwd_altroot(td, nd.ni_vp);
+ vrele(nd.ni_vp);
+ return (0);
+}
- return (retval);
+void
+linux_pwd_onexec_native(struct thread *td)
+{
+
+ pwd_altroot(td, NULL);
}
void
@@ -239,6 +230,31 @@ linux_vn_get_major_minor(const struct vnode *vp, int *major, int *minor)
return (error);
}
+void
+translate_vnhook_major_minor(struct vnode *vp, struct stat *sb)
+{
+ int major, minor;
+
+ if (vn_isdisk(vp)) {
+ sb->st_mode &= ~S_IFMT;
+ sb->st_mode |= S_IFBLK;
+ }
+
+ /*
+ * Return the same st_dev for every devfs instance. The reason
+ * for this is to work around an idiosyncrasy of glibc getttynam()
+ * implementation: it checks whether st_dev returned for fd 0
+ * is the same as st_dev returned for the target of /proc/self/fd/0
+ * symlink, and with linux chroots having their own devfs instance,
+ * the check will fail if you chroot into it.
+ */
+ if (rootdevmp != NULL && vp->v_mount->mnt_vfc == rootdevmp->mnt_vfc)
+ sb->st_dev = rootdevmp->mnt_stat.f_fsid.val[0];
+
+ if (linux_vn_get_major_minor(vp, &major, &minor) == 0)
+ sb->st_rdev = makedev(major, minor);
+}
+
char *
linux_get_char_devices(void)
{
@@ -324,9 +340,3 @@ linux_device_unregister_handler(struct linux_device_handler *d)
return (EINVAL);
}
-
-bool
-linux_use_real_ifname(const struct ifnet *ifp)
-{
- return (use_real_ifnames || !IFP_IS_ETH(ifp));
-}
diff --git a/sys/compat/linux/linux_util.h b/sys/compat/linux/linux_util.h
index 6f7b55be8123..58f7c533d647 100644
--- a/sys/compat/linux/linux_util.h
+++ b/sys/compat/linux/linux_util.h
@@ -30,49 +30,21 @@
*
* from: svr4_util.h,v 1.5 1994/11/18 02:54:31 christos Exp
* from: linux_util.h,v 1.2 1995/03/05 23:23:50 fvdl Exp
- * $FreeBSD$
*/
#ifndef _LINUX_UTIL_H_
#define _LINUX_UTIL_H_
-#include <vm/vm.h>
-#include <vm/vm_param.h>
-#include <vm/pmap.h>
-#include <sys/exec.h>
-#include <sys/sysent.h>
-#include <sys/syslog.h>
-#include <sys/cdefs.h>
+#include <sys/malloc.h>
#include <sys/uio.h>
+extern int linux_debug;
+
MALLOC_DECLARE(M_LINUX);
MALLOC_DECLARE(M_EPOLL);
-extern char linux_emul_path[];
-extern int linux_use_emul_path;
-
-int linux_emul_convpath(const char *, enum uio_seg, char **, int, int);
-
-#define LUSECONVPATH(td) atomic_load_int(&linux_use_emul_path)
-
-#define LCONVPATH_AT(upath, pathp, i, dfd) \
- do { \
- int _error; \
- \
- _error = linux_emul_convpath(upath, UIO_USERSPACE, \
- pathp, i, dfd); \
- if (*(pathp) == NULL) \
- return (_error); \
- } while (0)
-
-#define LCONVPATH(upath, pathp, i) \
- LCONVPATH_AT(upath, pathp, i, AT_FDCWD)
-
-#define LCONVPATHEXIST(upath, pathp) LCONVPATH(upath, pathp, 0)
-#define LCONVPATHEXIST_AT(upath, pathp, dfd) LCONVPATH_AT(upath, pathp, 0, dfd)
-#define LCONVPATHCREAT(upath, pathp) LCONVPATH(upath, pathp, 1)
-#define LCONVPATHCREAT_AT(upath, pathp, dfd) LCONVPATH_AT(upath, pathp, 1, dfd)
-#define LFREEPATH(path) free(path, M_TEMP)
+int linux_pwd_onexec(struct thread *);
+void linux_pwd_onexec_native(struct thread *);
#define DUMMY(s) \
LIN_SDT_PROBE_DEFINE0(dummy, s, not_implemented); \
@@ -112,6 +84,8 @@ struct linux_device_handler {
int linux_char_device;
};
+struct stat;
+
int linux_device_register_handler(struct linux_device_handler *h);
int linux_device_unregister_handler(struct linux_device_handler *h);
char *linux_driver_get_name_dev(device_t dev);
@@ -119,15 +93,7 @@ int linux_driver_get_major_minor(const char *node, int *major, int *minor);
int linux_vn_get_major_minor(const struct vnode *vn, int *major, int *minor);
char *linux_get_char_devices(void);
void linux_free_get_char_devices(char *string);
-
-/*
- * Criteria for interface name translation
- */
-#define IFP_IS_ETH(ifp) ((ifp)->if_type == IFT_ETHER)
-#define IFP_IS_LOOP(ifp) ((ifp)->if_type == IFT_LOOP)
-
-struct ifnet;
-bool linux_use_real_ifname(const struct ifnet *ifp);
+void translate_vnhook_major_minor(struct vnode *vp, struct stat *sb);
#if defined(KTR)
diff --git a/sys/compat/linux/linux_vdso.c b/sys/compat/linux/linux_vdso.c
index f5fc7a20b1ef..a415a92783de 100644
--- a/sys/compat/linux/linux_vdso.c
+++ b/sys/compat/linux/linux_vdso.c
@@ -1,33 +1,30 @@
/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
* Copyright (c) 2013-2021 Dmitry Chagin <dchagin@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
- * in this position and unchanged.
+ * notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 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.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include "opt_compat.h"
-
#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
#define __ELF_WORD_SIZE 32
#else
@@ -35,22 +32,20 @@ __FBSDID("$FreeBSD$");
#endif
#include <sys/param.h>
-#include <sys/systm.h>
#include <sys/elf.h>
#include <sys/imgact.h>
-#include <sys/kernel.h>
+#include <sys/lock.h>
#include <sys/proc.h>
#include <sys/rwlock.h>
-#include <sys/queue.h>
#include <sys/sysent.h>
-#include <vm/vm_param.h>
#include <vm/pmap.h>
#include <vm/vm_extern.h>
#include <vm/vm_map.h>
#include <vm/vm_object.h>
#include <vm/vm_page.h>
#include <vm/vm_pager.h>
+#include <vm/vm_param.h>
#include <compat/linux/linux_vdso.h>
diff --git a/sys/compat/linux/linux_vdso.h b/sys/compat/linux/linux_vdso.h
index 6708b94f2694..e7f45f38c662 100644
--- a/sys/compat/linux/linux_vdso.h
+++ b/sys/compat/linux/linux_vdso.h
@@ -1,35 +1,33 @@
/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
* Copyright (c) 2013-2021 Dmitry Chagin <dchagin@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
- * in this position and unchanged.
+ * notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD$
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
*/
#ifndef _LINUX_VDSO_H_
#define _LINUX_VDSO_H_
-#include <sys/types.h>
-
struct linux_vdso_sym {
SLIST_ENTRY(linux_vdso_sym) sym;
uint32_t size;
diff --git a/sys/compat/linux/linux_vdso_gtod.inc b/sys/compat/linux/linux_vdso_gtod.inc
index 8a3840edd87d..e508f821725d 100644
--- a/sys/compat/linux/linux_vdso_gtod.inc
+++ b/sys/compat/linux/linux_vdso_gtod.inc
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org>
* Copyright (c) 2021 Dmitry Chagin <dchagin@FreeBSD.org>
@@ -26,6 +26,14 @@
* SUCH DAMAGE.
*/
+#if defined(__aarch64__)
+#define __VDSO_PREFIX __kernel
+#else
+#define __VDSO_PREFIX __vdso
+#endif
+
+#define __vdsoN(x) __CONCAT(__CONCAT(__VDSO_PREFIX,_),x)
+
static int
fls(int mask)
{
@@ -295,7 +303,7 @@ freebsd_clock_gettime(clockid_t clock_id, struct timespec *ts)
*
*/
int
-__vdso_clock_gettime(clockid_t clock_id, struct l_timespec *lts)
+__vdsoN(clock_gettime)(clockid_t clock_id, struct l_timespec *lts)
{
struct timespec ts;
clockid_t which;
@@ -312,7 +320,7 @@ __vdso_clock_gettime(clockid_t clock_id, struct l_timespec *lts)
}
int
-__vdso_gettimeofday(l_timeval *ltv, struct timezone *tz)
+__vdsoN(gettimeofday)(l_timeval *ltv, struct timezone *tz)
{
struct timeval tv;
int error;
@@ -324,7 +332,7 @@ __vdso_gettimeofday(l_timeval *ltv, struct timezone *tz)
}
int
-__vdso_clock_getres(clockid_t clock_id, struct l_timespec *lts)
+__vdsoN(clock_getres)(clockid_t clock_id, struct l_timespec *lts)
{
return (__vdso_clock_getres_fallback(clock_id, lts));
diff --git a/sys/compat/linux/linux_videodev2_compat.h b/sys/compat/linux/linux_videodev2_compat.h
index 0d9a3a348b8f..cd7ca5f002e1 100644
--- a/sys/compat/linux/linux_videodev2_compat.h
+++ b/sys/compat/linux/linux_videodev2_compat.h
@@ -1,8 +1,4 @@
/*
- * $FreeBSD$
- */
-
-/*
* This file defines compatibility versions of several video structures
* defined in the Linux videodev2.h header (linux_videodev2.h). The
* structures defined in this file are the ones that have been determined
diff --git a/sys/compat/linux/linux_videodev_compat.h b/sys/compat/linux/linux_videodev_compat.h
index 98034bcbb04d..c35a59d2ecf8 100644
--- a/sys/compat/linux/linux_videodev_compat.h
+++ b/sys/compat/linux/linux_videodev_compat.h
@@ -1,8 +1,4 @@
/*
- * $FreeBSD$
- */
-
-/*
* This file defines compatibility versions of several video structures
* defined in the Linux videodev.h header (linux_videodev.h). The
* structures defined in this file are the ones that have been determined
diff --git a/sys/compat/linux/linux_xattr.c b/sys/compat/linux/linux_xattr.c
new file mode 100644
index 000000000000..6979fff9c82d
--- /dev/null
+++ b/sys/compat/linux/linux_xattr.c
@@ -0,0 +1,460 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Dmitry Chagin <dchagin@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.
+ */
+
+#include <sys/param.h>
+#include <sys/extattr.h>
+#include <sys/fcntl.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/syscallsubr.h>
+
+#ifdef COMPAT_LINUX32
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+
+#include <compat/linux/linux_util.h>
+
+#define LINUX_XATTR_SIZE_MAX 65536
+#define LINUX_XATTR_LIST_MAX 65536
+#define LINUX_XATTR_NAME_MAX 255
+
+#define LINUX_XATTR_CREATE 0x1
+#define LINUX_XATTR_REPLACE 0x2
+#define LINUX_XATTR_FLAGS LINUX_XATTR_CREATE|LINUX_XATTR_REPLACE
+
+struct listxattr_args {
+ int fd;
+ const char *path;
+ char *list;
+ l_size_t size;
+ int follow;
+};
+
+struct setxattr_args {
+ int fd;
+ const char *path;
+ const char *name;
+ void *value;
+ l_size_t size;
+ l_int flags;
+ int follow;
+};
+
+struct getxattr_args {
+ int fd;
+ const char *path;
+ const char *name;
+ void *value;
+ l_size_t size;
+ int follow;
+};
+
+struct removexattr_args {
+ int fd;
+ const char *path;
+ const char *name;
+ int follow;
+};
+
+static char *extattr_namespace_names[] = EXTATTR_NAMESPACE_NAMES;
+
+
+static int
+error_to_xattrerror(int attrnamespace, int error)
+{
+
+ if (attrnamespace == EXTATTR_NAMESPACE_SYSTEM && error == EPERM)
+ return (ENOTSUP);
+ else
+ return (error);
+}
+
+static int
+xatrr_to_extattr(const char *uattrname, int *attrnamespace, char *attrname)
+{
+ char uname[LINUX_XATTR_NAME_MAX + 1], *dot;
+ size_t len, cplen;
+ int error;
+
+ error = copyinstr(uattrname, uname, sizeof(uname), &cplen);
+ if (error != 0)
+ return (error);
+ if (cplen == sizeof(uname))
+ return (ERANGE);
+ dot = strchr(uname, '.');
+ if (dot == NULL)
+ return (ENOTSUP);
+ *dot = '\0';
+ for (*attrnamespace = EXTATTR_NAMESPACE_USER;
+ *attrnamespace < nitems(extattr_namespace_names);
+ (*attrnamespace)++) {
+ if (bcmp(uname, extattr_namespace_names[*attrnamespace],
+ dot - uname + 1) == 0) {
+ dot++;
+ len = strlen(dot) + 1;
+ bcopy(dot, attrname, len);
+ return (0);
+ }
+ }
+ return (ENOTSUP);
+}
+
+static int
+listxattr(struct thread *td, struct listxattr_args *args)
+{
+ char attrname[LINUX_XATTR_NAME_MAX + 1];
+ char *data, *prefix, *key;
+ struct uio auio;
+ struct iovec aiov;
+ unsigned char keylen;
+ size_t sz, cnt, rs, prefixlen, pairlen;
+ int attrnamespace, error;
+
+ if (args->size != 0)
+ sz = min(LINUX_XATTR_LIST_MAX, args->size);
+ else
+ sz = LINUX_XATTR_LIST_MAX;
+
+ data = malloc(sz, M_LINUX, M_WAITOK);
+ auio.uio_iov = &aiov;
+ auio.uio_iovcnt = 1;
+ auio.uio_rw = UIO_READ;
+ auio.uio_segflg = UIO_SYSSPACE;
+ auio.uio_td = td;
+ cnt = 0;
+ for (attrnamespace = EXTATTR_NAMESPACE_USER;
+ attrnamespace < nitems(extattr_namespace_names);
+ attrnamespace++) {
+ aiov.iov_base = data;
+ aiov.iov_len = sz;
+ auio.uio_resid = sz;
+ auio.uio_offset = 0;
+
+ if (args->path != NULL)
+ error = kern_extattr_list_path(td, args->path,
+ attrnamespace, &auio, args->follow, UIO_USERSPACE);
+ else
+ error = kern_extattr_list_fd(td, args->fd,
+ attrnamespace, &auio);
+ rs = sz - auio.uio_resid;
+ if (error == EPERM)
+ break;
+ if (error != 0 || rs == 0)
+ continue;
+ prefix = extattr_namespace_names[attrnamespace];
+ prefixlen = strlen(prefix);
+ key = data;
+ while (rs > 0) {
+ keylen = (unsigned char)key[0];
+ pairlen = prefixlen + 1 + keylen + 1;
+ cnt += pairlen;
+ if (cnt > LINUX_XATTR_LIST_MAX) {
+ error = E2BIG;
+ break;
+ }
+ /*
+ * If size is specified as zero, return the current size
+ * of the list of extended attribute names.
+ */
+ if ((args->size > 0 && cnt > args->size) ||
+ pairlen >= sizeof(attrname)) {
+ error = ERANGE;
+ break;
+ }
+ ++key;
+ if (args->list != NULL && args->size > 0) {
+ sprintf(attrname, "%s.%.*s", prefix, keylen, key);
+ error = copyout(attrname, args->list, pairlen);
+ if (error != 0)
+ break;
+ args->list += pairlen;
+ }
+ key += keylen;
+ rs -= (keylen + 1);
+ }
+ }
+ if (error == 0)
+ td->td_retval[0] = cnt;
+ free(data, M_LINUX);
+ return (error_to_xattrerror(attrnamespace, error));
+}
+
+int
+linux_listxattr(struct thread *td, struct linux_listxattr_args *args)
+{
+ struct listxattr_args eargs = {
+ .fd = -1,
+ .path = args->path,
+ .list = args->list,
+ .size = args->size,
+ .follow = FOLLOW,
+ };
+
+ return (listxattr(td, &eargs));
+}
+
+int
+linux_llistxattr(struct thread *td, struct linux_llistxattr_args *args)
+{
+ struct listxattr_args eargs = {
+ .fd = -1,
+ .path = args->path,
+ .list = args->list,
+ .size = args->size,
+ .follow = NOFOLLOW,
+ };
+
+ return (listxattr(td, &eargs));
+}
+
+int
+linux_flistxattr(struct thread *td, struct linux_flistxattr_args *args)
+{
+ struct listxattr_args eargs = {
+ .fd = args->fd,
+ .path = NULL,
+ .list = args->list,
+ .size = args->size,
+ .follow = 0,
+ };
+
+ return (listxattr(td, &eargs));
+}
+
+static int
+removexattr(struct thread *td, struct removexattr_args *args)
+{
+ char attrname[LINUX_XATTR_NAME_MAX + 1];
+ int attrnamespace, error;
+
+ error = xatrr_to_extattr(args->name, &attrnamespace, attrname);
+ if (error != 0)
+ return (error);
+ if (args->path != NULL)
+ error = kern_extattr_delete_path(td, args->path, attrnamespace,
+ attrname, args->follow, UIO_USERSPACE);
+ else
+ error = kern_extattr_delete_fd(td, args->fd, attrnamespace,
+ attrname);
+ return (error_to_xattrerror(attrnamespace, error));
+}
+
+int
+linux_removexattr(struct thread *td, struct linux_removexattr_args *args)
+{
+ struct removexattr_args eargs = {
+ .fd = -1,
+ .path = args->path,
+ .name = args->name,
+ .follow = FOLLOW,
+ };
+
+ return (removexattr(td, &eargs));
+}
+
+int
+linux_lremovexattr(struct thread *td, struct linux_lremovexattr_args *args)
+{
+ struct removexattr_args eargs = {
+ .fd = -1,
+ .path = args->path,
+ .name = args->name,
+ .follow = NOFOLLOW,
+ };
+
+ return (removexattr(td, &eargs));
+}
+
+int
+linux_fremovexattr(struct thread *td, struct linux_fremovexattr_args *args)
+{
+ struct removexattr_args eargs = {
+ .fd = args->fd,
+ .path = NULL,
+ .name = args->name,
+ .follow = 0,
+ };
+
+ return (removexattr(td, &eargs));
+}
+
+static int
+getxattr(struct thread *td, struct getxattr_args *args)
+{
+ char attrname[LINUX_XATTR_NAME_MAX + 1];
+ int attrnamespace, error;
+
+ error = xatrr_to_extattr(args->name, &attrnamespace, attrname);
+ if (error != 0)
+ return (error);
+ if (args->path != NULL)
+ error = kern_extattr_get_path(td, args->path, attrnamespace,
+ attrname, args->value, args->size, args->follow, UIO_USERSPACE);
+ else
+ error = kern_extattr_get_fd(td, args->fd, attrnamespace,
+ attrname, args->value, args->size);
+ return (error == EPERM ? ENOATTR : error);
+}
+
+int
+linux_getxattr(struct thread *td, struct linux_getxattr_args *args)
+{
+ struct getxattr_args eargs = {
+ .fd = -1,
+ .path = args->path,
+ .name = args->name,
+ .value = args->value,
+ .size = args->size,
+ .follow = FOLLOW,
+ };
+
+ return (getxattr(td, &eargs));
+}
+
+int
+linux_lgetxattr(struct thread *td, struct linux_lgetxattr_args *args)
+{
+ struct getxattr_args eargs = {
+ .fd = -1,
+ .path = args->path,
+ .name = args->name,
+ .value = args->value,
+ .size = args->size,
+ .follow = NOFOLLOW,
+ };
+
+ return (getxattr(td, &eargs));
+}
+
+int
+linux_fgetxattr(struct thread *td, struct linux_fgetxattr_args *args)
+{
+ struct getxattr_args eargs = {
+ .fd = args->fd,
+ .path = NULL,
+ .name = args->name,
+ .value = args->value,
+ .size = args->size,
+ .follow = 0,
+ };
+
+ return (getxattr(td, &eargs));
+}
+
+static int
+setxattr(struct thread *td, struct setxattr_args *args)
+{
+ char attrname[LINUX_XATTR_NAME_MAX + 1];
+ int attrnamespace, error;
+
+ if ((args->flags & ~(LINUX_XATTR_FLAGS)) != 0 ||
+ args->flags == (LINUX_XATTR_FLAGS))
+ return (EINVAL);
+ error = xatrr_to_extattr(args->name, &attrnamespace, attrname);
+ if (error != 0)
+ return (error);
+
+ if ((args->flags & (LINUX_XATTR_FLAGS)) != 0 ) {
+ if (args->path != NULL)
+ error = kern_extattr_get_path(td, args->path,
+ attrnamespace, attrname, NULL, args->size,
+ args->follow, UIO_USERSPACE);
+ else
+ error = kern_extattr_get_fd(td, args->fd,
+ attrnamespace, attrname, NULL, args->size);
+ if ((args->flags & LINUX_XATTR_CREATE) != 0) {
+ if (error == 0)
+ error = EEXIST;
+ else if (error == ENOATTR)
+ error = 0;
+ }
+ if (error != 0)
+ goto out;
+ }
+ if (args->path != NULL)
+ error = kern_extattr_set_path(td, args->path, attrnamespace,
+ attrname, args->value, args->size, args->follow,
+ UIO_USERSPACE);
+ else
+ error = kern_extattr_set_fd(td, args->fd, attrnamespace,
+ attrname, args->value, args->size);
+out:
+ td->td_retval[0] = 0;
+ return (error_to_xattrerror(attrnamespace, error));
+}
+
+int
+linux_setxattr(struct thread *td, struct linux_setxattr_args *args)
+{
+ struct setxattr_args eargs = {
+ .fd = -1,
+ .path = args->path,
+ .name = args->name,
+ .value = args->value,
+ .size = args->size,
+ .flags = args->flags,
+ .follow = FOLLOW,
+ };
+
+ return (setxattr(td, &eargs));
+}
+
+int
+linux_lsetxattr(struct thread *td, struct linux_lsetxattr_args *args)
+{
+ struct setxattr_args eargs = {
+ .fd = -1,
+ .path = args->path,
+ .name = args->name,
+ .value = args->value,
+ .size = args->size,
+ .flags = args->flags,
+ .follow = NOFOLLOW,
+ };
+
+ return (setxattr(td, &eargs));
+}
+
+int
+linux_fsetxattr(struct thread *td, struct linux_fsetxattr_args *args)
+{
+ struct setxattr_args eargs = {
+ .fd = args->fd,
+ .path = NULL,
+ .name = args->name,
+ .value = args->value,
+ .size = args->size,
+ .flags = args->flags,
+ .follow = 0,
+ };
+
+ return (setxattr(td, &eargs));
+}
diff --git a/sys/compat/linux/stats_timing.d b/sys/compat/linux/stats_timing.d
index 66a813a9af92..f0aa291e2155 100644
--- a/sys/compat/linux/stats_timing.d
+++ b/sys/compat/linux/stats_timing.d
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
/**
diff --git a/sys/compat/linux/trace_futexes.d b/sys/compat/linux/trace_futexes.d
index 94129212043a..0827cf78aa8f 100644
--- a/sys/compat/linux/trace_futexes.d
+++ b/sys/compat/linux/trace_futexes.d
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
/**
diff --git a/sys/compat/linuxkpi/common/include/acpi/acpi.h b/sys/compat/linuxkpi/common/include/acpi/acpi.h
index e996301e27f0..e0218bdde12e 100644
--- a/sys/compat/linuxkpi/common/include/acpi/acpi.h
+++ b/sys/compat/linuxkpi/common/include/acpi/acpi.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org>
* Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_ACPI_ACPI_H_
@@ -97,4 +95,10 @@ acpi_get_table(ACPI_STRING Signature, UINT32 Instance,
return (AcpiGetTable(Signature, Instance, OutTable));
}
+static inline void
+acpi_put_table(ACPI_TABLE_HEADER *Table)
+{
+ AcpiPutTable(Table);
+}
+
#endif /* _LINUXKPI_ACPI_ACPI_H_ */
diff --git a/sys/compat/linuxkpi/common/include/acpi/acpi_bus.h b/sys/compat/linuxkpi/common/include/acpi/acpi_bus.h
index c8a6385f26b2..f107902a26ad 100644
--- a/sys/compat/linuxkpi/common/include/acpi/acpi_bus.h
+++ b/sys/compat/linuxkpi/common/include/acpi/acpi_bus.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
*
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_ACPI_ACPI_BUS_H_
@@ -39,6 +37,8 @@ struct acpi_bus_event {
uint32_t data;
};
+#define acpi_dev_present(...) lkpi_acpi_dev_present(__VA_ARGS__)
+
ACPI_HANDLE bsd_acpi_get_handle(device_t bsddev);
bool acpi_check_dsm(ACPI_HANDLE handle, const char *uuid, int rev,
uint64_t funcs);
@@ -48,5 +48,7 @@ ACPI_OBJECT * acpi_evaluate_dsm_typed(ACPI_HANDLE handle, const char *uuid,
int register_acpi_notifier(struct notifier_block *nb);
int unregister_acpi_notifier(struct notifier_block *nb);
uint32_t acpi_target_system_state(void);
+bool lkpi_acpi_dev_present(const char *hid, const char *uid,
+ int64_t hrv);
#endif /* _LINUXKPI_ACPI_ACPI_BUS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/acpi/actbl.h b/sys/compat/linuxkpi/common/include/acpi/actbl.h
new file mode 100644
index 000000000000..dbb7db41bb66
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/acpi/actbl.h
@@ -0,0 +1 @@
+#include <contrib/dev/acpica/include/actbl.h>
diff --git a/sys/compat/linuxkpi/common/include/acpi/video.h b/sys/compat/linuxkpi/common/include/acpi/video.h
index 63f876e78b57..fd2ffd6764d0 100644
--- a/sys/compat/linuxkpi/common/include/acpi/video.h
+++ b/sys/compat/linuxkpi/common/include/acpi/video.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
*
@@ -24,15 +24,39 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_ACPI_VIDEO_H_
#define _LINUXKPI_ACPI_VIDEO_H_
+#include <sys/types.h>
+#include <sys/errno.h>
+
#define ACPI_VIDEO_CLASS "video"
#define ACPI_VIDEO_NOTIFY_PROBE 0x81
+static inline int
+acpi_video_register(void)
+{
+
+ return (-ENODEV);
+}
+
+static inline void
+acpi_video_unregister(void)
+{
+}
+
+static inline void
+acpi_video_register_backlight(void)
+{
+}
+
+static inline bool
+acpi_video_backlight_use_native(void)
+{
+ return (true);
+}
+
#endif /* _LINUXKPI_ACPI_VIDEO_H_ */
diff --git a/sys/compat/linuxkpi/common/include/asm/atomic-long.h b/sys/compat/linuxkpi/common/include/asm/atomic-long.h
index f8bd9edfccf9..db3a94c539e5 100644
--- a/sys/compat/linuxkpi/common/include/asm/atomic-long.h
+++ b/sys/compat/linuxkpi/common/include/asm/atomic-long.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_ASM_ATOMIC_LONG_H_
#define _LINUXKPI_ASM_ATOMIC_LONG_H_
@@ -41,7 +39,7 @@ typedef struct {
} atomic_long_t;
#define atomic_long_add(i, v) atomic_long_add_return((i), (v))
-#define atomic_long_sub(i, v) atomic_long_add_return(-(i), (v))
+#define atomic_long_sub(i, v) atomic_long_sub_return((i), (v))
#define atomic_long_inc_return(v) atomic_long_add_return(1, (v))
#define atomic_long_inc_not_zero(v) atomic_long_add_unless((v), 1, 0)
@@ -51,6 +49,12 @@ atomic_long_add_return(long i, atomic_long_t *v)
return i + atomic_fetchadd_long(&v->counter, i);
}
+static inline long
+atomic_long_sub_return(long i, atomic_long_t *v)
+{
+ return atomic_fetchadd_long(&v->counter, -i) - i;
+}
+
static inline void
atomic_long_set(atomic_long_t *v, long i)
{
diff --git a/sys/compat/linuxkpi/common/include/asm/atomic.h b/sys/compat/linuxkpi/common/include/asm/atomic.h
index d7e5338c0356..edb478af8c82 100644
--- a/sys/compat/linuxkpi/common/include/asm/atomic.h
+++ b/sys/compat/linuxkpi/common/include/asm/atomic.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_ASM_ATOMIC_H_
@@ -166,9 +164,7 @@ atomic_cmpxchg(atomic_t *v, int old, int new)
#define LINUXKPI_ATOMIC_16(...)
#endif
-#if !(defined(i386) || (defined(__mips__) && !(defined(__mips_n32) || \
- defined(__mips_n64))) || (defined(__powerpc__) && \
- !defined(__powerpc64__)))
+#if !(defined(i386) || (defined(__powerpc__) && !defined(__powerpc64__)))
#define LINUXKPI_ATOMIC_64(...) __VA_ARGS__
#else
#define LINUXKPI_ATOMIC_64(...)
@@ -220,6 +216,7 @@ atomic_cmpxchg(atomic_t *v, int old, int new)
__ret.val; \
})
+#define cmpxchg64(...) cmpxchg(__VA_ARGS__)
#define cmpxchg_relaxed(...) cmpxchg(__VA_ARGS__)
#define xchg(ptr, new) ({ \
diff --git a/sys/compat/linuxkpi/common/include/asm/atomic64.h b/sys/compat/linuxkpi/common/include/asm/atomic64.h
index 4ee0fa5ecf84..fbfb9254b64c 100644
--- a/sys/compat/linuxkpi/common/include/asm/atomic64.h
+++ b/sys/compat/linuxkpi/common/include/asm/atomic64.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_ASM_ATOMIC64_H_
#define _LINUXKPI_ASM_ATOMIC64_H_
@@ -125,8 +123,7 @@ atomic64_fetch_add_unless(atomic64_t *v, int64_t a, int64_t u)
static inline int64_t
atomic64_xchg(atomic64_t *v, int64_t i)
{
-#if !((defined(__mips__) && !(defined(__mips_n32) || defined(__mips_n64))) || \
- (defined(__powerpc__) && !defined(__powerpc64__)))
+#if !(defined(__powerpc__) && !defined(__powerpc64__))
return (atomic_swap_64(&v->counter, i));
#else
int64_t ret = atomic64_read(v);
diff --git a/sys/compat/linuxkpi/common/include/asm/barrier.h b/sys/compat/linuxkpi/common/include/asm/barrier.h
index ab59ff19dee0..d09f9c6d2c97 100644
--- a/sys/compat/linuxkpi/common/include/asm/barrier.h
+++ b/sys/compat/linuxkpi/common/include/asm/barrier.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
*
diff --git a/sys/compat/linuxkpi/common/include/asm/byteorder.h b/sys/compat/linuxkpi/common/include/asm/byteorder.h
index 19961303596e..ad7a923ca143 100644
--- a/sys/compat/linuxkpi/common/include/asm/byteorder.h
+++ b/sys/compat/linuxkpi/common/include/asm/byteorder.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_ASM_BYTEORDER_H_
#define _LINUXKPI_ASM_BYTEORDER_H_
diff --git a/sys/compat/linuxkpi/common/include/asm/fcntl.h b/sys/compat/linuxkpi/common/include/asm/fcntl.h
index 2d0285e977e0..3820e15039f2 100644
--- a/sys/compat/linuxkpi/common/include/asm/fcntl.h
+++ b/sys/compat/linuxkpi/common/include/asm/fcntl.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_ASM_FCNTL_H_
#define _LINUXKPI_ASM_FCNTL_H_
diff --git a/sys/compat/linuxkpi/common/include/asm/fpu/api.h b/sys/compat/linuxkpi/common/include/asm/fpu/api.h
index 133754abdc4b..a4803bde461f 100644
--- a/sys/compat/linuxkpi/common/include/asm/fpu/api.h
+++ b/sys/compat/linuxkpi/common/include/asm/fpu/api.h
@@ -1,7 +1,7 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2020 Greg V <greg@unrelenting.technology>
+ * Copyright (c) 2020 Val Packett <val@packett.cool>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/sys/compat/linuxkpi/common/include/asm/hypervisor.h b/sys/compat/linuxkpi/common/include/asm/hypervisor.h
new file mode 100644
index 000000000000..f344a2929359
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/asm/hypervisor.h
@@ -0,0 +1,19 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_ASM_HYPERVISOR_H
+#define _LINUXKPI_ASM_HYPERVISOR_H
+
+#if defined(__i386__) || defined(__amd64__)
+
+#define X86_HYPER_NATIVE 1
+#define X86_HYPER_MS_HYPERV 2
+
+static inline bool
+hypervisor_is_type(int type)
+{
+ return (type == X86_HYPER_NATIVE);
+}
+
+#endif
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/asm/intel-family.h b/sys/compat/linuxkpi/common/include/asm/intel-family.h
new file mode 100644
index 000000000000..91ad1d1a8ff3
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/asm/intel-family.h
@@ -0,0 +1,6 @@
+/* Public domain. */
+
+#define INTEL_FAM6_ALDERLAKE 0x97
+#define INTEL_FAM6_ALDERLAKE_L 0x9A
+
+#define INTEL_FAM6_ROCKETLAKE 0xA7
diff --git a/sys/compat/linuxkpi/common/include/asm/io.h b/sys/compat/linuxkpi/common/include/asm/io.h
index 49eca70a38eb..63d1c8f72f8e 100644
--- a/sys/compat/linuxkpi/common/include/asm/io.h
+++ b/sys/compat/linuxkpi/common/include/asm/io.h
@@ -25,12 +25,17 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_ASM_IO_H_
#define _LINUXKPI_ASM_IO_H_
+#include <sys/param.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
#include <linux/io.h>
+#define virt_to_phys(x) vtophys(x)
+
#endif /* _LINUXKPI_ASM_IO_H_ */
diff --git a/sys/compat/linuxkpi/common/include/asm/memtype.h b/sys/compat/linuxkpi/common/include/asm/memtype.h
new file mode 100644
index 000000000000..c433e54fd7bf
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/asm/memtype.h
@@ -0,0 +1,18 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_ASM_MEMTYPE_H_
+#define _LINUXKPI_ASM_MEMTYPE_H_
+
+#if defined(__amd64__) || defined(__i386__)
+
+#include <asm/cpufeature.h>
+
+static inline bool
+pat_enabled(void)
+{
+ return (boot_cpu_has(X86_FEATURE_PAT));
+}
+
+#endif
+
+#endif /* _LINUXKPI_ASM_MEMTYPE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/asm/msr.h b/sys/compat/linuxkpi/common/include/asm/msr.h
index 9d23e6b1bbc7..6f7c10f2860b 100644
--- a/sys/compat/linuxkpi/common/include/asm/msr.h
+++ b/sys/compat/linuxkpi/common/include/asm/msr.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_ASM_MSR_H_
diff --git a/sys/compat/linuxkpi/common/include/asm/neon.h b/sys/compat/linuxkpi/common/include/asm/neon.h
index 2547fa9304d5..0488a90d6664 100644
--- a/sys/compat/linuxkpi/common/include/asm/neon.h
+++ b/sys/compat/linuxkpi/common/include/asm/neon.h
@@ -1,7 +1,7 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2022 Greg V <greg@unrelenting.technology>
+ * Copyright (c) 2022 Val Packett <val@packett.cool>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/sys/compat/linuxkpi/common/include/asm/pgtable.h b/sys/compat/linuxkpi/common/include/asm/pgtable.h
index 9e66fab8eae4..865662d587db 100644
--- a/sys/compat/linuxkpi/common/include/asm/pgtable.h
+++ b/sys/compat/linuxkpi/common/include/asm/pgtable.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_ASM_PGTABLE_H_
#define _LINUXKPI_ASM_PGTABLE_H_
@@ -42,4 +40,19 @@ typedef struct page *pgtable_t;
#define pgprot_decrypted(prot) (prot)
+#if defined(__i386__) || defined(__amd64__)
+#define _PAGE_BIT_PRESENT 0
+#define _PAGE_BIT_RW 1
+#define _PAGE_BIT_USER 2
+#define _PAGE_BIT_PWT 3
+#define _PAGE_BIT_PCD 4
+#define _PAGE_BIT_PAT 7
+
+#define _PAGE_PRESENT (((pteval_t) 1) << _PAGE_BIT_PRESENT)
+#define _PAGE_RW (((pteval_t) 1) << _PAGE_BIT_RW)
+#define _PAGE_PWT (((pteval_t) 1) << _PAGE_BIT_PWT)
+#define _PAGE_PCD (((pteval_t) 1) << _PAGE_BIT_PCD)
+#define _PAGE_PAT (((pteval_t) 1) << _PAGE_BIT_PAT)
+#endif
+
#endif /* _LINUXKPI_ASM_PGTABLE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/asm/processor.h b/sys/compat/linuxkpi/common/include/asm/processor.h
new file mode 100644
index 000000000000..2bc4b6532544
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/asm/processor.h
@@ -0,0 +1,63 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_ASM_PROCESSOR_H_
+#define _LINUXKPI_ASM_PROCESSOR_H_
+
+#include <sys/types.h>
+#include <machine/cpufunc.h>
+#include <machine/cpu.h>
+
+#if defined(__i386__) || defined(__amd64__)
+#define X86_VENDOR_INTEL 0
+#define X86_VENDOR_CYRIX 1
+#define X86_VENDOR_AMD 2
+#define X86_VENDOR_UMC 3
+#define X86_VENDOR_CENTAUR 5
+#define X86_VENDOR_TRANSMETA 7
+#define X86_VENDOR_NSC 8
+#define X86_VENDOR_HYGON 9
+#define X86_VENDOR_NUM 12
+
+#define X86_VENDOR_UNKNOWN 0xff
+
+struct cpuinfo_x86 {
+ uint8_t x86;
+ uint8_t x86_model;
+ uint16_t x86_clflush_size;
+ uint16_t x86_max_cores;
+ uint8_t x86_vendor;
+};
+
+extern struct cpuinfo_x86 boot_cpu_data;
+extern struct cpuinfo_x86 *__cpu_data;
+#define cpu_data(cpu) __cpu_data[cpu]
+#endif
+
+#define cpu_relax() cpu_spinwait()
+
+#endif /* _LINUXKPI_ASM_PROCESSOR_H_ */
diff --git a/sys/compat/linuxkpi/common/include/asm/set_memory.h b/sys/compat/linuxkpi/common/include/asm/set_memory.h
index cdb7ad912acc..69f659001c60 100644
--- a/sys/compat/linuxkpi/common/include/asm/set_memory.h
+++ b/sys/compat/linuxkpi/common/include/asm/set_memory.h
@@ -34,14 +34,26 @@
static inline int
set_memory_uc(unsigned long addr, int numpages)
{
- return (pmap_change_attr(addr, numpages, VM_MEMATTR_UNCACHEABLE));
+ vm_offset_t va;
+ vm_size_t len;
+
+ va = PHYS_TO_DMAP(addr);
+ len = numpages << PAGE_SHIFT;
+
+ return (-pmap_change_attr(va, len, VM_MEMATTR_UNCACHEABLE));
}
static inline int
set_memory_wc(unsigned long addr, int numpages)
{
#ifdef VM_MEMATTR_WRITE_COMBINING
- return (pmap_change_attr(addr, numpages, VM_MEMATTR_WRITE_COMBINING));
+ vm_offset_t va;
+ vm_size_t len;
+
+ va = PHYS_TO_DMAP(addr);
+ len = numpages << PAGE_SHIFT;
+
+ return (-pmap_change_attr(va, len, VM_MEMATTR_WRITE_COMBINING));
#else
return (set_memory_uc(addr, numpages));
#endif
@@ -50,11 +62,17 @@ set_memory_wc(unsigned long addr, int numpages)
static inline int
set_memory_wb(unsigned long addr, int numpages)
{
- return (pmap_change_attr(addr, numpages, VM_MEMATTR_WRITE_BACK));
+ vm_offset_t va;
+ vm_size_t len;
+
+ va = PHYS_TO_DMAP(addr);
+ len = numpages << PAGE_SHIFT;
+
+ return (-pmap_change_attr(va, len, VM_MEMATTR_WRITE_BACK));
}
static inline int
-set_pages_uc(vm_page_t page, int numpages)
+set_pages_uc(struct page *page, int numpages)
{
KASSERT(numpages == 1, ("%s: numpages %d", __func__, numpages));
@@ -63,7 +81,7 @@ set_pages_uc(vm_page_t page, int numpages)
}
static inline int
-set_pages_wc(vm_page_t page, int numpages)
+set_pages_wc(struct page *page, int numpages)
{
KASSERT(numpages == 1, ("%s: numpages %d", __func__, numpages));
@@ -76,7 +94,7 @@ set_pages_wc(vm_page_t page, int numpages)
}
static inline int
-set_pages_wb(vm_page_t page, int numpages)
+set_pages_wb(struct page *page, int numpages)
{
KASSERT(numpages == 1, ("%s: numpages %d", __func__, numpages));
@@ -85,7 +103,7 @@ set_pages_wb(vm_page_t page, int numpages)
}
static inline int
-set_pages_array_wb(vm_page_t *pages, int addrinarray)
+set_pages_array_wb(struct page **pages, int addrinarray)
{
int i;
@@ -95,7 +113,7 @@ set_pages_array_wb(vm_page_t *pages, int addrinarray)
}
static inline int
-set_pages_array_wc(vm_page_t *pages, int addrinarray)
+set_pages_array_wc(struct page **pages, int addrinarray)
{
int i;
@@ -105,7 +123,7 @@ set_pages_array_wc(vm_page_t *pages, int addrinarray)
}
static inline int
-set_pages_array_uc(vm_page_t *pages, int addrinarray)
+set_pages_array_uc(struct page **pages, int addrinarray)
{
int i;
diff --git a/sys/compat/linuxkpi/common/include/asm/smp.h b/sys/compat/linuxkpi/common/include/asm/smp.h
index c349edb16bf4..27c3a81ef101 100644
--- a/sys/compat/linuxkpi/common/include/asm/smp.h
+++ b/sys/compat/linuxkpi/common/include/asm/smp.h
@@ -22,13 +22,15 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_ASM_SMP_H_
#define _LINUXKPI_ASM_SMP_H_
+#include <linux/jump_label.h>
+#include <linux/preempt.h>
+#include <asm/fpu/api.h>
+
#if defined(__i386__) || defined(__amd64__)
#define wbinvd_on_all_cpus() linux_wbinvd_on_all_cpus()
diff --git a/sys/compat/linuxkpi/common/include/asm/types.h b/sys/compat/linuxkpi/common/include/asm/types.h
index e7d3de60e987..2e61bcfdb5e6 100644
--- a/sys/compat/linuxkpi/common/include/asm/types.h
+++ b/sys/compat/linuxkpi/common/include/asm/types.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_ASM_TYPES_H_
#define _LINUXKPI_ASM_TYPES_H_
diff --git a/sys/compat/linuxkpi/common/include/asm/uaccess.h b/sys/compat/linuxkpi/common/include/asm/uaccess.h
index b3b2cb53d22a..94354f8ddeee 100644
--- a/sys/compat/linuxkpi/common/include/asm/uaccess.h
+++ b/sys/compat/linuxkpi/common/include/asm/uaccess.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_ASM_UACCESS_H_
#define _LINUXKPI_ASM_UACCESS_H_
diff --git a/sys/compat/linuxkpi/common/include/asm/unaligned.h b/sys/compat/linuxkpi/common/include/asm/unaligned.h
index 8a001ec38c3d..e45846a3b543 100644
--- a/sys/compat/linuxkpi/common/include/asm/unaligned.h
+++ b/sys/compat/linuxkpi/common/include/asm/unaligned.h
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2020 The FreeBSD Foundation
+ * Copyright (c) 2020,2023 The FreeBSD Foundation
*
* This software was developed by Björn Zeeb under sponsorship from
* the FreeBSD Foundation.
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_ASM_UNALIGNED_H
@@ -51,6 +49,15 @@ get_unaligned_le32(const void *p)
}
static __inline void
+put_unaligned_le16(__le16 v, void *p)
+{
+ __le16 x;
+
+ x = cpu_to_le16(v);
+ memcpy(p, &x, sizeof(x));
+}
+
+static __inline void
put_unaligned_le32(__le32 v, void *p)
{
__le32 x;
@@ -82,4 +89,11 @@ get_unaligned_be32(const void *p)
return (be32_to_cpup((const __be32 *)p));
}
+static __inline uint64_t
+get_unaligned_be64(const void *p)
+{
+
+ return (be64_to_cpup((const __be64 *)p));
+}
+
#endif /* _LINUXKPI_ASM_UNALIGNED_H */
diff --git a/sys/compat/linuxkpi/common/include/crypto/hash.h b/sys/compat/linuxkpi/common/include/crypto/hash.h
new file mode 100644
index 000000000000..bf401691722a
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/crypto/hash.h
@@ -0,0 +1,94 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Bjoern A. Zeeb
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_CRYPTO_HASH_H
+#define _LINUXKPI_CRYPTO_HASH_H
+
+#include <linux/kernel.h> /* for pr_debug */
+
+struct crypto_shash {
+};
+
+struct shash_desc {
+ struct crypto_shash *tfm;
+};
+
+static inline struct crypto_shash *
+crypto_alloc_shash(const char *algostr, int x, int y)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (NULL);
+}
+
+static inline void
+crypto_free_shash(struct crypto_shash *csh)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static inline int
+crypto_shash_init(struct shash_desc *desc)
+{
+ pr_debug("%s: TODO\n", __func__);
+ return (-ENXIO);
+}
+
+static inline int
+crypto_shash_final(struct shash_desc *desc, uint8_t *mic)
+{
+ pr_debug("%s: TODO\n", __func__);
+ return (-ENXIO);
+}
+
+static inline int
+crypto_shash_setkey(struct crypto_shash *csh, const uint8_t *key, size_t keylen)
+{
+ pr_debug("%s: TODO\n", __func__);
+ return (-ENXIO);
+}
+
+static inline int
+crypto_shash_update(struct shash_desc *desc, uint8_t *data, size_t datalen)
+{
+ pr_debug("%s: TODO\n", __func__);
+ return (-ENXIO);
+}
+
+static inline void
+shash_desc_zero(struct shash_desc *desc)
+{
+
+ explicit_bzero(desc, sizeof(*desc));
+}
+
+/* XXX review this. */
+#define SHASH_DESC_ON_STACK(desc, tfm) \
+ uint8_t ___ ## desc ## _desc[sizeof(struct shash_desc)]; \
+ struct shash_desc *desc = (struct shash_desc *)___ ## desc ## _desc
+
+#endif /* _LINUXKPI_CRYPTO_HASH_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/acpi.h b/sys/compat/linuxkpi/common/include/linux/acpi.h
index 1a9d25e7a7ff..610aa0784cb9 100644
--- a/sys/compat/linuxkpi/common/include/linux/acpi.h
+++ b/sys/compat/linuxkpi/common/include/linux/acpi.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
*
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_ACPI_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/agp_backend.h b/sys/compat/linuxkpi/common/include/linux/agp_backend.h
new file mode 100644
index 000000000000..c855fd842970
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/agp_backend.h
@@ -0,0 +1,28 @@
+/* Public domain */
+
+#ifndef _LINUXKPI_LINUX_AGP_BACKEND_H_
+#define _LINUXKPI_LINUX_AGP_BACKEND_H_
+
+#include <sys/types.h>
+
+struct agp_version {
+ uint16_t major;
+ uint16_t minor;
+};
+
+struct agp_kern_info {
+ struct agp_version version;
+ uint16_t vendor;
+ uint16_t device;
+ unsigned long mode;
+ unsigned long aper_base;
+ size_t aper_size;
+ int max_memory;
+ int current_memory;
+ bool cant_use_aperture;
+ unsigned long page_mask;
+};
+
+struct agp_memory;
+
+#endif /* _LINUXKPI_LINUX_AGP_BACKEND_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/anon_inodes.h b/sys/compat/linuxkpi/common/include/linux/anon_inodes.h
index cab5cbd4d67e..c69f6e152b17 100644
--- a/sys/compat/linuxkpi/common/include/linux/anon_inodes.h
+++ b/sys/compat/linuxkpi/common/include/linux/anon_inodes.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
*
diff --git a/sys/compat/linuxkpi/common/include/linux/apple-gmux.h b/sys/compat/linuxkpi/common/include/linux/apple-gmux.h
new file mode 100644
index 000000000000..812a782c57d4
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/apple-gmux.h
@@ -0,0 +1,12 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_APPLE_GMUX_H
+#define _LINUXKPI_LINUX_APPLE_GMUX_H
+
+static inline bool
+apple_gmux_detect(void *a, void *b)
+{
+ return false;
+}
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/atomic.h b/sys/compat/linuxkpi/common/include/linux/atomic.h
index e491283ae6e5..bc76928a7d67 100644
--- a/sys/compat/linuxkpi/common/include/linux/atomic.h
+++ b/sys/compat/linuxkpi/common/include/linux/atomic.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_ATOMIC_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/average.h b/sys/compat/linuxkpi/common/include/linux/average.h
index 61b2010d6509..4191a351c5c6 100644
--- a/sys/compat/linuxkpi/common/include/linux/average.h
+++ b/sys/compat/linuxkpi/common/include/linux/average.h
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_AVERAGE_H
diff --git a/sys/compat/linuxkpi/common/include/linux/backlight.h b/sys/compat/linuxkpi/common/include/linux/backlight.h
index 9591a4b671ab..4f8f7440925a 100644
--- a/sys/compat/linuxkpi/common/include/linux/backlight.h
+++ b/sys/compat/linuxkpi/common/include/linux/backlight.h
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_BACKLIGHT_H_
@@ -92,6 +90,13 @@ backlight_force_update(struct backlight_device *bd, int reason)
}
static inline int
+backlight_get_brightness(struct backlight_device *bd)
+{
+
+ return (bd->props.brightness);
+}
+
+static inline int
backlight_device_set_brightness(struct backlight_device *bd, int brightness)
{
@@ -119,4 +124,11 @@ backlight_disable(struct backlight_device *bd)
return (backlight_update_status(bd));
}
+static inline bool
+backlight_is_blank(struct backlight_device *bd)
+{
+
+ return (bd->props.power != 0/* FB_BLANK_UNBLANK */);
+}
+
#endif /* _LINUXKPI_LINUX_BACKLIGHT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/bcd.h b/sys/compat/linuxkpi/common/include/linux/bcd.h
index 8a40da1a330b..385819910454 100644
--- a/sys/compat/linuxkpi/common/include/linux/bcd.h
+++ b/sys/compat/linuxkpi/common/include/linux/bcd.h
@@ -23,8 +23,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_BCD_H
diff --git a/sys/compat/linuxkpi/common/include/linux/bitfield.h b/sys/compat/linuxkpi/common/include/linux/bitfield.h
index c22757d54290..a2020d247489 100644
--- a/sys/compat/linuxkpi/common/include/linux/bitfield.h
+++ b/sys/compat/linuxkpi/common/include/linux/bitfield.h
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_BITFIELD_H
@@ -127,6 +125,9 @@ _uX_replace_bits(8)
#define __bf_shf(x) (__builtin_ffsll(x) - 1)
+#define FIELD_FIT(_mask, _value) \
+ (!(((typeof(_mask))(_value) << __bf_shf(_mask)) & ~(_mask)))
+
#define FIELD_PREP(_mask, _value) \
(((typeof(_mask))(_value) << __bf_shf(_mask)) & (_mask))
diff --git a/sys/compat/linuxkpi/common/include/linux/bitmap.h b/sys/compat/linuxkpi/common/include/linux/bitmap.h
index 1ae6078966a4..f26a0f99dc03 100644
--- a/sys/compat/linuxkpi/common/include/linux/bitmap.h
+++ b/sys/compat/linuxkpi/common/include/linux/bitmap.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_BITMAP_H_
@@ -266,6 +264,27 @@ bitmap_subset(const unsigned long *pa,
return (1);
}
+static inline bool
+bitmap_intersects(const unsigned long *pa, const unsigned long *pb,
+ unsigned size)
+{
+ const unsigned end = BIT_WORD(size);
+ const unsigned tail = size & (BITS_PER_LONG - 1);
+ unsigned i;
+
+ for (i = 0; i != end; i++)
+ if (pa[i] & pb[i])
+ return (true);
+
+ if (tail) {
+ const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
+
+ if (pa[end] & pb[end] & mask)
+ return (true);
+ }
+ return (false);
+}
+
static inline void
bitmap_complement(unsigned long *dst, const unsigned long *src,
const unsigned int size)
@@ -289,6 +308,49 @@ bitmap_copy(unsigned long *dst, const unsigned long *src,
}
static inline void
+bitmap_to_arr32(uint32_t *dst, const unsigned long *src, unsigned int size)
+{
+ const unsigned int end = howmany(size, 32);
+
+#ifdef __LP64__
+ unsigned int i = 0;
+ while (i < end) {
+ dst[i++] = (uint32_t)(*src & UINT_MAX);
+ if (i < end)
+ dst[i++] = (uint32_t)(*src >> 32);
+ src++;
+ }
+#else
+ bitmap_copy((unsigned long *)dst, src, size);
+#endif
+ if ((size % 32) != 0) /* Linux uses BITS_PER_LONG. Seems to be a bug */
+ dst[end - 1] &= (uint32_t)(UINT_MAX >> (32 - (size % 32)));
+}
+
+static inline void
+bitmap_from_arr32(unsigned long *dst, const uint32_t *src,
+ unsigned int size)
+{
+ const unsigned int end = BIT_WORD(size);
+ const unsigned int tail = size & (BITS_PER_LONG - 1);
+
+#ifdef __LP64__
+ const unsigned int end32 = howmany(size, 32);
+ unsigned int i = 0;
+
+ while (i < end32) {
+ dst[i++/2] = (unsigned long) *(src++);
+ if (i < end32)
+ dst[i++/2] |= ((unsigned long) *(src++)) << 32;
+ }
+#else
+ bitmap_copy(dst, (const unsigned long *)src, size);
+#endif
+ if ((size % BITS_PER_LONG) != 0)
+ dst[end] &= BITMAP_LAST_WORD_MASK(tail);
+}
+
+static inline void
bitmap_or(unsigned long *dst, const unsigned long *src1,
const unsigned long *src2, const unsigned int size)
{
@@ -332,6 +394,40 @@ bitmap_xor(unsigned long *dst, const unsigned long *src1,
dst[i] = src1[i] ^ src2[i];
}
+static inline void
+bitmap_shift_right(unsigned long *dst, const unsigned long *src,
+ unsigned int shift, unsigned int size)
+{
+ const unsigned int end = BITS_TO_LONGS(size);
+ const unsigned int tail = size & (BITS_PER_LONG - 1);
+ const unsigned long mask = BITMAP_LAST_WORD_MASK(tail);
+ const unsigned int off = BIT_WORD(shift);
+ const unsigned int rem = shift & (BITS_PER_LONG - 1);
+ unsigned long left, right;
+ unsigned int i, srcpos;
+
+ for (i = 0, srcpos = off; srcpos < end; i++, srcpos++) {
+ right = src[srcpos];
+ left = 0;
+
+ if (srcpos == end - 1)
+ right &= mask;
+
+ if (rem != 0) {
+ right >>= rem;
+ if (srcpos + 1 < end) {
+ left = src[srcpos + 1];
+ if (srcpos + 1 == end - 1)
+ left &= mask;
+ left <<= (BITS_PER_LONG - rem);
+ }
+ }
+ dst[i] = left | right;
+ }
+ if (off != 0)
+ memset(dst + end - off, 0, off * sizeof(unsigned long));
+}
+
static inline unsigned long *
bitmap_alloc(unsigned int size, gfp_t flags)
{
diff --git a/sys/compat/linuxkpi/common/include/linux/bitops.h b/sys/compat/linuxkpi/common/include/linux/bitops.h
index b6c54b2e6858..1415d5224084 100644
--- a/sys/compat/linuxkpi/common/include/linux/bitops.h
+++ b/sys/compat/linuxkpi/common/include/linux/bitops.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_BITOPS_H_
#define _LINUXKPI_LINUX_BITOPS_H_
@@ -56,6 +54,7 @@
#define GENMASK_ULL(h, l) (((~0ULL) >> (BITS_PER_LONG_LONG - (h) - 1)) & ((~0ULL) << (l)))
#define BITS_PER_BYTE 8
#define BITS_PER_TYPE(t) (sizeof(t) * BITS_PER_BYTE)
+#define BITS_TO_BYTES(n) howmany((n), BITS_PER_BYTE)
#define hweight8(x) bitcount((uint8_t)(x))
#define hweight16(x) bitcount16(x)
diff --git a/sys/compat/linuxkpi/common/include/linux/bottom_half.h b/sys/compat/linuxkpi/common/include/linux/bottom_half.h
index 1b139c481283..12b170845cbc 100644
--- a/sys/compat/linuxkpi/common/include/linux/bottom_half.h
+++ b/sys/compat/linuxkpi/common/include/linux/bottom_half.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_BOTTOM_HALF_H_
#define _LINUXKPI_LINUX_BOTTOM_HALF_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/bsearch.h b/sys/compat/linuxkpi/common/include/linux/bsearch.h
index 8cc329aa855c..fb67109e4bba 100644
--- a/sys/compat/linuxkpi/common/include/linux/bsearch.h
+++ b/sys/compat/linuxkpi/common/include/linux/bsearch.h
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_BSEARCH_H
diff --git a/sys/compat/linuxkpi/common/include/linux/build_bug.h b/sys/compat/linuxkpi/common/include/linux/build_bug.h
new file mode 100644
index 000000000000..6a026376cfc8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/build_bug.h
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org>
+ * Copyright (c) 2018 Johannes Lundberg <johalun0@gmail.com>
+ * Copyright (c) 2021 The FreeBSD Foundation
+ * Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
+ * Copyright (c) 2023 Serenity Cyber Security, LLC
+ *
+ * Portions of this software were developed by Bjoern A. Zeeb
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_LINUX_BUILD_BUG_H_
+#define _LINUXKPI_LINUX_BUILD_BUG_H_
+
+#include <sys/param.h>
+
+#include <linux/compiler.h>
+
+/*
+ * BUILD_BUG_ON() can happen inside functions where _Static_assert() does not
+ * seem to work. Use old-schoold-ish CTASSERT from before commit
+ * a3085588a88fa58eb5b1eaae471999e1995a29cf but also make sure we do not
+ * end up with an unused typedef or variable. The compiler should optimise
+ * it away entirely.
+ */
+#define _O_CTASSERT(x) _O__CTASSERT(x, __LINE__)
+#define _O__CTASSERT(x, y) _O___CTASSERT(x, y)
+#define _O___CTASSERT(x, y) while (0) { \
+ typedef char __assert_line_ ## y[(x) ? 1 : -1]; \
+ __assert_line_ ## y _x __unused; \
+ _x[0] = '\0'; \
+}
+
+#define BUILD_BUG() do { CTASSERT(0); } while (0)
+#define BUILD_BUG_ON(x) do { _O_CTASSERT(!(x)) } while (0)
+#define BUILD_BUG_ON_MSG(x, msg) BUILD_BUG_ON(x)
+#define BUILD_BUG_ON_NOT_POWER_OF_2(x) BUILD_BUG_ON(!powerof2(x))
+#define BUILD_BUG_ON_INVALID(expr) while (0) { (void)(expr); }
+#define BUILD_BUG_ON_ZERO(x) ((int)sizeof(struct { int:-((x) != 0); }))
+
+#define static_assert(x, ...) __static_assert(x, ##__VA_ARGS__, #x)
+#define __static_assert(x, msg, ...) _Static_assert(x, msg)
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/cache.h b/sys/compat/linuxkpi/common/include/linux/cache.h
index 6479d5d04d3a..b02b28d08ea9 100644
--- a/sys/compat/linuxkpi/common/include/linux/cache.h
+++ b/sys/compat/linuxkpi/common/include/linux/cache.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_CACHE_H_
#define _LINUXKPI_LINUX_CACHE_H_
@@ -35,6 +33,7 @@
#define cache_line_size() CACHE_LINE_SIZE
#define L1_CACHE_BYTES CACHE_LINE_SIZE
+#define L1_CACHE_ALIGN(x) ALIGN(x, CACHE_LINE_SIZE)
#define SMP_CACHE_BYTES L1_CACHE_BYTES
diff --git a/sys/compat/linuxkpi/common/include/linux/capability.h b/sys/compat/linuxkpi/common/include/linux/capability.h
index 547ee586ad8e..e3dacd4e9f15 100644
--- a/sys/compat/linuxkpi/common/include/linux/capability.h
+++ b/sys/compat/linuxkpi/common/include/linux/capability.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2015 Rimvydas Jasinskas
* All rights reserved.
diff --git a/sys/compat/linuxkpi/common/include/linux/cc_platform.h b/sys/compat/linuxkpi/common/include/linux/cc_platform.h
new file mode 100644
index 000000000000..01c0de17f7d2
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/cc_platform.h
@@ -0,0 +1,20 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_CC_PLATFORM_H_
+#define _LINUXKPI_LINUX_CC_PLATFORM_H_
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+
+enum cc_attr {
+ CC_ATTR_MEM_ENCRYPT,
+};
+
+static inline bool
+cc_platform_has(enum cc_attr attr __unused)
+{
+
+ return (false);
+}
+
+#endif /* _LINUXKPI_LINUX_CC_PLATFORM_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/cdev.h b/sys/compat/linuxkpi/common/include/linux/cdev.h
index 2befe9b259cb..d989db14c2f8 100644
--- a/sys/compat/linuxkpi/common/include/linux/cdev.h
+++ b/sys/compat/linuxkpi/common/include/linux/cdev.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_CDEV_H_
#define _LINUXKPI_LINUX_CDEV_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/clocksource.h b/sys/compat/linuxkpi/common/include/linux/clocksource.h
index 8027ed76ec0f..3e7664c3e57e 100644
--- a/sys/compat/linuxkpi/common/include/linux/clocksource.h
+++ b/sys/compat/linuxkpi/common/include/linux/clocksource.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_CLOCKSOURCE_H
#define _LINUXKPI_LINUX_CLOCKSOURCE_H
diff --git a/sys/compat/linuxkpi/common/include/linux/compat.h b/sys/compat/linuxkpi/common/include/linux/compat.h
index b6bb5e8ed24b..8a5a6918bb7c 100644
--- a/sys/compat/linuxkpi/common/include/linux/compat.h
+++ b/sys/compat/linuxkpi/common/include/linux/compat.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_COMPAT_H_
#define _LINUXKPI_LINUX_COMPAT_H_
@@ -43,17 +41,20 @@ extern int linux_alloc_current(struct thread *, int flags);
extern void linux_free_current(struct task_struct *);
extern struct domainset *linux_get_vm_domain_set(int node);
+#define __current_unallocated(td) \
+ __predict_false((td)->td_lkpi_task == NULL)
+
static inline void
linux_set_current(struct thread *td)
{
- if (__predict_false(td->td_lkpi_task == NULL))
+ if (__current_unallocated(td))
lkpi_alloc_current(td, M_WAITOK);
}
static inline int
linux_set_current_flags(struct thread *td, int flags)
{
- if (__predict_false(td->td_lkpi_task == NULL))
+ if (__current_unallocated(td))
return (lkpi_alloc_current(td, flags));
return (0);
}
@@ -61,4 +62,7 @@ linux_set_current_flags(struct thread *td, int flags)
#define compat_ptr(x) ((void *)(uintptr_t)x)
#define ptr_to_compat(x) ((uintptr_t)x)
+typedef void fpu_safe_exec_cb_t(void *ctx);
+void lkpi_fpu_safe_exec(fpu_safe_exec_cb_t func, void *ctx);
+
#endif /* _LINUXKPI_LINUX_COMPAT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/compiler.h b/sys/compat/linuxkpi/common/include/linux/compiler.h
index 87a37228736f..d59e6faed12d 100644
--- a/sys/compat/linuxkpi/common/include/linux/compiler.h
+++ b/sys/compat/linuxkpi/common/include/linux/compiler.h
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_COMPILER_H_
#define _LINUXKPI_LINUX_COMPILER_H_
@@ -64,10 +62,22 @@
#undef __always_inline
#define __always_inline inline
#define noinline __noinline
+#define noinline_for_stack __noinline
#define ____cacheline_aligned __aligned(CACHE_LINE_SIZE)
#define ____cacheline_aligned_in_smp __aligned(CACHE_LINE_SIZE)
#define fallthrough /* FALLTHROUGH */ do { } while(0)
+#if __has_attribute(__nonstring__)
+#define __nonstring __attribute__((__nonstring__))
+#else
+#define __nonstring
+#endif
+#if __has_attribute(__counted_by__)
+#define __counted_by(_x) __attribute__((__counted_by__(_x)))
+#else
+#define __counted_by(_x)
+#endif
+
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#define typeof(x) __typeof(x)
@@ -87,18 +97,16 @@
#define ___PASTE(a,b) a##b
#define __PASTE(a,b) ___PASTE(a,b)
-#define ACCESS_ONCE(x) (*(volatile __typeof(x) *)&(x))
-
#define WRITE_ONCE(x,v) do { \
barrier(); \
- ACCESS_ONCE(x) = (v); \
+ (*(volatile __typeof(x) *)(uintptr_t)&(x)) = (v); \
barrier(); \
} while (0)
#define READ_ONCE(x) ({ \
__typeof(x) __var = ({ \
barrier(); \
- ACCESS_ONCE(x); \
+ (*(const volatile __typeof(x) *)&(x)); \
}); \
barrier(); \
__var; \
@@ -113,4 +121,7 @@
#define sizeof_field(_s, _m) sizeof(((_s *)0)->_m)
+#define is_signed_type(t) ((t)-1 < (t)1)
+#define is_unsigned_type(t) ((t)-1 > (t)1)
+
#endif /* _LINUXKPI_LINUX_COMPILER_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/completion.h b/sys/compat/linuxkpi/common/include/linux/completion.h
index 2f58bd5c03e6..26e41a51c10b 100644
--- a/sys/compat/linuxkpi/common/include/linux/completion.h
+++ b/sys/compat/linuxkpi/common/include/linux/completion.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_COMPLETION_H_
#define _LINUXKPI_LINUX_COMPLETION_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/container_of.h b/sys/compat/linuxkpi/common/include/linux/container_of.h
new file mode 100644
index 000000000000..449507fcf9c1
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/container_of.h
@@ -0,0 +1,46 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2017 Matt Macy <mmacy@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_LINUX_CONTAINER_OF_H
+#define _LINUXKPI_LINUX_CONTAINER_OF_H
+
+#include <sys/stdint.h>
+
+#include <linux/build_bug.h>
+#include <linux/stddef.h>
+
+#define container_of(ptr, type, member) \
+({ \
+ const __typeof(((type *)0)->member) *__p = (ptr); \
+ (type *)((uintptr_t)__p - offsetof(type, member)); \
+})
+
+#define typeof_member(type, member) __typeof(((type *)0)->member)
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/cpu.h b/sys/compat/linuxkpi/common/include/linux/cpu.h
index 53fa9db424c2..43ec3d66a2e3 100644
--- a/sys/compat/linuxkpi/common/include/linux/cpu.h
+++ b/sys/compat/linuxkpi/common/include/linux/cpu.h
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_CPU_H
@@ -44,6 +42,8 @@ typedef cpuset_t cpumask_t;
extern cpumask_t cpu_online_mask;
+cpumask_t *lkpi_get_static_single_cpu_mask(int);
+
static __inline int
cpumask_next(int cpuid, cpumask_t mask)
{
@@ -73,4 +73,6 @@ cpumask_set_cpu(int cpu, cpumask_t *mask)
CPU_SET(cpu, mask);
}
+#define cpumask_of(_cpu) (lkpi_get_static_single_cpu_mask(_cpu))
+
#endif /* _LINUXKPI_LINUX_CPU_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/crc32.h b/sys/compat/linuxkpi/common/include/linux/crc32.h
index a93be642fb1a..e6d39fa7c5ff 100644
--- a/sys/compat/linuxkpi/common/include/linux/crc32.h
+++ b/sys/compat/linuxkpi/common/include/linux/crc32.h
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_CRC32_H
diff --git a/sys/compat/linuxkpi/common/include/linux/dcache.h b/sys/compat/linuxkpi/common/include/linux/dcache.h
index 9f9943a18dc6..992d6f7c2720 100644
--- a/sys/compat/linuxkpi/common/include/linux/dcache.h
+++ b/sys/compat/linuxkpi/common/include/linux/dcache.h
@@ -22,15 +22,14 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_DCACHE_H
#define _LINUXKPI_LINUX_DCACHE_H
-struct vnode;
-struct pfs_node;
+#include <sys/vnode.h>
+
+#include <fs/pseudofs/pseudofs.h>
struct dentry {
struct vnode *d_inode;
diff --git a/sys/compat/linuxkpi/common/include/linux/debugfs.h b/sys/compat/linuxkpi/common/include/linux/debugfs.h
index 6a3273cbbf3c..470b50cb730c 100644
--- a/sys/compat/linuxkpi/common/include/linux/debugfs.h
+++ b/sys/compat/linuxkpi/common/include/linux/debugfs.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2016-2018, Matthew Macy <mmacy@freebsd.org>
*
@@ -23,29 +23,96 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_DEBUGFS_H_
#define _LINUXKPI_LINUX_DEBUGFS_H_
#include <linux/fs.h>
+#include <linux/module.h>
#include <linux/seq_file.h>
-
#include <linux/types.h>
-void debugfs_remove(struct dentry *dentry);
+MALLOC_DECLARE(M_DFSINT);
+
+struct debugfs_reg32 {
+ char *name;
+ unsigned long offset;
+};
+
+struct debugfs_regset32 {
+ const struct debugfs_reg32 *regs;
+ int nregs;
+};
+
+struct debugfs_blob_wrapper {
+ void *data;
+ size_t size;
+};
+
+static inline bool
+debugfs_initialized(void)
+{
+
+ return (true);
+}
struct dentry *debugfs_create_file(const char *name, umode_t mode,
- struct dentry *parent, void *data,
- const struct file_operations *fops);
+ struct dentry *parent, void *data,
+ const struct file_operations *fops);
+
+/* TODO: We currently ignore the `file_size` argument. */
+struct dentry *debugfs_create_file_size(const char *name, umode_t mode,
+ struct dentry *parent, void *data,
+ const struct file_operations *fops,
+ loff_t file_size);
+
+struct dentry *debugfs_create_file_unsafe(const char *name, umode_t mode,
+struct dentry *parent, void *data,
+ const struct file_operations *fops);
+
+struct dentry *debugfs_create_mode_unsafe(const char *name, umode_t mode,
+ struct dentry *parent, void *data,
+ const struct file_operations *fops,
+ const struct file_operations *fops_ro,
+ const struct file_operations *fops_wo);
struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
- const char *dest);
+ const char *dest);
+
+void debugfs_remove(struct dentry *dentry);
void debugfs_remove_recursive(struct dentry *dentry);
-#endif
+#define DEFINE_DEBUGFS_ATTRIBUTE(__fops, __get, __set, __fmt) \
+ DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt)
+
+void debugfs_create_bool(const char *name, umode_t mode, struct dentry *parent,
+ bool *value);
+void debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent,
+ uint8_t *value);
+void debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent,
+ uint16_t *value);
+void debugfs_create_u32(const char *name, umode_t mode, struct dentry *parent,
+ uint32_t *value);
+void debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent,
+ uint64_t *value);
+void debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent,
+ uint8_t *value);
+void debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent,
+ uint16_t *value);
+void debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent,
+ uint32_t *value);
+void debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent,
+ uint64_t *value);
+void debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent,
+ unsigned long *value);
+void debugfs_create_atomic_t(const char *name, umode_t mode, struct dentry *parent,
+ atomic_t *value);
+
+struct dentry *debugfs_create_blob(const char *name, umode_t mode,
+ struct dentry *parent, struct debugfs_blob_wrapper *value);
+
+#endif /* _LINUXKPI_LINUX_DEBUGFS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/delay.h b/sys/compat/linuxkpi/common/include/linux/delay.h
index ea0a8253b09f..f19d1a759c26 100644
--- a/sys/compat/linuxkpi/common/include/linux/delay.h
+++ b/sys/compat/linuxkpi/common/include/linux/delay.h
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_DELAY_H_
#define _LINUXKPI_LINUX_DELAY_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/devcoredump.h b/sys/compat/linuxkpi/common/include/linux/devcoredump.h
index eecf5380bfc3..b58c490615ad 100644
--- a/sys/compat/linuxkpi/common/include/linux/devcoredump.h
+++ b/sys/compat/linuxkpi/common/include/linux/devcoredump.h
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _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 1c26cecfd955..668fe9cb8650 100644
--- a/sys/compat/linuxkpi/common/include/linux/device.h
+++ b/sys/compat/linuxkpi/common/include/linux/device.h
@@ -4,6 +4,10 @@
* Copyright (c) 2010 Panasas, Inc.
* Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
* All rights reserved.
+ * Copyright (c) 2021-2022 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,8 +29,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_DEVICE_H_
#define _LINUXKPI_LINUX_DEVICE_H_
@@ -37,21 +39,21 @@
#include <linux/sysfs.h>
#include <linux/list.h>
#include <linux/compiler.h>
-#include <linux/types.h>
#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/kdev_t.h>
#include <linux/backlight.h>
#include <linux/pm.h>
#include <linux/idr.h>
+#include <linux/overflow.h>
#include <linux/ratelimit.h> /* via linux/dev_printk.h */
+#include <linux/fwnode.h>
#include <asm/atomic.h>
#include <sys/bus.h>
#include <sys/backlight.h>
struct device;
-struct fwnode_handle;
struct class {
const char *name;
@@ -67,6 +69,7 @@ struct class {
struct dev_pm_ops {
int (*prepare)(struct device *dev);
+ void (*complete)(struct device *dev);
int (*suspend)(struct device *dev);
int (*suspend_late)(struct device *dev);
int (*resume)(struct device *dev);
@@ -79,6 +82,7 @@ struct dev_pm_ops {
int (*poweroff_late)(struct device *dev);
int (*restore)(struct device *dev);
int (*restore_early)(struct device *dev);
+ int (*suspend_noirq)(struct device *dev);
int (*runtime_suspend)(struct device *dev);
int (*runtime_resume)(struct device *dev);
int (*runtime_idle)(struct device *dev);
@@ -124,6 +128,8 @@ struct device {
spinlock_t devres_lock;
struct list_head devres_head;
+
+ struct dev_pm_info power;
};
extern struct device linux_root_device;
@@ -183,15 +189,31 @@ show_class_attr_string(struct class *class,
struct class_attribute_string class_attr_##_name = \
_CLASS_ATTR_STRING(_name, _mode, _str)
-#define dev_err(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
-#define dev_crit(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
-#define dev_warn(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
-#define dev_info(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
-#define dev_notice(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
-#define dev_emerg(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
-#define dev_dbg(dev, fmt, ...) do { } while (0)
#define dev_printk(lvl, dev, fmt, ...) \
- device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+ device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+
+#define dev_emerg(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+#define dev_alert(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+#define dev_crit(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+#define dev_err(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+#define dev_warn(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+#define dev_notice(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+#define dev_info(dev, fmt, ...) device_printf((dev)->bsddev, fmt, ##__VA_ARGS__)
+#define dev_dbg(dev, fmt, ...) do { } while (0)
+
+#define dev_WARN(dev, fmt, ...) \
+ device_printf((dev)->bsddev, "%s:%d: " fmt, __func__, __LINE__, ##__VA_ARGS__)
+
+#define dev_WARN_ONCE(dev, condition, fmt, ...) do { \
+ static bool __dev_WARN_ONCE; \
+ bool __ret_warn_on = (condition); \
+ if (unlikely(__ret_warn_on)) { \
+ if (!__dev_WARN_ONCE) { \
+ __dev_WARN_ONCE = true; \
+ device_printf((dev)->bsddev, "%s:%d: " fmt, __func__, __LINE__, ##__VA_ARGS__); \
+ } \
+ } \
+} while (0)
#define dev_info_once(dev, ...) do { \
static bool __dev_info_once; \
@@ -201,6 +223,14 @@ show_class_attr_string(struct class *class,
} \
} while (0)
+#define dev_warn_once(dev, ...) do { \
+ static bool __dev_warn_once; \
+ if (!__dev_warn_once) { \
+ __dev_warn_once = 1; \
+ dev_warn(dev, __VA_ARGS__); \
+ } \
+} while (0)
+
#define dev_err_once(dev, ...) do { \
static bool __dev_err_once; \
if (!__dev_err_once) { \
@@ -209,6 +239,14 @@ show_class_attr_string(struct class *class,
} \
} while (0)
+#define dev_dbg_once(dev, ...) do { \
+ static bool __dev_dbg_once; \
+ if (!__dev_dbg_once) { \
+ __dev_dbg_once = 1; \
+ dev_dbg(dev, __VA_ARGS__); \
+ } \
+} while (0)
+
#define dev_err_ratelimited(dev, ...) do { \
static linux_ratelimit_t __ratelimited; \
if (linux_ratelimited(&__ratelimited)) \
@@ -221,6 +259,12 @@ show_class_attr_string(struct class *class,
dev_warn(dev, __VA_ARGS__); \
} while (0)
+#define dev_dbg_ratelimited(dev, ...) do { \
+ static linux_ratelimit_t __ratelimited; \
+ if (linux_ratelimited(&__ratelimited)) \
+ dev_dbg(dev, __VA_ARGS__); \
+} while (0)
+
/* Public and LinuxKPI internal devres functions. */
void *lkpi_devres_alloc(void(*release)(struct device *, void *), size_t, gfp_t);
void lkpi_devres_add(struct device *, void *);
@@ -239,6 +283,7 @@ int lkpi_devres_destroy(struct device *, void(*release)(struct device *, void *)
void lkpi_devres_release_free_list(struct device *);
void lkpi_devres_unlink(struct device *, void *);
void lkpi_devm_kmalloc_release(struct device *, void *);
+#define devm_kfree(_d, _p) lkpi_devm_kmalloc_release(_d, _p)
static inline const char *
dev_driver_string(const struct device *dev)
@@ -525,6 +570,30 @@ device_reprobe(struct device *dev)
return (-error);
}
+static inline void
+device_set_wakeup_enable(struct device *dev __unused, bool enable __unused)
+{
+
+ /*
+ * XXX-BZ TODO This is used by wireless drivers supporting WoWLAN which
+ * we currently do not support.
+ */
+}
+
+static inline int
+device_wakeup_enable(struct device *dev)
+{
+
+ device_set_wakeup_enable(dev, true);
+ return (0);
+}
+
+static inline bool
+device_iommu_mapped(struct device *dev __unused)
+{
+ return (false);
+}
+
#define dev_pm_set_driver_flags(dev, flags) do { \
} while (0)
@@ -601,10 +670,32 @@ devm_kmalloc(struct device *dev, size_t size, gfp_t gfp)
return (p);
}
+static inline void *
+devm_kmemdup(struct device *dev, const void *src, size_t len, gfp_t gfp)
+{
+ void *dst;
+
+ if (len == 0)
+ return (NULL);
+
+ dst = devm_kmalloc(dev, len, gfp);
+ if (dst != NULL)
+ memcpy(dst, src, len);
+
+ return (dst);
+}
+
#define devm_kzalloc(_dev, _size, _gfp) \
devm_kmalloc((_dev), (_size), (_gfp) | __GFP_ZERO)
#define devm_kcalloc(_dev, _sizen, _size, _gfp) \
devm_kmalloc((_dev), ((_sizen) * (_size)), (_gfp) | __GFP_ZERO)
+int lkpi_devm_add_action(struct device *dev, void (*action)(void *), void *data);
+#define devm_add_action(dev, action, data) \
+ lkpi_devm_add_action(dev, action, data);
+int lkpi_devm_add_action_or_reset(struct device *dev, void (*action)(void *), void *data);
+#define devm_add_action_or_reset(dev, action, data) \
+ lkpi_devm_add_action_or_reset(dev, action, data)
+
#endif /* _LINUXKPI_LINUX_DEVICE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/dma-attrs.h b/sys/compat/linuxkpi/common/include/linux/dma-attrs.h
index 741e1aa15d67..c9cfa9b621d5 100644
--- a/sys/compat/linuxkpi/common/include/linux/dma-attrs.h
+++ b/sys/compat/linuxkpi/common/include/linux/dma-attrs.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_DMA_ATTR_H_
#define _LINUXKPI_LINUX_DMA_ATTR_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/dma-buf-map.h b/sys/compat/linuxkpi/common/include/linux/dma-buf-map.h
new file mode 100644
index 000000000000..567ce3b072b3
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/dma-buf-map.h
@@ -0,0 +1,91 @@
+/* Public domain. */
+
+#ifndef _LINUX_DMA_BUF_MAP_H
+#define _LINUX_DMA_BUF_MAP_H
+
+#include <linux/io.h>
+#include <linux/string.h>
+
+struct dma_buf_map {
+ union {
+ void *vaddr_iomem;
+ void *vaddr;
+ };
+ bool is_iomem;
+};
+
+static inline void
+dma_buf_map_incr(struct dma_buf_map *dbm, size_t n)
+{
+ if (dbm->is_iomem)
+ dbm->vaddr_iomem += n;
+ else
+ dbm->vaddr += n;
+}
+
+static inline void
+dma_buf_map_memcpy_to(struct dma_buf_map *dbm, const void *src, size_t len)
+{
+ if (dbm->is_iomem)
+ memcpy_toio(dbm->vaddr_iomem, src, len);
+ else
+ memcpy(dbm->vaddr, src, len);
+}
+
+static inline bool
+dma_buf_map_is_null(const struct dma_buf_map *dbm)
+{
+ if (dbm->is_iomem)
+ return (dbm->vaddr_iomem == NULL);
+ else
+ return (dbm->vaddr == NULL);
+}
+
+static inline bool
+dma_buf_map_is_set(const struct dma_buf_map *dbm)
+{
+ if (dbm->is_iomem)
+ return (dbm->vaddr_iomem != NULL);
+ else
+ return (dbm->vaddr != NULL);
+}
+
+static inline bool
+dma_buf_map_is_equal(
+ const struct dma_buf_map *dbm_a, const struct dma_buf_map *dbm_b)
+{
+ if (dbm_a->is_iomem != dbm_b->is_iomem)
+ return (false);
+
+ if (dbm_a->is_iomem)
+ return (dbm_a->vaddr_iomem == dbm_b->vaddr_iomem);
+ else
+ return (dbm_a->vaddr == dbm_b->vaddr);
+}
+
+static inline void
+dma_buf_map_clear(struct dma_buf_map *dbm)
+{
+ if (dbm->is_iomem) {
+ dbm->vaddr_iomem = NULL;
+ dbm->is_iomem = false;
+ } else {
+ dbm->vaddr = NULL;
+ }
+}
+
+static inline void
+dma_buf_map_set_vaddr_iomem(struct dma_buf_map *dbm, void *addr)
+{
+ dbm->vaddr_iomem = addr;
+ dbm->is_iomem = true;
+}
+
+static inline void
+dma_buf_map_set_vaddr(struct dma_buf_map *dbm, void *addr)
+{
+ dbm->vaddr = addr;
+ dbm->is_iomem = false;
+}
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/dma-mapping.h b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h
index dd3bbc094dfb..84f0361de765 100644
--- a/sys/compat/linuxkpi/common/include/linux/dma-mapping.h
+++ b/sys/compat/linuxkpi/common/include/linux/dma-mapping.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_DMA_MAPPING_H_
#define _LINUXKPI_LINUX_DMA_MAPPING_H_
@@ -45,6 +43,7 @@
#include <vm/vm.h>
#include <vm/vm_page.h>
+#include <vm/uma_align_mask.h>
#include <vm/pmap.h>
#include <machine/bus.h>
@@ -95,6 +94,8 @@ int linux_dma_tag_init(struct device *, u64);
int linux_dma_tag_init_coherent(struct device *, u64);
void *linux_dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flag);
+void *linuxkpi_dmam_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag);
dma_addr_t linux_dma_map_phys(struct device *dev, vm_paddr_t phys, size_t len);
void linux_dma_unmap(struct device *dev, dma_addr_t dma_addr, size_t size);
int linux_dma_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
@@ -159,13 +160,21 @@ dma_zalloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
return (dma_alloc_coherent(dev, size, dma_handle, flag | __GFP_ZERO));
}
+static inline void *
+dmam_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+ gfp_t flag)
+{
+
+ return (linuxkpi_dmam_alloc_coherent(dev, size, dma_handle, flag));
+}
+
static inline void
dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
dma_addr_t dma_addr)
{
linux_dma_unmap(dev, dma_addr, size);
- kmem_free((vm_offset_t)cpu_addr, size);
+ kmem_free(cpu_addr, size);
}
static inline dma_addr_t
@@ -173,7 +182,7 @@ dma_map_page_attrs(struct device *dev, struct page *page, size_t offset,
size_t size, enum dma_data_direction dir, unsigned long attrs)
{
- return (linux_dma_map_phys(dev, VM_PAGE_TO_PHYS(page) + offset, size));
+ return (linux_dma_map_phys(dev, page_to_phys(page) + offset, size));
}
/* linux_dma_(un)map_sg_attrs does not support attrs yet */
@@ -188,7 +197,7 @@ 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, VM_PAGE_TO_PHYS(page) + offset, size));
+ return (linux_dma_map_phys(dev, page_to_phys(page) + offset, size));
}
static inline void
@@ -278,11 +287,15 @@ dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
{
}
+#define DMA_MAPPING_ERROR (~(dma_addr_t)0)
+
static inline int
dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
- return (dma_addr == 0);
+ if (dma_addr == 0 || dma_addr == DMA_MAPPING_ERROR)
+ return (-ENOMEM);
+ return (0);
}
static inline unsigned int dma_set_max_seg_size(struct device *dev,
@@ -338,7 +351,31 @@ dma_max_mapping_size(struct device *dev)
#define dma_unmap_len(p, name) ((p)->name)
#define dma_unmap_len_set(p, name, v) (((p)->name) = (v))
-extern int uma_align_cache;
-#define dma_get_cache_alignment() uma_align_cache
+#define dma_get_cache_alignment() (uma_get_cache_align_mask() + 1)
+
+
+static inline int
+dma_map_sgtable(struct device *dev, struct sg_table *sgt,
+ enum dma_data_direction dir,
+ unsigned long attrs)
+{
+ int nents;
+
+ nents = dma_map_sg_attrs(dev, sgt->sgl, sgt->nents, dir, attrs);
+ if (nents < 0)
+ return (nents);
+ sgt->nents = nents;
+ return (0);
+}
+
+static inline void
+dma_unmap_sgtable(struct device *dev, struct sg_table *sgt,
+ enum dma_data_direction dir,
+ unsigned long attrs)
+{
+
+ dma_unmap_sg_attrs(dev, sgt->sgl, sgt->nents, dir, attrs);
+}
+
#endif /* _LINUXKPI_LINUX_DMA_MAPPING_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/dmapool.h b/sys/compat/linuxkpi/common/include/linux/dmapool.h
index e45472dabc60..8501a32e30b7 100644
--- a/sys/compat/linuxkpi/common/include/linux/dmapool.h
+++ b/sys/compat/linuxkpi/common/include/linux/dmapool.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_DMAPOOL_H_
#define _LINUXKPI_LINUX_DMAPOOL_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/dmi.h b/sys/compat/linuxkpi/common/include/linux/dmi.h
index 339f622f89b2..d9760ee0324f 100644
--- a/sys/compat/linuxkpi/common/include/linux/dmi.h
+++ b/sys/compat/linuxkpi/common/include/linux/dmi.h
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef __LINUXKPI_LINUX_DMI_H__
@@ -34,6 +32,12 @@
#include <sys/types.h>
#include <linux/mod_devicetable.h>
+struct dmi_header {
+ uint8_t type;
+ uint8_t length;
+ uint16_t handle;
+};
+
int linux_dmi_check_system(const struct dmi_system_id *);
bool linux_dmi_match(enum dmi_field, const char *);
const struct dmi_system_id *linux_dmi_first_match(const struct dmi_system_id *);
@@ -44,4 +48,11 @@ const char *linux_dmi_get_system_info(int);
#define dmi_first_match(sysid) linux_dmi_first_match(sysid)
#define dmi_get_system_info(sysid) linux_dmi_get_system_info(sysid)
+static inline int
+dmi_walk(void (*callbackf)(const struct dmi_header *, void *), void *arg)
+{
+
+ return (-ENXIO);
+}
+
#endif /* __LINUXKPI_LINUX_DMI_H__ */
diff --git a/sys/compat/linuxkpi/common/include/linux/dynamic_debug.h b/sys/compat/linuxkpi/common/include/linux/dynamic_debug.h
new file mode 100644
index 000000000000..12915eec3b68
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/dynamic_debug.h
@@ -0,0 +1,8 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_DYNAMIC_DEBUG_H
+#define _LINUXKPI_LINUX_DYNAMIC_DEBUG_H
+
+#define DECLARE_DYNDBG_CLASSMAP(a, b, c, ...)
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/efi.h b/sys/compat/linuxkpi/common/include/linux/efi.h
index 03702bba557a..a485b4b1fd94 100644
--- a/sys/compat/linuxkpi/common/include/linux/efi.h
+++ b/sys/compat/linuxkpi/common/include/linux/efi.h
@@ -29,6 +29,7 @@
#define _LINUXKPI_LINUX_EFI_H_
#include <sys/param.h>
+#include <sys/queue.h>
#include <sys/linker.h>
#include <sys/systm.h>
diff --git a/sys/compat/linuxkpi/common/include/linux/err.h b/sys/compat/linuxkpi/common/include/linux/err.h
index 693f7962df65..3d19949e641e 100644
--- a/sys/compat/linuxkpi/common/include/linux/err.h
+++ b/sys/compat/linuxkpi/common/include/linux/err.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_ERR_H_
#define _LINUXKPI_LINUX_ERR_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/errno.h b/sys/compat/linuxkpi/common/include/linux/errno.h
index 72d8af6779a5..ea258587c6f7 100644
--- a/sys/compat/linuxkpi/common/include/linux/errno.h
+++ b/sys/compat/linuxkpi/common/include/linux/errno.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_ERRNO_H_
#define _LINUXKPI_LINUX_ERRNO_H_
@@ -34,6 +32,8 @@
#include <sys/errno.h>
#define EBADRQC 56 /* Bad request code */
+#define EBADSLT 57 /* Invalid slot */
+#define ENOKEY 126 /* Required key not available */
#define ECHRNG EDOM
#define ETIME ETIMEDOUT
diff --git a/sys/compat/linuxkpi/common/include/linux/etherdevice.h b/sys/compat/linuxkpi/common/include/linux/etherdevice.h
index 219ed55a880d..89cd4c8e0ba0 100644
--- a/sys/compat/linuxkpi/common/include/linux/etherdevice.h
+++ b/sys/compat/linuxkpi/common/include/linux/etherdevice.h
@@ -21,8 +21,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_ETHERDEVICE_H_
#define _LINUXKPI_LINUX_ETHERDEVICE_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/ethtool.h b/sys/compat/linuxkpi/common/include/linux/ethtool.h
index 9195766f752d..f5567cd7ea40 100644
--- a/sys/compat/linuxkpi/common/include/linux/ethtool.h
+++ b/sys/compat/linuxkpi/common/include/linux/ethtool.h
@@ -23,8 +23,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_ETHTOOL_H_
@@ -32,10 +30,28 @@
#include <linux/types.h>
-#define ETHTOOL_FWVERS_LEN 64
+#define ETH_GSTRING_LEN (2 * IF_NAMESIZE) /* Increase if not large enough */
+
+#define ETHTOOL_FWVERS_LEN 32
struct ethtool_stats {
uint8_t __dummy[0];
};
+enum ethtool_ss {
+ ETH_SS_STATS,
+};
+
+struct ethtool_drvinfo {
+ char driver[32];
+ char version[32];
+ char fw_version[ETHTOOL_FWVERS_LEN];
+ char bus_info[32];
+};
+
+struct net_device;
+struct ethtool_ops {
+ void(*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);
+};
+
#endif /* _LINUXKPI_LINUX_ETHTOOL_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/eventpoll.h b/sys/compat/linuxkpi/common/include/linux/eventpoll.h
new file mode 100644
index 000000000000..e77e6d689f86
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/eventpoll.h
@@ -0,0 +1,45 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022, Jake Freeland <jfree@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_LINUX_EVENTPOLL_H_
+#define _LINUXKPI_LINUX_EVENTPOLL_H_
+
+#include <sys/poll.h>
+
+#define EPOLLIN POLLIN
+#define EPOLLPRI POLLPRI
+#define EPOLLOUT POLLOUT
+#define EPOLLERR POLLERR
+#define EPOLLHUP POLLHUP
+#define EPOLLNVAL POLLNVAL
+#define EPOLLRDNORM POLLRDNORM
+#define EPOLLRDBAND POLLRDBAND
+#define EPOLLWRNORM POLLWRNORM
+#define EPOLLWRBAND POLLWRBAND
+#define EPOLLRDHUP POLLRDHUP
+
+#endif /* _LINUXKPI_LINUX_EVENTPOLL_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/export.h b/sys/compat/linuxkpi/common/include/linux/export.h
index e9ac669a535f..f48bd6af45d3 100644
--- a/sys/compat/linuxkpi/common/include/linux/export.h
+++ b/sys/compat/linuxkpi/common/include/linux/export.h
@@ -21,8 +21,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_EXPORT_H
#define _LINUXKPI_LINUX_EXPORT_H
diff --git a/sys/compat/linuxkpi/common/include/linux/file.h b/sys/compat/linuxkpi/common/include/linux/file.h
index 32db72d771fc..f94e3d89ced1 100644
--- a/sys/compat/linuxkpi/common/include/linux/file.h
+++ b/sys/compat/linuxkpi/common/include/linux/file.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_FILE_H_
#define _LINUXKPI_LINUX_FILE_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/firmware.h b/sys/compat/linuxkpi/common/include/linux/firmware.h
index ada7d0d73edf..a6330ddafb55 100644
--- a/sys/compat/linuxkpi/common/include/linux/firmware.h
+++ b/sys/compat/linuxkpi/common/include/linux/firmware.h
@@ -2,6 +2,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020-2021 The FreeBSD Foundation
+ * Copyright (c) 2022 Bjoern A. Zeeb
*
* This software was developed by Björn Zeeb under sponsorship from
* the FreeBSD Foundation.
@@ -26,8 +27,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_FIRMWARE_H
@@ -56,6 +55,8 @@ int linuxkpi_request_firmware(const struct linuxkpi_firmware **,
int linuxkpi_firmware_request_nowarn(const struct linuxkpi_firmware **,
const char *, struct device *);
void linuxkpi_release_firmware(const struct linuxkpi_firmware *);
+int linuxkpi_request_partial_firmware_into_buf(const struct linuxkpi_firmware **,
+ const char *, struct device *, uint8_t *, size_t, size_t);
static __inline int
@@ -100,6 +101,16 @@ release_firmware(const struct linuxkpi_firmware *fw)
linuxkpi_release_firmware(fw);
}
+static inline int
+request_partial_firmware_into_buf(const struct linuxkpi_firmware **fw,
+ const char *fw_name, struct device *dev, void *buf, size_t buflen,
+ size_t offset)
+{
+
+ return (linuxkpi_request_partial_firmware_into_buf(fw, fw_name,
+ dev, buf, buflen, offset));
+}
+
#define firmware linuxkpi_firmware
#endif /* _LINUXKPI_LINUX_FIRMWARE_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/fs.h b/sys/compat/linuxkpi/common/include/linux/fs.h
index a21c140d5a9b..a28d5bf97121 100644
--- a/sys/compat/linuxkpi/common/include/linux/fs.h
+++ b/sys/compat/linuxkpi/common/include/linux/fs.h
@@ -25,13 +25,10 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_FS_H_
#define _LINUXKPI_LINUX_FS_H_
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
@@ -45,6 +42,8 @@
#include <linux/dcache.h>
#include <linux/capability.h>
#include <linux/wait_bit.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
struct module;
struct kiocb;
@@ -250,6 +249,7 @@ nonseekable_open(struct inode *inode, struct file *filp)
static inline int
simple_open(struct inode *inode, struct file *filp)
{
+ filp->private_data = inode->i_private;
return 0;
}
@@ -298,6 +298,18 @@ no_llseek(struct file *file, loff_t offset, int whence)
}
static inline loff_t
+default_llseek(struct file *file, loff_t offset, int whence)
+{
+ return (no_llseek(file, offset, whence));
+}
+
+static inline loff_t
+generic_file_llseek(struct file *file, loff_t offset, int whence)
+{
+ return (no_llseek(file, offset, whence));
+}
+
+static inline loff_t
noop_llseek(struct linux_file *file, loff_t offset, int whence)
{
@@ -318,4 +330,73 @@ call_mmap(struct linux_file *file, struct vm_area_struct *vma)
return (file->f_op->mmap(file, vma));
}
+static inline void
+i_size_write(struct inode *inode, loff_t i_size)
+{
+}
+
+/*
+ * simple_read_from_buffer: copy data from kernel-space origin
+ * buffer into user-space destination buffer
+ *
+ * @dest: destination buffer
+ * @read_size: number of bytes to be transferred
+ * @ppos: starting transfer position pointer
+ * @orig: origin buffer
+ * @buf_size: size of destination and origin buffers
+ *
+ * Return value:
+ * On success, total bytes copied with *ppos incremented accordingly.
+ * On failure, negative value.
+ */
+static inline ssize_t
+simple_read_from_buffer(void __user *dest, size_t read_size, loff_t *ppos,
+ void *orig, size_t buf_size)
+{
+ void *read_pos = ((char *) orig) + *ppos;
+ size_t buf_remain = buf_size - *ppos;
+ ssize_t num_read;
+
+ if (buf_remain < 0 || buf_remain > buf_size)
+ return -EINVAL;
+
+ if (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);
+}
+
+MALLOC_DECLARE(M_LSATTR);
+
+#define DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \
+static inline int \
+__fops ## _open(struct inode *inode, struct file *filp) \
+{ \
+ return (simple_attr_open(inode, filp, __get, __set, __fmt)); \
+} \
+static const struct file_operations __fops = { \
+ .owner = THIS_MODULE, \
+ .open = __fops ## _open, \
+ .release = simple_attr_release, \
+ .read = simple_attr_read, \
+ .write = simple_attr_write, \
+ .llseek = no_llseek \
+}
+
+int simple_attr_open(struct inode *inode, struct file *filp,
+ int (*get)(void *, uint64_t *), int (*set)(void *, uint64_t),
+ const char *fmt);
+
+int simple_attr_release(struct inode *inode, struct file *filp);
+
+ssize_t simple_attr_read(struct file *filp, char *buf, size_t read_size, loff_t *ppos);
+
+ssize_t simple_attr_write(struct file *filp, const char *buf, size_t write_size, loff_t *ppos);
+
#endif /* _LINUXKPI_LINUX_FS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/fwnode.h b/sys/compat/linuxkpi/common/include/linux/fwnode.h
new file mode 100644
index 000000000000..a1fbc1b6d6a3
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/fwnode.h
@@ -0,0 +1,10 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_FWNODE_H_
+#define _LINUXKPI_LINUX_FWNODE_H_
+
+struct fwnode_handle {
+ struct fwnode_handle *secondary;
+};
+
+#endif /* _LINUXKPI_LINUX_FWNODE_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/gcd.h b/sys/compat/linuxkpi/common/include/linux/gcd.h
index 40523bd6cba6..5ca0540e5102 100644
--- a/sys/compat/linuxkpi/common/include/linux/gcd.h
+++ b/sys/compat/linuxkpi/common/include/linux/gcd.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_GCD_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/gfp.h b/sys/compat/linuxkpi/common/include/linux/gfp.h
index 6273fa969db8..f6cce379924d 100644
--- a/sys/compat/linuxkpi/common/include/linux/gfp.h
+++ b/sys/compat/linuxkpi/common/include/linux/gfp.h
@@ -25,13 +25,10 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_GFP_H_
#define _LINUXKPI_LINUX_GFP_H_
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/malloc.h>
@@ -47,6 +44,7 @@
#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
#define __GFP_RETRY_MAYFAIL 0
@@ -71,6 +69,7 @@
#define GFP_HIGHUSER_MOVABLE M_WAITOK
#define GFP_IOFS M_NOWAIT
#define GFP_NOIO M_NOWAIT
+#define GFP_NOFS M_NOWAIT
#define GFP_DMA32 __GFP_DMA32
#define GFP_TEMPORARY M_NOWAIT
#define GFP_NATIVE_MASK (M_NOWAIT | M_WAITOK | M_USE_RESERVE | M_ZERO)
@@ -80,6 +79,11 @@
CTASSERT((__GFP_DMA32 & GFP_NATIVE_MASK) == 0);
CTASSERT((__GFP_BITS_MASK & GFP_NATIVE_MASK) == GFP_NATIVE_MASK);
+struct page_frag_cache {
+ void *va;
+ int pagecnt_bias;
+};
+
/*
* Resolve a page into a virtual address:
*
@@ -92,8 +96,11 @@ extern void *linux_page_address(struct page *);
/*
* Page management for unmapped pages:
*/
-extern vm_page_t linux_alloc_pages(gfp_t flags, unsigned int order);
-extern void linux_free_pages(vm_page_t page, unsigned int order);
+extern struct page *linux_alloc_pages(gfp_t flags, unsigned int order);
+extern void linux_free_pages(struct page *page, unsigned int order);
+void *linuxkpi_page_frag_alloc(struct page_frag_cache *, size_t, gfp_t);
+void linuxkpi_page_frag_free(void *);
+void linuxkpi__page_frag_cache_drain(struct page *, size_t);
static inline struct page *
alloc_page(gfp_t flags)
@@ -130,6 +137,12 @@ __free_page(struct page *page)
linux_free_pages(page, 0);
}
+static inline struct page *
+dev_alloc_pages(unsigned int order)
+{
+ return (linux_alloc_pages(GFP_ATOMIC, order));
+}
+
/*
* Page management for mapped pages:
*/
@@ -175,6 +188,27 @@ free_page(uintptr_t addr)
linux_free_kmem(addr, 0);
}
+static inline void *
+page_frag_alloc(struct page_frag_cache *pfc, size_t fragsz, gfp_t gfp)
+{
+
+ return (linuxkpi_page_frag_alloc(pfc, fragsz, gfp));
+}
+
+static inline void
+page_frag_free(void *addr)
+{
+
+ linuxkpi_page_frag_free(addr);
+}
+
+static inline void
+__page_frag_cache_drain(struct page *page, size_t count)
+{
+
+ linuxkpi__page_frag_cache_drain(page, count);
+}
+
static inline bool
gfpflags_allow_blocking(const gfp_t gfp_flags)
{
diff --git a/sys/compat/linuxkpi/common/include/linux/hardirq.h b/sys/compat/linuxkpi/common/include/linux/hardirq.h
index 07f00f076860..f79451dd0d35 100644
--- a/sys/compat/linuxkpi/common/include/linux/hardirq.h
+++ b/sys/compat/linuxkpi/common/include/linux/hardirq.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_HARDIRQ_H_
#define _LINUXKPI_LINUX_HARDIRQ_H_
@@ -40,4 +38,14 @@
#define synchronize_irq(irq) _intr_drain((irq))
+/*
+ * FIXME: In the i915 driver's `intel_engine_cs.c` file,
+ * `synchronize_hardirq()` was replaced by `synchronize_rcu()` with the
+ * following comment:
+ * "Is it enough to wait that all cpu have context-switched?"
+ *
+ * See commit f6d50b7af554e21c380486d6f41c8537b265c777 in drm-kmod.
+ */
+#define synchronize_hardirq(irq) _intr_drain((irq))
+
#endif /* _LINUXKPI_LINUX_HARDIRQ_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/hashtable.h b/sys/compat/linuxkpi/common/include/linux/hashtable.h
index a7a30143a58e..55755c354959 100644
--- a/sys/compat/linuxkpi/common/include/linux/hashtable.h
+++ b/sys/compat/linuxkpi/common/include/linux/hashtable.h
@@ -23,8 +23,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_HASHTABLE_H
@@ -94,8 +92,6 @@ __hash_node_type_assert(struct hlist_node *node)
#define hash_add_rcu(ht, node, key) do { \
struct lkpi_hash_head *__head = &(ht)[hash_min(key, HASH_BITS(ht))]; \
__hash_node_type_assert(node); \
- KASSERT(((struct lkpi_hash_entry *)(node))->entry.cle_prev == NULL, \
- ("node is already on list or was not zeroed")); \
CK_LIST_INSERT_HEAD(&__head->head, \
(struct lkpi_hash_entry *)(node), entry); \
} while (0)
diff --git a/sys/compat/linuxkpi/common/include/linux/hdmi.h b/sys/compat/linuxkpi/common/include/linux/hdmi.h
new file mode 100644
index 000000000000..c8ec982ff498
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/hdmi.h
@@ -0,0 +1,440 @@
+/*
+ * Copyright (C) 2012 Avionic Design GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LINUX_HDMI_H_
+#define __LINUX_HDMI_H_
+
+#include <linux/types.h>
+#include <linux/device.h>
+
+enum hdmi_packet_type {
+ HDMI_PACKET_TYPE_NULL = 0x00,
+ HDMI_PACKET_TYPE_AUDIO_CLOCK_REGEN = 0x01,
+ HDMI_PACKET_TYPE_AUDIO_SAMPLE = 0x02,
+ HDMI_PACKET_TYPE_GENERAL_CONTROL = 0x03,
+ HDMI_PACKET_TYPE_ACP = 0x04,
+ HDMI_PACKET_TYPE_ISRC1 = 0x05,
+ HDMI_PACKET_TYPE_ISRC2 = 0x06,
+ HDMI_PACKET_TYPE_ONE_BIT_AUDIO_SAMPLE = 0x07,
+ HDMI_PACKET_TYPE_DST_AUDIO = 0x08,
+ HDMI_PACKET_TYPE_HBR_AUDIO_STREAM = 0x09,
+ HDMI_PACKET_TYPE_GAMUT_METADATA = 0x0a,
+ /* + enum hdmi_infoframe_type */
+};
+
+enum hdmi_infoframe_type {
+ HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
+ HDMI_INFOFRAME_TYPE_AVI = 0x82,
+ HDMI_INFOFRAME_TYPE_SPD = 0x83,
+ HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
+ HDMI_INFOFRAME_TYPE_DRM = 0x87,
+};
+
+#define HDMI_IEEE_OUI 0x000c03
+#define HDMI_FORUM_IEEE_OUI 0xc45dd8
+#define HDMI_INFOFRAME_HEADER_SIZE 4
+#define HDMI_AVI_INFOFRAME_SIZE 13
+#define HDMI_SPD_INFOFRAME_SIZE 25
+#define HDMI_AUDIO_INFOFRAME_SIZE 10
+#define HDMI_DRM_INFOFRAME_SIZE 26
+#define HDMI_VENDOR_INFOFRAME_SIZE 4
+
+#define HDMI_INFOFRAME_SIZE(type) \
+ (HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE)
+
+struct hdmi_any_infoframe {
+ enum hdmi_infoframe_type type;
+ unsigned char version;
+ unsigned char length;
+};
+
+enum hdmi_colorspace {
+ HDMI_COLORSPACE_RGB,
+ HDMI_COLORSPACE_YUV422,
+ HDMI_COLORSPACE_YUV444,
+ HDMI_COLORSPACE_YUV420,
+ HDMI_COLORSPACE_RESERVED4,
+ HDMI_COLORSPACE_RESERVED5,
+ HDMI_COLORSPACE_RESERVED6,
+ HDMI_COLORSPACE_IDO_DEFINED,
+};
+
+enum hdmi_scan_mode {
+ HDMI_SCAN_MODE_NONE,
+ HDMI_SCAN_MODE_OVERSCAN,
+ HDMI_SCAN_MODE_UNDERSCAN,
+ HDMI_SCAN_MODE_RESERVED,
+};
+
+enum hdmi_colorimetry {
+ HDMI_COLORIMETRY_NONE,
+ HDMI_COLORIMETRY_ITU_601,
+ HDMI_COLORIMETRY_ITU_709,
+ HDMI_COLORIMETRY_EXTENDED,
+};
+
+enum hdmi_picture_aspect {
+ HDMI_PICTURE_ASPECT_NONE,
+ HDMI_PICTURE_ASPECT_4_3,
+ HDMI_PICTURE_ASPECT_16_9,
+ HDMI_PICTURE_ASPECT_64_27,
+ HDMI_PICTURE_ASPECT_256_135,
+ HDMI_PICTURE_ASPECT_RESERVED,
+};
+
+enum hdmi_active_aspect {
+ HDMI_ACTIVE_ASPECT_16_9_TOP = 2,
+ HDMI_ACTIVE_ASPECT_14_9_TOP = 3,
+ HDMI_ACTIVE_ASPECT_16_9_CENTER = 4,
+ HDMI_ACTIVE_ASPECT_PICTURE = 8,
+ HDMI_ACTIVE_ASPECT_4_3 = 9,
+ HDMI_ACTIVE_ASPECT_16_9 = 10,
+ HDMI_ACTIVE_ASPECT_14_9 = 11,
+ HDMI_ACTIVE_ASPECT_4_3_SP_14_9 = 13,
+ HDMI_ACTIVE_ASPECT_16_9_SP_14_9 = 14,
+ HDMI_ACTIVE_ASPECT_16_9_SP_4_3 = 15,
+};
+
+enum hdmi_extended_colorimetry {
+ HDMI_EXTENDED_COLORIMETRY_XV_YCC_601,
+ HDMI_EXTENDED_COLORIMETRY_XV_YCC_709,
+ HDMI_EXTENDED_COLORIMETRY_S_YCC_601,
+ HDMI_EXTENDED_COLORIMETRY_OPYCC_601,
+ HDMI_EXTENDED_COLORIMETRY_OPRGB,
+
+ /* The following EC values are only defined in CEA-861-F. */
+ HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM,
+ HDMI_EXTENDED_COLORIMETRY_BT2020,
+ HDMI_EXTENDED_COLORIMETRY_RESERVED,
+};
+
+enum hdmi_quantization_range {
+ HDMI_QUANTIZATION_RANGE_DEFAULT,
+ HDMI_QUANTIZATION_RANGE_LIMITED,
+ HDMI_QUANTIZATION_RANGE_FULL,
+ HDMI_QUANTIZATION_RANGE_RESERVED,
+};
+
+/* non-uniform picture scaling */
+enum hdmi_nups {
+ HDMI_NUPS_UNKNOWN,
+ HDMI_NUPS_HORIZONTAL,
+ HDMI_NUPS_VERTICAL,
+ HDMI_NUPS_BOTH,
+};
+
+enum hdmi_ycc_quantization_range {
+ HDMI_YCC_QUANTIZATION_RANGE_LIMITED,
+ HDMI_YCC_QUANTIZATION_RANGE_FULL,
+};
+
+enum hdmi_content_type {
+ HDMI_CONTENT_TYPE_GRAPHICS,
+ HDMI_CONTENT_TYPE_PHOTO,
+ HDMI_CONTENT_TYPE_CINEMA,
+ HDMI_CONTENT_TYPE_GAME,
+};
+
+enum hdmi_metadata_type {
+ HDMI_STATIC_METADATA_TYPE1 = 0,
+};
+
+enum hdmi_eotf {
+ HDMI_EOTF_TRADITIONAL_GAMMA_SDR,
+ HDMI_EOTF_TRADITIONAL_GAMMA_HDR,
+ HDMI_EOTF_SMPTE_ST2084,
+ HDMI_EOTF_BT_2100_HLG,
+};
+
+struct hdmi_avi_infoframe {
+ enum hdmi_infoframe_type type;
+ unsigned char version;
+ unsigned char length;
+ 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;
+ unsigned short right_bar;
+};
+
+/* DRM Infoframe as per CTA 861.G spec */
+struct hdmi_drm_infoframe {
+ enum hdmi_infoframe_type type;
+ unsigned char version;
+ unsigned char length;
+ enum hdmi_eotf eotf;
+ enum hdmi_metadata_type metadata_type;
+ struct {
+ u16 x, y;
+ } display_primaries[3];
+ struct {
+ u16 x, y;
+ } white_point;
+ u16 max_display_mastering_luminance;
+ u16 min_display_mastering_luminance;
+ u16 max_cll;
+ u16 max_fall;
+};
+
+void hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame);
+ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
+ size_t size);
+ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
+ void *buffer, size_t size);
+int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame);
+int hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *frame);
+ssize_t hdmi_drm_infoframe_pack(struct hdmi_drm_infoframe *frame, void *buffer,
+ size_t size);
+ssize_t hdmi_drm_infoframe_pack_only(const struct hdmi_drm_infoframe *frame,
+ void *buffer, size_t size);
+int hdmi_drm_infoframe_check(struct hdmi_drm_infoframe *frame);
+int hdmi_drm_infoframe_unpack_only(struct hdmi_drm_infoframe *frame,
+ const void *buffer, size_t size);
+
+enum hdmi_spd_sdi {
+ HDMI_SPD_SDI_UNKNOWN,
+ HDMI_SPD_SDI_DSTB,
+ HDMI_SPD_SDI_DVDP,
+ HDMI_SPD_SDI_DVHS,
+ HDMI_SPD_SDI_HDDVR,
+ HDMI_SPD_SDI_DVC,
+ HDMI_SPD_SDI_DSC,
+ HDMI_SPD_SDI_VCD,
+ HDMI_SPD_SDI_GAME,
+ HDMI_SPD_SDI_PC,
+ HDMI_SPD_SDI_BD,
+ HDMI_SPD_SDI_SACD,
+ HDMI_SPD_SDI_HDDVD,
+ HDMI_SPD_SDI_PMP,
+};
+
+struct hdmi_spd_infoframe {
+ enum hdmi_infoframe_type type;
+ unsigned char version;
+ unsigned char length;
+ char vendor[8];
+ char product[16];
+ enum hdmi_spd_sdi sdi;
+};
+
+int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
+ const char *vendor, const char *product);
+ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
+ size_t size);
+ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
+ void *buffer, size_t size);
+int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame);
+
+enum hdmi_audio_coding_type {
+ HDMI_AUDIO_CODING_TYPE_STREAM,
+ HDMI_AUDIO_CODING_TYPE_PCM,
+ HDMI_AUDIO_CODING_TYPE_AC3,
+ HDMI_AUDIO_CODING_TYPE_MPEG1,
+ HDMI_AUDIO_CODING_TYPE_MP3,
+ HDMI_AUDIO_CODING_TYPE_MPEG2,
+ HDMI_AUDIO_CODING_TYPE_AAC_LC,
+ HDMI_AUDIO_CODING_TYPE_DTS,
+ HDMI_AUDIO_CODING_TYPE_ATRAC,
+ HDMI_AUDIO_CODING_TYPE_DSD,
+ HDMI_AUDIO_CODING_TYPE_EAC3,
+ HDMI_AUDIO_CODING_TYPE_DTS_HD,
+ HDMI_AUDIO_CODING_TYPE_MLP,
+ HDMI_AUDIO_CODING_TYPE_DST,
+ HDMI_AUDIO_CODING_TYPE_WMA_PRO,
+ HDMI_AUDIO_CODING_TYPE_CXT,
+};
+
+enum hdmi_audio_sample_size {
+ HDMI_AUDIO_SAMPLE_SIZE_STREAM,
+ HDMI_AUDIO_SAMPLE_SIZE_16,
+ HDMI_AUDIO_SAMPLE_SIZE_20,
+ HDMI_AUDIO_SAMPLE_SIZE_24,
+};
+
+enum hdmi_audio_sample_frequency {
+ HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM,
+ HDMI_AUDIO_SAMPLE_FREQUENCY_32000,
+ HDMI_AUDIO_SAMPLE_FREQUENCY_44100,
+ HDMI_AUDIO_SAMPLE_FREQUENCY_48000,
+ HDMI_AUDIO_SAMPLE_FREQUENCY_88200,
+ HDMI_AUDIO_SAMPLE_FREQUENCY_96000,
+ HDMI_AUDIO_SAMPLE_FREQUENCY_176400,
+ HDMI_AUDIO_SAMPLE_FREQUENCY_192000,
+};
+
+enum hdmi_audio_coding_type_ext {
+ /* Refer to Audio Coding Type (CT) field in Data Byte 1 */
+ HDMI_AUDIO_CODING_TYPE_EXT_CT,
+
+ /*
+ * The next three CXT values are defined in CEA-861-E only.
+ * They do not exist in older versions, and in CEA-861-F they are
+ * defined as 'Not in use'.
+ */
+ HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC,
+ HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC_V2,
+ HDMI_AUDIO_CODING_TYPE_EXT_MPEG_SURROUND,
+
+ /* The following CXT values are only defined in CEA-861-F. */
+ HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC,
+ HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_V2,
+ HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC,
+ HDMI_AUDIO_CODING_TYPE_EXT_DRA,
+ HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_SURROUND,
+ HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC_SURROUND = 10,
+};
+
+struct hdmi_audio_infoframe {
+ enum hdmi_infoframe_type type;
+ unsigned char version;
+ unsigned char length;
+ unsigned char channels;
+ enum hdmi_audio_coding_type coding_type;
+ enum hdmi_audio_sample_size sample_size;
+ enum hdmi_audio_sample_frequency sample_frequency;
+ enum hdmi_audio_coding_type_ext coding_type_ext;
+ unsigned char channel_allocation;
+ unsigned char level_shift_value;
+ bool downmix_inhibit;
+
+};
+
+int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame);
+ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
+ void *buffer, size_t size);
+ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
+ void *buffer, size_t size);
+int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame);
+
+enum hdmi_3d_structure {
+ HDMI_3D_STRUCTURE_INVALID = -1,
+ HDMI_3D_STRUCTURE_FRAME_PACKING = 0,
+ HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE,
+ HDMI_3D_STRUCTURE_LINE_ALTERNATIVE,
+ HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL,
+ HDMI_3D_STRUCTURE_L_DEPTH,
+ HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH,
+ HDMI_3D_STRUCTURE_TOP_AND_BOTTOM,
+ HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF = 8,
+};
+
+
+struct hdmi_vendor_infoframe {
+ enum hdmi_infoframe_type type;
+ unsigned char version;
+ unsigned char length;
+ unsigned int oui;
+ u8 vic;
+ enum hdmi_3d_structure s3d_struct;
+ unsigned int s3d_ext_data;
+};
+
+/* HDR Metadata as per 861.G spec */
+struct hdr_static_metadata {
+ __u8 eotf;
+ __u8 metadata_type;
+ __u16 max_cll;
+ __u16 max_fall;
+ __u16 min_cll;
+};
+
+/**
+ * struct hdr_sink_metadata - HDR sink metadata
+ *
+ * Metadata Information read from Sink's EDID
+ */
+struct hdr_sink_metadata {
+ /**
+ * @metadata_type: Static_Metadata_Descriptor_ID.
+ */
+ __u32 metadata_type;
+ /**
+ * @hdmi_type1: HDR Metadata Infoframe.
+ */
+ union {
+ struct hdr_static_metadata hdmi_type1;
+ };
+};
+
+int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
+ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
+ void *buffer, size_t size);
+ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
+ void *buffer, size_t size);
+int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame);
+
+union hdmi_vendor_any_infoframe {
+ struct {
+ enum hdmi_infoframe_type type;
+ unsigned char version;
+ unsigned char length;
+ unsigned int oui;
+ } any;
+ struct hdmi_vendor_infoframe hdmi;
+};
+
+/**
+ * union hdmi_infoframe - overall union of all abstract infoframe representations
+ * @any: generic infoframe
+ * @avi: avi infoframe
+ * @spd: spd infoframe
+ * @vendor: union of all vendor infoframes
+ * @audio: audio infoframe
+ * @drm: Dynamic Range and Mastering infoframe
+ *
+ * This is used by the generic pack function. This works since all infoframes
+ * have the same header which also indicates which type of infoframe should be
+ * packed.
+ */
+union hdmi_infoframe {
+ struct hdmi_any_infoframe any;
+ struct hdmi_avi_infoframe avi;
+ struct hdmi_spd_infoframe spd;
+ union hdmi_vendor_any_infoframe vendor;
+ struct hdmi_audio_infoframe audio;
+ struct hdmi_drm_infoframe drm;
+};
+
+ssize_t hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer,
+ size_t size);
+ssize_t hdmi_infoframe_pack_only(const union hdmi_infoframe *frame,
+ void *buffer, size_t size);
+int hdmi_infoframe_check(union hdmi_infoframe *frame);
+int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
+ const void *buffer, size_t size);
+void hdmi_infoframe_log(const char *level, struct device *dev,
+ const union hdmi_infoframe *frame);
+
+#endif /* _DRM_HDMI_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/highmem.h b/sys/compat/linuxkpi/common/include/linux/highmem.h
index 53efbec06385..f770bef6b3b7 100644
--- a/sys/compat/linuxkpi/common/include/linux/highmem.h
+++ b/sys/compat/linuxkpi/common/include/linux/highmem.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2010 Isilon Systems, Inc.
* Copyright (c) 2016 Matthew Macy (mmacy@mattmacy.io)
@@ -47,19 +47,20 @@
#define PageHighMem(p) (0)
-static inline vm_page_t
+static inline struct page *
kmap_to_page(void *addr)
{
+
return (virt_to_page(addr));
}
static inline void *
-kmap(vm_page_t page)
+kmap(struct page *page)
{
struct sf_buf *sf;
if (PMAP_HAS_DMAP) {
- return ((void *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(page)));
+ return ((void *)PHYS_TO_DMAP(page_to_phys(page)));
} else {
sched_pin();
sf = sf_buf_alloc(page, SFB_NOWAIT | SFB_CPUPRIVATE);
@@ -72,7 +73,7 @@ kmap(vm_page_t page)
}
static inline void *
-kmap_atomic_prot(vm_page_t page, pgprot_t prot)
+kmap_atomic_prot(struct page *page, pgprot_t prot)
{
vm_memattr_t attr = pgprot2cachemode(prot);
@@ -86,13 +87,21 @@ kmap_atomic_prot(vm_page_t page, pgprot_t prot)
}
static inline void *
-kmap_atomic(vm_page_t page)
+kmap_atomic(struct page *page)
{
+
return (kmap_atomic_prot(page, VM_PROT_ALL));
}
+static inline void *
+kmap_local_page_prot(struct page *page, pgprot_t prot)
+{
+
+ return (kmap_atomic_prot(page, prot));
+}
+
static inline void
-kunmap(vm_page_t page)
+kunmap(struct page *page)
{
struct sf_buf *sf;
@@ -111,8 +120,16 @@ kunmap(vm_page_t page)
static inline void
kunmap_atomic(void *vaddr)
{
+
if (!PMAP_HAS_DMAP)
kunmap(virt_to_page(vaddr));
}
+static inline void
+kunmap_local(void *addr)
+{
+
+ kunmap_atomic(addr);
+}
+
#endif /* _LINUXKPI_LINUX_HIGHMEM_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/hrtimer.h b/sys/compat/linuxkpi/common/include/linux/hrtimer.h
index 23e707d906b4..88f9487d0b85 100644
--- a/sys/compat/linuxkpi/common/include/linux/hrtimer.h
+++ b/sys/compat/linuxkpi/common/include/linux/hrtimer.h
@@ -21,8 +21,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_HRTIMER_H_
@@ -32,6 +30,7 @@
#include <sys/_mutex.h>
#include <linux/ktime.h>
+#include <linux/rbtree.h>
#include <linux/timer.h>
enum hrtimer_mode {
@@ -53,6 +52,7 @@ struct hrtimer {
};
#define hrtimer_active(hrtimer) linux_hrtimer_active(hrtimer)
+#define hrtimer_try_to_cancel(hrtimer) linux_hrtimer_try_to_cancel(hrtimer)
#define hrtimer_cancel(hrtimer) linux_hrtimer_cancel(hrtimer)
#define hrtimer_init(hrtimer, clock, mode) do { \
@@ -79,6 +79,7 @@ struct hrtimer {
} while (0)
bool linux_hrtimer_active(struct hrtimer *);
+int linux_hrtimer_try_to_cancel(struct hrtimer *);
int linux_hrtimer_cancel(struct hrtimer *);
void linux_hrtimer_init(struct hrtimer *);
void linux_hrtimer_set_expires(struct hrtimer *, ktime_t);
diff --git a/sys/compat/linuxkpi/common/include/linux/i2c.h b/sys/compat/linuxkpi/common/include/linux/i2c.h
index 0bb8b470edd7..f24d282586f6 100644
--- a/sys/compat/linuxkpi/common/include/linux/i2c.h
+++ b/sys/compat/linuxkpi/common/include/linux/i2c.h
@@ -46,6 +46,7 @@
#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0
#define I2C_FUNC_10BIT_ADDR 0
+#define I2C_CLASS_HWMON 0x1
#define I2C_CLASS_DDC 0x8
#define I2C_CLASS_SPD 0x80
@@ -58,6 +59,7 @@ struct i2c_adapter {
const struct i2c_lock_operations *lock_ops;
const struct i2c_algorithm *algo;
+ const struct i2c_adapter_quirks *quirks;
void *algo_data;
int retries;
@@ -82,6 +84,29 @@ struct i2c_lock_operations {
void (*unlock_bus)(struct i2c_adapter *, unsigned int);
};
+struct i2c_adapter_quirks {
+ uint64_t flags;
+ int max_num_msgs;
+ uint16_t max_write_len;
+ uint16_t max_read_len;
+ uint16_t max_comb_1st_msg_len;
+ uint16_t max_comb_2nd_msg_len;
+};
+
+#define I2C_AQ_COMB BIT(0)
+#define I2C_AQ_COMB_WRITE_FIRST BIT(1)
+#define I2C_AQ_COMB_READ_SECOND BIT(2)
+#define I2C_AQ_COMB_SAME_ADDR BIT(3)
+#define I2C_AQ_COMB_WRITE_THEN_READ \
+ (I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | \
+ I2C_AQ_COMB_READ_SECOND | I2C_AQ_COMB_SAME_ADDR)
+#define I2C_AQ_NO_CLK_STRETCH BIT(4)
+#define I2C_AQ_NO_ZERO_LEN_READ BIT(5)
+#define I2C_AQ_NO_ZERO_LEN_WRITE BIT(6)
+#define I2C_AQ_NO_ZERO_LEN \
+ (I2C_AQ_NO_ZERO_LEN_READ | I2C_AQ_NO_ZERO_LEN_WRITE)
+#define I2C_AQ_NO_REP_START BIT(7)
+
int lkpi_i2c_add_adapter(struct i2c_adapter *adapter);
int lkpi_i2c_del_adapter(struct i2c_adapter *adapter);
@@ -100,7 +125,7 @@ do_i2c_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int nmsgs)
retries = adapter->retries == 0 ? 1 : adapter->retries;
for (; retries != 0; retries--) {
- if (adapter->algo->master_xfer != NULL)
+ if (adapter->algo != NULL && adapter->algo->master_xfer != NULL)
ret = adapter->algo->master_xfer(adapter, msgs, nmsgs);
else
ret = lkpi_i2cbb_transfer(adapter, msgs, nmsgs);
@@ -116,7 +141,7 @@ i2c_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int nmsgs)
{
int ret;
- if (!adapter->algo)
+ if (adapter->algo == NULL && adapter->algo_data == NULL)
return (-EOPNOTSUPP);
if (adapter->lock_ops)
diff --git a/sys/compat/linuxkpi/common/include/linux/idr.h b/sys/compat/linuxkpi/common/include/linux/idr.h
index 5310fcf9950c..ca3f8171ff44 100644
--- a/sys/compat/linuxkpi/common/include/linux/idr.h
+++ b/sys/compat/linuxkpi/common/include/linux/idr.h
@@ -25,14 +25,13 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_IDR_H_
#define _LINUXKPI_LINUX_IDR_H_
#include <sys/param.h>
#include <sys/lock.h>
+#include <sys/limits.h>
#include <sys/mutex.h>
#include <linux/types.h>
@@ -134,6 +133,12 @@ ida_get_new(struct ida *ida, int *p_id)
}
static inline int
+ida_alloc_min(struct ida *ida, unsigned int min, gfp_t gfp)
+{
+ return (ida_simple_get(ida, min, UINT_MAX, gfp));
+}
+
+static inline int
ida_alloc_max(struct ida *ida, unsigned int max, gfp_t gfp)
{
diff --git a/sys/compat/linuxkpi/common/include/linux/ieee80211.h b/sys/compat/linuxkpi/common/include/linux/ieee80211.h
index 6698b84dc1ca..2000e7480ff8 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-2021 The FreeBSD Foundation
+ * Copyright (c) 2020-2023 The FreeBSD Foundation
*
* This software was developed by Björn Zeeb under sponsorship from
* the FreeBSD Foundation.
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_IEEE80211_H
@@ -62,9 +60,9 @@ struct ieee80211_mmie_16 {
#define IEEE80211_INVAL_HW_QUEUE ((uint8_t)-1)
-#define IEEE80211_MAX_AMPDU_BUF_HT 0x40
-#define IEEE80211_MAX_AMPDU_BUF 256 /* for HE? */
+#define IEEE80211_MAX_AMPDU_BUF_HT IEEE80211_AGGR_BAWMAX
#define IEEE80211_MAX_AMPDU_BUF_HE 256
+#define IEEE80211_MAX_AMPDU_BUF_EHT 1024
#define IEEE80211_MAX_FRAME_LEN 2352
#define IEEE80211_MAX_DATA_LEN (2300 + IEEE80211_CRC_LEN)
@@ -132,16 +130,22 @@ enum wlan_ht_cap_sm_ps {
#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
/* 802.11-2020, 9.4.2.55.3, Table 9-185 Subfields of the A-MPDU Parameters field */
enum ieee80211_min_mpdu_start_spacing {
IEEE80211_HT_MPDU_DENSITY_NONE = 0,
#if 0
IEEE80211_HT_MPDU_DENSITY_XXX = 1, /* 1/4 us */
- IEEE80211_HT_MPDU_DENSITY_YYY = 2, /* 1/2 us */
#endif
+ IEEE80211_HT_MPDU_DENSITY_0_5 = 2, /* 1/2 us */
IEEE80211_HT_MPDU_DENSITY_1 = 3, /* 1 us */
IEEE80211_HT_MPDU_DENSITY_2 = 4, /* 2 us */
IEEE80211_HT_MPDU_DENSITY_4 = 5, /* 4us */
@@ -159,6 +163,7 @@ enum ieee80211_min_mpdu_start_spacing {
#define IEEE80211_FCTL_FROMDS (IEEE80211_FC1_DIR_FROMDS << 8)
#define IEEE80211_FCTL_TODS (IEEE80211_FC1_DIR_TODS << 8)
#define IEEE80211_FCTL_MOREFRAGS (IEEE80211_FC1_MORE_FRAG << 8)
+#define IEEE80211_FCTL_PM (IEEE80211_FC1_PWR_MGT << 8)
#define IEEE80211_FTYPE_MGMT IEEE80211_FC0_TYPE_MGT
#define IEEE80211_FTYPE_CTL IEEE80211_FC0_TYPE_CTL
@@ -170,8 +175,12 @@ enum ieee80211_min_mpdu_start_spacing {
#define IEEE80211_STYPE_DISASSOC IEEE80211_FC0_SUBTYPE_DISASSOC
#define IEEE80211_STYPE_AUTH IEEE80211_FC0_SUBTYPE_AUTH
#define IEEE80211_STYPE_DEAUTH IEEE80211_FC0_SUBTYPE_DEAUTH
+#define IEEE80211_STYPE_CTS IEEE80211_FC0_SUBTYPE_CTS
+#define IEEE80211_STYPE_RTS IEEE80211_FC0_SUBTYPE_RTS
#define IEEE80211_STYPE_ACTION IEEE80211_FC0_SUBTYPE_ACTION
-#define IEEE80211_STYPE_QOS_DATA IEEE80211_FC0_SUBTYPE_QOS
+#define IEEE80211_STYPE_QOS_DATA IEEE80211_FC0_SUBTYPE_QOS_DATA
+#define IEEE80211_STYPE_QOS_NULLFUNC IEEE80211_FC0_SUBTYPE_QOS_NULL
+#define IEEE80211_STYPE_QOS_CFACK 0xd0 /* XXX-BZ reserved? */
#define IEEE80211_NUM_ACS 4 /* net8021::WME_NUM_AC */
@@ -188,11 +197,12 @@ enum ieee80211_min_mpdu_start_spacing {
#define IEEE80211_PPE_THRES_RU_INDEX_BITMASK_MASK 8 /* TODO FIXME ax? */
#define IEEE80211_HE_PPE_THRES_INFO_HEADER_SIZE 16 /* TODO FIXME ax? */
-#define IEEE80211_HT_OP_MODE_PROTECTION 0x03 /* MASK */
-#define IEEE80211_HT_OP_MODE_PROTECTION_NONE 0x00
-#define IEEE80211_HT_OP_MODE_PROTECTION_20MHZ 0x01
-#define IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED 0x02
-#define IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER 0x03
+/* 802.11-2012, Table 8-130-HT Operation element fields and subfields, HT Protection */
+#define IEEE80211_HT_OP_MODE_PROTECTION IEEE80211_HTINFO_OPMODE /* Mask. */
+#define IEEE80211_HT_OP_MODE_PROTECTION_NONE IEEE80211_HTINFO_OPMODE_PURE /* No protection */
+#define IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER IEEE80211_HTINFO_OPMODE_PROTOPT /* Nonmember protection */
+#define IEEE80211_HT_OP_MODE_PROTECTION_20MHZ IEEE80211_HTINFO_OPMODE_HT20PR /* 20 MHz protection */
+#define IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED IEEE80211_HTINFO_OPMODE_MIXED /* Non-HT mixed */
/* 9.6.13.1, Table 9-342 TDLS Action field values. */
@@ -211,15 +221,19 @@ enum ieee80211_tdls_action_code {
/* 11-255 reserved */
};
-/* 9.4.2.27, Table 9-135. Extended Capabilities field. */
+/* 802.11-2020 9.4.2.26, Table 9-153. Extended Capabilities field. */
/* This is split up into octets CAPA1 = octet 1, ... */
#define WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING BIT(2 % 8)
#define WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT BIT(22 % 8)
+#define WLAN_EXT_CAPA3_TIMING_MEASUREMENT_SUPPORT BIT(23 % 8)
#define WLAN_EXT_CAPA8_OPMODE_NOTIF BIT(62 % 8)
+#define WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB BIT(63 % 8)
+#define WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB BIT(64 % 8)
+#define WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT BIT(77 % 8)
+#define WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT BIT(78 % 8)
+#define WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT BIT(79 % 8)
-#define WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT BIT(5) /* XXX */
-#define WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT BIT(7) /* XXX */
-#define WLAN_EXT_CAPA10_TWT_RESPONDER_SUPPORT BIT(6) /* XXX */
+#define WLAN_EXT_CAPA11_EMA_SUPPORT 0x00 /* XXX TODO FIXME */
/* iwlwifi/mvm/utils:: for (ac = IEEE80211_AC_VO; ac <= IEEE80211_AC_VI; ac++) */
@@ -243,6 +257,8 @@ enum ieee80211_ac_numbers {
/* 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 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 */
@@ -251,8 +267,6 @@ enum ieee80211_ac_numbers {
#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_SM_PS 0x000c /* IEEE80211_HTCAP_SMPS */
-#define IEEE80211_HT_CAP_SM_PS_SHIFT 2
#define IEEE80211_HT_CAP_LSIG_TXOP_PROT 0x8000 /* IEEE80211_HTCAP_LSIGTXOPPROT */
#define IEEE80211_HT_MCS_TX_DEFINED 0x0001
@@ -262,6 +276,8 @@ enum ieee80211_ac_numbers {
#define IEEE80211_HT_MCS_RX_HIGHEST_MASK 0x3ff
#define IEEE80211_HT_MCS_MASK_LEN 10
+#define IEEE80211_MLD_MAX_NUM_LINKS 15
+
struct ieee80211_mcs_info {
uint8_t rx_mask[IEEE80211_HT_MCS_MASK_LEN];
uint16_t rx_highest;
@@ -269,13 +285,6 @@ struct ieee80211_mcs_info {
uint8_t __reserved[3];
};
-struct vht_mcs {
- uint16_t rx_mcs_map;
- uint16_t rx_highest;
- uint16_t tx_mcs_map;
- uint16_t tx_highest;
-};
-
/* 802.11-2020, 9.4.2.55.1 HT Capabilities element structure */
struct ieee80211_ht_cap {
uint16_t cap_info;
@@ -286,12 +295,10 @@ struct ieee80211_ht_cap {
uint8_t antenna_selection_info;
};
-struct ieee80211_vht_cap {
- __le32 vht_cap_info;
- struct vht_mcs supp_mcs;
-};
-
#define IEEE80211_HT_MAX_AMPDU_FACTOR 13
+#define IEEE80211_HE_HT_MAX_AMPDU_FACTOR 16
+#define IEEE80211_HE_VHT_MAX_AMPDU_FACTOR 20
+#define IEEE80211_HE_6GHZ_MAX_AMPDU_FACTOR 13
enum ieee80211_ht_max_ampdu_len {
IEEE80211_HT_MAX_AMPDU_64K
@@ -357,11 +364,11 @@ enum ieee80211_smps_mode {
/* net80211::IEEE80211_S_* different but represents the state machine. */
/* Note: order here is important! */
enum ieee80211_sta_state {
- IEEE80211_STA_NOTEXIST,
- IEEE80211_STA_NONE,
- IEEE80211_STA_AUTH,
- IEEE80211_STA_ASSOC,
- IEEE80211_STA_AUTHORIZED, /* 802.1x */
+ IEEE80211_STA_NOTEXIST = 0,
+ IEEE80211_STA_NONE = 1,
+ IEEE80211_STA_AUTH = 2,
+ IEEE80211_STA_ASSOC = 3,
+ IEEE80211_STA_AUTHORIZED = 4, /* 802.1x */
};
enum ieee80211_sta_rx_bw {
@@ -393,12 +400,20 @@ enum ieee80211_tx_info_flags {
IEEE80211_TX_CTL_HW_80211_ENCAP = BIT(16),
IEEE80211_TX_CTL_USE_MINRATE = BIT(17),
IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(18),
+ IEEE80211_TX_CTL_LDPC = BIT(19),
+ IEEE80211_TX_CTL_STBC = BIT(20),
+};
+
+enum ieee80211_tx_status_flags {
+ IEEE80211_TX_STATUS_ACK_SIGNAL_VALID = BIT(0),
};
enum ieee80211_tx_control_flags {
/* XXX TODO .. right shift numbers */
IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0),
IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1),
+ IEEE80211_TX_CTRL_RATE_INJECT = BIT(2),
+ IEEE80211_TX_CTRL_MLO_LINK = 0xF0000000, /* This is IEEE80211_LINK_UNSPECIFIED on the high bits. */
};
enum ieee80211_tx_rate_flags {
@@ -413,6 +428,8 @@ enum ieee80211_tx_rate_flags {
IEEE80211_TX_RC_USE_SHORT_PREAMBLE = BIT(7),
};
+#define IEEE80211_RNR_TBTT_PARAMS_PSD_RESERVED -128
+
#define IEEE80211_HT_CTL_LEN 4
struct ieee80211_hdr { /* net80211::ieee80211_frame_addr4 */
@@ -434,6 +451,16 @@ struct ieee80211_hdr_3addr { /* net80211::ieee80211_frame */
__le16 seq_ctrl;
};
+struct ieee80211_qos_hdr { /* net80211:ieee80211_qosframe */
+ __le16 frame_control;
+ __le16 duration_id;
+ uint8_t addr1[ETH_ALEN];
+ uint8_t addr2[ETH_ALEN];
+ uint8_t addr3[ETH_ALEN];
+ __le16 seq_ctrl;
+ __le16 qos_ctrl;
+};
+
struct ieee80211_vendor_ie {
};
@@ -447,7 +474,7 @@ enum ieee80211_category {
WLAN_CATEGORY_BACK = 3,
};
-/* 9.3.3.2 Format of Management frames */
+/* 80211-2020 9.3.3.2 Format of Management frames */
struct ieee80211_mgmt {
__le16 frame_control;
__le16 duration_id;
@@ -480,6 +507,16 @@ struct ieee80211_mgmt {
uint8_t category;
/* 9.6.8 Public Action details */
union {
+ /* 9.6.2.5 TPC Report frame format */
+ struct {
+ uint8_t spec_mgmt;
+ uint8_t dialog_token;
+ /* uint32_t tpc_rep_elem:: */
+ uint8_t tpc_elem_id;
+ uint8_t tpc_elem_length;
+ uint8_t tpc_elem_tx_power;
+ uint8_t tpc_elem_link_margin;
+ } tpc_report;
/* 9.6.8.33 Fine Timing Measurement frame format */
struct {
uint8_t dialog_token;
@@ -500,11 +537,28 @@ struct ieee80211_mgmt {
/* Optional follows... */
uint8_t variable[0];
} addba_req;
+ /* XXX */
+ struct {
+ uint8_t dialog_token;
+ } wnm_timing_msr;
} u;
} action;
} u;
};
+struct ieee80211_cts { /* net80211::ieee80211_frame_cts */
+ __le16 frame_control;
+ __le16 duration;
+ uint8_t ra[ETH_ALEN];
+} __packed;
+
+struct ieee80211_rts { /* net80211::ieee80211_frame_rts */
+ __le16 frame_control;
+ __le16 duration;
+ uint8_t ra[ETH_ALEN];
+ uint8_t ta[ETH_ALEN];
+} __packed;
+
#define MHZ_TO_KHZ(_f) ((_f) * 1000)
#define DBI_TO_MBI(_g) ((_g) * 100)
#define MBI_TO_DBI(_x) ((_x) / 100)
@@ -535,12 +589,13 @@ enum ieee80211_eid {
WLAN_EID_HT_CAPABILITY = 45, /* IEEE80211_ELEMID_HTCAP */
WLAN_EID_RSN = 48, /* IEEE80211_ELEMID_RSN */
WLAN_EID_EXT_SUPP_RATES = 50,
+ WLAN_EID_EXT_NON_INHERITANCE = 56,
WLAN_EID_EXT_CHANSWITCH_ANN = 60,
WLAN_EID_MULTIPLE_BSSID = 71, /* IEEE80211_ELEMID_MULTIBSSID */
WLAN_EID_MULTI_BSSID_IDX = 85,
WLAN_EID_EXT_CAPABILITY = 127,
WLAN_EID_VHT_CAPABILITY = 191, /* IEEE80211_ELEMID_VHT_CAP */
- WLAN_EID_VENDOR_SPECIFIC = 221,
+ WLAN_EID_VENDOR_SPECIFIC = 221, /* IEEE80211_ELEMID_VENDOR */
};
enum ieee80211_eid_ext {
@@ -639,6 +694,12 @@ struct ieee80211_bssid_index {
int bssid_index;
};
+enum ieee80211_reg_ap_power {
+ IEEE80211_REG_LPI_AP,
+ IEEE80211_REG_SP_AP,
+ IEEE80211_REG_VLP_AP,
+};
+
/* net80211: IEEE80211_IS_CTL() */
static __inline bool
ieee80211_is_ctl(__le16 fc)
@@ -669,9 +730,8 @@ ieee80211_is_data_qos(__le16 fc)
{
__le16 v;
- fc &= htole16(IEEE80211_FC0_SUBTYPE_QOS | IEEE80211_FC0_TYPE_MASK |
- IEEE80211_FC0_VERSION_MASK);
- v = htole16(IEEE80211_FC0_QOSDATA);
+ fc &= htole16(IEEE80211_FC0_SUBTYPE_QOS_DATA | IEEE80211_FC0_TYPE_MASK);
+ v = htole16(IEEE80211_FC0_SUBTYPE_QOS_DATA | IEEE80211_FC0_TYPE_DATA);
return (fc == v);
}
@@ -711,9 +771,9 @@ ieee80211_hdrlen(__le16 fc)
if ((fc & htole16(IEEE80211_FC1_DIR_MASK << 8)) ==
htole16(IEEE80211_FC1_DIR_DSTODS << 8))
size += IEEE80211_ADDR_LEN;
- if ((fc & htole16(IEEE80211_FC0_SUBTYPE_QOS |
+ if ((fc & htole16(IEEE80211_FC0_SUBTYPE_QOS_DATA |
IEEE80211_FC0_TYPE_MASK)) ==
- htole16(IEEE80211_FC0_SUBTYPE_QOS |
+ htole16(IEEE80211_FC0_SUBTYPE_QOS_DATA |
IEEE80211_FC0_TYPE_DATA))
size += sizeof(uint16_t);
}
diff --git a/sys/compat/linuxkpi/common/include/linux/if_arp.h b/sys/compat/linuxkpi/common/include/linux/if_arp.h
index abd30eac49c9..6201c3a1c284 100644
--- a/sys/compat/linuxkpi/common/include/linux/if_arp.h
+++ b/sys/compat/linuxkpi/common/include/linux/if_arp.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_IF_ARP_H_
#define _LINUXKPI_LINUX_IF_ARP_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/if_ether.h b/sys/compat/linuxkpi/common/include/linux/if_ether.h
index 178b778ec736..3735ad2f5527 100644
--- a/sys/compat/linuxkpi/common/include/linux/if_ether.h
+++ b/sys/compat/linuxkpi/common/include/linux/if_ether.h
@@ -4,6 +4,10 @@
* Copyright (c) 2010 Panasas, Inc.
* Copyright (c) 2013 Mellanox Technologies, Ltd.
* All rights reserved.
+ * Copyright (c) 2021-2022 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,8 +29,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_IF_ETHER_H_
#define _LINUXKPI_LINUX_IF_ETHER_H_
@@ -55,6 +57,9 @@
#define ETH_P_8021AD ETHERTYPE_QINQ
#define ETH_P_PAE ETHERTYPE_PAE
#define ETH_P_802_2 ETHERTYPE_8023
+#define ETH_P_IPX ETHERTYPE_IPX
+#define ETH_P_AARP ETHERTYPE_AARP
+#define ETH_P_802_3_MIN 0x05DD /* See comment in sys/net/ethernet.h */
#define ETH_P_LINK_CTL 0x886C /* ITU-T G.989.2 */
#define ETH_P_TDLS 0x890D /* 802.11z-2010, see wpa. */
diff --git a/sys/compat/linuxkpi/common/include/linux/if_vlan.h b/sys/compat/linuxkpi/common/include/linux/if_vlan.h
index 7c5531f6ec11..3d1c61db1882 100644
--- a/sys/compat/linuxkpi/common/include/linux/if_vlan.h
+++ b/sys/compat/linuxkpi/common/include/linux/if_vlan.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_IF_VLAN_H_
#define _LINUXKPI_LINUX_IF_VLAN_H_
@@ -44,7 +42,7 @@
static inline int
is_vlan_dev(struct ifnet *ifp)
{
- return (ifp->if_type == IFT_L2VLAN);
+ return (if_gettype(ifp) == IFT_L2VLAN);
}
static inline uint16_t
diff --git a/sys/compat/linuxkpi/common/include/linux/in.h b/sys/compat/linuxkpi/common/include/linux/in.h
index ae2be5be1799..5cc92416c7da 100644
--- a/sys/compat/linuxkpi/common/include/linux/in.h
+++ b/sys/compat/linuxkpi/common/include/linux/in.h
@@ -25,15 +25,12 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_IN_H_
#define _LINUXKPI_LINUX_IN_H_
#include "opt_inet.h"
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <netinet/in.h>
diff --git a/sys/compat/linuxkpi/common/include/linux/in6.h b/sys/compat/linuxkpi/common/include/linux/in6.h
index 5f5f548de06d..79be45b6819a 100644
--- a/sys/compat/linuxkpi/common/include/linux/in6.h
+++ b/sys/compat/linuxkpi/common/include/linux/in6.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_IN6_H_
#define _LINUXKPI_LINUX_IN6_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/interrupt.h b/sys/compat/linuxkpi/common/include/linux/interrupt.h
index 905a29a77f91..d5f9a0ae7a47 100644
--- a/sys/compat/linuxkpi/common/include/linux/interrupt.h
+++ b/sys/compat/linuxkpi/common/include/linux/interrupt.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_INTERRUPT_H_
#define _LINUXKPI_LINUX_INTERRUPT_H_
@@ -42,7 +40,12 @@
typedef irqreturn_t (*irq_handler_t)(int, void *);
-#define IRQF_SHARED RF_SHAREABLE
+#define IRQF_SHARED 0x0004 /* Historically */
+#define IRQF_NOBALANCING 0
+
+#define IRQ_DISABLE_UNLAZY 0
+
+#define IRQ_NOTCONNECTED (1U << 31)
int lkpi_request_irq(struct device *, unsigned int, irq_handler_t,
irq_handler_t, unsigned long, const char *, void *);
@@ -71,6 +74,14 @@ request_threaded_irq(int irq, irq_handler_t handler,
}
static inline int
+devm_request_irq(struct device *dev, int irq,
+ irq_handler_t handler, unsigned long flags, const char *name, void *arg)
+{
+
+ return (lkpi_request_irq(dev, irq, handler, NULL, flags, name, arg));
+}
+
+static inline int
devm_request_threaded_irq(struct device *dev, int irq,
irq_handler_t handler, irq_handler_t thread_handler,
unsigned long flags, const char *name, void *arg)
@@ -92,6 +103,12 @@ disable_irq(unsigned int irq)
lkpi_disable_irq(irq);
}
+static inline void
+disable_irq_nosync(unsigned int irq)
+{
+ lkpi_disable_irq(irq);
+}
+
static inline int
bind_irq_to_cpu(unsigned int irq, int cpu_id)
{
@@ -111,22 +128,36 @@ devm_free_irq(struct device *xdev, unsigned int irq, void *p)
}
static inline int
-irq_set_affinity_hint(int vector, cpumask_t *mask)
+irq_set_affinity_hint(int vector, const cpumask_t *mask)
{
int error;
if (mask != NULL)
- error = intr_setaffinity(vector, CPU_WHICH_IRQ, mask);
+ error = intr_setaffinity(vector, CPU_WHICH_IRQ, __DECONST(cpumask_t *, mask));
else
error = intr_setaffinity(vector, CPU_WHICH_IRQ, cpuset_root);
return (-error);
}
+static inline struct msi_desc *
+irq_get_msi_desc(unsigned int irq)
+{
+
+ return (lkpi_pci_msi_desc_alloc(irq));
+}
+
+static inline void
+irq_set_status_flags(unsigned int irq __unused, unsigned long flags __unused)
+{
+}
+
/*
* LinuxKPI tasklet support
*/
+struct tasklet_struct;
typedef void tasklet_func_t(unsigned long);
+typedef void tasklet_callback_t(struct tasklet_struct *);
struct tasklet_struct {
TAILQ_ENTRY(tasklet_struct) entry;
@@ -135,6 +166,8 @@ struct tasklet_struct {
volatile u_int tasklet_state;
atomic_t count;
unsigned long data;
+ tasklet_callback_t *callback;
+ bool use_callback;
};
#define DECLARE_TASKLET(_name, _func, _data) \
@@ -142,6 +175,11 @@ struct tasklet_struct _name = { .func = (_func), .data = (_data) }
#define tasklet_hi_schedule(t) tasklet_schedule(t)
+/* Some other compat code in the tree has this defined as well. */
+#define from_tasklet(_dev, _t, _field) \
+ container_of(_t, typeof(*(_dev)), _field)
+
+void tasklet_setup(struct tasklet_struct *, tasklet_callback_t *);
extern void tasklet_schedule(struct tasklet_struct *);
extern void tasklet_kill(struct tasklet_struct *);
extern void tasklet_init(struct tasklet_struct *, tasklet_func_t *,
@@ -152,5 +190,6 @@ extern void tasklet_disable_nosync(struct tasklet_struct *);
extern int tasklet_trylock(struct tasklet_struct *);
extern void tasklet_unlock(struct tasklet_struct *);
extern void tasklet_unlock_wait(struct tasklet_struct *ts);
+#define tasklet_unlock_spin_wait(ts) tasklet_unlock_wait(ts)
#endif /* _LINUXKPI_LINUX_INTERRUPT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/interval_tree.h b/sys/compat/linuxkpi/common/include/linux/interval_tree.h
index 3f8e0cb743d9..1eb8a2fb9181 100644
--- a/sys/compat/linuxkpi/common/include/linux/interval_tree.h
+++ b/sys/compat/linuxkpi/common/include/linux/interval_tree.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
*
diff --git a/sys/compat/linuxkpi/common/include/linux/interval_tree_generic.h b/sys/compat/linuxkpi/common/include/linux/interval_tree_generic.h
index 2ee615fda159..3ed6e105cbda 100644
--- a/sys/compat/linuxkpi/common/include/linux/interval_tree_generic.h
+++ b/sys/compat/linuxkpi/common/include/linux/interval_tree_generic.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Mark Kettenis <kettenis@OpenBSD.org>
* Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
diff --git a/sys/compat/linuxkpi/common/include/linux/io-64-nonatomic-lo-hi.h b/sys/compat/linuxkpi/common/include/linux/io-64-nonatomic-lo-hi.h
new file mode 100644
index 000000000000..844b3ef171d5
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/io-64-nonatomic-lo-hi.h
@@ -0,0 +1,65 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Felix Palmen
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef _LINUXKPI_LINUX_IO_64_NONATOMIC_LO_HI_H_
+#define _LINUXKPI_LINUX_IO_64_NONATOMIC_LO_HI_H_
+
+#include <linux/io.h>
+
+static inline uint64_t
+lo_hi_readq(const volatile void *addr)
+{
+ const volatile uint32_t *p = addr;
+ uint32_t l, h;
+
+ __io_br();
+ l = le32toh(__raw_readl(p));
+ h = le32toh(__raw_readl(p + 1));
+ __io_ar();
+
+ return (l + ((uint64_t)h << 32));
+}
+
+static inline void
+lo_hi_writeq(uint64_t v, volatile void *addr)
+{
+ volatile uint32_t *p = addr;
+
+ __io_bw();
+ __raw_writel(htole32(v), p);
+ __raw_writel(htole32(v >> 32), p + 1);
+ __io_aw();
+}
+
+#ifndef readq
+#define readq(addr) lo_hi_readq(addr)
+#endif
+
+#ifndef writeq
+#define writeq(v, addr) lo_hi_writeq(v, addr)
+#endif
+
+#endif /* _LINUXKPI_LINUX_IO_64_NONATOMIC_LO_HI_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/io-mapping.h b/sys/compat/linuxkpi/common/include/linux/io-mapping.h
index 5c24f1ff8659..f5f2fbc5c2cb 100644
--- a/sys/compat/linuxkpi/common/include/linux/io-mapping.h
+++ b/sys/compat/linuxkpi/common/include/linux/io-mapping.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_IO_MAPPING_H_
@@ -37,6 +35,7 @@
#include <linux/types.h>
#include <linux/io.h>
+#include <linux/mm.h>
#include <linux/slab.h>
struct io_mapping {
@@ -93,6 +92,18 @@ io_mapping_unmap_atomic(void *vaddr)
}
static inline void *
+io_mapping_map_local_wc(struct io_mapping *mapping, unsigned long offset)
+{
+
+ return (io_mapping_map_atomic_wc(mapping, offset));
+}
+
+static inline void
+io_mapping_unmap_local(void *vaddr __unused)
+{
+}
+
+static inline void *
io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset,
unsigned long size)
{
@@ -100,6 +111,17 @@ io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset,
return ((char *)mapping->mem + offset);
}
+int lkpi_io_mapping_map_user(struct io_mapping *iomap,
+ struct vm_area_struct *vma, unsigned long addr, unsigned long pfn,
+ unsigned long size);
+
+static inline int
+io_mapping_map_user(struct io_mapping *iomap, struct vm_area_struct *vma,
+ unsigned long addr, unsigned long pfn, unsigned long size)
+{
+ return (lkpi_io_mapping_map_user(iomap, vma, addr, pfn, size));
+}
+
static inline void
io_mapping_unmap(void *vaddr)
{
diff --git a/sys/compat/linuxkpi/common/include/linux/io.h b/sys/compat/linuxkpi/common/include/linux/io.h
index e12f9b36a9a1..bce70ed0cb8d 100644
--- a/sys/compat/linuxkpi/common/include/linux/io.h
+++ b/sys/compat/linuxkpi/common/include/linux/io.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_IO_H_
#define _LINUXKPI_LINUX_IO_H_
@@ -37,6 +35,7 @@
#include <machine/vm.h>
#include <linux/compiler.h>
+#include <linux/err.h>
#include <linux/types.h>
#if !defined(__arm__)
#include <asm/set_memory.h>
@@ -351,6 +350,16 @@ ioread32be(const volatile void *addr)
}
#define ioread32be(addr) ioread32be(addr)
+#ifdef __LP64__
+#undef ioread64
+static inline uint64_t
+ioread64(const volatile void *addr)
+{
+ return (readq(addr));
+}
+#define ioread64(addr) ioread64(addr)
+#endif
+
#undef iowrite8
static inline void
iowrite8(uint8_t v, volatile void *addr)
@@ -403,6 +412,13 @@ _ioremap_attr(vm_paddr_t _phys_addr, unsigned long _size, int _attr)
}
#endif
+struct device;
+static inline void *
+devm_ioremap(struct device *dev, resource_size_t offset, resource_size_t size)
+{
+ return (NULL);
+}
+
#ifdef VM_MEMATTR_DEVICE
#define ioremap_nocache(addr, size) \
_ioremap_attr((addr), (size), VM_MEMATTR_DEVICE)
@@ -424,7 +440,7 @@ _ioremap_attr(vm_paddr_t _phys_addr, unsigned long _size, int _attr)
#else
#define ioremap_wc(addr, size) ioremap_nocache(addr, size)
#endif
-#define ioremap_wb(addr, size) \
+#define ioremap_cache(addr, size) \
_ioremap_attr((addr), (size), VM_MEMATTR_WRITE_BACK)
void iounmap(void *addr);
@@ -433,9 +449,9 @@ void iounmap(void *addr);
#define memcpy_toio(a, b, c) memcpy((a), (b), (c))
static inline void
-__iowrite32_copy(void *to, void *from, size_t count)
+__iowrite32_copy(void *to, const void *from, size_t count)
{
- uint32_t *src;
+ const uint32_t *src;
uint32_t *dst;
int i;
@@ -444,10 +460,10 @@ __iowrite32_copy(void *to, void *from, size_t count)
}
static inline void
-__iowrite64_copy(void *to, void *from, size_t count)
+__iowrite64_copy(void *to, const void *from, size_t count)
{
#ifdef __LP64__
- uint64_t *src;
+ const uint64_t *src;
uint64_t *dst;
int i;
@@ -458,6 +474,32 @@ __iowrite64_copy(void *to, void *from, size_t count)
#endif
}
+static inline void
+__ioread32_copy(void *to, const void *from, size_t count)
+{
+ const uint32_t *src;
+ uint32_t *dst;
+ int i;
+
+ for (i = 0, src = from, dst = to; i < count; i++, src++, dst++)
+ *dst = __raw_readl(src);
+}
+
+static inline void
+__ioread64_copy(void *to, const void *from, size_t count)
+{
+#ifdef __LP64__
+ const uint64_t *src;
+ uint64_t *dst;
+ int i;
+
+ for (i = 0, src = from, dst = to; i < count; i++, src++, dst++)
+ *dst = __raw_readq(src);
+#else
+ __ioread32_copy(to, from, count * 2);
+#endif
+}
+
enum {
MEMREMAP_WB = 1 << 0,
MEMREMAP_WT = 1 << 1,
@@ -470,7 +512,7 @@ memremap(resource_size_t offset, size_t size, unsigned long flags)
void *addr = NULL;
if ((flags & MEMREMAP_WB) &&
- (addr = ioremap_wb(offset, size)) != NULL)
+ (addr = ioremap_cache(offset, size)) != NULL)
goto done;
if ((flags & MEMREMAP_WT) &&
(addr = ioremap_wt(offset, size)) != NULL)
@@ -489,6 +531,8 @@ memunmap(void *addr)
iounmap(addr);
}
+#define IOMEM_ERR_PTR(err) (void __iomem *)ERR_PTR(err)
+
#define __MTRR_ID_BASE 1
int lkpi_arch_phys_wc_add(unsigned long, unsigned long);
void lkpi_arch_phys_wc_del(int);
@@ -501,14 +545,25 @@ void lkpi_arch_phys_wc_del(int);
static inline int
arch_io_reserve_memtype_wc(resource_size_t start, resource_size_t size)
{
+ vm_offset_t va;
- return (set_memory_wc(start, size >> PAGE_SHIFT));
+ 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));
+#endif
}
static inline void
arch_io_free_memtype_wc(resource_size_t start, resource_size_t size)
{
- set_memory_wb(start, size >> PAGE_SHIFT);
+ vm_offset_t va;
+
+ va = PHYS_TO_DMAP(start);
+
+ pmap_change_attr(va, size, VM_MEMATTR_WRITE_BACK);
}
#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/ioctl.h b/sys/compat/linuxkpi/common/include/linux/ioctl.h
index b1b5443fa150..77c01224e6a5 100644
--- a/sys/compat/linuxkpi/common/include/linux/ioctl.h
+++ b/sys/compat/linuxkpi/common/include/linux/ioctl.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_IOCTL_H_
#define _LINUXKPI_LINUX_IOCTL_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/iommu.h b/sys/compat/linuxkpi/common/include/linux/iommu.h
new file mode 100644
index 000000000000..391d9778a0c8
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/iommu.h
@@ -0,0 +1,29 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_IOMMU_H_
+#define _LINUXKPI_LINUX_IOMMU_H_
+
+#include <linux/device.h>
+
+#define __IOMMU_DOMAIN_PAGING (1U << 0)
+#define __IOMMU_DOMAIN_DMA_API (1U << 1)
+#define __IOMMU_DOMAIN_PT (1U << 2)
+#define __IOMMU_DOMAIN_DMA_FQ (1U << 3)
+
+#define IOMMU_DOMAIN_BLOCKED (0U)
+#define IOMMU_DOMAIN_IDENTITY (__IOMMU_DOMAIN_PT)
+#define IOMMU_DOMAIN_UNMANAGED (__IOMMU_DOMAIN_PAGING)
+#define IOMMU_DOMAIN_DMA (__IOMMU_DOMAIN_PAGING | __IOMMU_DOMAIN_DMA_API)
+#define IOMMU_DOMAIN_DMA_FQ (__IOMMU_DOMAIN_PAGING | __IOMMU_DOMAIN_DMA_API | __IOMMU_DOMAIN_DMA_FQ)
+
+struct iommu_domain {
+ unsigned int type;
+};
+
+static inline struct iommu_domain *
+iommu_get_domain_for_dev(struct device *dev __unused)
+{
+ return (NULL);
+}
+
+#endif /* _LINUXKPI_LINUX_IOMMU_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/iopoll.h b/sys/compat/linuxkpi/common/include/linux/iopoll.h
index 478d875c846c..8d0498a26da1 100644
--- a/sys/compat/linuxkpi/common/include/linux/iopoll.h
+++ b/sys/compat/linuxkpi/common/include/linux/iopoll.h
@@ -23,8 +23,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_IOPOLL_H
diff --git a/sys/compat/linuxkpi/common/include/linux/ioport.h b/sys/compat/linuxkpi/common/include/linux/ioport.h
new file mode 100644
index 000000000000..444f3ad94602
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/ioport.h
@@ -0,0 +1,57 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Serenity Cyber Security, LLC.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_LINUX_IOPORT_H
+#define _LINUXKPI_LINUX_IOPORT_H
+
+#include <linux/compiler.h>
+#include <linux/types.h>
+
+#define DEFINE_RES_MEM(_start, _size) \
+ (struct resource) { \
+ .start = (_start), \
+ .end = (_start) + (_size) - 1, \
+ }
+
+struct resource {
+ resource_size_t start;
+ resource_size_t end;
+};
+
+static inline resource_size_t
+resource_size(const struct resource *r)
+{
+ return (r->end - r->start + 1);
+}
+
+static inline bool
+resource_contains(struct resource *a, struct resource *b)
+{
+ return (a->start <= b->start && a->end >= b->end);
+}
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/iosys-map.h b/sys/compat/linuxkpi/common/include/linux/iosys-map.h
new file mode 100644
index 000000000000..66c442b8668f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/iosys-map.h
@@ -0,0 +1,161 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_IOSYS_MAP_H
+#define _LINUXKPI_LINUX_IOSYS_MAP_H
+
+#include <linux/io.h>
+#include <linux/string.h>
+
+struct iosys_map {
+ union {
+ void *vaddr_iomem;
+ void *vaddr;
+ };
+ bool is_iomem;
+#ifdef __OpenBSD__
+ bus_space_handle_t bsh;
+ bus_size_t size;
+#endif
+};
+
+#define IOSYS_MAP_INIT_OFFSET(_ism_src_p, _off) ({ \
+ struct iosys_map ism_dst = *(_ism_src_p); \
+ iosys_map_incr(&ism_dst, _off); \
+ ism_dst; \
+})
+
+static inline void
+iosys_map_incr(struct iosys_map *ism, size_t n)
+{
+ if (ism->is_iomem)
+ ism->vaddr_iomem += n;
+ else
+ ism->vaddr += n;
+}
+
+static inline void
+iosys_map_memcpy_to(struct iosys_map *ism, size_t off, const void *src,
+ size_t len)
+{
+ if (ism->is_iomem)
+ memcpy_toio(ism->vaddr_iomem + off, src, len);
+ else
+ memcpy(ism->vaddr + off, src, len);
+}
+
+static inline bool
+iosys_map_is_null(const struct iosys_map *ism)
+{
+ if (ism->is_iomem)
+ return (ism->vaddr_iomem == NULL);
+ else
+ return (ism->vaddr == NULL);
+}
+
+static inline bool
+iosys_map_is_set(const struct iosys_map *ism)
+{
+ if (ism->is_iomem)
+ return (ism->vaddr_iomem != NULL);
+ else
+ return (ism->vaddr != NULL);
+}
+
+static inline bool
+iosys_map_is_equal(const struct iosys_map *ism_a,
+ const struct iosys_map *ism_b)
+{
+ if (ism_a->is_iomem != ism_b->is_iomem)
+ return (false);
+
+ if (ism_a->is_iomem)
+ return (ism_a->vaddr_iomem == ism_b->vaddr_iomem);
+ else
+ return (ism_a->vaddr == ism_b->vaddr);
+}
+
+static inline void
+iosys_map_clear(struct iosys_map *ism)
+{
+ if (ism->is_iomem) {
+ ism->vaddr_iomem = NULL;
+ ism->is_iomem = false;
+ } else {
+ ism->vaddr = NULL;
+ }
+}
+
+static inline void
+iosys_map_set_vaddr_iomem(struct iosys_map *ism, void *addr)
+{
+ ism->vaddr_iomem = addr;
+ ism->is_iomem = true;
+}
+
+static inline void
+iosys_map_set_vaddr(struct iosys_map *ism, void *addr)
+{
+ ism->vaddr = addr;
+ ism->is_iomem = false;
+}
+
+static inline void
+iosys_map_memset(struct iosys_map *ism, size_t off, int value, size_t len)
+{
+ if (ism->is_iomem)
+ memset_io(ism->vaddr_iomem + off, value, len);
+ else
+ memset(ism->vaddr + off, value, len);
+}
+
+#ifdef __LP64__
+#define _iosys_map_readq(_addr) readq(_addr)
+#define _iosys_map_writeq(_val, _addr) writeq(_val, _addr)
+#else
+#define _iosys_map_readq(_addr) ({ \
+ uint64_t val; \
+ memcpy_fromio(&val, _addr, sizeof(uint64_t)); \
+ val; \
+})
+#define _iosys_map_writeq(_val, _addr) \
+ memcpy_toio(_addr, &(_val), sizeof(uint64_t))
+#endif
+
+#define iosys_map_rd(_ism, _off, _type) ({ \
+ _type val; \
+ if ((_ism)->is_iomem) { \
+ void *addr = (_ism)->vaddr_iomem + (_off); \
+ val = _Generic(val, \
+ uint8_t : readb(addr), \
+ uint16_t: readw(addr), \
+ uint32_t: readl(addr), \
+ uint64_t: _iosys_map_readq(addr)); \
+ } else \
+ val = READ_ONCE(*(_type *)((_ism)->vaddr + (_off))); \
+ val; \
+})
+#define iosys_map_wr(_ism, _off, _type, _val) ({ \
+ _type val = (_val); \
+ if ((_ism)->is_iomem) { \
+ void *addr = (_ism)->vaddr_iomem + (_off); \
+ _Generic(val, \
+ uint8_t : writeb(val, addr), \
+ uint16_t: writew(val, addr), \
+ uint32_t: writel(val, addr), \
+ uint64_t: _iosys_map_writeq(val, addr)); \
+ } else \
+ WRITE_ONCE(*(_type *)((_ism)->vaddr + (_off)), val); \
+})
+
+#define iosys_map_rd_field(_ism, _off, _type, _field) ({ \
+ _type *s; \
+ iosys_map_rd(_ism, (_off) + offsetof(_type, _field), \
+ __typeof(s->_field)); \
+})
+#define iosys_map_wr_field(_ism, _off, _type, _field, _val) ({ \
+ _type *s; \
+ iosys_map_wr(_ism, (_off) + offsetof(_type, _field), \
+ __typeof(s->_field), _val); \
+})
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/ip.h b/sys/compat/linuxkpi/common/include/linux/ip.h
index 11f4aed180d1..137cf89e7dcb 100644
--- a/sys/compat/linuxkpi/common/include/linux/ip.h
+++ b/sys/compat/linuxkpi/common/include/linux/ip.h
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_IP_H
diff --git a/sys/compat/linuxkpi/common/include/linux/irq_work.h b/sys/compat/linuxkpi/common/include/linux/irq_work.h
index ec71a7ee094f..7c4019bc0242 100644
--- a/sys/compat/linuxkpi/common/include/linux/irq_work.h
+++ b/sys/compat/linuxkpi/common/include/linux/irq_work.h
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_IRQ_WORK_H_
@@ -51,7 +49,12 @@ typedef void (*irq_work_func_t)(struct irq_work *);
struct irq_work {
struct task irq_task;
- struct llist_node llnode;
+ union {
+ struct llist_node llnode;
+ struct {
+ struct llist_node llist;
+ } node;
+ };
irq_work_func_t func;
};
diff --git a/sys/compat/linuxkpi/common/include/linux/irqdomain.h b/sys/compat/linuxkpi/common/include/linux/irqdomain.h
new file mode 100644
index 000000000000..c7788e51cc89
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/irqdomain.h
@@ -0,0 +1,10 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_IRQDOMAIN_H
+#define _LINUXKPI_LINUX_IRQDOMAIN_H
+
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/radix-tree.h>
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/irqreturn.h b/sys/compat/linuxkpi/common/include/linux/irqreturn.h
index 8fbb0217573d..ff2618449d5e 100644
--- a/sys/compat/linuxkpi/common/include/linux/irqreturn.h
+++ b/sys/compat/linuxkpi/common/include/linux/irqreturn.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_IRQRETURN_H
diff --git a/sys/compat/linuxkpi/common/include/linux/jhash.h b/sys/compat/linuxkpi/common/include/linux/jhash.h
index 1bab37f22b5d..25e2c04f1965 100644
--- a/sys/compat/linuxkpi/common/include/linux/jhash.h
+++ b/sys/compat/linuxkpi/common/include/linux/jhash.h
@@ -20,8 +20,6 @@
*
* I've modified Bob's hash to be useful in the Linux kernel, and
* any bugs present are surely my fault. -DaveM
- *
- * $FreeBSD$
*/
/* NOTE: Arguments are modified. */
diff --git a/sys/compat/linuxkpi/common/include/linux/jiffies.h b/sys/compat/linuxkpi/common/include/linux/jiffies.h
index 76c9c6a749c1..d5cb6e14860e 100644
--- a/sys/compat/linuxkpi/common/include/linux/jiffies.h
+++ b/sys/compat/linuxkpi/common/include/linux/jiffies.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_JIFFIES_H_
#define _LINUXKPI_LINUX_JIFFIES_H_
@@ -40,7 +38,7 @@
#define jiffies ticks
#define jiffies_64 ticks
-#define jiffies_to_msecs(x) (((int64_t)(int)(x)) * 1000 / hz)
+#define jiffies_to_msecs(x) ((unsigned int)(((int64_t)(int)(x)) * 1000 / hz))
#define MAX_JIFFY_OFFSET ((INT_MAX >> 1) - 1)
diff --git a/sys/compat/linuxkpi/common/include/linux/kconfig.h b/sys/compat/linuxkpi/common/include/linux/kconfig.h
new file mode 100644
index 000000000000..c1d186b56e1f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/kconfig.h
@@ -0,0 +1,76 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_LINUX_KCONFIG_H_
+#define _LINUXKPI_LINUX_KCONFIG_H_
+
+/*
+ * Checking if an option is defined would be easy if we could do CPP inside CPP.
+ * The defined case whether -Dxxx or -Dxxx=1 are easy to deal with. In either
+ * case the defined value is "1". A more general -Dxxx=<c> case will require
+ * more effort to deal with all possible "true" values. Hope we do not have
+ * to do this as well.
+ * The real problem is the undefined case. To avoid this problem we do the
+ * concat/varargs trick: "yyy" ## xxx can make two arguments if xxx is "1"
+ * by having a #define for yyy_1 which is "ignore,".
+ * Otherwise we will just get "yyy".
+ * Need to be careful about variable substitutions in macros though.
+ * This way we make a (true, false) problem a (don't care, true, false) or a
+ * (don't care true, false). Then we can use a variadic macro to only select
+ * the always well known and defined argument #2. And that seems to be
+ * exactly what we need. Use 1 for true and 0 for false to also allow
+ * #if IS_*() checks pre-compiler checks which do not like #if true.
+ */
+#define ___XAB_1 dontcare,
+#define ___IS_XAB(_ignore, _x, ...) (_x)
+#define __IS_XAB(_x) ___IS_XAB(_x 1, 0)
+#define _IS_XAB(_x) __IS_XAB(__CONCAT(___XAB_, _x))
+
+/* This is if CONFIG_ccc=y. */
+#define IS_BUILTIN(_x) _IS_XAB(_x)
+/* This is if CONFIG_ccc=m. */
+#define IS_MODULE(_x) _IS_XAB(_x ## _MODULE)
+/* This is if CONFIG_ccc is compiled in(=y) or a module(=m). */
+#define IS_ENABLED(_x) (IS_BUILTIN(_x) || IS_MODULE(_x))
+/*
+ * This is weird case. If the CONFIG_ccc is builtin (=y) this returns true;
+ * or if the CONFIG_ccc is a module (=m) and the caller is built as a module
+ * (-DMODULE defined) this returns true, but if the callers is not a module
+ * (-DMODULE not defined, which means caller is BUILTIN) then it returns
+ * false. In other words, a module can reach the kernel, a module can reach
+ * a module, but the kernel cannot reach a module, and code never compiled
+ * cannot be reached either.
+ * XXX -- I'd hope the module-to-module case would be handled by a proper
+ * module dependency definition (MODULE_DEPEND() in FreeBSD).
+ */
+#define IS_REACHABLE(_x) (IS_BUILTIN(_x) || \
+ (IS_MODULE(_x) && IS_BUILTIN(MODULE)))
+
+#endif /* _LINUXKPI_LINUX_KCONFIG_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kdev_t.h b/sys/compat/linuxkpi/common/include/linux/kdev_t.h
index f2a5b53effec..988dd771254a 100644
--- a/sys/compat/linuxkpi/common/include/linux/kdev_t.h
+++ b/sys/compat/linuxkpi/common/include/linux/kdev_t.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_KDEV_T_H_
#define _LINUXKPI_LINUX_KDEV_T_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/kernel.h b/sys/compat/linuxkpi/common/include/linux/kernel.h
index 4987c582f0f3..ed4320e80fa7 100644
--- a/sys/compat/linuxkpi/common/include/linux/kernel.h
+++ b/sys/compat/linuxkpi/common/include/linux/kernel.h
@@ -26,13 +26,10 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_KERNEL_H_
#define _LINUXKPI_LINUX_KERNEL_H_
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/param.h>
@@ -44,18 +41,25 @@
#include <sys/time.h>
#include <linux/bitops.h>
+#include <linux/build_bug.h>
#include <linux/compiler.h>
+#include <linux/container_of.h>
+#include <linux/limits.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>
#include <linux/log2.h>
+#include <linux/kconfig.h>
#include <asm/byteorder.h>
+#include <asm/cpufeature.h>
+#include <asm/processor.h>
#include <asm/uaccess.h>
-#include <machine/stdarg.h>
+#include <linux/stdarg.h>
#define KERN_CONT ""
#define KERN_EMERG "<0>"
@@ -67,19 +71,6 @@
#define KERN_INFO "<6>"
#define KERN_DEBUG "<7>"
-#define U8_MAX ((u8)~0U)
-#define S8_MAX ((s8)(U8_MAX >> 1))
-#define S8_MIN ((s8)(-S8_MAX - 1))
-#define U16_MAX ((u16)~0U)
-#define S16_MAX ((s16)(U16_MAX >> 1))
-#define S16_MIN ((s16)(-S16_MAX - 1))
-#define U32_MAX ((u32)~0U)
-#define S32_MAX ((s32)(U32_MAX >> 1))
-#define S32_MIN ((s32)(-S32_MAX - 1))
-#define U64_MAX ((u64)~0ULL)
-#define S64_MAX ((s64)(U64_MAX >> 1))
-#define S64_MIN ((s64)(-S64_MAX - 1))
-
#define S8_C(x) x
#define U8_C(x) x ## U
#define S16_C(x) x
@@ -89,28 +80,6 @@
#define S64_C(x) x ## LL
#define U64_C(x) x ## ULL
-/*
- * BUILD_BUG_ON() can happen inside functions where _Static_assert() does not
- * seem to work. Use old-schoold-ish CTASSERT from before commit
- * a3085588a88fa58eb5b1eaae471999e1995a29cf but also make sure we do not
- * end up with an unused typedef or variable. The compiler should optimise
- * it away entirely.
- */
-#define _O_CTASSERT(x) _O__CTASSERT(x, __LINE__)
-#define _O__CTASSERT(x, y) _O___CTASSERT(x, y)
-#define _O___CTASSERT(x, y) while (0) { \
- typedef char __assert_line_ ## y[(x) ? 1 : -1]; \
- __assert_line_ ## y _x; \
- _x[0] = '\0'; \
-}
-
-#define BUILD_BUG() do { CTASSERT(0); } while (0)
-#define BUILD_BUG_ON(x) do { _O_CTASSERT(!(x)) } while (0)
-#define BUILD_BUG_ON_MSG(x, msg) BUILD_BUG_ON(x)
-#define BUILD_BUG_ON_NOT_POWER_OF_2(x) BUILD_BUG_ON(!powerof2(x))
-#define BUILD_BUG_ON_INVALID(expr) while (0) { (void)(expr); }
-#define BUILD_BUG_ON_ZERO(x) ((int)sizeof(struct { int:-((x) != 0); }))
-
#define BUG() panic("BUG at %s:%d", __FILE__, __LINE__)
#define BUG_ON(cond) do { \
if (cond) { \
@@ -163,6 +132,8 @@ extern int linuxkpi_warn_dump_stack;
#define printk(...) printf(__VA_ARGS__)
#define vprintk(f, a) vprintf(f, a)
+#define PTR_IF(x, p) ((x) ? (p) : NULL)
+
#define asm __asm
extern void linux_dump_stack(void);
@@ -293,12 +264,6 @@ extern int linuxkpi_debug;
})
#endif
-#define container_of(ptr, type, member) \
-({ \
- const __typeof(((type *)0)->member) *__p = (ptr); \
- (type *)((uintptr_t)__p - offsetof(type, member)); \
-})
-
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define u64_to_user_ptr(val) ((void *)(uintptr_t)(val))
@@ -434,19 +399,8 @@ kstrtou16(const char *cp, unsigned int base, u16 *res)
static inline int
kstrtou32(const char *cp, unsigned int base, u32 *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 != (u32)temp)
- return (-ERANGE);
- return (0);
+ return (kstrtouint(cp, base, res));
}
static inline int
@@ -527,7 +481,7 @@ kstrtoint_from_user(const char __user *s, size_t count, unsigned int base,
static inline int
kstrtouint_from_user(const char __user *s, size_t count, unsigned int base,
- int *p)
+ unsigned int *p)
{
char buf[36] = {};
@@ -541,6 +495,14 @@ kstrtouint_from_user(const char __user *s, size_t count, unsigned int base,
}
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)
{
@@ -622,12 +584,6 @@ mult_frac(uintmax_t x, uintmax_t multiplier, uintmax_t divisor)
return ((q * multiplier) + ((r * multiplier) / divisor));
}
-static inline int64_t
-abs64(int64_t x)
-{
- return (x < 0 ? -x : x);
-}
-
typedef struct linux_ratelimit {
struct timeval lasttime;
int counter;
@@ -639,12 +595,6 @@ linux_ratelimited(linux_ratelimit_t *rl)
return (ppsratecheck(&rl->lasttime, &rl->counter, 1));
}
-#define struct_size(ptr, field, num) ({ \
- const size_t __size = offsetof(__typeof(*(ptr)), field); \
- const size_t __max = (SIZE_MAX - __size) / sizeof((ptr)->field[0]); \
- ((num) > __max) ? SIZE_MAX : (__size + sizeof((ptr)->field[0]) * (num)); \
-})
-
#define __is_constexpr(x) \
__builtin_constant_p(x)
@@ -654,31 +604,10 @@ linux_ratelimited(linux_ratelimit_t *rl)
*/
#define is_signed(datatype) (((datatype)-1 / (datatype)2) == (datatype)0)
-/*
- * The type_max() macro below returns the maxium positive value the
- * passed data type can hold.
- */
-#define type_max(datatype) ( \
- (sizeof(datatype) >= 8) ? (is_signed(datatype) ? INT64_MAX : UINT64_MAX) : \
- (sizeof(datatype) >= 4) ? (is_signed(datatype) ? INT32_MAX : UINT32_MAX) : \
- (sizeof(datatype) >= 2) ? (is_signed(datatype) ? INT16_MAX : UINT16_MAX) : \
- (is_signed(datatype) ? INT8_MAX : UINT8_MAX) \
-)
-
-/*
- * The type_min() macro below returns the minimum value the passed
- * data type can hold. For unsigned types the minimum value is always
- * zero. For signed types it may vary.
- */
-#define type_min(datatype) ( \
- (sizeof(datatype) >= 8) ? (is_signed(datatype) ? INT64_MIN : 0) : \
- (sizeof(datatype) >= 4) ? (is_signed(datatype) ? INT32_MIN : 0) : \
- (sizeof(datatype) >= 2) ? (is_signed(datatype) ? INT16_MIN : 0) : \
- (is_signed(datatype) ? INT8_MIN : 0) \
-)
-
#define TAINT_WARN 0
#define test_taint(x) (0)
+#define add_taint(x,y) do { \
+ } while (0)
static inline int
_h2b(const char c)
@@ -711,49 +640,49 @@ hex2bin(uint8_t *bindst, const char *hexsrc, size_t binlen)
return (0);
}
+static inline bool
+mac_pton(const char *macin, uint8_t *macout)
+{
+ const char *s, *d;
+ uint8_t mac[6], hx, lx;;
+ int i;
+
+ if (strlen(macin) < (3 * 6 - 1))
+ return (false);
+
+ i = 0;
+ s = macin;
+ do {
+ /* Should we also support '-'-delimiters? */
+ d = strchrnul(s, ':');
+ hx = lx = 0;
+ while (s < d) {
+ /* Fail on abc:123:xxx:... */
+ if ((d - s) > 2)
+ return (false);
+ /* We do support non-well-formed strings: 3:45:6:... */
+ if ((d - s) > 1) {
+ hx = _h2b(*s);
+ if (hx < 0)
+ return (false);
+ s++;
+ }
+ lx = _h2b(*s);
+ if (lx < 0)
+ return (false);
+ s++;
+ }
+ mac[i] = (hx << 4) | lx;
+ i++;
+ if (i >= 6)
+ return (false);
+ } while (d != NULL && *d != '\0');
+
+ memcpy(macout, mac, 6);
+ return (true);
+}
+
#define DECLARE_FLEX_ARRAY(_t, _n) \
struct { struct { } __dummy_ ## _n; _t _n[0]; }
-/*
- * Checking if an option is defined would be easy if we could do CPP inside CPP.
- * The defined case whether -Dxxx or -Dxxx=1 are easy to deal with. In either
- * case the defined value is "1". A more general -Dxxx=<c> case will require
- * more effort to deal with all possible "true" values. Hope we do not have
- * to do this as well.
- * The real problem is the undefined case. To avoid this problem we do the
- * concat/varargs trick: "yyy" ## xxx can make two arguments if xxx is "1"
- * by having a #define for yyy_1 which is "ignore,".
- * Otherwise we will just get "yyy".
- * Need to be careful about variable substitutions in macros though.
- * This way we make a (true, false) problem a (don't care, true, false) or a
- * (don't care true, false). Then we can use a variadic macro to only select
- * the always well known and defined argument #2. And that seems to be
- * exactly what we need. Use 1 for true and 0 for false to also allow
- * #if IS_*() checks pre-compiler checks which do not like #if true.
- */
-#define ___XAB_1 dontcare,
-#define ___IS_XAB(_ignore, _x, ...) (_x)
-#define __IS_XAB(_x) ___IS_XAB(_x 1, 0)
-#define _IS_XAB(_x) __IS_XAB(__CONCAT(___XAB_, _x))
-
-/* This is if CONFIG_ccc=y. */
-#define IS_BUILTIN(_x) _IS_XAB(_x)
-/* This is if CONFIG_ccc=m. */
-#define IS_MODULE(_x) _IS_XAB(_x ## _MODULE)
-/* This is if CONFIG_ccc is compiled in(=y) or a module(=m). */
-#define IS_ENABLED(_x) (IS_BUILTIN(_x) || IS_MODULE(_x))
-/*
- * This is weird case. If the CONFIG_ccc is builtin (=y) this returns true;
- * or if the CONFIG_ccc is a module (=m) and the caller is built as a module
- * (-DMODULE defined) this returns true, but if the callers is not a module
- * (-DMODULE not defined, which means caller is BUILTIN) then it returns
- * false. In other words, a module can reach the kernel, a module can reach
- * a module, but the kernel cannot reach a module, and code never compiled
- * cannot be reached either.
- * XXX -- I'd hope the module-to-module case would be handled by a proper
- * module dependency definition (MODULE_DEPEND() in FreeBSD).
- */
-#define IS_REACHABLE(_x) (IS_BUILTIN(_x) || \
- (IS_MODULE(_x) && IS_BUILTIN(MODULE)))
-
#endif /* _LINUXKPI_LINUX_KERNEL_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kfifo.h b/sys/compat/linuxkpi/common/include/linux/kfifo.h
index 6ba1528d965c..d2f570781661 100644
--- a/sys/compat/linuxkpi/common/include/linux/kfifo.h
+++ b/sys/compat/linuxkpi/common/include/linux/kfifo.h
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
+ * Copyright (c) 2022 Bjoern A. Zeeb
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,7 +28,95 @@
#ifndef _LINUXKPI_LINUX_KFIFO_H_
#define _LINUXKPI_LINUX_KFIFO_H_
+#include <sys/types.h>
+
+#include <linux/slab.h>
+#include <linux/gfp.h>
+
#define INIT_KFIFO(x) 0
#define DECLARE_KFIFO(x, y, z)
+#define DECLARE_KFIFO_PTR(_name, _type) \
+ struct kfifo_ ## _name { \
+ size_t total; \
+ size_t count; \
+ size_t first; \
+ size_t last; \
+ _type *head; \
+ } _name
+
+#define kfifo_len(_kf) \
+({ \
+ (_kf)->count; \
+})
+
+#define kfifo_is_empty(_kf) \
+({ \
+ ((_kf)->count == 0) ? true : false; \
+})
+
+#define kfifo_is_full(_kf) \
+({ \
+ ((_kf)->count == (_kf)->total) ? true : false; \
+})
+
+#define kfifo_put(_kf, _e) \
+({ \
+ bool _rc; \
+ \
+ /* Would overflow. */ \
+ if (kfifo_is_full(_kf)) { \
+ _rc = false; \
+ } else { \
+ (_kf)->head[(_kf)->last] = (_e); \
+ (_kf)->count++; \
+ (_kf)->last++; \
+ if ((_kf)->last > (_kf)->total) \
+ (_kf)->last = 0; \
+ _rc = true; \
+ } \
+ \
+ _rc; \
+})
+
+#define kfifo_get(_kf, _e) \
+({ \
+ bool _rc; \
+ \
+ if (kfifo_is_empty(_kf)) { \
+ _rc = false; \
+ } else { \
+ *(_e) = (_kf)->head[(_kf)->first]; \
+ (_kf)->count--; \
+ (_kf)->first++; \
+ if ((_kf)->first > (_kf)->total) \
+ (_kf)->first = 0; \
+ _rc = true; \
+ } \
+ \
+ _rc; \
+})
+
+#define kfifo_alloc(_kf, _s, _gfp) \
+({ \
+ int _error; \
+ \
+ (_kf)->head = kmalloc(sizeof(__typeof(*(_kf)->head)) * (_s), _gfp); \
+ if ((_kf)->head == NULL) \
+ _error = ENOMEM; \
+ else { \
+ (_kf)->total = (_s); \
+ _error = 0; \
+ } \
+ \
+ _error; \
+})
+
+#define kfifo_free(_kf) \
+({ \
+ kfree((_kf)->head); \
+ (_kf)->head = NULL; \
+ (_kf)->total = (_kf)->count = (_kf)->first = (_kf)->last = 0; \
+})
+
#endif /* _LINUXKPI_LINUX_KFIFO_H_*/
diff --git a/sys/compat/linuxkpi/common/include/linux/kmod.h b/sys/compat/linuxkpi/common/include/linux/kmod.h
index b8e8a483210f..b3cbe2ed2e02 100644
--- a/sys/compat/linuxkpi/common/include/linux/kmod.h
+++ b/sys/compat/linuxkpi/common/include/linux/kmod.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_KMOD_H_
#define _LINUXKPI_LINUX_KMOD_H_
@@ -41,9 +39,8 @@
#define request_module(...) \
({\
char modname[128]; \
- int fileid; \
snprintf(modname, sizeof(modname), __VA_ARGS__); \
- kern_kldload(curthread, modname, &fileid); \
+ kern_kldload(curthread, modname, NULL); \
})
#define request_module_nowait request_module
diff --git a/sys/compat/linuxkpi/common/include/linux/kobject.h b/sys/compat/linuxkpi/common/include/linux/kobject.h
index ad25058028fc..512f47f9e4b4 100644
--- a/sys/compat/linuxkpi/common/include/linux/kobject.h
+++ b/sys/compat/linuxkpi/common/include/linux/kobject.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_KOBJECT_H_
#define _LINUXKPI_LINUX_KOBJECT_H_
@@ -37,8 +35,12 @@
#include <linux/kref.h>
#include <linux/list.h>
#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
struct kobject;
+struct kset;
struct sysctl_oid;
#define KOBJ_CHANGE 0x01
@@ -47,6 +49,7 @@ struct kobj_type {
void (*release)(struct kobject *kobj);
const struct sysfs_ops *sysfs_ops;
struct attribute **default_attrs;
+ const struct attribute_group **default_groups;
};
extern const struct kobj_type linux_kfree_type;
@@ -58,6 +61,7 @@ struct kobject {
const struct kobj_type *ktype;
struct list_head entry;
struct sysctl_oid *oidp;
+ struct kset *kset;
};
extern struct kobject *mm_kobj;
@@ -78,6 +82,17 @@ struct kobj_attribute {
const char *buf, size_t count);
};
+struct kset_uevent_ops {
+ /* TODO */
+};
+
+struct kset {
+ struct list_head list;
+ spinlock_t list_lock;
+ struct kobject kobj;
+ const struct kset_uevent_ops *uevent_ops;
+};
+
static inline void
kobject_init(struct kobject *kobj, const struct kobj_type *ktype)
{
@@ -155,4 +170,41 @@ kobject_uevent_env(struct kobject *kobj, int action, char *envp[])
*/
}
+void kset_init(struct kset *kset);
+int kset_register(struct kset *kset);
+void kset_unregister(struct kset *kset);
+struct kset * kset_create_and_add(const char *name,
+ const struct kset_uevent_ops *u, struct kobject *parent_kobj);
+
+static inline struct kset *
+to_kset(struct kobject *kobj)
+{
+ if (kobj != NULL)
+ return container_of(kobj, struct kset, kobj);
+ else
+ return NULL;
+}
+
+static inline struct kset *
+kset_get(struct kset *kset)
+{
+ if (kset != NULL) {
+ struct kobject *kobj;
+
+ kobj = kobject_get(&kset->kobj);
+ return to_kset(kobj);
+ } else {
+ return NULL;
+ }
+}
+
+static inline void
+kset_put(struct kset *kset)
+{
+ if (kset != NULL)
+ kobject_put(&kset->kobj);
+}
+
+void linux_kobject_kfree_name(struct kobject *kobj);
+
#endif /* _LINUXKPI_LINUX_KOBJECT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/kref.h b/sys/compat/linuxkpi/common/include/linux/kref.h
index 2c59794f4ddc..47d61c9ee316 100644
--- a/sys/compat/linuxkpi/common/include/linux/kref.h
+++ b/sys/compat/linuxkpi/common/include/linux/kref.h
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_KREF_H_
#define _LINUXKPI_LINUX_KREF_H_
@@ -43,6 +41,7 @@
#include <asm/atomic.h>
struct kref {
+ /* XXX In Linux this is a refcount_t */
atomic_t refcount;
};
@@ -50,28 +49,28 @@ static inline void
kref_init(struct kref *kref)
{
- refcount_init(&kref->refcount.counter, 1);
+ refcount_init((uint32_t *)&kref->refcount, 1);
}
static inline unsigned int
kref_read(const struct kref *kref)
{
- return (atomic_read(&kref->refcount));
+ return (refcount_load(__DECONST(u_int32_t *, &kref->refcount)));
}
static inline void
kref_get(struct kref *kref)
{
- refcount_acquire(&kref->refcount.counter);
+ refcount_acquire((uint32_t *)&kref->refcount);
}
static inline int
kref_put(struct kref *kref, void (*rel)(struct kref *kref))
{
- if (refcount_release(&kref->refcount.counter)) {
+ if (refcount_release((uint32_t *)&kref->refcount)) {
rel(kref);
return 1;
}
@@ -83,7 +82,7 @@ kref_put_lock(struct kref *kref, void (*rel)(struct kref *kref),
spinlock_t *lock)
{
- if (refcount_release(&kref->refcount.counter)) {
+ if (refcount_release((uint32_t *)&kref->refcount)) {
spin_lock(lock);
rel(kref);
return (1);
@@ -97,7 +96,7 @@ kref_sub(struct kref *kref, unsigned int count,
{
while (count--) {
- if (refcount_release(&kref->refcount.counter)) {
+ if (refcount_release((uint32_t *)&kref->refcount)) {
rel(kref);
return 1;
}
@@ -109,16 +108,16 @@ static inline int __must_check
kref_get_unless_zero(struct kref *kref)
{
- return atomic_add_unless(&kref->refcount, 1, 0);
+ return refcount_acquire_if_not_zero((uint32_t *)&kref->refcount);
}
static inline int kref_put_mutex(struct kref *kref,
void (*release)(struct kref *kref), struct mutex *lock)
{
WARN_ON(release == NULL);
- if (unlikely(!atomic_add_unless(&kref->refcount, -1, 1))) {
+ if (unlikely(!refcount_release_if_not_last((uint32_t *)&kref->refcount))) {
mutex_lock(lock);
- if (unlikely(!atomic_dec_and_test(&kref->refcount))) {
+ if (unlikely(!refcount_release((uint32_t *)&kref->refcount))) {
mutex_unlock(lock);
return 0;
}
diff --git a/sys/compat/linuxkpi/common/include/linux/kthread.h b/sys/compat/linuxkpi/common/include/linux/kthread.h
index 49309cd47a40..1fde734fd767 100644
--- a/sys/compat/linuxkpi/common/include/linux/kthread.h
+++ b/sys/compat/linuxkpi/common/include/linux/kthread.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_KTHREAD_H_
#define _LINUXKPI_LINUX_KTHREAD_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/ktime.h b/sys/compat/linuxkpi/common/include/linux/ktime.h
index e0722aa2589b..53c2abd64fc6 100644
--- a/sys/compat/linuxkpi/common/include/linux/ktime.h
+++ b/sys/compat/linuxkpi/common/include/linux/ktime.h
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_KTIME_H
@@ -71,6 +69,12 @@ ktime_to_ms(ktime_t kt)
return (ktime_divns(kt, NSEC_PER_MSEC));
}
+static inline ktime_t
+ms_to_ktime(uint64_t ms)
+{
+ return (ms * NSEC_PER_MSEC);
+}
+
static inline struct timeval
ktime_to_timeval(ktime_t kt)
{
@@ -190,6 +194,7 @@ timespec64_to_ns(struct timespec64 *ts)
#define ktime_get_ts(ts) getnanouptime(ts)
#define ktime_get_ts64(ts) getnanouptime(ts)
#define ktime_get_raw_ts64(ts) getnanouptime(ts)
+#define ktime_get_real_ts64(ts) getnanotime(ts)
#define getrawmonotonic64(ts) getnanouptime(ts)
static inline int64_t
@@ -263,4 +268,13 @@ ktime_get_raw_ns(void)
return (ktime_to_ns(timespec_to_ktime(ts)));
}
+static inline uint64_t
+ktime_get_raw_fast_ns(void)
+{
+ struct timespec ts;
+
+ getnanouptime(&ts);
+ return (ktime_to_ns(timespec_to_ktime(ts)));
+}
+
#endif /* _LINUXKPI_LINUX_KTIME_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/leds.h b/sys/compat/linuxkpi/common/include/linux/leds.h
new file mode 100644
index 000000000000..f7ee7a68dcf5
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/leds.h
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2022 Bjoern A. Zeeb
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_LINUX_LEDS_H
+#define _LINUXKPI_LINUX_LEDS_H
+
+enum led_brightness {
+ __DUMMY,
+};
+
+struct led_classdev {
+ const char *name;
+ const char *default_trigger;
+ int (*blink_set)(struct led_classdev *, unsigned long *, unsigned long *);
+ void (*brightness_set)(struct led_classdev *, enum led_brightness);
+};
+
+#endif /* _LINUXKPI_LINUX_LEDS_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/limits.h b/sys/compat/linuxkpi/common/include/linux/limits.h
new file mode 100644
index 000000000000..716366033bb3
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/limits.h
@@ -0,0 +1,47 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Serenity Cyber Security, LLC.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_LINUX_LIMITS_H
+#define _LINUXKPI_LINUX_LIMITS_H
+
+#include <sys/types.h>
+#include <sys/stdint.h>
+
+#define U8_MAX UINT8_MAX
+#define S8_MAX INT8_MAX
+#define S8_MIN INT8_MIN
+#define U16_MAX UINT16_MAX
+#define S16_MAX INT16_MAX
+#define S16_MIN INT16_MIN
+#define U32_MAX UINT32_MAX
+#define S32_MAX INT32_MAX
+#define S32_MIN INT32_MIN
+#define U64_MAX UINT64_MAX
+#define S64_MAX INT64_MAX
+#define S64_MIN INT64_MIN
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/list.h b/sys/compat/linuxkpi/common/include/linux/list.h
index 80ac57fecf6d..eecb517d780e 100644
--- a/sys/compat/linuxkpi/common/include/linux/list.h
+++ b/sys/compat/linuxkpi/common/include/linux/list.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_LIST_H_
#define _LINUXKPI_LINUX_LIST_H_
@@ -86,14 +84,6 @@
#define LINUX_LIST_HEAD(name) \
struct list_head name = LINUX_LIST_HEAD_INIT(name)
-#ifndef LIST_HEAD_DEF
-#define LIST_HEAD_DEF
-struct list_head {
- struct list_head *next;
- struct list_head *prev;
-};
-#endif
-
static inline void
INIT_LIST_HEAD(struct list_head *list)
{
@@ -154,7 +144,7 @@ list_replace_init(struct list_head *old, struct list_head *new)
}
static inline void
-linux_list_add(struct list_head *new, struct list_head *prev,
+__list_add(struct list_head *new, struct list_head *prev,
struct list_head *next)
{
@@ -235,6 +225,11 @@ list_del_init(struct list_head *entry)
#define list_for_each_prev(p, h) for (p = (h)->prev; p != (h); p = (p)->prev)
+#define list_for_each_prev_safe(p, n, h) \
+ for (p = (h)->prev, n = (p)->prev; \
+ p != (h); \
+ p = n, n = (p)->prev)
+
#define list_for_each_entry_from_reverse(p, h, field) \
for (; &p->field != (h); \
p = list_prev_entry(p, field))
@@ -243,14 +238,14 @@ static inline void
list_add(struct list_head *new, struct list_head *head)
{
- linux_list_add(new, head, head->next);
+ __list_add(new, head, head->next);
}
static inline void
list_add_tail(struct list_head *new, struct list_head *head)
{
- linux_list_add(new, head->prev, head);
+ __list_add(new, head->prev, head);
}
static inline void
@@ -474,6 +469,20 @@ static inline int list_is_last(const struct list_head *list,
return list->next == head;
}
+static inline size_t
+list_count_nodes(const struct list_head *list)
+{
+ const struct list_head *lh;
+ size_t count;
+
+ count = 0;
+ list_for_each(lh, list) {
+ count++;
+ }
+
+ return (count);
+}
+
#define hlist_entry(ptr, type, field) container_of(ptr, type, field)
#define hlist_for_each(p, head) \
@@ -504,7 +513,12 @@ static inline int list_is_last(const struct list_head *list,
(pos) && ({ n = (pos)->member.next; 1; }); \
pos = hlist_entry_safe(n, typeof(*(pos)), member))
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
+extern void list_sort(void *priv, struct list_head *head, int (*cmp)(void *priv,
+ const struct list_head *a, const struct list_head *b));
+#else
extern void list_sort(void *priv, struct list_head *head, int (*cmp)(void *priv,
struct list_head *a, struct list_head *b));
+#endif
#endif /* _LINUXKPI_LINUX_LIST_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/lockdep.h b/sys/compat/linuxkpi/common/include/linux/lockdep.h
index 2289db7756d4..a379e191aad7 100644
--- a/sys/compat/linuxkpi/common/include/linux/lockdep.h
+++ b/sys/compat/linuxkpi/common/include/linux/lockdep.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_LOCKDEP_H_
@@ -48,8 +46,13 @@ struct pin_cookie {
#define lockdep_set_current_reclaim_state(g) do { } while (0)
#define lockdep_clear_current_reclaim_state() do { } while (0)
#define lockdep_init_map(_map, _name, _key, _x) do { } while(0)
+#define lockdep_register_key(key) do { } while(0)
+#define lockdep_unregister_key(key) do { } while(0)
#ifdef INVARIANTS
+#define lockdep_assert(cond) do { WARN_ON(!cond); } while (0)
+#define lockdep_assert_once(cond) do { WARN_ON_ONCE(!cond); } while (0)
+
#define lockdep_assert_not_held(m) do { \
struct lock_object *__lock = (struct lock_object *)(m); \
LOCK_CLASS(__lock)->lc_assert(__lock, LA_UNLOCKED); \
@@ -65,6 +68,8 @@ struct pin_cookie {
LOCK_CLASS(__lock)->lc_assert(__lock, LA_LOCKED | LA_NOTRECURSED); \
} while (0)
+#define lockdep_assert_none_held_once() do { } while (0)
+
static __inline bool
lockdep_is_held(void *__m)
{
@@ -77,8 +82,12 @@ lockdep_is_held(void *__m)
#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)
+
#define lockdep_assert_not_held(m) do { (void)(m); } while (0)
#define lockdep_assert_held(m) do { (void)(m); } while (0)
+#define lockdep_assert_none_held_once() do { } while (0)
#define lockdep_assert_held_once(m) do { (void)(m); } while (0)
diff --git a/sys/compat/linuxkpi/common/include/linux/log2.h b/sys/compat/linuxkpi/common/include/linux/log2.h
index 4c356136ca98..27e91a8bdbe0 100644
--- a/sys/compat/linuxkpi/common/include/linux/log2.h
+++ b/sys/compat/linuxkpi/common/include/linux/log2.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_LOG2_H_
#define _LINUXKPI_LINUX_LOG2_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/math64.h b/sys/compat/linuxkpi/common/include/linux/math64.h
index f708f1ae81fa..cae5e30b08df 100644
--- a/sys/compat/linuxkpi/common/include/linux/math64.h
+++ b/sys/compat/linuxkpi/common/include/linux/math64.h
@@ -23,14 +23,13 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_MATH64_H
#define _LINUXKPI_LINUX_MATH64_H
#include <sys/stdint.h>
+#include <sys/systm.h>
#define do_div(n, base) ({ \
uint32_t __base = (base); \
@@ -109,6 +108,54 @@ mul_u64_u32_div(uint64_t x, uint32_t y, uint32_t div)
}
static inline uint64_t
+mul_u64_u64_div_u64(uint64_t x, uint64_t y, uint64_t z)
+{
+ uint64_t res, rem;
+ uint64_t x1, y1, y1z;
+
+ res = rem = 0;
+ x1 = x;
+ y1z = y / z;
+ y1 = y - y1z * z;
+
+ /*
+ * INVARIANT: x * y = res * z + rem + (y1 + y1z * z) * x1
+ * INVARIANT: y1 < z
+ * INVARIANT: rem < z
+ */
+ while (x1 > 0) {
+ /* Handle low bit. */
+ if (x1 & 1) {
+ x1 &= ~1;
+ res += y1z;
+ rem += y1;
+ if ((rem < y1) || (rem >= z)) {
+ res += 1;
+ rem -= z;
+ }
+ }
+
+ /* Shift x1 right and (y1 + y1z * z) left */
+ x1 >>= 1;
+ if ((y1 * 2 < y1) || (y1 * 2 >= z)) {
+ y1z = y1z * 2 + 1;
+ y1 = y1 * 2 - z;
+ } else {
+ y1z *= 2;
+ y1 *= 2;
+ }
+ }
+
+ KASSERT(res * z + rem == x * y, ("%s: res %ju * z %ju + rem %ju != "
+ "x %ju * y %ju", __func__, (uintmax_t)res, (uintmax_t)z,
+ (uintmax_t)rem, (uintmax_t)x, (uintmax_t)y));
+ KASSERT(rem < z, ("%s: rem %ju >= z %ju\n", __func__,
+ (uintmax_t)rem, (uintmax_t)z));
+
+ return (res);
+}
+
+static inline uint64_t
mul_u64_u32_shr(uint64_t x, uint32_t y, unsigned int shift)
{
uint32_t hi, lo;
diff --git a/sys/compat/linuxkpi/common/include/linux/mhi.h b/sys/compat/linuxkpi/common/include/linux/mhi.h
new file mode 100644
index 000000000000..2e0b74f29def
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/mhi.h
@@ -0,0 +1,220 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022-2023 Bjoern A. Zeeb
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_LINUX_MHI_H
+#define _LINUXKPI_LINUX_MHI_H
+
+#include <linux/types.h>
+
+/* Modem Host Interface (MHI) */
+
+/* XXX FIXME */
+#define MHI_DB_BRST_DISABLE 0
+#define MHI_ER_CTRL 0
+
+enum mhi_callback {
+ MHI_CB_SYS_ERROR,
+ MHI_CB_BW_REQ,
+ MHI_CB_EE_MISSION_MODE,
+ MHI_CB_EE_RDDM,
+ MHI_CB_FATAL_ERROR,
+ MHI_CB_IDLE,
+ MHI_CB_LPM_ENTER,
+ MHI_CB_LPM_EXIT,
+ MHI_CB_PENDING_DATA,
+};
+
+struct mhi_channel_config {
+ const char *name;
+ int auto_queue, dir, doorbell, doorbell_mode_switch, ee_mask, event_ring, lpm_notify, num, num_elements, offload_channel, pollcfg;
+};
+
+struct mhi_event_config {
+ int client_managed, data_type, hardware_event, irq, irq_moderation_ms, mode, num_elements, offload_channel, priority;
+};
+
+struct mhi_device {
+};
+
+struct mhi_controller_config {
+ const struct mhi_channel_config *ch_cfg;
+ struct mhi_event_config *event_cfg;
+
+ int buf_len, max_channels, num_channels, num_events, use_bounce_buf;
+
+ uint32_t timeout_ms;
+};
+
+struct mhi_controller {
+ struct device *cntrl_dev;
+ struct mhi_device *mhi_dev;
+ void *regs;
+ int *irq;
+ const char *fw_image;
+
+ bool fbc_download;
+ size_t rddm_size;
+ size_t sbl_size;
+ size_t seg_len;
+ size_t reg_len;
+ int nr_irqs;
+ unsigned long irq_flags;
+ uint32_t timeout_ms;
+
+ dma_addr_t iova_start;
+ dma_addr_t iova_stop;
+
+ int (*runtime_get)(struct mhi_controller *);
+ void (*runtime_put)(struct mhi_controller *);
+ void (*status_cb)(struct mhi_controller *, enum mhi_callback);
+ int (*read_reg)(struct mhi_controller *, void __iomem *, uint32_t *);
+ void (*write_reg)(struct mhi_controller *, void __iomem *, uint32_t);
+};
+
+/* -------------------------------------------------------------------------- */
+
+struct mhi_controller *linuxkpi_mhi_alloc_controller(void);
+void linuxkpi_mhi_free_controller(struct mhi_controller *);
+int linuxkpi_mhi_register_controller(struct mhi_controller *,
+ const struct mhi_controller_config *);
+void linuxkpi_mhi_unregister_controller(struct mhi_controller *);
+
+/* -------------------------------------------------------------------------- */
+
+static inline struct mhi_controller *
+mhi_alloc_controller(void)
+{
+
+ /* Keep allocations internal to our implementation. */
+ return (linuxkpi_mhi_alloc_controller());
+}
+
+static inline void
+mhi_free_controller(struct mhi_controller *mhi_ctrl)
+{
+
+ linuxkpi_mhi_free_controller(mhi_ctrl);
+}
+
+static inline int
+mhi_register_controller(struct mhi_controller *mhi_ctrl,
+ const struct mhi_controller_config *cfg)
+{
+
+ return (linuxkpi_mhi_register_controller(mhi_ctrl, cfg));
+}
+
+static inline void
+mhi_unregister_controller(struct mhi_controller *mhi_ctrl)
+{
+
+ linuxkpi_mhi_unregister_controller(mhi_ctrl);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static __inline int
+mhi_device_get_sync(struct mhi_device *mhi_dev)
+{
+ /* XXX TODO */
+ return (-1);
+}
+
+static __inline void
+mhi_device_put(struct mhi_device *mhi_dev)
+{
+ /* XXX TODO */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static __inline int
+mhi_prepare_for_power_up(struct mhi_controller *mhi_ctrl)
+{
+ /* XXX TODO */
+ return (0);
+}
+
+static __inline int
+mhi_sync_power_up(struct mhi_controller *mhi_ctrl)
+{
+ /* XXX TODO */
+ return (0);
+}
+
+static __inline int
+mhi_async_power_up(struct mhi_controller *mhi_ctrl)
+{
+ /* XXX TODO */
+ return (0);
+}
+
+static __inline void
+mhi_power_down(struct mhi_controller *mhi_ctrl, bool x)
+{
+ /* XXX TODO */
+}
+
+static __inline void
+mhi_unprepare_after_power_down(struct mhi_controller *mhi_ctrl)
+{
+ /* XXX TODO */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static __inline int
+mhi_pm_suspend(struct mhi_controller *mhi_ctrl)
+{
+ /* XXX TODO */
+ return (0);
+}
+
+static __inline int
+mhi_pm_resume(struct mhi_controller *mhi_ctrl)
+{
+ /* XXX TODO */
+ return (0);
+}
+
+static __inline int
+mhi_pm_resume_force(struct mhi_controller *mhi_ctrl)
+{
+ /* XXX TODO */
+ return (0);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static __inline int
+mhi_force_rddm_mode(struct mhi_controller *mhi_ctrl)
+{
+ /* XXX TODO */
+ return (0);
+}
+
+#endif /* _LINUXKPI_LINUX_MHI_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/miscdevice.h b/sys/compat/linuxkpi/common/include/linux/miscdevice.h
index 1aa37454ffed..c66006a6b78e 100644
--- a/sys/compat/linuxkpi/common/include/linux/miscdevice.h
+++ b/sys/compat/linuxkpi/common/include/linux/miscdevice.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_MISCDEVICE_H_
#define _LINUXKPI_LINUX_MISCDEVICE_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/mm.h b/sys/compat/linuxkpi/common/include/linux/mm.h
index a266b5913625..109bfffe7d6a 100644
--- a/sys/compat/linuxkpi/common/include/linux/mm.h
+++ b/sys/compat/linuxkpi/common/include/linux/mm.h
@@ -27,8 +27,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_MM_H_
#define _LINUXKPI_LINUX_MM_H_
@@ -40,6 +38,9 @@
#include <linux/pfn.h>
#include <linux/list.h>
#include <linux/mmap_lock.h>
+#include <linux/overflow.h>
+#include <linux/shrinker.h>
+#include <linux/page.h>
#include <asm/pgtable.h>
@@ -55,6 +56,8 @@ CTASSERT((VM_PROT_ALL & -(1 << 8)) == 0);
#define VM_WRITE VM_PROT_WRITE
#define VM_EXEC VM_PROT_EXECUTE
+#define VM_ACCESS_FLAGS (VM_READ | VM_WRITE | VM_EXEC)
+
#define VM_PFNINTERNAL (1 << 8) /* FreeBSD private flag to vm_insert_pfn() */
#define VM_MIXEDMAP (1 << 9)
#define VM_NORESERVE (1 << 10)
@@ -143,11 +146,20 @@ struct vm_operations_struct {
};
struct sysinfo {
- uint64_t totalram;
- uint64_t totalhigh;
- uint32_t mem_unit;
+ uint64_t totalram; /* Total usable main memory size */
+ uint64_t freeram; /* Available memory size */
+ uint64_t totalhigh; /* Total high memory size */
+ uint64_t freehigh; /* Available high memory size */
+ uint32_t mem_unit; /* Memory unit size in bytes */
};
+static inline struct page *
+virt_to_head_page(const void *p)
+{
+
+ return (virt_to_page(p));
+}
+
/*
* Compute log2 of the power of two rounded up count of pages
* needed for size bytes.
@@ -217,11 +229,15 @@ apply_to_page_range(struct mm_struct *mm, unsigned long address,
int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address,
unsigned long size);
+int lkpi_remap_pfn_range(struct vm_area_struct *vma,
+ unsigned long start_addr, unsigned long start_pfn, unsigned long size,
+ pgprot_t prot);
+
static inline int
remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn, unsigned long size, pgprot_t prot)
{
- return (-ENOTSUP);
+ return (lkpi_remap_pfn_range(vma, addr, pfn, size, prot));
}
static inline unsigned long
@@ -233,44 +249,73 @@ vma_pages(struct vm_area_struct *vma)
#define offset_in_page(off) ((unsigned long)(off) & (PAGE_SIZE - 1))
static inline void
-set_page_dirty(struct vm_page *page)
+set_page_dirty(struct page *page)
{
vm_page_dirty(page);
}
static inline void
-mark_page_accessed(struct vm_page *page)
+mark_page_accessed(struct page *page)
{
vm_page_reference(page);
}
static inline void
-get_page(struct vm_page *page)
+get_page(struct page *page)
{
vm_page_wire(page);
}
extern long
get_user_pages(unsigned long start, unsigned long nr_pages,
- int gup_flags, struct page **,
+ unsigned int gup_flags, struct page **,
struct vm_area_struct **);
+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);
+}
+
extern int
__get_user_pages_fast(unsigned long start, int nr_pages, int write,
struct page **);
+static inline int
+pin_user_pages_fast(unsigned long start, int nr_pages,
+ unsigned int gup_flags, struct page **pages)
+{
+ return __get_user_pages_fast(
+ start, nr_pages, !!(gup_flags & FOLL_WRITE), pages);
+}
+
extern long
get_user_pages_remote(struct task_struct *, struct mm_struct *,
unsigned long start, unsigned long nr_pages,
- int gup_flags, struct page **,
+ unsigned int gup_flags, struct page **,
struct vm_area_struct **);
+static inline long
+pin_user_pages_remote(struct task_struct *task, struct mm_struct *mm,
+ unsigned long start, unsigned long nr_pages,
+ unsigned int gup_flags, struct page **pages,
+ struct vm_area_struct **vmas)
+{
+ return get_user_pages_remote(
+ task, mm, start, nr_pages, gup_flags, pages, vmas);
+}
+
static inline void
-put_page(struct vm_page *page)
+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)
+
#define copy_highpage(to, from) pmap_copy_page(from, to)
static inline pgprot_t
@@ -279,7 +324,19 @@ vm_get_page_prot(unsigned long vm_flags)
return (vm_flags & VM_PROT_ALL);
}
-static inline vm_page_t
+static inline void
+vm_flags_set(struct vm_area_struct *vma, unsigned long flags)
+{
+ vma->vm_flags |= flags;
+}
+
+static inline void
+vm_flags_clear(struct vm_area_struct *vma, unsigned long flags)
+{
+ vma->vm_flags &= ~flags;
+}
+
+static inline struct page *
vmalloc_to_page(const void *addr)
{
vm_paddr_t paddr;
@@ -304,10 +361,31 @@ unlock_page(struct page *page)
extern int is_vmalloc_addr(const void *addr);
void si_meminfo(struct sysinfo *si);
+static inline unsigned long
+totalram_pages(void)
+{
+ return ((unsigned long)physmem);
+}
+
#define unmap_mapping_range(...) lkpi_unmap_mapping_range(__VA_ARGS__)
void lkpi_unmap_mapping_range(void *obj, loff_t const holebegin __unused,
loff_t const holelen, int even_cows __unused);
#define PAGE_ALIGNED(p) __is_aligned(p, PAGE_SIZE)
+void vma_set_file(struct vm_area_struct *vma, struct linux_file *file);
+
+static inline void
+might_alloc(gfp_t gfp_mask __unused)
+{
+}
+
+#define is_cow_mapping(flags) (false)
+
+static inline bool
+want_init_on_free(void)
+{
+ return (false);
+}
+
#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 2a7b33d15054..c08e2511725b 100644
--- a/sys/compat/linuxkpi/common/include/linux/mm_types.h
+++ b/sys/compat/linuxkpi/common/include/linux/mm_types.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_MM_TYPES_H_
@@ -31,6 +29,7 @@
#include <linux/types.h>
#include <linux/page.h>
+#include <linux/rbtree.h>
#include <linux/rwsem.h>
#include <asm/atomic.h>
diff --git a/sys/compat/linuxkpi/common/include/linux/mman.h b/sys/compat/linuxkpi/common/include/linux/mman.h
new file mode 100644
index 000000000000..eff80759b4cd
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/mman.h
@@ -0,0 +1,38 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUX_MMAN_H
+#define _LINUX_MMAN_H
+
+/*
+ * In Linux, <linux/mman.h> includes <linux/percpu_counter.h>, which includes
+ * <linux/smp.h>.
+ */
+#include <linux/smp.h>
+
+#endif /* _LINUX_MMAN_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/mmu_context.h b/sys/compat/linuxkpi/common/include/linux/mmu_context.h
index afcc9cf07249..4c1bc61b3edb 100644
--- a/sys/compat/linuxkpi/common/include/linux/mmu_context.h
+++ b/sys/compat/linuxkpi/common/include/linux/mmu_context.h
@@ -21,8 +21,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_MMU_CONTEXT_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/mmu_notifier.h b/sys/compat/linuxkpi/common/include/linux/mmu_notifier.h
index 395f41c36a65..2492a6a3bd4f 100644
--- a/sys/compat/linuxkpi/common/include/linux/mmu_notifier.h
+++ b/sys/compat/linuxkpi/common/include/linux/mmu_notifier.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_MMU_NOTIFIER_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/mmzone.h b/sys/compat/linuxkpi/common/include/linux/mmzone.h
new file mode 100644
index 000000000000..49cc218c6fce
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/mmzone.h
@@ -0,0 +1,11 @@
+/* Public domain. */
+
+#ifndef _LINUX_MMZONE_H
+#define _LINUX_MMZONE_H
+
+#include <linux/mm_types.h>
+#include <linux/page-flags.h>
+
+#define MAX_ORDER 11
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/mod_devicetable.h b/sys/compat/linuxkpi/common/include/linux/mod_devicetable.h
index 441faab6df81..87bd6ec24bce 100644
--- a/sys/compat/linuxkpi/common/include/linux/mod_devicetable.h
+++ b/sys/compat/linuxkpi/common/include/linux/mod_devicetable.h
@@ -24,23 +24,27 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef __LINUXKPI_LINUX_MOD_DEVICETABLE_H__
#define __LINUXKPI_LINUX_MOD_DEVICETABLE_H__
+#include <linux/types.h>
+
enum dmi_field {
DMI_NONE,
DMI_BIOS_VENDOR,
DMI_BIOS_VERSION,
DMI_BIOS_DATE,
+ DMI_BIOS_RELEASE,
+ DMI_EC_FIRMWARE_RELEASE,
DMI_SYS_VENDOR,
DMI_PRODUCT_NAME,
DMI_PRODUCT_VERSION,
DMI_PRODUCT_SERIAL,
DMI_PRODUCT_UUID,
+ DMI_PRODUCT_SKU,
+ DMI_PRODUCT_FAMILY,
DMI_BOARD_VENDOR,
DMI_BOARD_NAME,
DMI_BOARD_VERSION,
@@ -52,6 +56,7 @@ enum dmi_field {
DMI_CHASSIS_SERIAL,
DMI_CHASSIS_ASSET_TAG,
DMI_STRING_MAX,
+ DMI_OEM_STRING,
};
struct dmi_strmatch {
@@ -70,4 +75,9 @@ struct dmi_system_id {
#define DMI_MATCH(a, b) { .slot = a, .substr = b }
#define DMI_EXACT_MATCH(a, b) { .slot = a, .substr = b, .exact_match = 1 }
+#define I2C_NAME_SIZE 20
+#define I2C_MODULE_PREFIX "i2c:"
+
+#define ACPI_ID_LEN 16
+
#endif /* __LINUXKPI_LINUX_MOD_DEVICETABLE_H__ */
diff --git a/sys/compat/linuxkpi/common/include/linux/module.h b/sys/compat/linuxkpi/common/include/linux/module.h
index ac7dfc07e468..9d98ef7cf3db 100644
--- a/sys/compat/linuxkpi/common/include/linux/module.h
+++ b/sys/compat/linuxkpi/common/include/linux/module.h
@@ -25,13 +25,10 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_MODULE_H_
#define _LINUXKPI_LINUX_MODULE_H_
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/module.h>
diff --git a/sys/compat/linuxkpi/common/include/linux/moduleparam.h b/sys/compat/linuxkpi/common/include/linux/moduleparam.h
index d9485de88f56..b61bbce495ea 100644
--- a/sys/compat/linuxkpi/common/include/linux/moduleparam.h
+++ b/sys/compat/linuxkpi/common/include/linux/moduleparam.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_MODULEPARAM_H_
#define _LINUXKPI_LINUX_MODULEPARAM_H_
@@ -90,6 +88,15 @@
LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
LINUXKPI_PARAM_DESC(name)))
+#define LINUXKPI_PARAM_bint(name, var, perm) \
+ LINUXKPI_PARAM_int(name, var, perm)
+
+#define LINUXKPI_PARAM_hexint(name, var, perm) \
+ extern const char LINUXKPI_PARAM_DESC(name)[]; \
+ LINUXKPI_PARAM_PASS(SYSCTL_UINT(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
+ LINUXKPI_PARAM_DESC(name)))
+
#define LINUXKPI_PARAM_long(name, var, perm) \
extern const char LINUXKPI_PARAM_DESC(name)[]; \
LINUXKPI_PARAM_PASS(SYSCTL_LONG(LINUXKPI_PARAM_PARENT, OID_AUTO, \
diff --git a/sys/compat/linuxkpi/common/include/linux/mutex.h b/sys/compat/linuxkpi/common/include/linux/mutex.h
index 7af95e9d2dc5..1d85ba20baca 100644
--- a/sys/compat/linuxkpi/common/include/linux/mutex.h
+++ b/sys/compat/linuxkpi/common/include/linux/mutex.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_MUTEX_H_
#define _LINUXKPI_LINUX_MUTEX_H_
@@ -36,6 +34,8 @@
#include <sys/lock.h>
#include <sys/sx.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
#include <linux/spinlock.h>
#include <asm/atomic.h>
diff --git a/sys/compat/linuxkpi/common/include/linux/net.h b/sys/compat/linuxkpi/common/include/linux/net.h
index 5438fccb8512..a5172f3f31eb 100644
--- a/sys/compat/linuxkpi/common/include/linux/net.h
+++ b/sys/compat/linuxkpi/common/include/linux/net.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_NET_H_
#define _LINUXKPI_LINUX_NET_H_
@@ -47,26 +45,27 @@ sock_create_kern(int family, int type, int proto, struct socket **res)
}
static inline int
-sock_getname(struct socket *so, struct sockaddr *addr, int *sockaddr_len,
+sock_getname(struct socket *so, struct sockaddr *sa, int *sockaddr_len,
int peer)
{
- struct sockaddr *nam;
int error;
- nam = NULL;
+ /*
+ * XXXGL: we can't use sopeeraddr()/sosockaddr() here since with
+ * INVARIANTS they would check if supplied sockaddr has enough
+ * length. Such notion doesn't even exist in Linux KPI.
+ */
if (peer) {
- if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0)
+ if ((so->so_state & SS_ISCONNECTED) == 0)
return (-ENOTCONN);
- error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, &nam);
+ error = so->so_proto->pr_peeraddr(so, sa);
} else
- error = (*so->so_proto->pr_usrreqs->pru_sockaddr)(so, &nam);
+ error = so->so_proto->pr_sockaddr(so, sa);
if (error)
return (-error);
- *addr = *nam;
- *sockaddr_len = addr->sa_len;
+ *sockaddr_len = sa->sa_len;
- free(nam, M_SONAME);
return (0);
}
diff --git a/sys/compat/linuxkpi/common/include/linux/net_dim.h b/sys/compat/linuxkpi/common/include/linux/net_dim.h
index 08a8bb758c32..4fe3e39210e7 100644
--- a/sys/compat/linuxkpi/common/include/linux/net_dim.h
+++ b/sys/compat/linuxkpi/common/include/linux/net_dim.h
@@ -31,8 +31,6 @@
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
- *
- * $FreeBSD$
*/
/* This file implements Dynamic Interrupt Moderation, DIM */
diff --git a/sys/compat/linuxkpi/common/include/linux/netdev_features.h b/sys/compat/linuxkpi/common/include/linux/netdev_features.h
index e21d1965bec6..06e88d107708 100644
--- a/sys/compat/linuxkpi/common/include/linux/netdev_features.h
+++ b/sys/compat/linuxkpi/common/include/linux/netdev_features.h
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_NETDEV_FEATURES_H_
#define _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 f8c03f92b025..3d2b309909b4 100644
--- a/sys/compat/linuxkpi/common/include/linux/netdevice.h
+++ b/sys/compat/linuxkpi/common/include/linux/netdevice.h
@@ -5,7 +5,7 @@
* Copyright (c) 2013-2019 Mellanox Technologies, Ltd.
* All rights reserved.
* Copyright (c) 2020-2021 The FreeBSD Foundation
- * Copyright (c) 2020-2021 Bjoern A. Zeeb
+ * Copyright (c) 2020-2022 Bjoern A. Zeeb
*
* Portions of this software were developed by Björn Zeeb
* under sponsorship from the FreeBSD Foundation.
@@ -30,8 +30,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_NETDEVICE_H
#define _LINUXKPI_LINUX_NETDEVICE_H
@@ -53,6 +51,7 @@
#include <net/if_var.h>
#include <net/if_dl.h>
+#include <linux/kernel.h>
#include <linux/bitops.h>
#include <linux/list.h>
#include <linux/device.h>
@@ -105,9 +104,6 @@ struct net_device_ops {
};
struct net_device {
- /* BSD specific for compat. */
- struct ifnet bsdifp;
-
/* net_device fields seen publicly. */
/* XXX can we later make some aliases to ifnet? */
char name[IFNAMSIZ];
@@ -134,6 +130,7 @@ struct net_device {
/* Not properly typed as-of now. */
int flags, type;
int name_assign_type, needed_headroom;
+ int threaded;
void (*priv_destructor)(struct net_device *);
@@ -182,6 +179,30 @@ int unregister_inetaddr_notifier(struct notifier_block *);
#define NAPI_POLL_WEIGHT 64 /* budget */
+/*
+ * There are drivers directly testing napi state bits, so we need to publicly
+ * expose them. If you ask me, those accesses should be hid behind an
+ * inline function and the bit flags not be directly exposed.
+ */
+enum napi_state_bits {
+ /*
+ * Official Linux flags encountered.
+ */
+ NAPI_STATE_SCHED = 1,
+
+ /*
+ * Our internal versions (for now).
+ */
+ /* Do not schedule new things while we are waiting to clear things. */
+ LKPI_NAPI_FLAG_DISABLE_PENDING = 0,
+ /* To synchronise that only one poll is ever running. */
+ LKPI_NAPI_FLAG_IS_SCHEDULED = 1,
+ /* If trying to schedule while poll is running. Need to re-schedule. */
+ LKPI_NAPI_FLAG_LOST_RACE_TRY_AGAIN = 2,
+ /* When shutting down forcefully prevent anything from running task/poll. */
+ LKPI_NAPI_FLAG_SHUTDOWN = 3,
+};
+
struct napi_struct {
TAILQ_ENTRY(napi_struct) entry;
@@ -191,11 +212,12 @@ struct napi_struct {
int budget;
int rx_count;
+
/*
* These flags mostly need to be checked/changed atomically
* (multiple together in some cases).
*/
- volatile unsigned long _flags;
+ volatile unsigned long state;
/* FreeBSD internal. */
/* Use task for now, so we can easily switch between direct and task. */
@@ -204,11 +226,11 @@ struct napi_struct {
void linuxkpi_init_dummy_netdev(struct net_device *);
void linuxkpi_netif_napi_add(struct net_device *, struct napi_struct *,
- int(*napi_poll)(struct napi_struct *, int), int);
+ int(*napi_poll)(struct napi_struct *, int));
void linuxkpi_netif_napi_del(struct napi_struct *);
bool linuxkpi_napi_schedule_prep(struct napi_struct *);
void linuxkpi___napi_schedule(struct napi_struct *);
-void linuxkpi_napi_schedule(struct napi_struct *);
+bool linuxkpi_napi_schedule(struct napi_struct *);
void linuxkpi_napi_reschedule(struct napi_struct *);
bool linuxkpi_napi_complete_done(struct napi_struct *, int);
bool linuxkpi_napi_complete(struct napi_struct *);
@@ -218,8 +240,8 @@ void linuxkpi_napi_synchronize(struct napi_struct *);
#define init_dummy_netdev(_n) \
linuxkpi_init_dummy_netdev(_n)
-#define netif_napi_add(_nd, _ns, _p, _b) \
- linuxkpi_netif_napi_add(_nd, _ns, _p, _b)
+#define netif_napi_add(_nd, _ns, _p) \
+ linuxkpi_netif_napi_add(_nd, _ns, _p)
#define netif_napi_del(_n) \
linuxkpi_netif_napi_del(_n)
#define napi_schedule_prep(_n) \
@@ -241,6 +263,22 @@ void linuxkpi_napi_synchronize(struct napi_struct *);
#define napi_synchronize(_n) \
linuxkpi_napi_synchronize(_n)
+
+static inline void
+netif_napi_add_tx(struct net_device *dev, struct napi_struct *napi,
+ int(*napi_poll)(struct napi_struct *, int))
+{
+
+ netif_napi_add(dev, napi, napi_poll);
+}
+
+static inline bool
+napi_is_scheduled(struct napi_struct *napi)
+{
+
+ return (test_bit(LKPI_NAPI_FLAG_IS_SCHEDULED, &napi->state));
+}
+
/* -------------------------------------------------------------------------- */
static inline void
@@ -283,6 +321,134 @@ synchronize_net(void)
synchronize_rcu();
}
+static __inline void
+netif_receive_skb_list(struct list_head *head)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static __inline int
+napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (-1);
+}
+
+static __inline void
+ether_setup(struct net_device *ndev)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static __inline void
+dev_net_set(struct net_device *ndev, void *p)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static __inline int
+dev_set_threaded(struct net_device *ndev, bool threaded)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (-ENODEV);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static __inline bool
+netif_carrier_ok(struct net_device *ndev)
+{
+ pr_debug("%s: TODO\n", __func__);
+ return (false);
+}
+
+static __inline void
+netif_carrier_off(struct net_device *ndev)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static __inline void
+netif_carrier_on(struct net_device *ndev)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static __inline bool
+netif_queue_stopped(struct net_device *ndev)
+{
+ pr_debug("%s: TODO\n", __func__);
+ return (false);
+}
+
+static __inline void
+netif_stop_queue(struct net_device *ndev)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static __inline void
+netif_wake_queue(struct net_device *ndev)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static __inline int
+register_netdevice(struct net_device *ndev)
+{
+
+ /* assert rtnl_locked? */
+ pr_debug("%s: TODO\n", __func__);
+ return (0);
+}
+
+static __inline int
+register_netdev(struct net_device *ndev)
+{
+ int error;
+
+ /* lock */
+ error = register_netdevice(ndev);
+ /* unlock */
+ pr_debug("%s: TODO\n", __func__);
+ return (error);
+}
+
+static __inline void
+unregister_netdev(struct net_device *ndev)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static __inline void
+unregister_netdevice(struct net_device *ndev)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static __inline void
+netif_rx(struct sk_buff *skb)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static __inline void
+netif_rx_ni(struct sk_buff *skb)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
/* -------------------------------------------------------------------------- */
struct net_device *linuxkpi_alloc_netdev(size_t, const char *, uint32_t,
@@ -306,5 +472,6 @@ netdev_priv(const struct net_device *ndev)
#define rtnl_lock() do { } while(0)
#define rtnl_unlock() do { } while(0)
+#define rcu_dereference_rtnl(x) READ_ONCE(x)
#endif /* _LINUXKPI_LINUX_NETDEVICE_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/nl80211.h b/sys/compat/linuxkpi/common/include/linux/nl80211.h
index a85abfc10453..5b43ff675e19 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-2021 The FreeBSD Foundation
+ * Copyright (c) 2020-2023 The FreeBSD Foundation
*
* This software was developed by Björn Zeeb under sponsorship from
* the FreeBSD Foundation.
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_NL80211_H
@@ -80,6 +78,8 @@ enum nl80211_reg_rule_flags {
NL80211_RRF_NO_160MHZ = BIT(8),
NL80211_RRF_NO_HE = BIT(9),
NL80211_RRF_NO_OFDM = BIT(10),
+ NL80211_RRF_NO_320MHZ = BIT(11),
+ NL80211_RRF_NO_EHT = BIT(12),
};
#define NL80211_RRF_NO_HT40 (NL80211_RRF_NO_HT40MINUS|NL80211_RRF_NO_HT40PLUS)
@@ -145,6 +145,7 @@ enum nl80211_chan_width {
NL80211_CHAN_WIDTH_160,
NL80211_CHAN_WIDTH_5,
NL80211_CHAN_WIDTH_10,
+ NL80211_CHAN_WIDTH_320,
};
enum nl80211_iftype {
@@ -161,6 +162,7 @@ enum nl80211_iftype {
NL80211_IFTYPE_MESH_POINT,
NL80211_IFTYPE_WDS,
NL80211_IFTYPE_OCB,
+ NL80211_IFTYPE_NAN,
/* Keep this last. */
NUM_NL80211_IFTYPES
@@ -225,6 +227,9 @@ enum nl80211_ext_feature {
NL80211_EXT_FEATURE_FILS_DISCOVERY,
NL80211_EXT_FEATURE_RADAR_BACKGROUND,
NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP,
+ NL80211_EXT_FEATURE_BEACON_PROTECTION,
+ NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT,
+ NL80211_EXT_FEATURE_PUNCT,
/* Keep this last. */
NUM_NL80211_EXT_FEATURES
@@ -248,10 +253,14 @@ enum nl80211_sta_info {
NL80211_STA_INFO_TX_BITRATE,
NL80211_STA_INFO_TX_PACKETS,
NL80211_STA_INFO_TX_BYTES,
+ NL80211_STA_INFO_TX_BYTES64,
+ NL80211_STA_INFO_RX_BYTES64,
NL80211_STA_INFO_TX_FAILED,
NL80211_STA_INFO_TX_RETRIES,
NL80211_STA_INFO_RX_DURATION,
NL80211_STA_INFO_TX_DURATION,
+ NL80211_STA_INFO_ACK_SIGNAL,
+ NL80211_STA_INFO_ACK_SIGNAL_AVG,
};
enum nl80211_ftm_stats {
@@ -321,6 +330,37 @@ enum nl80211_he_gi {
NL80211_RATE_INFO_HE_GI_3_2,
};
+enum nl80211_he_ltf {
+ NL80211_RATE_INFO_HE_1XLTF,
+ NL80211_RATE_INFO_HE_2XLTF,
+ NL80211_RATE_INFO_HE_4XLTF,
+};
+
+enum nl80211_eht_gi {
+ NL80211_RATE_INFO_EHT_GI_0_8,
+ NL80211_RATE_INFO_EHT_GI_1_6,
+ NL80211_RATE_INFO_EHT_GI_3_2,
+};
+
+enum nl80211_eht_ru_alloc {
+ NL80211_RATE_INFO_EHT_RU_ALLOC_26,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_52,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_52P26,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_106,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_106P26,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_242,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_484P242,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_996,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_996P484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_996P484P242,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_2x996,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_2x996P484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_3x996,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_3x996P484,
+ NL80211_RATE_INFO_EHT_RU_ALLOC_4x996,
+};
+
enum nl80211_dfs_regions {
NL80211_DFS_UNSET,
NL80211_DFS_FCC,
@@ -328,11 +368,16 @@ enum nl80211_dfs_regions {
NL80211_DFS_JP,
};
+enum nl80211_dfs_state {
+ NL80211_DFS_USABLE,
+};
+
enum nl80211_sar_type {
NL80211_SAR_TYPE_POWER,
};
#define NL80211_VHT_NSS_MAX 8
+#define NL80211_HE_NSS_MAX 8
enum nl80211_tid_cfg_attr {
NL80211_TID_CONFIG_ATTR_NOACK,
@@ -342,6 +387,7 @@ enum nl80211_tid_cfg_attr {
NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL,
NL80211_TID_CONFIG_ATTR_RETRY_LONG,
NL80211_TID_CONFIG_ATTR_AMPDU_CTRL,
+ NL80211_TID_CONFIG_ATTR_AMSDU_CTRL,
};
enum nl80211_tid_config {
@@ -366,7 +412,13 @@ enum nl80211_probe_resp_offload_support {
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P,
};
+enum nl80211_user_reg_hint_type {
+ NL80211_USER_REG_HINT_USER,
+};
+
#define NL80211_KCK_LEN 16
+#define NL80211_KCK_EXT_LEN 24
#define NL80211_KEK_LEN 16
+#define NL80211_KEK_EXT_LEN 32
#define NL80211_REPLAY_CTR_LEN 8
#endif /* _LINUXKPI_LINUX_NL80211_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/notifier.h b/sys/compat/linuxkpi/common/include/linux/notifier.h
index bd822d73d5e3..9302a1ce4606 100644
--- a/sys/compat/linuxkpi/common/include/linux/notifier.h
+++ b/sys/compat/linuxkpi/common/include/linux/notifier.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_NOTIFIER_H_
#define _LINUXKPI_LINUX_NOTIFIER_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/numa.h b/sys/compat/linuxkpi/common/include/linux/numa.h
index b51a92951f3f..6b227e177a64 100644
--- a/sys/compat/linuxkpi/common/include/linux/numa.h
+++ b/sys/compat/linuxkpi/common/include/linux/numa.h
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_NUMA_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/of.h b/sys/compat/linuxkpi/common/include/linux/of.h
new file mode 100644
index 000000000000..fb4554a8ddbc
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/of.h
@@ -0,0 +1,33 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Serenity Cyber Security, LLC.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_LINUX_OF_H
+#define _LINUXKPI_LINUX_OF_H
+
+#include <linux/kobject.h>
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/overflow.h b/sys/compat/linuxkpi/common/include/linux/overflow.h
index d2e15d8d2383..9ba9b9500f11 100644
--- a/sys/compat/linuxkpi/common/include/linux/overflow.h
+++ b/sys/compat/linuxkpi/common/include/linux/overflow.h
@@ -1,53 +1,349 @@
-/*-
- * Copyright (c) 2020 The FreeBSD Foundation
- *
- * This software was developed by Emmanuel Vadot under sponsorship
- * from the FreeBSD Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#ifndef __LINUXKPI_LINUX_OVERFLOW_H__
-#define __LINUXKPI_LINUX_OVERFLOW_H__
-
-#include <sys/stdint.h>
-#include <sys/types.h>
-
-#define check_add_overflow(a, b, c) \
- __builtin_add_overflow(a, b, c)
-
-#define check_mul_overflow(a, b, c) \
- __builtin_mul_overflow(a, b, c)
-
-static inline size_t
-array_size(size_t x, size_t y)
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+#ifndef _LINUXKPI_LINUX_OVERFLOW_H
+#define _LINUXKPI_LINUX_OVERFLOW_H
+
+#include <linux/compiler.h>
+#include <linux/limits.h>
+#ifdef __linux__
+#include <linux/const.h>
+#endif
+
+/*
+ * We need to compute the minimum and maximum values representable in a given
+ * type. These macros may also be useful elsewhere. It would seem more obvious
+ * to do something like:
+ *
+ * #define type_min(T) (T)(is_signed_type(T) ? (T)1 << (8*sizeof(T)-1) : 0)
+ * #define type_max(T) (T)(is_signed_type(T) ? ((T)1 << (8*sizeof(T)-1)) - 1 : ~(T)0)
+ *
+ * Unfortunately, the middle expressions, strictly speaking, have
+ * undefined behaviour, and at least some versions of gcc warn about
+ * the type_max expression (but not if -fsanitize=undefined is in
+ * effect; in that case, the warning is deferred to runtime...).
+ *
+ * The slightly excessive casting in type_min is to make sure the
+ * macros also produce sensible values for the exotic type _Bool. [The
+ * overflow checkers only almost work for _Bool, but that's
+ * a-feature-not-a-bug, since people shouldn't be doing arithmetic on
+ * _Bools. Besides, the gcc builtins don't allow _Bool* as third
+ * argument.]
+ *
+ * Idea stolen from
+ * https://mail-index.netbsd.org/tech-misc/2007/02/05/0000.html -
+ * credit to Christian Biere.
+ */
+#define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type)))
+#define type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T)))
+#define type_min(T) ((T)((T)-type_max(T)-(T)1))
+
+/*
+ * Avoids triggering -Wtype-limits compilation warning,
+ * while using unsigned data types to check a < 0.
+ */
+#define is_non_negative(a) ((a) > 0 || (a) == 0)
+#define is_negative(a) (!(is_non_negative(a)))
+
+/*
+ * Allows for effectively applying __must_check to a macro so we can have
+ * both the type-agnostic benefits of the macros while also being able to
+ * enforce that the return value is, in fact, checked.
+ */
+static inline bool __must_check __must_check_overflow(bool overflow)
{
- size_t retval;
+ return unlikely(overflow);
+}
+
+/**
+ * check_add_overflow() - Calculate addition with overflow checking
+ * @a: first addend
+ * @b: second addend
+ * @d: pointer to store sum
+ *
+ * Returns 0 on success.
+ *
+ * *@d holds the results of the attempted addition, but is not considered
+ * "safe for use" on a non-zero return value, which indicates that the
+ * sum has overflowed or been truncated.
+ */
+#define check_add_overflow(a, b, d) \
+ __must_check_overflow(__builtin_add_overflow(a, b, d))
+
+/**
+ * check_sub_overflow() - Calculate subtraction with overflow checking
+ * @a: minuend; value to subtract from
+ * @b: subtrahend; value to subtract from @a
+ * @d: pointer to store difference
+ *
+ * Returns 0 on success.
+ *
+ * *@d holds the results of the attempted subtraction, but is not considered
+ * "safe for use" on a non-zero return value, which indicates that the
+ * difference has underflowed or been truncated.
+ */
+#define check_sub_overflow(a, b, d) \
+ __must_check_overflow(__builtin_sub_overflow(a, b, d))
+
+/**
+ * check_mul_overflow() - Calculate multiplication with overflow checking
+ * @a: first factor
+ * @b: second factor
+ * @d: pointer to store product
+ *
+ * Returns 0 on success.
+ *
+ * *@d holds the results of the attempted multiplication, but is not
+ * considered "safe for use" on a non-zero return value, which indicates
+ * that the product has overflowed or been truncated.
+ */
+#define check_mul_overflow(a, b, d) \
+ __must_check_overflow(__builtin_mul_overflow(a, b, d))
+
+/**
+ * check_shl_overflow() - Calculate a left-shifted value and check overflow
+ * @a: Value to be shifted
+ * @s: How many bits left to shift
+ * @d: Pointer to where to store the result
+ *
+ * Computes *@d = (@a << @s)
+ *
+ * Returns true if '*@d' cannot hold the result or when '@a << @s' doesn't
+ * make sense. Example conditions:
+ *
+ * - '@a << @s' causes bits to be lost when stored in *@d.
+ * - '@s' is garbage (e.g. negative) or so large that the result of
+ * '@a << @s' is guaranteed to be 0.
+ * - '@a' is negative.
+ * - '@a << @s' sets the sign bit, if any, in '*@d'.
+ *
+ * '*@d' will hold the results of the attempted shift, but is not
+ * considered "safe for use" if true is returned.
+ */
+#define check_shl_overflow(a, s, d) __must_check_overflow(({ \
+ typeof(a) _a = a; \
+ typeof(s) _s = s; \
+ typeof(d) _d = d; \
+ u64 _a_full = _a; \
+ unsigned int _to_shift = \
+ is_non_negative(_s) && _s < 8 * sizeof(*d) ? _s : 0; \
+ *_d = (_a_full << _to_shift); \
+ (_to_shift != _s || is_negative(*_d) || is_negative(_a) || \
+ (*_d >> _to_shift) != _a); \
+}))
+
+#define __overflows_type_constexpr(x, T) ( \
+ is_unsigned_type(typeof(x)) ? \
+ (x) > type_max(typeof(T)) : \
+ is_unsigned_type(typeof(T)) ? \
+ (x) < 0 || (x) > type_max(typeof(T)) : \
+ (x) < type_min(typeof(T)) || (x) > type_max(typeof(T)))
+
+#define __overflows_type(x, T) ({ \
+ typeof(T) v = 0; \
+ check_add_overflow((x), v, &v); \
+})
+
+/**
+ * overflows_type - helper for checking the overflows between value, variables,
+ * or data type
+ *
+ * @n: source constant value or variable to be checked
+ * @T: destination variable or data type proposed to store @x
+ *
+ * Compares the @x expression for whether or not it can safely fit in
+ * the storage of the type in @T. @x and @T can have different types.
+ * If @x is a constant expression, this will also resolve to a constant
+ * expression.
+ *
+ * Returns: true if overflow can occur, false otherwise.
+ */
+#define overflows_type(n, T) \
+ __builtin_choose_expr(__is_constexpr(n), \
+ __overflows_type_constexpr(n, T), \
+ __overflows_type(n, T))
- if (__builtin_mul_overflow(x, y, &retval))
- retval = SIZE_MAX;
- return (retval);
+/**
+ * castable_to_type - like __same_type(), but also allows for casted literals
+ *
+ * @n: variable or constant value
+ * @T: variable or data type
+ *
+ * Unlike the __same_type() macro, this allows a constant value as the
+ * first argument. If this value would not overflow into an assignment
+ * of the second argument's type, it returns true. Otherwise, this falls
+ * back to __same_type().
+ */
+#define castable_to_type(n, T) \
+ __builtin_choose_expr(__is_constexpr(n), \
+ !__overflows_type_constexpr(n, T), \
+ __same_type(n, T))
+
+/**
+ * size_mul() - Calculate size_t multiplication with saturation at SIZE_MAX
+ * @factor1: first factor
+ * @factor2: second factor
+ *
+ * Returns: calculate @factor1 * @factor2, both promoted to size_t,
+ * with any overflow causing the return value to be SIZE_MAX. The
+ * lvalue must be size_t to avoid implicit type conversion.
+ */
+static inline size_t __must_check size_mul(size_t factor1, size_t factor2)
+{
+ size_t bytes;
+
+ if (check_mul_overflow(factor1, factor2, &bytes))
+ return SIZE_MAX;
+
+ return bytes;
+}
+
+/**
+ * size_add() - Calculate size_t addition with saturation at SIZE_MAX
+ * @addend1: first addend
+ * @addend2: second addend
+ *
+ * Returns: calculate @addend1 + @addend2, both promoted to size_t,
+ * with any overflow causing the return value to be SIZE_MAX. The
+ * lvalue must be size_t to avoid implicit type conversion.
+ */
+static inline size_t __must_check size_add(size_t addend1, size_t addend2)
+{
+ size_t bytes;
+
+ if (check_add_overflow(addend1, addend2, &bytes))
+ return SIZE_MAX;
+
+ return bytes;
+}
+
+/**
+ * size_sub() - Calculate size_t subtraction with saturation at SIZE_MAX
+ * @minuend: value to subtract from
+ * @subtrahend: value to subtract from @minuend
+ *
+ * Returns: calculate @minuend - @subtrahend, both promoted to size_t,
+ * with any overflow causing the return value to be SIZE_MAX. For
+ * composition with the size_add() and size_mul() helpers, neither
+ * argument may be SIZE_MAX (or the result with be forced to SIZE_MAX).
+ * The lvalue must be size_t to avoid implicit type conversion.
+ */
+static inline size_t __must_check size_sub(size_t minuend, size_t subtrahend)
+{
+ size_t bytes;
+
+ if (minuend == SIZE_MAX || subtrahend == SIZE_MAX ||
+ check_sub_overflow(minuend, subtrahend, &bytes))
+ return SIZE_MAX;
+
+ return bytes;
}
-#endif /* __LINUXKPI_LINUX_OVERFLOW_H__ */
+/**
+ * array_size() - Calculate size of 2-dimensional array.
+ * @a: dimension one
+ * @b: dimension two
+ *
+ * Calculates size of 2-dimensional array: @a * @b.
+ *
+ * Returns: number of bytes needed to represent the array or SIZE_MAX on
+ * overflow.
+ */
+#define array_size(a, b) size_mul(a, b)
+
+/**
+ * array3_size() - Calculate size of 3-dimensional array.
+ * @a: dimension one
+ * @b: dimension two
+ * @c: dimension three
+ *
+ * Calculates size of 3-dimensional array: @a * @b * @c.
+ *
+ * Returns: number of bytes needed to represent the array or SIZE_MAX on
+ * overflow.
+ */
+#define array3_size(a, b, c) size_mul(size_mul(a, b), c)
+
+/**
+ * flex_array_size() - Calculate size of a flexible array member
+ * within an enclosing structure.
+ * @p: Pointer to the structure.
+ * @member: Name of the flexible array member.
+ * @count: Number of elements in the array.
+ *
+ * Calculates size of a flexible array of @count number of @member
+ * elements, at the end of structure @p.
+ *
+ * Return: number of bytes needed or SIZE_MAX on overflow.
+ */
+#define flex_array_size(p, member, count) \
+ __builtin_choose_expr(__is_constexpr(count), \
+ (count) * sizeof(*(p)->member) + __must_be_array((p)->member), \
+ size_mul(count, sizeof(*(p)->member) + __must_be_array((p)->member)))
+
+/**
+ * struct_size() - Calculate size of structure with trailing flexible array.
+ * @p: Pointer to the structure.
+ * @member: Name of the array member.
+ * @count: Number of elements in the array.
+ *
+ * Calculates size of memory needed for structure of @p followed by an
+ * array of @count number of @member elements.
+ *
+ * Return: number of bytes needed or SIZE_MAX on overflow.
+ */
+#define struct_size(p, member, count) \
+ __builtin_choose_expr(__is_constexpr(count), \
+ sizeof(*(p)) + flex_array_size(p, member, count), \
+ size_add(sizeof(*(p)), flex_array_size(p, member, count)))
+
+/**
+ * struct_size_t() - Calculate size of structure with trailing flexible array
+ * @type: structure type name.
+ * @member: Name of the array member.
+ * @count: Number of elements in the array.
+ *
+ * Calculates size of memory needed for structure @type followed by an
+ * array of @count number of @member elements. Prefer using struct_size()
+ * when possible instead, to keep calculations associated with a specific
+ * instance variable of type @type.
+ *
+ * Return: number of bytes needed or SIZE_MAX on overflow.
+ */
+#define struct_size_t(type, member, count) \
+ struct_size((type *)NULL, member, count)
+
+/**
+ * _DEFINE_FLEX() - helper macro for DEFINE_FLEX() family.
+ * Enables caller macro to pass (different) initializer.
+ *
+ * @type: structure type name, including "struct" keyword.
+ * @name: Name for a variable to define.
+ * @member: Name of the array member.
+ * @count: Number of elements in the array; must be compile-time const.
+ * @initializer: initializer expression (could be empty for no init).
+ */
+#define _DEFINE_FLEX(type, name, member, count, initializer) \
+ _Static_assert(__builtin_constant_p(count), \
+ "onstack flex array members require compile-time const count"); \
+ union { \
+ u8 bytes[struct_size_t(type, member, count)]; \
+ type obj; \
+ } name##_u initializer; \
+ type *name = (type *)&name##_u
+
+/**
+ * DEFINE_FLEX() - Define an on-stack instance of structure with a trailing
+ * flexible array member.
+ *
+ * @type: structure type name, including "struct" keyword.
+ * @name: Name for a variable to define.
+ * @member: Name of the array member.
+ * @count: Number of elements in the array; must be compile-time const.
+ *
+ * Define a zeroed, on-stack, instance of @type structure with a trailing
+ * flexible array member.
+ * Use __struct_size(@name) to get compile-time size of it afterwards.
+ */
+#define DEFINE_FLEX(type, name, member, count) \
+ _DEFINE_FLEX(type, name, member, count, = {})
+
+#endif /* _LINUXKPI_LINUX_OVERFLOW_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/page-flags.h b/sys/compat/linuxkpi/common/include/linux/page-flags.h
new file mode 100644
index 000000000000..9dd49c8492a5
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/page-flags.h
@@ -0,0 +1,34 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_LINUX_PAGEFLAGS_H_
+#define _LINUXKPI_LINUX_PAGEFLAGS_H_
+
+#define PageHighMem(p) (0)
+
+#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 b582966b49c3..aa5acac4f5fe 100644
--- a/sys/compat/linuxkpi/common/include/linux/page.h
+++ b/sys/compat/linuxkpi/common/include/linux/page.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_PAGE_H_
#define _LINUXKPI_LINUX_PAGE_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/pagemap.h b/sys/compat/linuxkpi/common/include/linux/pagemap.h
index f3c8c04aa13e..7244b61257dc 100644
--- a/sys/compat/linuxkpi/common/include/linux/pagemap.h
+++ b/sys/compat/linuxkpi/common/include/linux/pagemap.h
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_PAGEMAP_H_
@@ -33,6 +31,13 @@
#include <linux/mm.h>
#include <linux/highmem.h>
+#include <linux/vmalloc.h>
+
+#define invalidate_mapping_pages(...) \
+ linux_invalidate_mapping_pages(__VA_ARGS__)
+
+unsigned long linux_invalidate_mapping_pages(vm_object_t obj, pgoff_t start,
+ pgoff_t end);
static inline void
release_pages(struct page **pages, int nr)
diff --git a/sys/compat/linuxkpi/common/include/linux/pagevec.h b/sys/compat/linuxkpi/common/include/linux/pagevec.h
index 4224124c4fe4..9ba8ff8effa0 100644
--- a/sys/compat/linuxkpi/common/include/linux/pagevec.h
+++ b/sys/compat/linuxkpi/common/include/linux/pagevec.h
@@ -13,7 +13,7 @@
struct pagevec {
uint8_t nr;
- struct vm_page *pages[PAGEVEC_SIZE];
+ struct page *pages[PAGEVEC_SIZE];
};
static inline unsigned int
@@ -41,7 +41,7 @@ pagevec_count(struct pagevec *pvec)
}
static inline unsigned int
-pagevec_add(struct pagevec *pvec, struct vm_page *page)
+pagevec_add(struct pagevec *pvec, struct page *page)
{
pvec->pages[pvec->nr++] = page;
return PAGEVEC_SIZE - pvec->nr;
diff --git a/sys/compat/linuxkpi/common/include/linux/pci.h b/sys/compat/linuxkpi/common/include/linux/pci.h
index 0652a250c697..be3b13f07e53 100644
--- a/sys/compat/linuxkpi/common/include/linux/pci.h
+++ b/sys/compat/linuxkpi/common/include/linux/pci.h
@@ -4,7 +4,7 @@
* Copyright (c) 2010 Panasas, Inc.
* Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
* All rights reserved.
- * Copyright (c) 2020-2021 The FreeBSD Foundation
+ * Copyright (c) 2020-2022 The FreeBSD Foundation
*
* Portions of this software were developed by Björn Zeeb
* under sponsorship from the FreeBSD Foundation.
@@ -29,8 +29,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_PCI_H_
#define _LINUXKPI_LINUX_PCI_H_
@@ -44,7 +42,6 @@
#include <sys/module.h>
#include <sys/nv.h>
#include <sys/pciio.h>
-#include <sys/rman.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pci_private.h>
@@ -57,6 +54,7 @@
#include <linux/compiler.h>
#include <linux/errno.h>
#include <asm/atomic.h>
+#include <asm/memtype.h>
#include <linux/device.h>
#include <linux/pci_ids.h>
#include <linux/pm.h>
@@ -96,6 +94,7 @@ MODULE_PNP_INFO("U32:vendor;U32:device;V32:subvendor;V32:subdevice", \
#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
#define PCI_FUNC(devfn) ((devfn) & 0x07)
#define PCI_BUS_NUM(devfn) (((devfn) >> 8) & 0xff)
+#define PCI_DEVID(bus, devfn) ((((uint16_t)(bus)) << 8) | (devfn))
#define PCI_VDEVICE(_vendor, _device) \
.vendor = PCI_VENDOR_ID_##_vendor, .device = (_device), \
@@ -106,9 +105,14 @@ MODULE_PNP_INFO("U32:vendor;U32:device;V32:subvendor;V32:subdevice", \
#define to_pci_dev(n) container_of(n, struct pci_dev, dev)
-#define PCI_VENDOR_ID PCIR_DEVVENDOR
+#define PCI_STD_NUM_BARS 6
+#define PCI_BASE_ADDRESS_0 PCIR_BARS
+#define PCI_BASE_ADDRESS_MEM_TYPE_64 PCIM_BAR_MEM_64
+#define PCI_VENDOR_ID PCIR_VENDOR
+#define PCI_DEVICE_ID PCIR_DEVICE
#define PCI_COMMAND PCIR_COMMAND
#define PCI_COMMAND_INTX_DISABLE PCIM_CMD_INTxDIS
+#define PCI_COMMAND_MEMORY PCIM_CMD_MEMEN
#define PCI_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
@@ -142,24 +146,38 @@ MODULE_PNP_INFO("U32:vendor;U32:device;V32:subvendor;V32:subdevice", \
#define PCI_EXP_TYPE_DOWNSTREAM PCIEM_TYPE_DOWNSTREAM_PORT /* Downstream Port */
#define PCI_EXP_FLAGS_SLOT PCIEM_FLAGS_SLOT /* Slot implemented */
#define PCI_EXP_TYPE_RC_EC PCIEM_TYPE_ROOT_EC /* Root Complex Event Collector */
+#define PCI_EXP_LNKSTA_CLS PCIEM_LINK_STA_SPEED
+#define PCI_EXP_LNKSTA_CLS_8_0GB 0x0003 /* Current Link Speed 8.0GT/s */
#define PCI_EXP_LNKCAP_SLS_2_5GB 0x01 /* Supported Link Speed 2.5GT/s */
#define PCI_EXP_LNKCAP_SLS_5_0GB 0x02 /* Supported Link Speed 5.0GT/s */
-#define PCI_EXP_LNKCAP_SLS_8_0GB 0x04 /* Supported Link Speed 8.0GT/s */
-#define PCI_EXP_LNKCAP_SLS_16_0GB 0x08 /* Supported Link Speed 16.0GT/s */
+#define PCI_EXP_LNKCAP_SLS_8_0GB 0x03 /* Supported Link Speed 8.0GT/s */
+#define PCI_EXP_LNKCAP_SLS_16_0GB 0x04 /* Supported Link Speed 16.0GT/s */
+#define PCI_EXP_LNKCAP_SLS_32_0GB 0x05 /* Supported Link Speed 32.0GT/s */
+#define PCI_EXP_LNKCAP_SLS_64_0GB 0x06 /* Supported Link Speed 64.0GT/s */
#define PCI_EXP_LNKCAP_MLW 0x03f0 /* Maximum Link Width */
#define PCI_EXP_LNKCAP2_SLS_2_5GB 0x02 /* Supported Link Speed 2.5GT/s */
#define PCI_EXP_LNKCAP2_SLS_5_0GB 0x04 /* Supported Link Speed 5.0GT/s */
#define PCI_EXP_LNKCAP2_SLS_8_0GB 0x08 /* Supported Link Speed 8.0GT/s */
#define PCI_EXP_LNKCAP2_SLS_16_0GB 0x10 /* Supported Link Speed 16.0GT/s */
+#define PCI_EXP_LNKCAP2_SLS_32_0GB 0x20 /* Supported Link Speed 32.0GT/s */
+#define PCI_EXP_LNKCAP2_SLS_64_0GB 0x40 /* Supported Link Speed 64.0GT/s */
#define PCI_EXP_LNKCTL2_TLS 0x000f
#define PCI_EXP_LNKCTL2_TLS_2_5GT 0x0001 /* Supported Speed 2.5GT/s */
#define PCI_EXP_LNKCTL2_TLS_5_0GT 0x0002 /* Supported Speed 5GT/s */
#define PCI_EXP_LNKCTL2_TLS_8_0GT 0x0003 /* Supported Speed 8GT/s */
#define PCI_EXP_LNKCTL2_TLS_16_0GT 0x0004 /* Supported Speed 16GT/s */
#define PCI_EXP_LNKCTL2_TLS_32_0GT 0x0005 /* Supported Speed 32GT/s */
+#define PCI_EXP_LNKCTL2_TLS_64_0GT 0x0006 /* Supported Speed 64GT/s */
#define PCI_EXP_LNKCTL2_ENTER_COMP 0x0010 /* Enter Compliance */
#define PCI_EXP_LNKCTL2_TX_MARGIN 0x0380 /* Transmit Margin */
+#define PCI_MSI_ADDRESS_LO PCIR_MSI_ADDR
+#define PCI_MSI_ADDRESS_HI PCIR_MSI_ADDR_HIGH
+#define PCI_MSI_FLAGS PCIR_MSI_CTRL
+#define PCI_MSI_FLAGS_ENABLE PCIM_MSICTRL_MSI_ENABLE
+#define PCI_MSIX_FLAGS PCIR_MSIX_CTRL
+#define PCI_MSIX_FLAGS_ENABLE PCIM_MSIXCTRL_MSIX_ENABLE
+
#define PCI_EXP_LNKCAP_CLKPM 0x00040000
#define PCI_EXP_DEVSTA_TRPND 0x0020
@@ -173,6 +191,8 @@ enum pci_bus_speed {
PCIE_SPEED_5_0GT,
PCIE_SPEED_8_0GT,
PCIE_SPEED_16_0GT,
+ PCIE_SPEED_32_0GT,
+ PCIE_SPEED_64_0GT,
};
enum pcie_link_width {
@@ -201,6 +221,8 @@ typedef int pci_power_t;
#define PCI_POWER_ERROR PCI_POWERSTATE_UNKNOWN
+extern const char *pci_power_names[6];
+
#define PCI_ERR_ROOT_COMMAND PCIR_AER_ROOTERR_CMD
#define PCI_ERR_ROOT_ERR_SRC PCIR_AER_COR_SOURCE_ID
@@ -213,6 +235,7 @@ typedef int pci_power_t;
#define PCI_IRQ_LEGACY 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)
struct pci_dev;
@@ -240,6 +263,7 @@ struct pci_driver {
struct pci_bus {
struct pci_dev *self;
+ /* struct pci_bus *parent */
int domain;
int number;
};
@@ -269,10 +293,31 @@ _pci_exit(void) \
module_init(_pci_init); \
module_exit(_pci_exit)
+struct msi_msg {
+ uint32_t data;
+};
+
+struct pci_msi_desc {
+ struct {
+ bool is_64;
+ } msi_attrib;
+};
+
+struct msi_desc {
+ struct msi_msg msg;
+ struct pci_msi_desc pci;
+};
+
+struct msix_entry {
+ int entry;
+ int vector;
+};
+
/*
* If we find drivers accessing this from multiple KPIs we may have to
* refcount objects of this structure.
*/
+struct resource;
struct pci_mmio_region {
TAILQ_ENTRY(pci_mmio_region) next;
struct resource *res;
@@ -286,6 +331,7 @@ struct pci_dev {
struct pci_driver *pdrv;
struct pci_bus *bus;
struct pci_dev *root;
+ pci_power_t current_state;
uint16_t device;
uint16_t vendor;
uint16_t subsystem_vendor;
@@ -294,39 +340,58 @@ struct pci_dev {
unsigned int devfn;
uint32_t class;
uint8_t revision;
+ uint8_t msi_cap;
+ uint8_t msix_cap;
bool managed; /* devres "pcim_*(). */
bool want_iomap_res;
bool msi_enabled;
bool msix_enabled;
phys_addr_t rom;
size_t romlen;
+ struct msi_desc **msi_desc;
+ char *path_name;
+ spinlock_t pcie_cap_lock;
TAILQ_HEAD(, pci_mmio_region) mmio;
};
-/* We need some meta-struct to keep track of these for devres. */
-struct pci_devres {
- bool enable_io;
- /* PCIR_MAX_BAR_0 + 1 = 6 => BIT(0..5). */
- uint8_t region_mask;
- struct resource *region_table[PCIR_MAX_BAR_0 + 1]; /* Not needed. */
-};
-struct pcim_iomap_devres {
- void *mmio_table[PCIR_MAX_BAR_0 + 1];
- struct resource *res_table[PCIR_MAX_BAR_0 + 1];
-};
-
int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name);
int pci_alloc_irq_vectors(struct pci_dev *pdev, int minv, int maxv,
unsigned int flags);
+bool pci_device_is_present(struct pci_dev *pdev);
+
+int linuxkpi_pcim_enable_device(struct pci_dev *pdev);
+void __iomem **linuxkpi_pcim_iomap_table(struct pci_dev *pdev);
+void *linuxkpi_pci_iomap(struct pci_dev *pdev, int mmio_bar, int mmio_size);
+void linuxkpi_pci_iounmap(struct pci_dev *pdev, void *res);
+int linuxkpi_pcim_iomap_regions(struct pci_dev *pdev, uint32_t mask,
+ const char *name);
+int linuxkpi_pci_request_regions(struct pci_dev *pdev, const char *res_name);
+void linuxkpi_pci_release_region(struct pci_dev *pdev, int bar);
+void linuxkpi_pci_release_regions(struct pci_dev *pdev);
+int linuxkpi_pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries,
+ int nreq);
/* Internal helper function(s). */
struct pci_dev *lkpinew_pci_dev(device_t);
-struct pci_devres *lkpi_pci_devres_get_alloc(struct pci_dev *pdev);
void lkpi_pci_devres_release(struct device *, void *);
-struct resource *_lkpi_pci_iomap(struct pci_dev *pdev, int bar, int mmio_size);
-struct pcim_iomap_devres *lkpi_pcim_iomap_devres_find(struct pci_dev *pdev);
-void lkpi_pcim_iomap_table_release(struct device *, void *);
+struct pci_dev *lkpi_pci_get_device(uint16_t, uint16_t, struct pci_dev *);
+struct msi_desc *lkpi_pci_msi_desc_alloc(int);
+struct device *lkpi_pci_find_irq_dev(unsigned int irq);
+int _lkpi_pci_enable_msi_range(struct pci_dev *pdev, int minvec, int maxvec);
+
+static inline bool
+dev_is_pci(struct device *dev)
+{
+
+ return (device_get_devclass(dev->bsddev) == devclass_find("pci"));
+}
+
+static inline uint16_t
+pci_dev_id(struct pci_dev *pdev)
+{
+ return (PCI_DEVID(pdev->bus->number, pdev->devfn));
+}
static inline int
pci_resource_type(struct pci_dev *pdev, int bar)
@@ -343,56 +408,6 @@ pci_resource_type(struct pci_dev *pdev, int bar)
return (SYS_RES_MEMORY);
}
-struct resource_list_entry *linux_pci_reserve_bar(struct pci_dev *pdev,
- struct resource_list *rl, int type, int rid);
-
-static inline struct resource_list_entry *
-linux_pci_get_rle(struct pci_dev *pdev, int type, int rid, bool reserve_bar)
-{
- struct pci_devinfo *dinfo;
- struct resource_list *rl;
- struct resource_list_entry *rle;
-
- dinfo = device_get_ivars(pdev->dev.bsddev);
- rl = &dinfo->resources;
- rle = resource_list_find(rl, type, rid);
- /* Reserve resources for this BAR if needed. */
- if (rle == NULL && reserve_bar)
- rle = linux_pci_reserve_bar(pdev, rl, type, rid);
- return (rle);
-}
-
-static inline struct resource_list_entry *
-linux_pci_get_bar(struct pci_dev *pdev, int bar, bool reserve)
-{
- int type;
-
- type = pci_resource_type(pdev, bar);
- if (type < 0)
- return (NULL);
- bar = PCIR_BAR(bar);
- return (linux_pci_get_rle(pdev, type, bar, reserve));
-}
-
-static inline struct device *
-linux_pci_find_irq_dev(unsigned int irq)
-{
- struct pci_dev *pdev;
- struct device *found;
-
- found = NULL;
- spin_lock(&pci_lock);
- list_for_each_entry(pdev, &pci_devices, links) {
- if (irq == pdev->dev.irq ||
- (irq >= pdev->dev.irq_start && irq < pdev->dev.irq_end)) {
- found = &pdev->dev;
- break;
- }
- }
- spin_unlock(&pci_lock);
- return (found);
-}
-
/*
* All drivers just seem to want to inspect the type not flags.
*/
@@ -410,8 +425,7 @@ pci_resource_flags(struct pci_dev *pdev, int bar)
static inline const char *
pci_name(struct pci_dev *d)
{
-
- return device_get_desc(d->dev.bsddev);
+ return d->path_name;
}
static inline void *
@@ -527,73 +541,10 @@ done:
return (pdev->bus->self);
}
-static inline struct pci_devres *
-lkpi_pci_devres_find(struct pci_dev *pdev)
-{
-
- if (!pdev->managed)
- return (NULL);
-
- return (lkpi_pci_devres_get_alloc(pdev));
-}
-
-static inline void
-pci_release_region(struct pci_dev *pdev, int bar)
-{
- struct resource_list_entry *rle;
- struct pci_devres *dr;
- struct pci_mmio_region *mmio, *p;
-
- if ((rle = linux_pci_get_bar(pdev, bar, false)) == NULL)
- return;
-
- /*
- * As we implicitly track the requests we also need to clear them on
- * release. Do clear before resource release.
- */
- dr = lkpi_pci_devres_find(pdev);
- if (dr != NULL) {
- KASSERT(dr->region_table[bar] == rle->res, ("%s: pdev %p bar %d"
- " region_table res %p != rel->res %p\n", __func__, pdev,
- bar, dr->region_table[bar], rle->res));
- dr->region_table[bar] = NULL;
- dr->region_mask &= ~(1 << bar);
- }
-
- TAILQ_FOREACH_SAFE(mmio, &pdev->mmio, next, p) {
- if (rle->res != (void *)rman_get_bushandle(mmio->res))
- continue;
- TAILQ_REMOVE(&pdev->mmio, mmio, next);
- free(mmio, M_DEVBUF);
- }
-
- bus_release_resource(pdev->dev.bsddev, rle->type, rle->rid, rle->res);
-}
-
-static inline void
-pci_release_regions(struct pci_dev *pdev)
-{
- int i;
-
- for (i = 0; i <= PCIR_MAX_BAR_0; i++)
- pci_release_region(pdev, i);
-}
-
-static inline int
-pci_request_regions(struct pci_dev *pdev, const char *res_name)
-{
- int error;
- int i;
-
- for (i = 0; i <= PCIR_MAX_BAR_0; i++) {
- error = pci_request_region(pdev, i, res_name);
- if (error && error != -ENODEV) {
- pci_release_regions(pdev);
- return (error);
- }
- }
- return (0);
-}
+#define pci_release_region(pdev, bar) linuxkpi_pci_release_region(pdev, bar)
+#define pci_release_regions(pdev) linuxkpi_pci_release_regions(pdev)
+#define pci_request_regions(pdev, res_name) \
+ linuxkpi_pci_request_regions(pdev, res_name)
static inline void
lkpi_pci_disable_msix(struct pci_dev *pdev)
@@ -604,7 +555,7 @@ lkpi_pci_disable_msix(struct pci_dev *pdev)
/*
* The MSIX IRQ numbers associated with this PCI device are no
* longer valid and might be re-assigned. Make sure
- * linux_pci_find_irq_dev() does no longer see them by
+ * lkpi_pci_find_irq_dev() does no longer see them by
* resetting their references to zero:
*/
pdev->dev.irq_start = 0;
@@ -762,11 +713,6 @@ void linux_pci_unregister_drm_driver(struct pci_driver *pdrv);
#define pci_register_driver(pdrv) linux_pci_register_driver(pdrv)
#define pci_unregister_driver(pdrv) linux_pci_unregister_driver(pdrv)
-struct msix_entry {
- int entry;
- int vector;
-};
-
/*
* Enable msix, positive errors indicate actual number of available
* vectors. Negative errors are failures.
@@ -774,42 +720,7 @@ struct msix_entry {
* NB: define added to prevent this definition of pci_enable_msix from
* clashing with the native FreeBSD version.
*/
-#define pci_enable_msix(...) \
- linux_pci_enable_msix(__VA_ARGS__)
-
-static inline int
-pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, int nreq)
-{
- struct resource_list_entry *rle;
- int error;
- int avail;
- int i;
-
- avail = pci_msix_count(pdev->dev.bsddev);
- if (avail < nreq) {
- if (avail == 0)
- return -EINVAL;
- return avail;
- }
- avail = nreq;
- if ((error = -pci_alloc_msix(pdev->dev.bsddev, &avail)) != 0)
- return error;
- /*
- * Handle case where "pci_alloc_msix()" may allocate less
- * interrupts than available and return with no error:
- */
- if (avail < nreq) {
- pci_release_msi(pdev->dev.bsddev);
- return avail;
- }
- rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1, false);
- pdev->dev.irq_start = rle->start;
- pdev->dev.irq_end = rle->start + avail;
- for (i = 0; i < nreq; i++)
- entries[i].vector = pdev->dev.irq_start + i;
- pdev->msix_enabled = true;
- return (0);
-}
+#define pci_enable_msix(...) linuxkpi_pci_enable_msix(__VA_ARGS__)
#define pci_enable_msix_range(...) \
linux_pci_enable_msix_range(__VA_ARGS__)
@@ -843,24 +754,8 @@ pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
static inline int
pci_enable_msi(struct pci_dev *pdev)
{
- struct resource_list_entry *rle;
- int error;
- int avail;
- avail = pci_msi_count(pdev->dev.bsddev);
- if (avail < 1)
- return -EINVAL;
-
- avail = 1; /* this function only enable one MSI IRQ */
- if ((error = -pci_alloc_msi(pdev->dev.bsddev, &avail)) != 0)
- return error;
-
- rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1, false);
- pdev->dev.irq_start = rle->start;
- pdev->dev.irq_end = rle->start + avail;
- pdev->irq = rle->start;
- pdev->msi_enabled = true;
- return (0);
+ return (_lkpi_pci_enable_msi_range(pdev, 1, 1));
}
static inline int
@@ -879,35 +774,9 @@ static inline void pci_disable_sriov(struct pci_dev *dev)
{
}
-static inline void *
-pci_iomap(struct pci_dev *pdev, int mmio_bar, int mmio_size)
-{
- struct resource *res;
-
- res = _lkpi_pci_iomap(pdev, mmio_bar, mmio_size);
- if (res == NULL)
- return (NULL);
- /* This is a FreeBSD extension so we can use bus_*(). */
- if (pdev->want_iomap_res)
- return (res);
- return ((void *)rman_get_bushandle(res));
-}
-
-static inline void
-pci_iounmap(struct pci_dev *pdev, void *res)
-{
- struct pci_mmio_region *mmio, *p;
-
- TAILQ_FOREACH_SAFE(mmio, &pdev->mmio, next, p) {
- if (res != (void *)rman_get_bushandle(mmio->res))
- continue;
- bus_release_resource(pdev->dev.bsddev,
- mmio->type, mmio->rid, mmio->res);
- TAILQ_REMOVE(&pdev->mmio, mmio, next);
- free(mmio, M_DEVBUF);
- return;
- }
-}
+#define pci_iomap(pdev, mmio_bar, mmio_size) \
+ linuxkpi_pci_iomap(pdev, mmio_bar, mmio_size)
+#define pci_iounmap(pdev, res) linuxkpi_pci_iounmap(pdev, res)
static inline void
lkpi_pci_save_state(struct pci_dev *pdev)
@@ -926,6 +795,13 @@ lkpi_pci_restore_state(struct pci_dev *pdev)
#define pci_save_state(dev) lkpi_pci_save_state(dev)
#define pci_restore_state(dev) lkpi_pci_restore_state(dev)
+static inline int
+pci_reset_function(struct pci_dev *pdev)
+{
+
+ return (-ENOSYS);
+}
+
#define DEFINE_PCI_DEVICE_TABLE(_table) \
const struct pci_device_id _table[] __devinitdata
@@ -1110,6 +986,7 @@ static bool pcie_capability_reg_implemented(struct pci_dev *dev, int pos)
static inline int
pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *dst)
{
+ *dst = 0;
if (pos & 3)
return -EINVAL;
@@ -1122,6 +999,7 @@ pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *dst)
static inline int
pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *dst)
{
+ *dst = 0;
if (pos & 3)
return -EINVAL;
@@ -1144,21 +1022,40 @@ pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val)
}
static inline int
-pcie_capability_set_word(struct pci_dev *dev, int pos, uint16_t val)
+pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos,
+ uint16_t clear, uint16_t set)
{
int error;
uint16_t v;
+ if (pos == PCI_EXP_LNKCTL || pos == PCI_EXP_RTCTL)
+ spin_lock(&dev->pcie_cap_lock);
+
error = pcie_capability_read_word(dev, pos, &v);
- if (error != 0)
- return (error);
+ if (error == 0) {
+ v &= ~clear;
+ v |= set;
+ error = pcie_capability_write_word(dev, pos, v);
+ }
- v |= val;
+ if (pos == PCI_EXP_LNKCTL || pos == PCI_EXP_RTCTL)
+ spin_unlock(&dev->pcie_cap_lock);
- error = pcie_capability_write_word(dev, pos, v);
return (error);
}
+static inline int
+pcie_capability_set_word(struct pci_dev *dev, int pos, uint16_t val)
+{
+ return (pcie_capability_clear_and_set_word(dev, pos, 0, val));
+}
+
+static inline int
+pcie_capability_clear_word(struct pci_dev *dev, int pos, uint16_t val)
+{
+ return (pcie_capability_clear_and_set_word(dev, pos, val, 0));
+}
+
static inline int pcie_get_minimum_link(struct pci_dev *dev,
enum pci_bus_speed *speed, enum pcie_link_width *width)
{
@@ -1208,6 +1105,10 @@ pcie_get_speed_cap(struct pci_dev *dev)
return (PCIE_SPEED_8_0GT);
if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_16_0GB)
return (PCIE_SPEED_16_0GT);
+ if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_32_0GB)
+ return (PCIE_SPEED_32_0GT);
+ if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_64_0GB)
+ return (PCIE_SPEED_64_0GT);
} else { /* pre-r3.0 */
lnkcap = pci_read_config(root, pos + PCIER_LINK_CAP, 4);
if (lnkcap & PCI_EXP_LNKCAP_SLS_2_5GB)
@@ -1218,6 +1119,10 @@ pcie_get_speed_cap(struct pci_dev *dev)
return (PCIE_SPEED_8_0GT);
if (lnkcap & PCI_EXP_LNKCAP_SLS_16_0GB)
return (PCIE_SPEED_16_0GT);
+ if (lnkcap & PCI_EXP_LNKCAP_SLS_32_0GB)
+ return (PCIE_SPEED_32_0GT);
+ if (lnkcap & PCI_EXP_LNKCAP_SLS_64_0GB)
+ return (PCIE_SPEED_64_0GT);
}
return (PCI_SPEED_UNKNOWN);
}
@@ -1245,6 +1150,10 @@ PCIE_SPEED2MBS_ENC(enum pci_bus_speed spd)
{
switch(spd) {
+ case PCIE_SPEED_64_0GT:
+ return (64000 * 128 / 130);
+ case PCIE_SPEED_32_0GT:
+ return (32000 * 128 / 130);
case PCIE_SPEED_16_0GT:
return (16000 * 128 / 130);
case PCIE_SPEED_8_0GT:
@@ -1275,6 +1184,12 @@ pcie_bandwidth_available(struct pci_dev *pdev,
return (nwidth * PCIE_SPEED2MBS_ENC(nspeed));
}
+static inline bool
+pcie_aspm_enabled(struct pci_dev *pdev)
+{
+ return (false);
+}
+
static inline struct pci_dev *
pcie_find_root_port(struct pci_dev *pdev)
{
@@ -1307,6 +1222,29 @@ pci_stop_and_remove_bus_device(struct pci_dev *pdev)
{
}
+static inline int
+pci_rescan_bus(struct pci_bus *pbus)
+{
+ device_t *devlist, parent;
+ int devcount, error;
+
+ if (!device_is_attached(pbus->self->dev.bsddev))
+ return (0);
+ /* pci_rescan_method() will work on the pcib (parent). */
+ error = BUS_RESCAN(pbus->self->dev.bsddev);
+ if (error != 0)
+ return (0);
+
+ parent = device_get_parent(pbus->self->dev.bsddev);
+ error = device_get_children(parent, &devlist, &devcount);
+ if (error != 0)
+ return (0);
+ if (devcount != 0)
+ free(devlist, M_TEMP);
+
+ return (devcount);
+}
+
/*
* The following functions can be used to attach/detach the LinuxKPI's
* PCI device runtime. The pci_driver and pci_device_id pointer is
@@ -1401,63 +1339,17 @@ struct pci_dev *lkpi_pci_get_class(unsigned int class, struct pci_dev *from);
/* -------------------------------------------------------------------------- */
-static inline int
-pcim_enable_device(struct pci_dev *pdev)
-{
- struct pci_devres *dr;
- int error;
-
- /* Here we cannot run through the pdev->managed check. */
- dr = lkpi_pci_devres_get_alloc(pdev);
- if (dr == NULL)
- return (-ENOMEM);
-
- /* If resources were enabled before do not do it again. */
- if (dr->enable_io)
- return (0);
-
- error = pci_enable_device(pdev);
- if (error == 0)
- dr->enable_io = true;
-
- /* This device is not managed. */
- pdev->managed = true;
-
- return (error);
-}
-
-static inline void __iomem **
-pcim_iomap_table(struct pci_dev *pdev)
-{
- struct pcim_iomap_devres *dr;
-
- dr = lkpi_pcim_iomap_devres_find(pdev);
- if (dr == NULL)
- return (NULL);
-
- /*
- * If the driver has manually set a flag to be able to request the
- * resource to use bus_read/write_<n>, return the shadow table.
- */
- if (pdev->want_iomap_res)
- return ((void **)dr->res_table);
-
- /* This is the Linux default. */
- return (dr->mmio_table);
-}
+#define pcim_enable_device(pdev) linuxkpi_pcim_enable_device(pdev)
+#define pcim_iomap_table(pdev) linuxkpi_pcim_iomap_table(pdev)
+#define pcim_iomap_regions(pdev, mask, name) \
+ linuxkpi_pcim_iomap_regions(pdev, mask, name)
static inline int
pcim_iomap_regions_request_all(struct pci_dev *pdev, uint32_t mask, char *name)
{
- struct pcim_iomap_devres *dr;
- void *res;
- uint32_t mappings, requests, req_mask;
+ uint32_t requests, req_mask;
int bar, error;
- dr = lkpi_pcim_iomap_devres_find(pdev);
- if (dr == NULL)
- return (-ENOMEM);
-
/* Request all the BARs ("regions") we do not iomap. */
req_mask = ((1 << (PCIR_MAX_BAR_0 + 1)) - 1) & ~mask;
for (bar = requests = 0; requests != req_mask; bar++) {
@@ -1469,44 +1361,34 @@ pcim_iomap_regions_request_all(struct pci_dev *pdev, uint32_t mask, char *name)
requests |= (1 << bar);
}
- /* Now iomap all the requested (by "mask") ones. */
- for (bar = mappings = 0; mappings != mask; bar++) {
- if ((mask & (1 << bar)) == 0)
- continue;
-
- /* Request double is not allowed. */
- if (dr->mmio_table[bar] != NULL) {
- device_printf(pdev->dev.bsddev, "%s: bar %d %p\n",
- __func__, bar, dr->mmio_table[bar]);
- goto err;
- }
-
- res = _lkpi_pci_iomap(pdev, bar, 0);
- if (res == NULL)
- goto err;
- dr->mmio_table[bar] = (void *)rman_get_bushandle(res);
- dr->res_table[bar] = res;
-
- mappings |= (1 << bar);
- }
+ error = pcim_iomap_regions(pdev, mask, name);
+ if (error != 0)
+ goto err;
return (0);
err:
for (bar = PCIR_MAX_BAR_0; bar >= 0; bar--) {
- if ((mappings & (1 << bar)) != 0) {
- res = dr->mmio_table[bar];
- if (res == NULL)
- continue;
- pci_iounmap(pdev, res);
- } else if ((requests & (1 << bar)) != 0) {
+ if ((requests & (1 << bar)) != 0)
pci_release_region(pdev, bar);
- }
}
return (-EINVAL);
}
+/*
+ * We cannot simply re-define pci_get_device() as we would normally do
+ * and then hide it in linux_pci.c as too many semi-native drivers still
+ * include linux/pci.h and run into the conflict with native PCI. Linux drivers
+ * using pci_get_device() need to be changed to call linuxkpi_pci_get_device().
+ */
+static inline struct pci_dev *
+linuxkpi_pci_get_device(uint16_t vendor, uint16_t device, struct pci_dev *odev)
+{
+
+ return (lkpi_pci_get_device(vendor, device, odev));
+}
+
/* This is a FreeBSD extension so we can use bus_*(). */
static inline void
linuxkpi_pcim_want_to_use_bus_functions(struct pci_dev *pdev)
@@ -1533,6 +1415,17 @@ pci_ignore_hotplug(struct pci_dev *pdev)
{
}
+static inline const char *
+pci_power_name(pci_power_t state)
+{
+ int pstate = state + 1;
+
+ if (pstate >= 0 && pstate < nitems(pci_power_names))
+ return (pci_power_names[pstate]);
+ else
+ return (pci_power_names[0]);
+}
+
static inline int
pcie_get_readrq(struct pci_dev *dev)
{
@@ -1544,4 +1437,45 @@ pcie_get_readrq(struct pci_dev *dev)
return (128 << ((ctl & PCI_EXP_DEVCTL_READRQ) >> 12));
}
+static inline bool
+pci_is_enabled(struct pci_dev *pdev)
+{
+
+ return ((pci_read_config(pdev->dev.bsddev, PCIR_COMMAND, 2) &
+ PCIM_CMD_BUSMASTEREN) != 0);
+}
+
+static inline int
+pci_wait_for_pending_transaction(struct pci_dev *pdev)
+{
+
+ return (0);
+}
+
+static inline int
+pci_assign_resource(struct pci_dev *pdev, int bar)
+{
+
+ return (0);
+}
+
+static inline int
+pci_irq_vector(struct pci_dev *pdev, unsigned int vector)
+{
+
+ if (!pdev->msix_enabled && !pdev->msi_enabled) {
+ if (vector != 0)
+ return (-EINVAL);
+ return (pdev->irq);
+ }
+
+ if (pdev->msix_enabled || pdev->msi_enabled) {
+ if ((pdev->dev.irq_start + vector) >= pdev->dev.irq_end)
+ return (-EINVAL);
+ return (pdev->dev.irq_start + vector);
+ }
+
+ return (-ENXIO);
+}
+
#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 519d1b6eb663..2f02d6ad1c14 100644
--- a/sys/compat/linuxkpi/common/include/linux/pci_ids.h
+++ b/sys/compat/linuxkpi/common/include/linux/pci_ids.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_PCI_IDS_H
@@ -41,23 +39,30 @@
#define PCI_BASE_CLASS_BRIDGE 0x06
#define PCI_CLASS_BRIDGE_ISA 0x0601
+#define PCI_CLASS_ACCELERATOR_PROCESSING 0x1200
+
/* XXX We should really generate these and use them throughout the tree. */
#define PCI_VENDOR_ID_APPLE 0x106b
#define PCI_VENDOR_ID_ASUSTEK 0x1043
+#define PCI_VENDOR_ID_ATHEROS 0x168c
#define PCI_VENDOR_ID_ATI 0x1002
#define PCI_VENDOR_ID_BROADCOM 0x14e4
#define PCI_VENDOR_ID_DELL 0x1028
#define PCI_VENDOR_ID_HP 0x103c
#define PCI_VENDOR_ID_IBM 0x1014
#define PCI_VENDOR_ID_INTEL 0x8086
+#define PCI_VENDOR_ID_ITTIM 0x0b48
+#define PCI_VENDOR_ID_MEDIATEK 0x14c3
#define PCI_VENDOR_ID_MELLANOX 0x15b3
+#define PCI_VENDOR_ID_QCOM 0x17cb
#define PCI_VENDOR_ID_REALTEK 0x10ec
#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4
#define PCI_VENDOR_ID_SERVERWORKS 0x1166
#define PCI_VENDOR_ID_SONY 0x104d
#define PCI_VENDOR_ID_TOPSPIN 0x1867
+#define PCI_VENDOR_ID_UBIQUITI 0x0777
#define PCI_VENDOR_ID_VIA 0x1106
#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4
#define PCI_DEVICE_ID_ATI_RADEON_QY 0x5159
diff --git a/sys/compat/linuxkpi/common/include/linux/pfn.h b/sys/compat/linuxkpi/common/include/linux/pfn.h
index 675f5d21364a..26d47b9bc3b1 100644
--- a/sys/compat/linuxkpi/common/include/linux/pfn.h
+++ b/sys/compat/linuxkpi/common/include/linux/pfn.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_PFN_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/pfn_t.h b/sys/compat/linuxkpi/common/include/linux/pfn_t.h
index 48fb4f59a3c6..f22289802cb8 100644
--- a/sys/compat/linuxkpi/common/include/linux/pfn_t.h
+++ b/sys/compat/linuxkpi/common/include/linux/pfn_t.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_PFN_T_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/pid.h b/sys/compat/linuxkpi/common/include/linux/pid.h
index be7c9384d4cf..60cb9f725b21 100644
--- a/sys/compat/linuxkpi/common/include/linux/pid.h
+++ b/sys/compat/linuxkpi/common/include/linux/pid.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_PID_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/platform_device.h b/sys/compat/linuxkpi/common/include/linux/platform_device.h
new file mode 100644
index 000000000000..6853e709cb70
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/platform_device.h
@@ -0,0 +1,97 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020-2022 Bjoern A. Zeeb
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_LINUX_PLATFORM_DEVICE_H
+#define _LINUXKPI_LINUX_PLATFORM_DEVICE_H
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+
+struct platform_device {
+ const char *name;
+ int id;
+ bool id_auto;
+ struct device dev;
+};
+
+struct platform_driver {
+ int (*remove)(struct platform_device *);
+ struct device_driver driver;
+};
+
+#define dev_is_platform(dev) (false)
+#define to_platform_device(dev) (NULL)
+
+static __inline int
+platform_driver_register(struct platform_driver *pdrv)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (-ENXIO);
+}
+
+static __inline void *
+dev_get_platdata(struct device *dev)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (NULL);
+}
+
+static __inline int
+platform_driver_probe(struct platform_driver *pdrv,
+ int(*pd_probe_f)(struct platform_device *))
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (-ENODEV);
+}
+
+static __inline void
+platform_driver_unregister(struct platform_driver *pdrv)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return;
+}
+
+static __inline int
+platform_device_register(struct platform_device *pdev)
+{
+ pr_debug("%s: TODO\n", __func__);
+ return (0);
+}
+
+static __inline void
+platform_device_unregister(struct platform_device *pdev)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return;
+}
+
+#endif /* _LINUXKPI_LINUX_PLATFORM_DEVICE_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/pm.h b/sys/compat/linuxkpi/common/include/linux/pm.h
index d67cebb9764a..871c7b587864 100644
--- a/sys/compat/linuxkpi/common/include/linux/pm.h
+++ b/sys/compat/linuxkpi/common/include/linux/pm.h
@@ -26,17 +26,20 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_PM_H
#define _LINUXKPI_LINUX_PM_H
+#include <linux/kernel.h> /* pr_debug */
+#include <asm/atomic.h>
+
/* Needed but breaks linux_usb.c */
/* #include <linux/completion.h> */
/* #include <linux/wait.h> */
+struct device;
+
typedef struct pm_message {
int event;
} pm_message_t;
@@ -44,23 +47,50 @@ typedef struct pm_message {
struct dev_pm_domain {
};
+struct dev_pm_info {
+ atomic_t usage_count;
+};
+
#define PM_EVENT_FREEZE 0x0001
#define PM_EVENT_SUSPEND 0x0002
+#define pm_sleep_ptr(_p) \
+ IS_ENABLED(CONFIG_PM_SLEEP) ? (_p) : NULL
+
#ifdef CONFIG_PM_SLEEP
#define 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, \
+ .suspend = _suspendfunc, \
+ .resume = _resumefunc, \
+ .freeze = _suspendfunc, \
+ .thaw = _resumefunc, \
+ .poweroff = _suspendfunc, \
+ .restore = _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, \
}
#else
#define SIMPLE_DEV_PM_OPS(_name, _suspendfunc, _resumefunc) \
const struct dev_pm_ops _name = { \
}
+#define DEFINE_SIMPLE_DEV_PM_OPS(_name, _suspendfunc, _resumefunc) \
+const struct dev_pm_ops _name = { \
+}
#endif
+static inline void
+pm_wakeup_event(struct device *dev __unused, unsigned int x __unused)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+}
+
#endif /* _LINUXKPI_LINUX_PM_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/pm_qos.h b/sys/compat/linuxkpi/common/include/linux/pm_qos.h
index 8a9b3bdbd1ef..47c41a819ba8 100644
--- a/sys/compat/linuxkpi/common/include/linux/pm_qos.h
+++ b/sys/compat/linuxkpi/common/include/linux/pm_qos.h
@@ -23,8 +23,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_PM_QOS_H
diff --git a/sys/compat/linuxkpi/common/include/linux/pm_runtime.h b/sys/compat/linuxkpi/common/include/linux/pm_runtime.h
index 42c96a92b1ad..616dd508e562 100644
--- a/sys/compat/linuxkpi/common/include/linux/pm_runtime.h
+++ b/sys/compat/linuxkpi/common/include/linux/pm_runtime.h
@@ -40,4 +40,10 @@ pm_runtime_get_if_active(struct device *dev, bool x)
return 1;
}
+static inline int
+pm_runtime_suspended(struct device *dev)
+{
+ return 0;
+}
+
#endif /* _LINUXKPI_LINUX_PM_RUNTIME_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/poll.h b/sys/compat/linuxkpi/common/include/linux/poll.h
index ff83fb1959f6..3acb3c740954 100644
--- a/sys/compat/linuxkpi/common/include/linux/poll.h
+++ b/sys/compat/linuxkpi/common/include/linux/poll.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_POLL_H_
#define _LINUXKPI_LINUX_POLL_H_
@@ -34,6 +32,7 @@
#include <sys/poll.h>
#include <sys/fcntl.h>
+#include <linux/eventpoll.h>
#include <linux/wait.h>
#include <linux/file.h>
diff --git a/sys/compat/linuxkpi/common/include/linux/power_supply.h b/sys/compat/linuxkpi/common/include/linux/power_supply.h
index cf8a937b04ad..8855cfff0539 100644
--- a/sys/compat/linuxkpi/common/include/linux/power_supply.h
+++ b/sys/compat/linuxkpi/common/include/linux/power_supply.h
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_POWER_SUPPLY_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/preempt.h b/sys/compat/linuxkpi/common/include/linux/preempt.h
index b8deb23d7089..32177d4a980c 100644
--- a/sys/compat/linuxkpi/common/include/linux/preempt.h
+++ b/sys/compat/linuxkpi/common/include/linux/preempt.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_PREEMPT_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/prefetch.h b/sys/compat/linuxkpi/common/include/linux/prefetch.h
index aa997d50a3f3..71839f0ca191 100644
--- a/sys/compat/linuxkpi/common/include/linux/prefetch.h
+++ b/sys/compat/linuxkpi/common/include/linux/prefetch.h
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_PREFETCH_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/printk.h b/sys/compat/linuxkpi/common/include/linux/printk.h
index 317c6232bbc5..933d5aa6f94a 100644
--- a/sys/compat/linuxkpi/common/include/linux/printk.h
+++ b/sys/compat/linuxkpi/common/include/linux/printk.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_PRINTK_H_
#define _LINUXKPI_LINUX_PRINTK_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/ptp_clock_kernel.h b/sys/compat/linuxkpi/common/include/linux/ptp_clock_kernel.h
new file mode 100644
index 000000000000..aad46cc25b1b
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/ptp_clock_kernel.h
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 2023 The FreeBSD Foundation
+ *
+ * This software was developed by Björn Zeeb under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_LINUX_PTP_CLOCK_KERNEL_H
+#define _LINUXKPI_LINUX_PTP_CLOCK_KERNEL_H
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/kernel.h> /* pr_debug */
+#include <linux/ktime.h> /* system_device_crosststamp */
+
+/* This very likely belongs elsewhere. */
+struct system_device_crosststamp {
+ ktime_t device;
+ ktime_t sys_realtime;
+ ktime_t sys_monotonic_raw; /* name guessed based on comment */
+};
+
+struct ptp_clock_info {
+ char name[32];
+ int max_adj;
+ void *owner; /* THIS_MODULE */
+ int (*adjfine)(struct ptp_clock_info *, long);
+ int (*adjtime)(struct ptp_clock_info *, s64);
+ int (*getcrosststamp)(struct ptp_clock_info *, struct system_device_crosststamp *);
+ int (*gettime64)(struct ptp_clock_info *, struct timespec *);
+};
+
+static inline struct ptp_clock *
+ptp_clock_register(struct ptp_clock_info *ptpci, struct device *dev)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (NULL);
+}
+
+static inline void
+ptp_clock_unregister(struct ptp_clock *ptpc)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static inline int
+ptp_clock_index(struct ptp_clock *ptpc)
+{
+ pr_debug("%s: TODO\n", __func__);
+ return (0);
+}
+
+#endif /* _LINUXKPI_LINUX_PTP_CLOCK_KERNEL_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/qrtr.h b/sys/compat/linuxkpi/common/include/linux/qrtr.h
new file mode 100644
index 000000000000..1d2af0efdce2
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/qrtr.h
@@ -0,0 +1,41 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Bjoern A. Zeeb
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_LINUX_QRTR_H
+#define _LINUXKPI_LINUX_QRTR_H
+
+/* Qualcomm IPC Router (QRTR) */
+
+#include <sys/socket.h>
+
+struct sockaddr_qrtr {
+ sa_family_t sq_family;
+ uint32_t sq_node;
+ uint32_t sq_port;
+};
+
+#endif /* _LINUXKPI_LINUX_QRTR_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/radix-tree.h b/sys/compat/linuxkpi/common/include/linux/radix-tree.h
index 86620614fb36..a1204cb20a79 100644
--- a/sys/compat/linuxkpi/common/include/linux/radix-tree.h
+++ b/sys/compat/linuxkpi/common/include/linux/radix-tree.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_RADIX_TREE_H_
#define _LINUXKPI_LINUX_RADIX_TREE_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/random.h b/sys/compat/linuxkpi/common/include/linux/random.h
index fafb87cae9fe..808c5bc55974 100644
--- a/sys/compat/linuxkpi/common/include/linux/random.h
+++ b/sys/compat/linuxkpi/common/include/linux/random.h
@@ -4,6 +4,10 @@
* Copyright (c) 2010 Panasas, Inc.
* Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
* All rights reserved.
+ * Copyright 2023 The FreeBSD Foundation
+ *
+ * Portions of this software was developed by Björn Zeeb
+ * under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -25,8 +29,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_RANDOM_H_
@@ -36,8 +38,6 @@
#include <sys/random.h>
#include <sys/libkern.h>
-#define get_random_u32() get_random_int()
-
static inline void
get_random_bytes(void *buf, int nbytes)
{
@@ -54,6 +54,30 @@ get_random_int(void)
return (val);
}
+#define get_random_u32() get_random_int()
+
+/*
+ * See "Fast Random Integer Generation in an Interval" by Daniel Lemire
+ * [https://arxiv.org/pdf/1805.10941.pdf] for implementation insights.
+ */
+static inline uint32_t
+get_random_u32_inclusive(uint32_t floor, uint32_t ceil)
+{
+ uint64_t x;
+ uint32_t t, v;
+
+ MPASS(ceil >= floor);
+
+ v = get_random_u32();
+ t = ceil - floor + 1;
+ x = (uint64_t)t * v;
+ while (x < t)
+ x = (uint64_t)t * get_random_u32();
+ v = x >> 32;
+
+ return (floor + v);
+}
+
static inline u_long
get_random_long(void)
{
@@ -63,6 +87,21 @@ get_random_long(void)
return (val);
}
+static inline uint64_t
+get_random_u64(void)
+{
+ uint64_t val;
+
+ get_random_bytes(&val, sizeof(val));
+ return (val);
+}
+
+static inline uint32_t
+get_random_u32_below(uint32_t max)
+{
+ return (arc4random_uniform(max));
+}
+
static __inline uint32_t
prandom_u32(void)
{
diff --git a/sys/compat/linuxkpi/common/include/linux/rbtree.h b/sys/compat/linuxkpi/common/include/linux/rbtree.h
index de5ef0d6a3ce..78bf938eb000 100644
--- a/sys/compat/linuxkpi/common/include/linux/rbtree.h
+++ b/sys/compat/linuxkpi/common/include/linux/rbtree.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_RBTREE_H_
#define _LINUXKPI_LINUX_RBTREE_H_
@@ -41,8 +39,8 @@
struct rb_node {
RB_ENTRY(rb_node) __entry;
};
-#define rb_left __entry.rbe_left
-#define rb_right __entry.rbe_right
+#define rb_left __entry.rbe_link[_RB_L]
+#define rb_right __entry.rbe_link[_RB_R]
/*
* We provide a false structure that has the same bit pattern as tree.h
@@ -74,8 +72,11 @@ RB_PROTOTYPE(linux_root, rb_node, __entry, panic_cmp);
#define RB_EMPTY_NODE(node) (RB_PARENT(node, __entry) == node)
#define RB_CLEAR_NODE(node) RB_SET_PARENT(node, node, __entry)
-#define rb_insert_color(node, root) \
- linux_root_RB_INSERT_COLOR((struct linux_root *)(root), (node))
+#define rb_insert_color(node, root) do { \
+ if (rb_parent(node)) \
+ linux_root_RB_INSERT_COLOR((struct linux_root *)(root), \
+ rb_parent(node), (node)); \
+} while (0)
#define rb_erase(node, root) \
linux_root_RB_REMOVE((struct linux_root *)(root), (node))
#define rb_next(node) RB_NEXT(linux_root, NULL, (node))
@@ -132,11 +133,12 @@ rb_replace_node(struct rb_node *victim, struct rb_node *new,
struct rb_root *root)
{
- RB_SWAP_CHILD((struct linux_root *)root, victim, new, __entry);
- if (victim->rb_left)
- RB_SET_PARENT(victim->rb_left, new, __entry);
- if (victim->rb_right)
- RB_SET_PARENT(victim->rb_right, new, __entry);
+ RB_SWAP_CHILD((struct linux_root *)root, rb_parent(victim),
+ victim, new, __entry);
+ if (RB_LEFT(victim, __entry))
+ RB_SET_PARENT(RB_LEFT(victim, __entry), new, __entry);
+ if (RB_RIGHT(victim, __entry))
+ RB_SET_PARENT(RB_RIGHT(victim, __entry), new, __entry);
*new = *victim;
}
@@ -144,7 +146,9 @@ static inline void
rb_insert_color_cached(struct rb_node *node, struct rb_root_cached *root,
bool leftmost)
{
- linux_root_RB_INSERT_COLOR((struct linux_root *)&root->rb_root, node);
+ if (rb_parent(node))
+ linux_root_RB_INSERT_COLOR((struct linux_root *)&root->rb_root,
+ rb_parent(node), node);
if (leftmost)
root->rb_leftmost = node;
}
diff --git a/sys/compat/linuxkpi/common/include/linux/rculist.h b/sys/compat/linuxkpi/common/include/linux/rculist.h
index e0c3f79d9e5a..066ed92b7996 100644
--- a/sys/compat/linuxkpi/common/include/linux/rculist.h
+++ b/sys/compat/linuxkpi/common/include/linux/rculist.h
@@ -23,8 +23,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_RCULIST_H_
@@ -44,6 +42,11 @@
&(pos)->member != (head); \
pos = list_entry_rcu((pos)->member.next, typeof(*(pos)), member))
+#define list_for_each_entry_from_rcu(pos, head, member) \
+ for (; \
+ &(pos)->member != (head); \
+ pos = list_entry_rcu((pos)->member.next, typeof(*(pos)), member))
+
#define list_for_each_entry_lockless(pos, head, member) \
list_for_each_entry_rcu(pos, head, member)
diff --git a/sys/compat/linuxkpi/common/include/linux/rcupdate.h b/sys/compat/linuxkpi/common/include/linux/rcupdate.h
index 3599616430af..95332217f8f5 100644
--- a/sys/compat/linuxkpi/common/include/linux/rcupdate.h
+++ b/sys/compat/linuxkpi/common/include/linux/rcupdate.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_RCUPDATE_H_
#define _LINUXKPI_LINUX_RCUPDATE_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/refcount.h b/sys/compat/linuxkpi/common/include/linux/refcount.h
index 7c055fb32029..61947485945d 100644
--- a/sys/compat/linuxkpi/common/include/linux/refcount.h
+++ b/sys/compat/linuxkpi/common/include/linux/refcount.h
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_REFCOUNT_H
@@ -79,4 +77,15 @@ refcount_dec_and_lock_irqsave(refcount_t *ref, spinlock_t *lock,
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)
+{
+
+ return (atomic_dec_and_test(r));
+}
+
#endif /* __LINUXKPI_LINUX_REFCOUNT_H__ */
diff --git a/sys/compat/linuxkpi/common/include/linux/rhashtable.h b/sys/compat/linuxkpi/common/include/linux/rhashtable.h
new file mode 100644
index 000000000000..c6958b6ee5f3
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/rhashtable.h
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2023 Bjoern A. Zeeb
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_LINUX_RHASHTABLE_H
+#define _LINUXKPI_LINUX_RHASHTABLE_H
+
+#include <linux/kernel.h> /* pr_debug */
+
+struct rhash_head {
+};
+
+struct rhashtable_params {
+ uint16_t head_offset;
+ uint16_t key_len;
+ uint16_t key_offset;
+ uint16_t nelem_hint;
+ bool automatic_shrinking;
+};
+
+struct rhashtable {
+};
+
+static inline int
+rhashtable_init(struct rhashtable *rht,
+ const struct rhashtable_params *params)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (-1);
+}
+
+static inline void
+rhashtable_destroy(struct rhashtable *rht)
+{
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static inline void *
+rhashtable_lookup_fast(struct rhashtable *rht, const void *key,
+ const struct rhashtable_params params)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (NULL);
+}
+
+static inline void *
+rhashtable_lookup_get_insert_fast(struct rhashtable *rht,
+ struct rhash_head *obj, const struct rhashtable_params params)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (NULL);
+}
+
+static inline int
+rhashtable_remove_fast(struct rhashtable *rht,
+ struct rhash_head *obj, const struct rhashtable_params params)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (-ENOENT);
+}
+
+#endif /* _LINUXKPI_LINUX_RHASHTABLE_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/rwlock.h b/sys/compat/linuxkpi/common/include/linux/rwlock.h
index e7557d29e77a..8c1ee36ac4de 100644
--- a/sys/compat/linuxkpi/common/include/linux/rwlock.h
+++ b/sys/compat/linuxkpi/common/include/linux/rwlock.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_RWLOCK_H_
#define _LINUXKPI_LINUX_RWLOCK_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/rwsem.h b/sys/compat/linuxkpi/common/include/linux/rwsem.h
index fc3580bc186e..b7a800b12e18 100644
--- a/sys/compat/linuxkpi/common/include/linux/rwsem.h
+++ b/sys/compat/linuxkpi/common/include/linux/rwsem.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_RWSEM_H_
#define _LINUXKPI_LINUX_RWSEM_H_
@@ -46,6 +44,7 @@ struct rw_semaphore {
#define down_read(_rw) sx_slock(&(_rw)->sx)
#define up_read(_rw) sx_sunlock(&(_rw)->sx)
#define down_read_trylock(_rw) !!sx_try_slock(&(_rw)->sx)
+#define down_read_killable(_rw) linux_down_read_killable(_rw)
#define down_write_trylock(_rw) !!sx_try_xlock(&(_rw)->sx)
#define down_write_killable(_rw) linux_down_write_killable(_rw)
#define downgrade_write(_rw) sx_downgrade(&(_rw)->sx)
@@ -80,6 +79,7 @@ linux_init_rwsem(struct rw_semaphore *rw, const char *name)
sx_init_flags(&rw->sx, name, SX_NOWITNESS);
}
+extern int linux_down_read_killable(struct rw_semaphore *);
extern int linux_down_write_killable(struct rw_semaphore *);
#endif /* _LINUXKPI_LINUX_RWSEM_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/scatterlist.h b/sys/compat/linuxkpi/common/include/linux/scatterlist.h
index a3da30e1b9a7..e462d5c649f1 100644
--- a/sys/compat/linuxkpi/common/include/linux/scatterlist.h
+++ b/sys/compat/linuxkpi/common/include/linux/scatterlist.h
@@ -27,8 +27,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_SCATTERLIST_H_
#define _LINUXKPI_LINUX_SCATTERLIST_H_
@@ -99,6 +97,12 @@ struct sg_dma_page_iter {
#define for_each_sg(sglist, sg, sgmax, iter) \
for (iter = 0, sg = (sglist); iter < (sgmax); iter++, sg = sg_next(sg))
+#define for_each_sgtable_sg(sgt, sg, i) \
+ for_each_sg((sgt)->sgl, sg, (sgt)->orig_nents, i)
+
+#define for_each_sgtable_page(sgt, iter, pgoffset) \
+ for_each_sg_page((sgt)->sgl, iter, (sgt)->orig_nents, pgoffset)
+
#define for_each_sgtable_dma_sg(sgt, sg, iter) \
for_each_sg((sgt)->sgl, sg, (sgt)->nents, iter)
@@ -152,7 +156,7 @@ sg_next(struct scatterlist *sg)
static inline vm_paddr_t
sg_phys(struct scatterlist *sg)
{
- return (VM_PAGE_TO_PHYS(sg_page(sg)) + sg->offset);
+ return (page_to_phys(sg_page(sg)) + sg->offset);
}
static inline void *
@@ -321,18 +325,40 @@ sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
return (ret);
}
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
+static inline struct scatterlist *
+__sg_alloc_table_from_pages(struct sg_table *sgt,
+ struct page **pages, unsigned int count,
+ unsigned long off, unsigned long size,
+ unsigned int max_segment,
+ struct scatterlist *prv, unsigned int left_pages,
+ gfp_t gfp_mask)
+#else
static inline int
__sg_alloc_table_from_pages(struct sg_table *sgt,
struct page **pages, unsigned int count,
unsigned long off, unsigned long size,
unsigned int max_segment, gfp_t gfp_mask)
+#endif
{
unsigned int i, segs, cur, len;
int rc;
- struct scatterlist *s;
+ struct scatterlist *s, *sg_iter;
+
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
+ if (prv != NULL) {
+ panic(
+ "Support for prv != NULL not implemented in "
+ "__sg_alloc_table_from_pages()");
+ }
+#endif
if (__predict_false(!max_segment || offset_in_page(max_segment)))
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
+ return (ERR_PTR(-EINVAL));
+#else
return (-EINVAL);
+#endif
len = 0;
for (segs = i = 1; i < count; ++i) {
@@ -344,13 +370,25 @@ __sg_alloc_table_from_pages(struct sg_table *sgt,
}
}
if (__predict_false((rc = sg_alloc_table(sgt, segs, gfp_mask))))
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
+ return (ERR_PTR(rc));
+#else
return (rc);
+#endif
cur = 0;
- for_each_sg(sgt->sgl, s, sgt->orig_nents, i) {
+ for_each_sg(sgt->sgl, sg_iter, sgt->orig_nents, i) {
unsigned long seg_size;
unsigned int j;
+ /*
+ * We need to make sure that when we exit this loop "s" has the
+ * last sg in the chain so we can call sg_mark_end() on it.
+ * Only set this inside the loop since sg_iter will be iterated
+ * until it is NULL.
+ */
+ s = sg_iter;
+
len = 0;
for (j = cur + 1; j < count; ++j) {
len += PAGE_SIZE;
@@ -365,7 +403,16 @@ __sg_alloc_table_from_pages(struct sg_table *sgt,
off = 0;
cur = j;
}
+ KASSERT(s != NULL, ("s is NULL after loop in __sg_alloc_table_from_pages()"));
+
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
+ if (left_pages == 0)
+ sg_mark_end(s);
+
+ return (s);
+#else
return (0);
+#endif
}
static inline int
@@ -375,8 +422,27 @@ sg_alloc_table_from_pages(struct sg_table *sgt,
gfp_t gfp_mask)
{
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
+ return (PTR_ERR_OR_ZERO(__sg_alloc_table_from_pages(sgt, pages, count, off, size,
+ SCATTERLIST_MAX_SEGMENT, NULL, 0, gfp_mask)));
+#else
return (__sg_alloc_table_from_pages(sgt, pages, count, off, size,
SCATTERLIST_MAX_SEGMENT, gfp_mask));
+#endif
+}
+
+static inline int
+sg_alloc_table_from_pages_segment(struct sg_table *sgt,
+ struct page **pages, unsigned int count, unsigned int off,
+ unsigned long size, unsigned int max_segment, gfp_t gfp_mask)
+{
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
+ return (PTR_ERR_OR_ZERO(__sg_alloc_table_from_pages(sgt, pages, count, off, size,
+ max_segment, NULL, 0, gfp_mask)));
+#else
+ return (__sg_alloc_table_from_pages(sgt, pages, count, off, size,
+ max_segment, gfp_mask));
+#endif
}
static inline int
@@ -587,7 +653,7 @@ sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents,
break;
vaddr = (char *)sf_buf_kva(sf);
} else
- vaddr = (char *)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(page));
+ vaddr = (char *)PHYS_TO_DMAP(page_to_phys(page));
memcpy(buf, vaddr + sg->offset + offset, len);
if (!PMAP_HAS_DMAP)
sf_buf_free(sf);
diff --git a/sys/compat/linuxkpi/common/include/linux/sched.h b/sys/compat/linuxkpi/common/include/linux/sched.h
index 24014e71cda6..8cb6b12100d5 100644
--- a/sys/compat/linuxkpi/common/include/linux/sched.h
+++ b/sys/compat/linuxkpi/common/include/linux/sched.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_SCHED_H_
#define _LINUXKPI_LINUX_SCHED_H_
@@ -50,6 +48,8 @@
#include <linux/spinlock.h>
#include <linux/time.h>
+#include <linux/sched/mm.h>
+
#include <asm/atomic.h>
#define MAX_SCHEDULE_TIMEOUT INT_MAX
diff --git a/sys/compat/linuxkpi/common/include/linux/sched/mm.h b/sys/compat/linuxkpi/common/include/linux/sched/mm.h
new file mode 100644
index 000000000000..c26d99378974
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/sched/mm.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _LINUXKPI_LINUX_SCHED_MM_H_
+#define _LINUXKPI_LINUX_SCHED_MM_H_
+
+#include <linux/gfp.h>
+
+#define fs_reclaim_acquire(x) do { \
+ } while (0)
+#define fs_reclaim_release(x) do { \
+ } while (0)
+#define memalloc_nofs_save(x) 0
+#define memalloc_nofs_restore(x) do { \
+ } while (0)
+#define memalloc_noreclaim_save(x) 0
+#define memalloc_noreclaim_restore(x) do { \
+ } while (0)
+
+#endif /* _BSD_LKPI_LINUX_SCHED_MM_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/semaphore.h b/sys/compat/linuxkpi/common/include/linux/semaphore.h
index da1fc73b1776..4b1a1502e589 100644
--- a/sys/compat/linuxkpi/common/include/linux/semaphore.h
+++ b/sys/compat/linuxkpi/common/include/linux/semaphore.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_SEMAPHORE_H_
#define _LINUXKPI_LINUX_SEMAPHORE_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/seq_file.h b/sys/compat/linuxkpi/common/include/linux/seq_file.h
index 9ab5ecce7768..d8b327f59538 100644
--- a/sys/compat/linuxkpi/common/include/linux/seq_file.h
+++ b/sys/compat/linuxkpi/common/include/linux/seq_file.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2016-2018, Matthew Macy <mmacy@freebsd.org>
*
@@ -23,8 +23,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_SEQ_FILE_H_
@@ -32,11 +30,13 @@
#include <linux/types.h>
#include <linux/fs.h>
-#include <sys/sbuf.h>
+#include <linux/string_helpers.h>
#undef file
#define inode vnode
+MALLOC_DECLARE(M_LSEQ);
+
#define DEFINE_SHOW_ATTRIBUTE(__name) \
static int __name ## _open(struct inode *inode, struct linux_file *file) \
{ \
@@ -51,11 +51,9 @@ static const struct file_operations __name ## _fops = { \
.release = single_release, \
}
-struct seq_operations;
-
struct seq_file {
- struct sbuf *buf;
-
+ struct sbuf *buf;
+ size_t size;
const struct seq_operations *op;
const struct linux_file *file;
void *private;
@@ -70,18 +68,26 @@ struct seq_operations {
ssize_t seq_read(struct linux_file *, char *, size_t, off_t *);
int seq_write(struct seq_file *seq, const void *data, size_t len);
+void seq_putc(struct seq_file *m, char c);
+void seq_puts(struct seq_file *m, const char *str);
+bool seq_has_overflowed(struct seq_file *m);
+
+void *__seq_open_private(struct linux_file *, const struct seq_operations *, int);
+int seq_release_private(struct inode *, struct linux_file *);
int seq_open(struct linux_file *f, const struct seq_operations *op);
int seq_release(struct inode *inode, struct linux_file *file);
off_t seq_lseek(struct linux_file *file, off_t offset, int whence);
int single_open(struct linux_file *, int (*)(struct seq_file *, void *), void *);
+int single_open_size(struct linux_file *, int (*)(struct seq_file *, void *), void *, size_t);
int single_release(struct inode *, struct linux_file *);
-#define seq_printf(m, fmt, ...) sbuf_printf((m)->buf, (fmt), ##__VA_ARGS__)
+void lkpi_seq_vprintf(struct seq_file *m, const char *fmt, va_list args);
+void lkpi_seq_printf(struct seq_file *m, const char *fmt, ...);
-#define seq_puts(m, str) sbuf_printf((m)->buf, str)
-#define seq_putc(m, str) sbuf_putc((m)->buf, str)
+#define seq_vprintf(...) lkpi_seq_vprintf(__VA_ARGS__)
+#define seq_printf(...) lkpi_seq_printf(__VA_ARGS__)
#define file linux_file
diff --git a/sys/compat/linuxkpi/common/include/linux/seqlock.h b/sys/compat/linuxkpi/common/include/linux/seqlock.h
index 6e81e7a0fa45..48e42efc10fe 100644
--- a/sys/compat/linuxkpi/common/include/linux/seqlock.h
+++ b/sys/compat/linuxkpi/common/include/linux/seqlock.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
*
@@ -31,8 +31,10 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/cdefs.h>
#include <sys/lock.h>
#include <sys/mutex.h>
+#include <sys/rwlock.h>
#include <sys/seqc.h>
struct lock_class_key;
@@ -48,6 +50,12 @@ struct seqlock {
};
typedef struct seqlock seqlock_t;
+struct seqcount_mutex {
+ seqc_t seqc;
+};
+typedef struct seqcount_mutex seqcount_mutex_t;
+typedef struct seqcount_mutex seqcount_ww_mutex_t;
+
static inline void
__seqcount_init(struct seqcount *seqcount, const char *name __unused,
struct lock_class_key *key __unused)
@@ -57,16 +65,43 @@ __seqcount_init(struct seqcount *seqcount, const char *name __unused,
#define seqcount_init(seqcount) __seqcount_init(seqcount, NULL, NULL)
static inline void
-write_seqcount_begin(struct seqcount *seqcount)
+seqcount_mutex_init(struct seqcount_mutex *seqcount, void *mutex __unused)
{
- seqc_sleepable_write_begin(&seqcount->seqc);
+ seqcount->seqc = 0;
}
+#define seqcount_ww_mutex_init(seqcount, ww_mutex) \
+ seqcount_mutex_init((seqcount), (ww_mutex))
+
+#define write_seqcount_begin(s) \
+ _Generic(*(s), \
+ struct seqcount: seqc_sleepable_write_begin, \
+ struct seqcount_mutex: seqc_write_begin \
+ )(&(s)->seqc)
+
+#define write_seqcount_end(s) \
+ _Generic(*(s), \
+ struct seqcount: seqc_sleepable_write_end, \
+ struct seqcount_mutex: seqc_write_end \
+ )(&(s)->seqc)
+
static inline void
-write_seqcount_end(struct seqcount *seqcount)
+lkpi_write_seqcount_invalidate(seqc_t *seqcp)
{
- seqc_sleepable_write_end(&seqcount->seqc);
+ atomic_thread_fence_rel();
+ *seqcp += SEQC_MOD * 2;
}
+#define write_seqcount_invalidate(s) lkpi_write_seqcount_invalidate(&(s)->seqc)
+
+#define read_seqcount_begin(s) seqc_read(&(s)->seqc)
+#define raw_read_seqcount(s) seqc_read_any(&(s)->seqc)
+
+static inline seqc_t
+lkpi_seqprop_sequence(const seqc_t *seqcp)
+{
+ return (atomic_load_int(__DECONST(seqc_t *, seqcp)));
+}
+#define seqprop_sequence(s) lkpi_seqprop_sequence(&(s)->seqc)
/*
* XXX: Are predicts from inline functions still not honored by clang?
@@ -76,18 +111,6 @@ write_seqcount_end(struct seqcount *seqcount)
#define read_seqcount_retry(seqcount, gen) \
(!seqc_consistent(&(seqcount)->seqc, gen))
-static inline unsigned
-read_seqcount_begin(const struct seqcount *seqcount)
-{
- return (seqc_read(&seqcount->seqc));
-}
-
-static inline unsigned
-raw_read_seqcount(const struct seqcount *seqcount)
-{
- return (seqc_read_any(&seqcount->seqc));
-}
-
static inline void
seqlock_init(struct seqlock *seqlock)
{
diff --git a/sys/compat/linuxkpi/common/include/linux/shmem_fs.h b/sys/compat/linuxkpi/common/include/linux/shmem_fs.h
index 240d26c47685..efa2c855fe7d 100644
--- a/sys/compat/linuxkpi/common/include/linux/shmem_fs.h
+++ b/sys/compat/linuxkpi/common/include/linux/shmem_fs.h
@@ -25,20 +25,22 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_SHMEM_FS_H_
#define _LINUXKPI_LINUX_SHMEM_FS_H_
-/* Shared memory support */
-unsigned long linux_invalidate_mapping_pages(vm_object_t, pgoff_t, pgoff_t);
-struct page *linux_shmem_read_mapping_page_gfp(vm_object_t, int, gfp_t);
-struct linux_file *linux_shmem_file_setup(const char *, loff_t, unsigned long);
-void linux_shmem_truncate_range(vm_object_t, loff_t, loff_t);
+#include <linux/file.h>
+#include <linux/mempolicy.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
-#define invalidate_mapping_pages(...) \
- linux_invalidate_mapping_pages(__VA_ARGS__)
+/* Shared memory support */
+struct page *linux_shmem_read_mapping_page_gfp(vm_object_t obj, int pindex,
+ gfp_t gfp);
+struct linux_file *linux_shmem_file_setup(const char *name, loff_t size,
+ unsigned long flags);
+void linux_shmem_truncate_range(vm_object_t obj, loff_t lstart,
+ loff_t lend);
#define shmem_read_mapping_page(...) \
linux_shmem_read_mapping_page_gfp(__VA_ARGS__, 0)
diff --git a/sys/compat/linuxkpi/common/include/linux/shrinker.h b/sys/compat/linuxkpi/common/include/linux/shrinker.h
index 05f702e62fd5..a865241cc7cb 100644
--- a/sys/compat/linuxkpi/common/include/linux/shrinker.h
+++ b/sys/compat/linuxkpi/common/include/linux/shrinker.h
@@ -21,16 +21,16 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_SHRINKER_H_
#define _LINUXKPI_LINUX_SHRINKER_H_
#include <sys/queue.h>
+#include <linux/gfp.h>
struct shrink_control {
+ gfp_t gfp_mask;
unsigned long nr_to_scan;
unsigned long nr_scanned;
};
@@ -49,8 +49,14 @@ struct shrinker {
int linuxkpi_register_shrinker(struct shrinker *s);
void linuxkpi_unregister_shrinker(struct shrinker *s);
+void linuxkpi_synchronize_shrinkers(void);
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 60000
+#define register_shrinker(s, ...) linuxkpi_register_shrinker(s)
+#else
#define register_shrinker(s) linuxkpi_register_shrinker(s)
+#endif
#define unregister_shrinker(s) linuxkpi_unregister_shrinker(s)
+#define synchronize_shrinkers() linuxkpi_synchronize_shrinkers()
#endif /* _LINUXKPI_LINUX_SHRINKER_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/sizes.h b/sys/compat/linuxkpi/common/include/linux/sizes.h
index b132eedff933..d8a6e75192f6 100644
--- a/sys/compat/linuxkpi/common/include/linux/sizes.h
+++ b/sys/compat/linuxkpi/common/include/linux/sizes.h
@@ -24,14 +24,13 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_SIZES_H_
#define _LINUXKPI_LINUX_SIZES_H_
#define SZ_1K (1024 * 1)
+#define SZ_2K (1024 * 2)
#define SZ_4K (1024 * 4)
#define SZ_8K (1024 * 8)
#define SZ_16K (1024 * 16)
@@ -43,9 +42,22 @@
#define SZ_1M (1024 * 1024 * 1)
#define SZ_2M (1024 * 1024 * 2)
+#define SZ_4M (1024 * 1024 * 4)
#define SZ_8M (1024 * 1024 * 8)
#define SZ_16M (1024 * 1024 * 16)
#define SZ_32M (1024 * 1024 * 32)
#define SZ_64M (1024 * 1024 * 64)
+#define SZ_128M (1024 * 1024 * 128)
+#define SZ_256M (1024 * 1024 * 256)
+#define SZ_512M (1024 * 1024 * 512)
+
+#define SZ_1G (1024 * 1024 * 1024 * 1)
+#define SZ_2G (1024 * 1024 * 1024 * 2)
+#define SZ_4G (1024 * 1024 * 1024 * 4)
+#define SZ_8G (1024 * 1024 * 1024 * 8)
+#define SZ_16G (1024 * 1024 * 1024 * 16)
+#define SZ_32G (1024 * 1024 * 1024 * 32)
+
+#define SZ_64T (1024 * 1024 * 1024 * 1024 * 64)
#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/skbuff.h b/sys/compat/linuxkpi/common/include/linux/skbuff.h
index d3a795344f86..ee3f427aa6e9 100644
--- a/sys/compat/linuxkpi/common/include/linux/skbuff.h
+++ b/sys/compat/linuxkpi/common/include/linux/skbuff.h
@@ -1,6 +1,6 @@
/*-
- * Copyright (c) 2020-2022 The FreeBSD Foundation
- * Copyright (c) 2021-2022 Bjoern A. Zeeb
+ * Copyright (c) 2020-2023 The FreeBSD Foundation
+ * Copyright (c) 2021-2023 Bjoern A. Zeeb
*
* This software was developed by Björn Zeeb under sponsorship from
* the FreeBSD Foundation.
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -46,6 +44,7 @@
#include <linux/gfp.h>
#include <linux/compiler.h>
#include <linux/spinlock.h>
+#include <linux/ktime.h>
/* #define SKB_DEBUG */
#ifdef SKB_DEBUG
@@ -85,12 +84,25 @@ enum sk_buff_pkt_type {
PACKET_OTHERHOST,
};
+struct skb_shared_hwtstamps {
+ ktime_t hwtstamp;
+};
+
#define NET_SKB_PAD max(CACHE_LINE_SIZE, 32)
+#define SKB_DATA_ALIGN(_x) roundup2(_x, CACHE_LINE_SIZE)
struct sk_buff_head {
/* XXX TODO */
- struct sk_buff *next;
- struct sk_buff *prev;
+ union {
+ struct {
+ struct sk_buff *next;
+ struct sk_buff *prev;
+ };
+ struct sk_buff_head_l {
+ struct sk_buff *next;
+ struct sk_buff *prev;
+ } list;
+ };
size_t qlen;
spinlock_t lock;
};
@@ -143,8 +155,10 @@ struct sk_buff {
uint16_t l4hdroff; /* transport header offset from *head */
uint32_t priority;
uint16_t qmap; /* queue mapping */
- uint16_t _spareu16_0;
+ uint16_t _flags; /* Internal flags. */
+#define _SKB_FLAGS_SKBEXTFRAG 0x0001
enum sk_buff_pkt_type pkt_type;
+ uint16_t mac_header; /* offset of mac_header */
/* "Scratch" area for layers to store metadata. */
/* ??? I see sizeof() operations so probably an array. */
@@ -174,6 +188,7 @@ struct sk_buff {
struct sk_buff *linuxkpi_alloc_skb(size_t, gfp_t);
struct sk_buff *linuxkpi_dev_alloc_skb(size_t, gfp_t);
+struct sk_buff *linuxkpi_build_skb(void *, size_t);
void linuxkpi_kfree_skb(struct sk_buff *);
struct sk_buff *linuxkpi_skb_copy(struct sk_buff *, gfp_t);
@@ -241,6 +256,16 @@ dev_kfree_skb_irq(struct sk_buff *skb)
dev_kfree_skb(skb);
}
+static inline struct sk_buff *
+build_skb(void *data, unsigned int fragsz)
+{
+ struct sk_buff *skb;
+
+ skb = linuxkpi_build_skb(data, fragsz);
+ SKB_TRACE(skb);
+ return (skb);
+}
+
/* -------------------------------------------------------------------------- */
/* XXX BZ review this one for terminal condition as Linux "queues" are special. */
@@ -467,6 +492,7 @@ skb_add_rx_frag(struct sk_buff *skb, int fragno, struct page *page,
shinfo->frags[fragno].size = size;
shinfo->nr_frags = fragno + 1;
skb->len += size;
+ skb->data_len += size;
skb->truesize += truesize;
/* XXX TODO EXTEND truesize? */
@@ -514,8 +540,8 @@ __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;
- next->prev = new;
- prev->next = new;
+ ((struct sk_buff_head_l *)next)->prev = new;
+ ((struct sk_buff_head_l *)prev)->next = new;
q->qlen++;
}
@@ -525,7 +551,7 @@ __skb_queue_after(struct sk_buff_head *q, struct sk_buff *skb,
{
SKB_TRACE_FMT(q, "skb %p new %p", skb, new);
- __skb_insert(new, skb, skb->next, q);
+ __skb_insert(new, skb, ((struct sk_buff_head_l *)skb)->next, q);
}
static inline void
@@ -538,24 +564,30 @@ __skb_queue_before(struct sk_buff_head *q, struct sk_buff *skb,
}
static inline void
-__skb_queue_tail(struct sk_buff_head *q, struct sk_buff *skb)
+__skb_queue_tail(struct sk_buff_head *q, struct sk_buff *new)
{
- struct sk_buff *s;
- SKB_TRACE2(q, skb);
- q->qlen++;
- s = (struct sk_buff *)q;
- s->prev->next = skb;
- skb->prev = s->prev;
- skb->next = s;
- s->prev = skb;
+ SKB_TRACE2(q, new);
+ __skb_queue_before(q, (struct sk_buff *)q, new);
}
static inline void
-skb_queue_tail(struct sk_buff_head *q, struct sk_buff *skb)
+skb_queue_tail(struct sk_buff_head *q, struct sk_buff *new)
+{
+ SKB_TRACE2(q, new);
+ return (__skb_queue_tail(q, new));
+}
+
+static inline struct sk_buff *
+skb_peek(struct sk_buff_head *q)
{
+ struct sk_buff *skb;
+
+ skb = q->next;
SKB_TRACE2(q, skb);
- return (__skb_queue_tail(q, skb));
+ if (skb == (struct sk_buff *)q)
+ return (NULL);
+ return (skb);
}
static inline struct sk_buff *
@@ -736,13 +768,6 @@ skb_frag_size(const skb_frag_t *frag)
return (-1);
}
-static inline bool
-skb_is_nonlinear(struct sk_buff *skb)
-{
- SKB_TRACE(skb);
- return ((skb->data_len > 0) ? true : false);
-}
-
#define skb_walk_frags(_skb, _frag) \
for ((_frag) = (_skb); false; (_frag)++)
@@ -773,7 +798,7 @@ static inline void
skb_free_frag(void *frag)
{
- SKB_TODO();
+ page_frag_free(frag);
}
static inline struct sk_buff *
@@ -800,25 +825,44 @@ skb_mark_not_on_list(struct sk_buff *skb)
}
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)
{
- struct sk_buff *b, *e, *n;
SKB_TRACE2(from, to);
if (skb_queue_empty(from))
return;
- /* XXX do we need a barrier around this? */
- b = from->next;
- e = from->prev;
- n = to->next;
+ ___skb_queue_splice(from, (struct sk_buff *)to, to->next);
+ to->qlen += from->qlen;
+ __skb_queue_head_init(from);
+}
- b->prev = (struct sk_buff *)to;
- to->next = b;
- e->next = n;
- n->prev = e;
+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);
}
@@ -847,6 +891,13 @@ 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)
{
@@ -856,6 +907,13 @@ __skb_linearize(struct sk_buff *skb)
}
static inline int
+skb_linearize(struct sk_buff *skb)
+{
+
+ return (skb_is_nonlinear(skb) ? __skb_linearize(skb) : 0);
+}
+
+static inline int
pskb_expand_head(struct sk_buff *skb, int x, int len, gfp_t gfp)
{
SKB_TRACE(skb);
@@ -889,35 +947,42 @@ skb_header_cloned(struct sk_buff *skb)
}
static inline uint8_t *
-skb_mac_header(struct sk_buff *skb)
+skb_mac_header(const struct sk_buff *skb)
{
SKB_TRACE(skb);
- SKB_TODO();
- return (NULL);
+ return (skb->head + skb->mac_header);
}
static inline void
-skb_orphan(struct sk_buff *skb)
+skb_reset_mac_header(struct sk_buff *skb)
{
SKB_TRACE(skb);
- SKB_TODO();
+ skb->mac_header = skb->data - skb->head;
}
static inline void
-skb_reset_mac_header(struct sk_buff *skb)
+skb_set_mac_header(struct sk_buff *skb, const size_t len)
{
SKB_TRACE(skb);
- SKB_TODO();
+ skb_reset_mac_header(skb);
+ skb->mac_header += len;
}
-static inline struct sk_buff *
-skb_peek(struct sk_buff_head *q)
+static inline struct skb_shared_hwtstamps *
+skb_hwtstamps(struct sk_buff *skb)
{
- SKB_TRACE(q);
+ SKB_TRACE(skb);
SKB_TODO();
return (NULL);
}
+static inline void
+skb_orphan(struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ SKB_TODO();
+}
+
static inline __sum16
csum_unfold(__sum16 sum)
{
@@ -936,7 +1001,10 @@ skb_reset_tail_pointer(struct sk_buff *skb)
{
SKB_TRACE(skb);
+#ifdef SKB_DOING_OFFSETS_US_NOT
skb->tail = (uint8_t *)(uintptr_t)(skb->data - skb->head);
+#endif
+ skb->tail = skb->data;
SKB_TRACE(skb);
}
@@ -965,14 +1033,6 @@ skb_copy_from_linear_data(const struct sk_buff *skb, void *dst, size_t len)
memcpy(dst, skb->data, len);
}
-static inline struct sk_buff *
-build_skb(void *data, unsigned int fragsz)
-{
-
- SKB_TODO();
- return (NULL);
-}
-
static inline int
skb_pad(struct sk_buff *skb, int pad)
{
@@ -998,13 +1058,35 @@ napi_consume_skb(struct sk_buff *skb, int budget)
SKB_TODO();
}
-static inline bool
-skb_linearize(struct sk_buff *skb)
+static inline struct sk_buff *
+napi_build_skb(void *data, size_t len)
{
+ SKB_TODO();
+ return (NULL);
+}
+
+static inline uint32_t
+skb_get_hash(struct sk_buff *skb)
+{
SKB_TRACE(skb);
SKB_TODO();
- return (false);
+ return (0);
+}
+
+static inline void
+skb_mark_for_recycle(struct sk_buff *skb)
+{
+ SKB_TRACE(skb);
+ SKB_TODO();
+}
+
+static inline int
+skb_cow_head(struct sk_buff *skb, unsigned int headroom)
+{
+ SKB_TRACE(skb);
+ SKB_TODO();
+ return (-1);
}
#define SKB_WITH_OVERHEAD(_s) \
diff --git a/sys/compat/linuxkpi/common/include/linux/slab.h b/sys/compat/linuxkpi/common/include/linux/slab.h
index 1228c4d07aa6..298306b6ea05 100644
--- a/sys/compat/linuxkpi/common/include/linux/slab.h
+++ b/sys/compat/linuxkpi/common/include/linux/slab.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_SLAB_H_
#define _LINUXKPI_LINUX_SLAB_H_
@@ -43,6 +41,7 @@
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)
@@ -55,7 +54,6 @@ MALLOC_DECLARE(M_KMALLOC);
#define vmalloc_node(size, node) __vmalloc_node(size, GFP_KERNEL, node)
#define vmalloc_user(size) __vmalloc(size, GFP_KERNEL | __GFP_ZERO, 0)
#define vmalloc(size) __vmalloc(size, GFP_KERNEL, 0)
-#define __kmalloc(...) kmalloc(__VA_ARGS__)
/*
* Prefix some functions with linux_ to avoid namespace conflict
@@ -67,6 +65,7 @@ MALLOC_DECLARE(M_KMALLOC);
#define kmem_cache_zalloc(...) lkpi_kmem_cache_zalloc(__VA_ARGS__)
#define kmem_cache_free(...) lkpi_kmem_cache_free(__VA_ARGS__)
#define kmem_cache_destroy(...) linux_kmem_cache_destroy(__VA_ARGS__)
+#define kmem_cache_shrink(x) (0)
#define KMEM_CACHE(__struct, flags) \
linux_kmem_cache_create(#__struct, sizeof(struct __struct), \
@@ -89,6 +88,9 @@ struct linux_kmem_cache;
/* 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)
+
static inline gfp_t
linux_check_m_flags(gfp_t flags)
{
@@ -105,7 +107,7 @@ linux_check_m_flags(gfp_t flags)
}
static inline void *
-kmalloc(size_t size, gfp_t flags)
+__kmalloc(size_t size, gfp_t flags)
{
return (malloc(MAX(size, sizeof(struct llist_node)), M_KMALLOC,
linux_check_m_flags(flags)));
@@ -177,11 +179,24 @@ krealloc(void *ptr, size_t size, gfp_t flags)
return (realloc(ptr, size, M_KMALLOC, linux_check_m_flags(flags)));
}
+static inline void *
+krealloc_array(void *ptr, size_t n, size_t size, gfp_t flags)
+{
+ if (WOULD_OVERFLOW(n, size)) {
+ return NULL;
+ }
+
+ return (realloc(ptr, n * size, M_KMALLOC, linux_check_m_flags(flags)));
+}
+
extern void linux_kfree_async(void *);
static inline void
kfree(const void *ptr)
{
+ if (ZERO_OR_NULL_PTR(ptr))
+ return;
+
if (curthread->td_critnest != 0)
linux_kfree_async(__DECONST(void *, ptr));
else
@@ -191,6 +206,9 @@ kfree(const void *ptr)
static __inline void
kfree_sensitive(const void *ptr)
{
+ if (ZERO_OR_NULL_PTR(ptr))
+ return;
+
zfree(__DECONST(void *, ptr), M_KMALLOC);
}
@@ -200,6 +218,7 @@ 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);
diff --git a/sys/compat/linuxkpi/common/include/linux/smp.h b/sys/compat/linuxkpi/common/include/linux/smp.h
index c6d011fceb5f..b057953e6282 100644
--- a/sys/compat/linuxkpi/common/include/linux/smp.h
+++ b/sys/compat/linuxkpi/common/include/linux/smp.h
@@ -22,13 +22,13 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_SMP_H_
#define _LINUXKPI_LINUX_SMP_H_
+#include <asm/smp.h>
+
/*
* Important note about the use of the function provided below:
*
diff --git a/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h b/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h
new file mode 100644
index 000000000000..b0aec2d4afbd
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/soc/mediatek/mtk_wed.h
@@ -0,0 +1,60 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022-2023 Bjoern A. Zeeb
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_LINUX_SOC_MEDIATEK_MTK_WED_H
+#define _LINUXKPI_LINUX_SOC_MEDIATEK_MTK_WED_H
+
+struct mtk_wed_device {
+};
+
+#define WED_WO_STA_REC 0x6
+
+#define mtk_wed_device_start(_dev, _mask) do { } while(0)
+#define mtk_wed_device_detach(_dev) do { } while(0)
+#define mtk_wed_device_irq_get(_dev, _mask) 0
+#define mtk_wed_device_irq_set_mask(_dev, _mask) do { } while(0)
+#define mtk_wed_device_update_msg(_dev, _id, _msg, _len) (-ENODEV)
+#define mtk_wed_device_dma_reset(_dev) do {} while (0)
+#define mtk_wed_device_ppe_check(_dev, _skb, _reason, _entry) \
+ do {} while (0)
+#define mtk_wed_device_stop(_dev) do { } while(0)
+
+static inline bool
+mtk_wed_device_active(struct mtk_wed_device *dev __unused)
+{
+
+ return (false);
+}
+
+static inline bool
+mtk_wed_get_rx_capa(struct mtk_wed_device *dev __unused)
+{
+
+ return (false);
+}
+
+#endif /* _LINUXKPI_LINUX_SOC_MEDIATEK_MTK_WED_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/soc/qcom/qmi.h b/sys/compat/linuxkpi/common/include/linux/soc/qcom/qmi.h
new file mode 100644
index 000000000000..647eaf271d87
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/soc/qcom/qmi.h
@@ -0,0 +1,173 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022-2023 Bjoern A. Zeeb
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_LINUX_SOC_QCOM_QMI_H
+#define _LINUXKPI_LINUX_SOC_QCOM_QMI_H
+
+/* QMI (Qualcomm MSM Interface) */
+
+#include <linux/qrtr.h>
+
+enum soc_qcom_qmi_data_type {
+ QMI_EOTI,
+ QMI_DATA_LEN,
+ QMI_OPT_FLAG,
+ QMI_UNSIGNED_1_BYTE,
+ QMI_UNSIGNED_2_BYTE,
+ QMI_UNSIGNED_4_BYTE,
+ QMI_UNSIGNED_8_BYTE,
+ QMI_SIGNED_4_BYTE_ENUM,
+ QMI_STRUCT,
+ QMI_STRING,
+};
+
+#define QMI_RESULT_SUCCESS_V01 __LINE__
+#define QMI_INDICATION __LINE__
+
+struct qmi_handle;
+
+enum soc_qcom_qmi_array_type {
+ NO_ARRAY,
+ STATIC_ARRAY,
+ VAR_LEN_ARRAY,
+};
+
+/* Should this become an enum? */
+#define QMI_COMMON_TLV_TYPE 0
+
+struct qmi_elem_info {
+ enum soc_qcom_qmi_data_type data_type;
+ uint32_t elem_len;
+ uint32_t elem_size;
+ enum soc_qcom_qmi_array_type array_type;
+ uint8_t tlv_type;
+ uint32_t offset;
+ const struct qmi_elem_info *ei_array;
+};
+
+struct qmi_response_type_v01 {
+ uint16_t result;
+ uint16_t error;
+};
+
+struct qmi_txn {
+};
+
+struct qmi_service {
+ uint32_t node;
+ uint32_t port;
+};
+
+struct qmi_msg_handler {
+ uint32_t type;
+ uint32_t msg_id;
+ const struct qmi_elem_info *ei;
+ size_t decoded_size;
+ void (*fn)(struct qmi_handle *, struct sockaddr_qrtr *, struct qmi_txn *, const void *);
+};
+
+struct qmi_ops {
+ int (*new_server)(struct qmi_handle *, struct qmi_service *);
+ void (*del_server)(struct qmi_handle *, struct qmi_service *);
+};
+
+struct qmi_handle {
+ int sock;
+
+ const struct qmi_msg_handler *handler;
+ struct qmi_ops ops;
+};
+
+
+/* XXX-TODO need implementation somewhere... it is not in ath1xk* */
+extern struct qmi_elem_info qmi_response_type_v01_ei[];
+
+static inline int
+qmi_handle_init(struct qmi_handle *handle, size_t resp_len_max,
+ const struct qmi_ops *ops, const struct qmi_msg_handler *handler)
+{
+
+ handle->handler = handler;
+ if (ops != NULL)
+ handle->ops = *ops;
+
+ /* We will find out what else to do here. */
+ /* XXX TODO */
+
+ return (0);
+}
+
+static __inline int
+qmi_add_lookup(struct qmi_handle *handle, uint32_t service, uint32_t version,
+ uint32_t service_ins_id)
+{
+
+ /* XXX TODO */
+ return (0);
+}
+
+static __inline void
+qmi_handle_release(struct qmi_handle *handle)
+{
+
+ /* XXX TODO */
+}
+
+static __inline int
+qmi_send_request(struct qmi_handle *handle, void *x, struct qmi_txn *txn,
+ uint32_t msd_id, size_t len, const struct qmi_elem_info *ei, void *req)
+{
+
+ /* XXX TODO */
+ return (-ENXIO);
+}
+
+static __inline void
+qmi_txn_cancel(struct qmi_txn *txn)
+{
+
+ /* XXX TODO */
+}
+
+static __inline int
+qmi_txn_init(struct qmi_handle *handle, struct qmi_txn *txn,
+ const struct qmi_elem_info *ei, void *resp)
+{
+
+ /* XXX TODO */
+ return (-ENXIO);
+}
+
+static __inline int
+qmi_txn_wait(struct qmi_txn *txn, uint64_t jiffies)
+{
+
+ /* XXX TODO */
+ return (-ENXIO);
+}
+
+#endif /* _LINUXKPI_LINUX_SOC_QCOM_QMI_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/socket.h b/sys/compat/linuxkpi/common/include/linux/socket.h
index 3afb9bdfe3ba..638ee058c2f5 100644
--- a/sys/compat/linuxkpi/common/include/linux/socket.h
+++ b/sys/compat/linuxkpi/common/include/linux/socket.h
@@ -25,14 +25,23 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_SOCKET_H_
#define _LINUXKPI_LINUX_SOCKET_H_
#include <sys/socket.h>
+#define AF_QIPCRTR 42
+
+static inline int
+kernel_connect(int sd, struct sockaddr *sa, size_t salen, int flags)
+{
+
+ /* kern_connectat()? It is used for sockaddr_qrtr by ath1xk/qmi. */
+ pr_debug("%s: TODO\n", __func__);
+ return (-EINVAL);
+}
+
#ifdef notyet
static inline int
memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len)
diff --git a/sys/compat/linuxkpi/common/include/linux/sort.h b/sys/compat/linuxkpi/common/include/linux/sort.h
index 91ccd7ff83c4..e6196d1f41c7 100644
--- a/sys/compat/linuxkpi/common/include/linux/sort.h
+++ b/sys/compat/linuxkpi/common/include/linux/sort.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
*
diff --git a/sys/compat/linuxkpi/common/include/linux/spinlock.h b/sys/compat/linuxkpi/common/include/linux/spinlock.h
index a87cb7180b28..4bc1e2a2d431 100644
--- a/sys/compat/linuxkpi/common/include/linux/spinlock.h
+++ b/sys/compat/linuxkpi/common/include/linux/spinlock.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_SPINLOCK_H_
#define _LINUXKPI_LINUX_SPINLOCK_H_
@@ -128,6 +126,7 @@ typedef struct {
} while (0)
#define spin_unlock_irqrestore(_l, flags) do { \
+ (void)(flags); \
spin_unlock(_l); \
} while (0)
diff --git a/sys/compat/linuxkpi/common/include/linux/srcu.h b/sys/compat/linuxkpi/common/include/linux/srcu.h
index 0742d25d11ac..b42c28a1311b 100644
--- a/sys/compat/linuxkpi/common/include/linux/srcu.h
+++ b/sys/compat/linuxkpi/common/include/linux/srcu.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_SRCU_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/stackdepot.h b/sys/compat/linuxkpi/common/include/linux/stackdepot.h
new file mode 100644
index 000000000000..df223d46be6e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/stackdepot.h
@@ -0,0 +1,32 @@
+/*-
+ * Copyright (c) 2022 Beckhoff Automation GmbH & Co. KG
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _LINUXKPI_LINUX_STACKDEPOT_H_
+#define _LINUXKPI_LINUX_STACKDEPOT_H_
+
+typedef bool depot_stack_handle_t;
+
+#endif /* _LINUXKPI_LINUX_STACKDEPOT_H_ */
diff --git a/sys/compat/linux/linux_sysproto.h b/sys/compat/linuxkpi/common/include/linux/stdarg.h
index cc392fb1b5ea..ab2fdf7534e5 100644
--- a/sys/compat/linux/linux_sysproto.h
+++ b/sys/compat/linuxkpi/common/include/linux/stdarg.h
@@ -1,20 +1,17 @@
/*-
- * SPDX-License-Identifier: BSD-3-Clause
+ * SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2005 Travis Poppe
- * All rights reserved.
+ * Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer
- * in this position and unchanged.
+ * 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.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
@@ -26,13 +23,11 @@
* 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.
- *
- * $FreeBSD$
*/
-#ifndef LINUX_SYSPROTO
-#define LINUX_SYSPROTO
+#ifndef _LINUXKPI_STDARG_H_
+#define _LINUXKPI_STDARG_H_
-int linux_nosys(struct thread *, struct nosys_args *);
+#include <machine/stdarg.h>
-#endif
+#endif /* _LINUXKPI_STDARG_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/stddef.h b/sys/compat/linuxkpi/common/include/linux/stddef.h
new file mode 100644
index 000000000000..a3bc6b13765e
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/stddef.h
@@ -0,0 +1,15 @@
+/* Public domain */
+
+#ifndef _LINUXKPI_LINUX_STDDEF_H_
+#define _LINUXKPI_LINUX_STDDEF_H_
+
+#include <sys/stddef.h>
+
+#define struct_group(NAME, ...) \
+ union { \
+ struct { __VA_ARGS__ }; \
+ struct { __VA_ARGS__ } NAME; \
+ }
+
+#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 7a118bb17c48..9e1818a38594 100644
--- a/sys/compat/linuxkpi/common/include/linux/string.h
+++ b/sys/compat/linuxkpi/common/include/linux/string.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_STRING_H_
#define _LINUXKPI_LINUX_STRING_H_
@@ -39,6 +37,8 @@
#include <linux/uaccess.h>
#include <linux/err.h>
#include <linux/bitops.h> /* for BITS_PER_LONG */
+#include <linux/overflow.h>
+#include <linux/stdarg.h>
#include <sys/libkern.h>
@@ -99,6 +99,15 @@ kmemdup(const void *src, size_t len, gfp_t gfp)
}
static inline char *
+strndup_user(const char __user *ustr, long n)
+{
+ if (n < 1)
+ return (ERR_PTR(-EINVAL));
+
+ return (memdup_user_nul(ustr, n - 1));
+}
+
+static inline char *
kstrdup(const char *string, gfp_t gfp)
{
char *retval;
@@ -197,6 +206,30 @@ strscpy(char* dst, const char* src, size_t len)
return (-E2BIG);
}
+static inline ssize_t
+strscpy_pad(char* dst, const char* src, size_t len)
+{
+
+ bzero(dst, len);
+
+ return (strscpy(dst, src, len));
+}
+
+static inline char *
+strnchr(const char *cp, size_t n, int ch)
+{
+ char *p;
+
+ for (p = __DECONST(char *, cp); n--; ++p) {
+ if (*p == ch)
+ return (p);
+ if (*p == '\0')
+ break;
+ }
+
+ return (NULL);
+}
+
static inline void *
memset32(uint32_t *b, uint32_t c, size_t len)
{
@@ -227,4 +260,40 @@ memset_p(void **p, void *v, size_t n)
return (memset64((uint64_t *)p, (uintptr_t)v, n));
}
+static inline void
+memcpy_and_pad(void *dst, size_t dstlen, const void *src, size_t len, int ch)
+{
+
+ if (len >= dstlen) {
+ memcpy(dst, src, dstlen);
+ } else {
+ memcpy(dst, src, len);
+ /* Pad with given padding character. */
+ memset((char *)dst + len, ch, dstlen - len);
+ }
+}
+
+#define memset_startat(ptr, bytepat, smember) \
+({ \
+ uint8_t *_ptr = (uint8_t *)(ptr); \
+ int _c = (int)(bytepat); \
+ size_t _o = offsetof(typeof(*(ptr)), smember); \
+ memset(_ptr + _o, _c, sizeof(*(ptr)) - _o); \
+})
+
+#define memset_after(ptr, bytepat, smember) \
+({ \
+ uint8_t *_ptr = (uint8_t *)(ptr); \
+ int _c = (int)(bytepat); \
+ size_t _o = offsetofend(typeof(*(ptr)), smember); \
+ memset(_ptr + _o, _c, sizeof(*(ptr)) - _o); \
+})
+
+static inline void
+memzero_explicit(void *p, size_t s)
+{
+ memset(p, 0, s);
+ __asm__ __volatile__("": :"r"(p) :"memory");
+}
+
#endif /* _LINUXKPI_LINUX_STRING_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/string_helpers.h b/sys/compat/linuxkpi/common/include/linux/string_helpers.h
new file mode 100644
index 000000000000..1bdff2730361
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/string_helpers.h
@@ -0,0 +1,69 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_LINUX_STRING_HELPERS_H_
+#define _LINUXKPI_LINUX_STRING_HELPERS_H_
+
+#include <sys/types.h>
+
+static inline const char *
+str_yes_no(bool value)
+{
+ if (value)
+ return "yes";
+ else
+ return "no";
+}
+
+static inline const char *
+str_on_off(bool value)
+{
+ if (value)
+ return "on";
+ else
+ return "off";
+}
+
+static inline const char *
+str_enabled_disabled(bool value)
+{
+ if (value)
+ return "enabled";
+ else
+ return "disabled";
+}
+
+static inline const char *
+str_enable_disable(bool value)
+{
+ if (value)
+ return "enable";
+ else
+ return "disable";
+}
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/linux/stringify.h b/sys/compat/linuxkpi/common/include/linux/stringify.h
index bfdf99a30f2f..9345bdc441aa 100644
--- a/sys/compat/linuxkpi/common/include/linux/stringify.h
+++ b/sys/compat/linuxkpi/common/include/linux/stringify.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_STRINGIFY_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/suspend.h b/sys/compat/linuxkpi/common/include/linux/suspend.h
new file mode 100644
index 000000000000..dacecbebdc08
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/suspend.h
@@ -0,0 +1,23 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_LINUX_SUSPEND_H_
+#define _LINUXKPI_LINUX_SUSPEND_H_
+
+typedef int suspend_state_t;
+
+extern suspend_state_t pm_suspend_target_state;
+
+#define PM_SUSPEND_ON 0
+#define PM_SUSPEND_TO_IDLE 1
+#define PM_SUSPEND_STANDBY 2
+#define PM_SUSPEND_MEM 3
+#define PM_SUSPEND_MIN PM_SUSPEND_TO_IDLE
+#define PM_SUSPEND_MAX 4
+
+static inline int
+pm_suspend_via_firmware(void)
+{
+ return 0;
+}
+
+#endif /* _LINUXKPI_LINUX_SUSPEND_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/swap.h b/sys/compat/linuxkpi/common/include/linux/swap.h
index a080895bed98..a353d353cd33 100644
--- a/sys/compat/linuxkpi/common/include/linux/swap.h
+++ b/sys/compat/linuxkpi/common/include/linux/swap.h
@@ -22,13 +22,18 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_SWAP_H_
#define _LINUXKPI_LINUX_SWAP_H_
+#include <sys/param.h>
+#include <sys/domainset.h>
+#include <sys/queue.h>
+#include <sys/proc.h>
+#include <sys/pcpu.h>
+
+#include <vm/vm.h>
#include <vm/swap_pager.h>
#include <vm/vm_pageout.h>
diff --git a/sys/compat/linuxkpi/common/include/linux/sysfs.h b/sys/compat/linuxkpi/common/include/linux/sysfs.h
index 0b6b479d9362..b5ad73e4460b 100644
--- a/sys/compat/linuxkpi/common/include/linux/sysfs.h
+++ b/sys/compat/linuxkpi/common/include/linux/sysfs.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_SYSFS_H_
#define _LINUXKPI_LINUX_SYSFS_H_
@@ -37,6 +35,7 @@
#include <linux/kobject.h>
#include <linux/stringify.h>
+#include <linux/mm.h>
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *, char *);
@@ -55,7 +54,10 @@ struct attribute_group {
.attr = { .name = __stringify(_name), .mode = _mode }, \
.show = _show, .store = _store, \
}
-#define __ATTR_RO(_name) __ATTR(_name, 0444, _name##_show, NULL)
+#define __ATTR_RO(_name) { \
+ .attr = { .name = __stringify(_name), .mode = 0444 }, \
+ .show = _name##_show, \
+}
#define __ATTR_WO(_name) __ATTR(_name, 0200, NULL, _name##_store)
#define __ATTR_RW(_name) __ATTR(_name, 0644, _name##_show, _name##_store)
#define __ATTR_NULL { .attr = { .name = NULL } }
@@ -154,6 +156,21 @@ sysfs_remove_file(struct kobject *kobj, const struct attribute *attr)
}
static inline int
+sysfs_create_link(struct kobject *kobj __unused,
+ struct kobject *target __unused, const char *name __unused)
+{
+ /* TODO */
+
+ return (0);
+}
+
+static inline void
+sysfs_remove_link(struct kobject *kobj, const char *name)
+{
+ /* TODO (along with sysfs_create_link) */
+}
+
+static inline int
sysfs_create_files(struct kobject *kobj, const struct attribute * const *attrs)
{
int error = 0;
@@ -246,7 +263,7 @@ sysfs_unmerge_group(struct kobject *kobj, const struct attribute_group *grp)
struct attribute **attr;
struct sysctl_oid *oidp;
- SLIST_FOREACH(oidp, SYSCTL_CHILDREN(kobj->oidp), oid_link) {
+ SYSCTL_FOREACH(oidp, SYSCTL_CHILDREN(kobj->oidp)) {
if (strcmp(oidp->oid_name, grp->name) != 0)
continue;
for (attr = grp->attrs; *attr != NULL; attr++) {
@@ -295,6 +312,42 @@ sysfs_streq(const char *s1, const char *s2)
return (l1 == l2 && strncmp(s1, s2, l1) == 0);
}
+static inline int
+sysfs_emit(char *buf, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ if (!buf || offset_in_page(buf)) {
+ pr_warn("invalid sysfs_emit: buf:%p\n", buf);
+ return (0);
+ }
+
+ va_start(args, fmt);
+ i = vscnprintf(buf, PAGE_SIZE, fmt, args);
+ va_end(args);
+
+ return (i);
+}
+
+static inline int
+sysfs_emit_at(char *buf, int at, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ if (!buf || offset_in_page(buf) || at < 0 || at >= PAGE_SIZE) {
+ pr_warn("invalid sysfs_emit: buf:%p at:%d\n", buf, at);
+ return (0);
+ }
+
+ va_start(args, fmt);
+ i = vscnprintf(buf + at, PAGE_SIZE - at, fmt, args);
+ va_end(args);
+
+ return (i);
+}
+
#define sysfs_attr_init(attr) do {} while(0)
#endif /* _LINUXKPI_LINUX_SYSFS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/tcp.h b/sys/compat/linuxkpi/common/include/linux/tcp.h
index cfc64b8c7e53..3e461d8e7075 100644
--- a/sys/compat/linuxkpi/common/include/linux/tcp.h
+++ b/sys/compat/linuxkpi/common/include/linux/tcp.h
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_TCP_H
diff --git a/sys/compat/linuxkpi/common/include/linux/time.h b/sys/compat/linuxkpi/common/include/linux/time.h
index c7a41a83f4aa..6c9a781d5e0e 100644
--- a/sys/compat/linuxkpi/common/include/linux/time.h
+++ b/sys/compat/linuxkpi/common/include/linux/time.h
@@ -22,12 +22,12 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_TIME_H_
#define _LINUXKPI_LINUX_TIME_H_
+#define MSEC_PER_SEC 1000L
+
#define NSEC_PER_USEC 1000L
#define NSEC_PER_MSEC 1000000L
#define NSEC_PER_SEC 1000000000L
@@ -40,6 +40,8 @@
#include <sys/time.h>
#include <sys/stdint.h>
+#include <linux/math64.h>
+
static inline struct timeval
ns_to_timeval(const int64_t nsec)
{
@@ -117,6 +119,8 @@ ns_to_timespec(const int64_t nsec)
return (ts);
}
+#define ns_to_timespec64(_x) ns_to_timespec(_x)
+
static inline int
timespec_valid(const struct timespec *ts)
{
diff --git a/sys/compat/linuxkpi/common/include/linux/timer.h b/sys/compat/linuxkpi/common/include/linux/timer.h
index 3432bfc46c4f..8bea082c3e6c 100644
--- a/sys/compat/linuxkpi/common/include/linux/timer.h
+++ b/sys/compat/linuxkpi/common/include/linux/timer.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_TIMER_H_
#define _LINUXKPI_LINUX_TIMER_H_
@@ -83,6 +81,8 @@ extern void add_timer(struct timer_list *);
extern void add_timer_on(struct timer_list *, int cpu);
extern int del_timer(struct timer_list *);
extern int del_timer_sync(struct timer_list *);
+extern int timer_delete_sync(struct timer_list *);
+extern int timer_shutdown_sync(struct timer_list *);
#define timer_pending(timer) callout_pending(&(timer)->callout)
#define round_jiffies(j) \
diff --git a/sys/compat/linuxkpi/common/include/linux/tracepoint.h b/sys/compat/linuxkpi/common/include/linux/tracepoint.h
index 0171427439f9..8ce7992306b9 100644
--- a/sys/compat/linuxkpi/common/include/linux/tracepoint.h
+++ b/sys/compat/linuxkpi/common/include/linux/tracepoint.h
@@ -23,8 +23,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_TRACEPOINT_H
@@ -37,7 +35,13 @@
#define TP_printk(...)
#define TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
-static void trace_ ## _name(_proto) \
+static inline void trace_ ## _name(_proto) \
+{ \
+}
+
+#define DECLARE_EVENT_CLASS(...)
+#define DEFINE_EVENT(_x, _name, _proto, _args) \
+static inline void trace_ ## _name(_proto) \
{ \
}
diff --git a/sys/compat/linuxkpi/common/include/linux/types.h b/sys/compat/linuxkpi/common/include/linux/types.h
index dab5e6ddce42..b11ce1cdd805 100644
--- a/sys/compat/linuxkpi/common/include/linux/types.h
+++ b/sys/compat/linuxkpi/common/include/linux/types.h
@@ -25,13 +25,10 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_TYPES_H_
#define _LINUXKPI_LINUX_TYPES_H_
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
@@ -79,6 +76,14 @@ typedef unsigned long kernel_ulong_t;
typedef unsigned long irq_hw_number_t;
+#ifndef LIST_HEAD_DEF
+#define LIST_HEAD_DEF
+struct list_head {
+ struct list_head *next;
+ struct list_head *prev;
+};
+#endif
+
struct rcu_head {
void *raw[2];
} __aligned(sizeof(void *));
diff --git a/sys/compat/linuxkpi/common/include/linux/uaccess.h b/sys/compat/linuxkpi/common/include/linux/uaccess.h
index c62a94e8e044..660e84e6af3b 100644
--- a/sys/compat/linuxkpi/common/include/linux/uaccess.h
+++ b/sys/compat/linuxkpi/common/include/linux/uaccess.h
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_UACCESS_H_
@@ -89,4 +87,29 @@ pagefault_disabled(void)
return ((curthread->td_pflags & TDP_NOFAULTING) != 0);
}
+static inline int
+__copy_to_user_inatomic(void __user *to, const void *from, unsigned n)
+{
+
+ return (copyout_nofault(from, to, n) != 0 ? n : 0);
+}
+#define __copy_to_user_inatomic_nocache(to, from, n) \
+ __copy_to_user_inatomic((to), (from), (n))
+
+static inline unsigned long
+__copy_from_user_inatomic(void *to, const void __user *from,
+ unsigned long n)
+{
+ /*
+ * XXXKIB. Equivalent Linux function is implemented using
+ * MOVNTI for aligned moves. For unaligned head and tail,
+ * normal move is performed. As such, it is not incorrect, if
+ * only somewhat slower, to use normal copyin. All uses
+ * except shmem_pwrite_fast() have the destination mapped WC.
+ */
+ return ((copyin_nofault(__DECONST(void *, from), to, n) != 0 ? n : 0));
+}
+#define __copy_from_user_inatomic_nocache(to, from, n) \
+ __copy_from_user_inatomic((to), (from), (n))
+
#endif /* _LINUXKPI_LINUX_UACCESS_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/udp.h b/sys/compat/linuxkpi/common/include/linux/udp.h
index 44c0763a1eeb..f3cd40cf8bb7 100644
--- a/sys/compat/linuxkpi/common/include/linux/udp.h
+++ b/sys/compat/linuxkpi/common/include/linux/udp.h
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_UDP_H
diff --git a/sys/compat/linuxkpi/common/include/linux/usb.h b/sys/compat/linuxkpi/common/include/linux/usb.h
index 3b7c8a2cde78..d9649dcb5471 100644
--- a/sys/compat/linuxkpi/common/include/linux/usb.h
+++ b/sys/compat/linuxkpi/common/include/linux/usb.h
@@ -1,4 +1,3 @@
-/* $FreeBSD$ */
/*-
* Copyright (c) 2007 Luigi Rizzo - Universita` di Pisa. All rights reserved.
* Copyright (c) 2007 Hans Petter Selasky. All rights reserved.
diff --git a/sys/compat/linuxkpi/common/include/linux/utsname.h b/sys/compat/linuxkpi/common/include/linux/utsname.h
new file mode 100644
index 000000000000..e6c52f8a5020
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/utsname.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2023 Bjoern A. Zeeb
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_LINUX_UTSNAME_H
+#define _LINUXKPI_LINUX_UTSNAME_H
+
+#include <sys/types.h>
+#include <sys/jail.h>
+
+struct _utsname {
+ char release[OSRELEASELEN];
+};
+
+struct uts_namespace {
+ struct _utsname name;
+};
+
+extern struct uts_namespace init_uts_ns;
+
+static inline struct _utsname *
+init_utsname(void)
+{
+
+ return &init_uts_ns.name;
+}
+
+#endif /* _LINUXKPI_LINUX_UTSNAME_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/uuid.h b/sys/compat/linuxkpi/common/include/linux/uuid.h
index 31a018497f78..4f6f4a8b34f0 100644
--- a/sys/compat/linuxkpi/common/include/linux/uuid.h
+++ b/sys/compat/linuxkpi/common/include/linux/uuid.h
@@ -1,7 +1,7 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2021 The FreeBSD Foundation
+ * Copyright (c) 2021,2023 The FreeBSD Foundation
*
* This software was developed by Björn Zeeb under sponsorship from
* the FreeBSD Foundation.
@@ -26,13 +26,13 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_UUID_H
#define _LINUXKPI_LINUX_UUID_H
+#include <linux/random.h>
+
#define UUID_STRING_LEN 36
#define GUID_INIT(x0_3, x4_5, x6_7, x8, x9, x10, x11, x12, x13, x14, x15) \
@@ -59,4 +59,19 @@ typedef struct {
char x[16];
} guid_t;
+static inline void
+guid_gen(guid_t *g)
+{
+
+ get_random_bytes(g, 16);
+ g->x[7] = (g->x[7] & 0x0f) | 0x40;
+ g->x[8] = (g->x[8] & 0x3f) | 0x80;
+}
+
+static inline void
+guid_copy(guid_t *dst, const guid_t *src)
+{
+ memcpy(dst, src, sizeof(*dst));
+}
+
#endif /* _LINUXKPI_LINUX_UUID_H */
diff --git a/sys/compat/linuxkpi/common/include/linux/vgaarb.h b/sys/compat/linuxkpi/common/include/linux/vgaarb.h
new file mode 100644
index 000000000000..d43a88136864
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/vgaarb.h
@@ -0,0 +1,281 @@
+/*
+ * The VGA aribiter manages VGA space routing and VGA resource decode to
+ * allow multiple VGA devices to be used in a system in a safe way.
+ *
+ * (C) Copyright 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ * (C) Copyright 2007 Paulo R. Zanoni <przanoni@gmail.com>
+ * (C) Copyright 2007, 2009 Tiago Vignatti <vignatti@freedesktop.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#ifndef _LINUXKPI_LINUX_VGA_H_
+#define _LINUXKPI_LINUX_VGA_H_
+
+#include <video/vga.h>
+
+/* Legacy VGA regions */
+#define VGA_RSRC_NONE 0x00
+#define VGA_RSRC_LEGACY_IO 0x01
+#define VGA_RSRC_LEGACY_MEM 0x02
+#define VGA_RSRC_LEGACY_MASK (VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM)
+/* Non-legacy access */
+#define VGA_RSRC_NORMAL_IO 0x04
+#define VGA_RSRC_NORMAL_MEM 0x08
+
+/* Passing that instead of a pci_dev to use the system "default"
+ * device, that is the one used by vgacon. Archs will probably
+ * have to provide their own vga_default_device();
+ */
+#define VGA_DEFAULT_DEVICE (NULL)
+
+struct pci_dev;
+
+/* For use by clients */
+
+/**
+ * vga_set_legacy_decoding
+ *
+ * @pdev: pci device of the VGA card
+ * @decodes: bit mask of what legacy regions the card decodes
+ *
+ * Indicates to the arbiter if the card decodes legacy VGA IOs,
+ * legacy VGA Memory, both, or none. All cards default to both,
+ * the card driver (fbdev for example) should tell the arbiter
+ * if it has disabled legacy decoding, so the card can be left
+ * out of the arbitration process (and can be safe to take
+ * interrupts at any time.
+ */
+#if defined(CONFIG_VGA_ARB)
+extern void vga_set_legacy_decoding(struct pci_dev *pdev,
+ unsigned int decodes);
+#else
+static inline void vga_set_legacy_decoding(struct pci_dev *pdev,
+ unsigned int decodes) { };
+#endif
+
+/**
+ * vga_get - acquire & locks VGA resources
+ *
+ * @pdev: pci device of the VGA card or NULL for the system default
+ * @rsrc: bit mask of resources to acquire and lock
+ * @interruptible: blocking should be interruptible by signals ?
+ *
+ * This function acquires VGA resources for the given
+ * card and mark those resources locked. If the resource requested
+ * are "normal" (and not legacy) resources, the arbiter will first check
+ * whether the card is doing legacy decoding for that type of resource. If
+ * yes, the lock is "converted" into a legacy resource lock.
+ * The arbiter will first look for all VGA cards that might conflict
+ * and disable their IOs and/or Memory access, including VGA forwarding
+ * on P2P bridges if necessary, so that the requested resources can
+ * be used. Then, the card is marked as locking these resources and
+ * the IO and/or Memory accesse are enabled on the card (including
+ * VGA forwarding on parent P2P bridges if any).
+ * This function will block if some conflicting card is already locking
+ * one of the required resources (or any resource on a different bus
+ * segment, since P2P bridges don't differenciate VGA memory and IO
+ * afaik). You can indicate whether this blocking should be interruptible
+ * by a signal (for userland interface) or not.
+ * Must not be called at interrupt time or in atomic context.
+ * If the card already owns the resources, the function succeeds.
+ * Nested calls are supported (a per-resource counter is maintained)
+ */
+
+#if defined(CONFIG_VGA_ARB)
+extern int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible);
+#else
+static inline int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible) { return 0; }
+#endif
+
+/**
+ * vga_get_interruptible
+ *
+ * Shortcut to vga_get
+ */
+
+static inline int vga_get_interruptible(struct pci_dev *pdev,
+ unsigned int rsrc)
+{
+ return vga_get(pdev, rsrc, 1);
+}
+
+/**
+ * vga_get_uninterruptible
+ *
+ * Shortcut to vga_get
+ */
+
+static inline int vga_get_uninterruptible(struct pci_dev *pdev,
+ unsigned int rsrc)
+{
+ return vga_get(pdev, rsrc, 0);
+}
+
+/**
+ * vga_tryget - try to acquire & lock legacy VGA resources
+ *
+ * @pdev: pci devivce of VGA card or NULL for system default
+ * @rsrc: bit mask of resources to acquire and lock
+ *
+ * This function performs the same operation as vga_get(), but
+ * will return an error (-EBUSY) instead of blocking if the resources
+ * are already locked by another card. It can be called in any context
+ */
+
+#if defined(CONFIG_VGA_ARB)
+extern int vga_tryget(struct pci_dev *pdev, unsigned int rsrc);
+#else
+static inline int vga_tryget(struct pci_dev *pdev, unsigned int rsrc) { return 0; }
+#endif
+
+/**
+ * vga_put - release lock on legacy VGA resources
+ *
+ * @pdev: pci device of VGA card or NULL for system default
+ * @rsrc: but mask of resource to release
+ *
+ * This function releases resources previously locked by vga_get()
+ * or vga_tryget(). The resources aren't disabled right away, so
+ * that a subsequence vga_get() on the same card will succeed
+ * immediately. Resources have a counter, so locks are only
+ * released if the counter reaches 0.
+ */
+
+#if defined(CONFIG_VGA_ARB)
+extern void vga_put(struct pci_dev *pdev, unsigned int rsrc);
+#else
+#define vga_put(pdev, rsrc)
+#endif
+
+
+/**
+ * vga_default_device
+ *
+ * This can be defined by the platform. The default implementation
+ * is rather dumb and will probably only work properly on single
+ * vga card setups and/or x86 platforms.
+ *
+ * If your VGA default device is not PCI, you'll have to return
+ * NULL here. In this case, I assume it will not conflict with
+ * any PCI card. If this is not true, I'll have to define two archs
+ * hooks for enabling/disabling the VGA default device if that is
+ * possible. This may be a problem with real _ISA_ VGA cards, in
+ * addition to a PCI one. I don't know at this point how to deal
+ * with that card. Can theirs IOs be disabled at all ? If not, then
+ * I suppose it's a matter of having the proper arch hook telling
+ * us about it, so we basically never allow anybody to succeed a
+ * vga_get()...
+ */
+
+#ifdef CONFIG_VGA_ARB
+extern struct pci_dev *vga_default_device(void);
+extern void vga_set_default_device(struct pci_dev *pdev);
+#else
+static inline struct pci_dev *vga_default_device(void) { return NULL; };
+static inline void vga_set_default_device(struct pci_dev *pdev) { };
+#endif
+
+/**
+ * vga_conflicts
+ *
+ * Architectures should define this if they have several
+ * independent PCI domains that can afford concurrent VGA
+ * decoding
+ */
+
+#ifndef __ARCH_HAS_VGA_CONFLICT
+static inline int vga_conflicts(struct pci_dev *p1, struct pci_dev *p2)
+{
+ return 1;
+}
+#endif
+
+/**
+ * vga_client_register
+ *
+ * @pdev: pci device of the VGA client
+ * @cookie: client cookie to be used in callbacks
+ * @irq_set_state: irq state change callback
+ * @set_vga_decode: vga decode change callback
+ *
+ * return value: 0 on success, -1 on failure
+ * Register a client with the VGA arbitration logic
+ *
+ * Clients have two callback mechanisms they can use.
+ * irq enable/disable callback -
+ * If a client can't disable its GPUs VGA resources, then we
+ * need to be able to ask it to turn off its irqs when we
+ * turn off its mem and io decoding.
+ * set_vga_decode
+ * If a client can disable its GPU VGA resource, it will
+ * get a callback from this to set the encode/decode state
+ *
+ * Rationale: we cannot disable VGA decode resources unconditionally
+ * some single GPU laptops seem to require ACPI or BIOS access to the
+ * VGA registers to control things like backlights etc.
+ * Hopefully newer multi-GPU laptops do something saner, and desktops
+ * won't have any special ACPI for this.
+ * They driver will get a callback when VGA arbitration is first used
+ * by userspace since we some older X servers have issues.
+ */
+#if defined(CONFIG_VGA_ARB)
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51501
+int vga_client_register(struct pci_dev *pdev,
+ unsigned int (*set_vga_decode)(struct pci_dev *pdev, bool state));
+#elif defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51500
+int vga_client_register(struct pci_dev *pdev, void *cookie,
+ unsigned int (*set_vga_decode)(void *cookie, bool state));
+#else
+int vga_client_register(struct pci_dev *pdev, void *cookie,
+ void (*irq_set_state)(void *cookie, bool state),
+ unsigned int (*set_vga_decode)(void *cookie, bool state));
+#endif
+#else
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51501
+static inline int vga_client_register(struct pci_dev *pdev,
+ unsigned int (*set_vga_decode)(struct pci_dev *pdev, bool state))
+#elif defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51500
+static inline int vga_client_register(struct pci_dev *pdev, void *cookie,
+ unsigned int (*set_vga_decode)(void *cookie, bool state))
+#else
+static inline int vga_client_register(struct pci_dev *pdev, void *cookie,
+ void (*irq_set_state)(void *cookie, bool state),
+ unsigned int (*set_vga_decode)(void *cookie, bool state))
+#endif
+{
+ return 0;
+}
+
+static inline int vga_client_unregister(struct pci_dev *pdev)
+{
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51501
+ return (vga_client_register(NULL, NULL));
+#elif defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51500
+ return (vga_client_register(NULL, NULL, NULL));
+#else
+ return (vga_client_register(NULL, NULL, NULL, NULL));
+#endif
+}
+#endif
+
+#endif /* _LINUXKPI_LINUX_VGA_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/vmalloc.h b/sys/compat/linuxkpi/common/include/linux/vmalloc.h
index 450db0f761f2..00650a2df9b6 100644
--- a/sys/compat/linuxkpi/common/include/linux/vmalloc.h
+++ b/sys/compat/linuxkpi/common/include/linux/vmalloc.h
@@ -25,12 +25,11 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_VMALLOC_H_
#define _LINUXKPI_LINUX_VMALLOC_H_
+#include <linux/overflow.h>
#include <linux/page.h>
#define VM_MAP 0x0000
diff --git a/sys/compat/linuxkpi/common/include/linux/wait.h b/sys/compat/linuxkpi/common/include/linux/wait.h
index 09cb5918b84b..d50003d44955 100644
--- a/sys/compat/linuxkpi/common/include/linux/wait.h
+++ b/sys/compat/linuxkpi/common/include/linux/wait.h
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_WAIT_H_
diff --git a/sys/compat/linuxkpi/common/include/linux/wait_bit.h b/sys/compat/linuxkpi/common/include/linux/wait_bit.h
index 66c1149da432..573798590b73 100644
--- a/sys/compat/linuxkpi/common/include/linux/wait_bit.h
+++ b/sys/compat/linuxkpi/common/include/linux/wait_bit.h
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef __LINUXKPI_LINUX_WAITBIT_H__
diff --git a/sys/compat/linuxkpi/common/include/linux/workqueue.h b/sys/compat/linuxkpi/common/include/linux/workqueue.h
index 7ced4270e1db..1c9df9fcb74d 100644
--- a/sys/compat/linuxkpi/common/include/linux/workqueue.h
+++ b/sys/compat/linuxkpi/common/include/linux/workqueue.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_WORKQUEUE_H_
#define _LINUXKPI_LINUX_WORKQUEUE_H_
@@ -190,6 +188,9 @@ do { \
#define delayed_work_pending(dwork) \
linux_work_pending(&(dwork)->work)
+#define cancel_work(work) \
+ linux_cancel_work(work)
+
#define cancel_delayed_work(dwork) \
linux_cancel_delayed_work(dwork)
@@ -245,6 +246,7 @@ 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);
+extern bool linux_cancel_work(struct work_struct *);
extern bool linux_cancel_delayed_work(struct delayed_work *);
extern bool linux_cancel_work_sync(struct work_struct *);
extern bool linux_cancel_delayed_work_sync(struct delayed_work *);
diff --git a/sys/compat/linuxkpi/common/include/linux/ww_mutex.h b/sys/compat/linuxkpi/common/include/linux/ww_mutex.h
index 82ba7a55a7e8..9219755bb78e 100644
--- a/sys/compat/linuxkpi/common/include/linux/ww_mutex.h
+++ b/sys/compat/linuxkpi/common/include/linux/ww_mutex.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_WW_MUTEX_H_
#define _LINUXKPI_LINUX_WW_MUTEX_H_
@@ -61,6 +59,8 @@ struct ww_mutex {
} \
SYSINIT(name, SI_SUB_LOCK, SI_ORDER_SECOND, name##_init, NULL)
+#define DEFINE_WD_CLASS(name) DEFINE_WW_CLASS(name)
+
#define ww_mutex_is_locked(_m) \
sx_xlocked(&(_m)->base.sx)
@@ -70,8 +70,13 @@ struct ww_mutex {
#define ww_mutex_lock_slow_interruptible(_m, _x) \
ww_mutex_lock_interruptible(_m, _x)
+#if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51600
+static inline int __must_check
+ww_mutex_trylock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx __unused)
+#else
static inline int __must_check
ww_mutex_trylock(struct ww_mutex *lock)
+#endif
{
return (mutex_trylock(&lock->base));
}
diff --git a/sys/compat/linuxkpi/common/include/linux/xarray.h b/sys/compat/linuxkpi/common/include/linux/xarray.h
index 408906867479..d293a8f7c2a3 100644
--- a/sys/compat/linuxkpi/common/include/linux/xarray.h
+++ b/sys/compat/linuxkpi/common/include/linux/xarray.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_LINUX_XARRAY_H_
#define _LINUXKPI_LINUX_XARRAY_H_
@@ -31,6 +29,7 @@
#include <linux/gfp.h>
#include <linux/radix-tree.h>
#include <linux/err.h>
+#include <linux/kconfig.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@@ -45,6 +44,9 @@
#define XA_ERROR(x) \
ERR_PTR(x)
+#define xa_is_err(x) \
+ IS_ERR(x)
+
#define xa_limit_32b XA_LIMIT(0, 0xFFFFFFFF)
#define XA_ASSERT_LOCKED(xa) mtx_assert(&(xa)->mtx, MA_OWNED)
@@ -87,6 +89,27 @@ void *__xa_store(struct xarray *, uint32_t, void *, gfp_t);
bool __xa_empty(struct xarray *);
void *__xa_next(struct xarray *, unsigned long *, bool);
+#define xa_store_irq(xa, index, ptr, gfp) \
+ xa_store((xa), (index), (ptr), (gfp))
+
+#define xa_erase_irq(xa, index) \
+ xa_erase((xa), (index))
+
+#define xa_lock_irq(xa) xa_lock(xa)
+#define xa_unlock_irq(xa) xa_unlock(xa)
+
+#define xa_lock_irqsave(xa, flags) \
+ do { \
+ xa_lock((xa)); \
+ flags = 0; \
+ } while (0)
+
+#define xa_unlock_irqrestore(xa, flags) \
+ do { \
+ xa_unlock((xa)); \
+ flags == 0; \
+ } while (0)
+
static inline int
xa_err(void *ptr)
{
diff --git a/sys/compat/linuxkpi/common/include/net/addrconf.h b/sys/compat/linuxkpi/common/include/net/addrconf.h
index 41cfd21db5be..33c07792d807 100644
--- a/sys/compat/linuxkpi/common/include/net/addrconf.h
+++ b/sys/compat/linuxkpi/common/include/net/addrconf.h
@@ -26,8 +26,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_NET_ADDRCONF_H
diff --git a/sys/compat/linuxkpi/common/include/net/cfg80211.h b/sys/compat/linuxkpi/common/include/net/cfg80211.h
index 15040ead3707..7e57ce67cc26 100644
--- a/sys/compat/linuxkpi/common/include/net/cfg80211.h
+++ b/sys/compat/linuxkpi/common/include/net/cfg80211.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2020-2021 The FreeBSD Foundation
+ * Copyright (c) 2020-2023 The FreeBSD Foundation
* Copyright (c) 2021-2022 Bjoern A. Zeeb
*
* This software was developed by Björn Zeeb under sponsorship from
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_NET_CFG80211_H
@@ -51,7 +49,7 @@ extern int linuxkpi_debug_80211;
#ifndef D80211_IMPROVE
#define D80211_IMPROVE 0x2
#endif
-#define TODO() if (linuxkpi_debug_80211 & D80211_TODO) \
+#define TODO(...) if (linuxkpi_debug_80211 & D80211_TODO) \
printf("%s:%d: XXX LKPI80211 TODO\n", __func__, __LINE__)
#define IMPROVE(...) if (linuxkpi_debug_80211 & D80211_IMPROVE) \
printf("%s:%d: XXX LKPI80211 IMPROVE\n", __func__, __LINE__)
@@ -72,10 +70,12 @@ enum rfkill_hard_block_reasons {
#define IEEE80211_MAX_CHAINS 4 /* net80211: IEEE80211_MAX_CHAINS copied */
enum cfg80211_rate_info_flags {
- RATE_INFO_FLAGS_SHORT_GI = BIT(0),
- RATE_INFO_FLAGS_MCS = BIT(1),
- RATE_INFO_FLAGS_VHT_MCS = BIT(2),
- RATE_INFO_FLAGS_HE_MCS = BIT(3),
+ RATE_INFO_FLAGS_MCS = BIT(0),
+ RATE_INFO_FLAGS_VHT_MCS = BIT(1),
+ RATE_INFO_FLAGS_SHORT_GI = BIT(2),
+ RATE_INFO_FLAGS_HE_MCS = BIT(4),
+ RATE_INFO_FLAGS_EHT_MCS = BIT(7),
+ /* Max 8 bits as used in struct rate_info. */
};
extern const uint8_t rfc1042_header[6];
@@ -129,23 +129,16 @@ struct linuxkpi_ieee80211_channel {
int orig_mpwr;
};
-enum ieee80211_vht_mcs_support {
- LKPI_IEEE80211_VHT_MCS_SUPPORT_0_7,
- LKPI_IEEE80211_VHT_MCS_SUPPORT_0_8,
- LKPI_IEEE80211_VHT_MCS_SUPPORT_0_9,
-};
-
struct cfg80211_bitrate_mask {
/* TODO FIXME */
- /* This is so weird but nothing else works out...*/
struct {
- uint64_t legacy; /* XXX? */
+ uint32_t legacy;
uint8_t ht_mcs[IEEE80211_HT_MCS_MASK_LEN];
- uint16_t vht_mcs[16]; /* XXX? */
- uint16_t he_mcs[16]; /* XXX? */
+ uint16_t vht_mcs[8];
+ uint16_t he_mcs[8];
enum nl80211_txrate_gi gi;
enum nl80211_he_gi he_gi;
- uint8_t he_ltf;
+ uint8_t he_ltf; /* XXX enum? */
} control[NUM_NL80211_BANDS];
};
@@ -157,11 +150,20 @@ enum rate_info_bw {
RATE_INFO_BW_80,
RATE_INFO_BW_160,
RATE_INFO_BW_HE_RU,
+ RATE_INFO_BW_320,
+ RATE_INFO_BW_EHT_RU,
};
struct rate_info {
- /* TODO FIXME */
- int bw, flags, he_dcm, he_gi, he_ru_alloc, legacy, mcs, nss;
+ uint8_t flags; /* enum cfg80211_rate_info_flags */
+ uint8_t bw;
+ uint16_t legacy;
+ uint8_t mcs;
+ uint8_t nss;
+ uint8_t he_dcm;
+ uint8_t he_gi;
+ uint8_t he_ru_alloc;
+ uint8_t eht_gi;
};
struct ieee80211_rate {
@@ -173,9 +175,9 @@ struct ieee80211_rate {
};
struct ieee80211_sta_ht_cap {
- /* TODO FIXME */
- int ampdu_density, ampdu_factor;
bool ht_supported;
+ uint8_t ampdu_density;
+ uint8_t ampdu_factor;
uint16_t cap;
struct ieee80211_mcs_info mcs;
};
@@ -226,12 +228,13 @@ struct ieee80211_sta_ht_cap {
#define IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK \
(7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT) /* IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK */
+#define IEEE80211_VHT_CAP_EXT_NSS_BW_MASK 0xc0000000
struct ieee80211_sta_vht_cap {
/* TODO FIXME */
- bool vht_supported;
- uint32_t cap;
- struct vht_mcs vht_mcs;
+ bool vht_supported;
+ uint32_t cap;
+ struct ieee80211_vht_mcs_info vht_mcs;
};
enum ieee80211_vht_opmode {
@@ -265,9 +268,8 @@ struct cfg80211_roam_info {
};
struct cfg80211_bss_ies {
- /* XXX TODO, type is best guess. Fix if more info. */
uint8_t *data;
- int len;
+ size_t len;
};
struct cfg80211_bss {
@@ -365,7 +367,7 @@ struct cfg80211_ssid {
struct cfg80211_scan_6ghz_params {
/* XXX TODO */
uint8_t *bssid;
- int channel_idx, psc_no_listen, short_ssid, short_ssid_valid, unsolicited_probe;
+ int channel_idx, psc_no_listen, short_ssid, short_ssid_valid, unsolicited_probe, psd_20;
};
struct cfg80211_match_set {
@@ -520,33 +522,6 @@ struct cfg80211_pmksa {
const uint8_t *pmkid;
};
-struct cfg80211_wowlan_nd_match {
- /* XXX TODO */
- struct cfg80211_ssid ssid;
- int n_channels;
- uint32_t channels[0]; /* freq! = ieee80211_channel_to_frequency() */
-};
-
-struct cfg80211_wowlan_nd_info {
- /* XXX TODO */
- int n_matches;
- struct cfg80211_wowlan_nd_match *matches[0];
-};
-
-enum wiphy_wowlan_support_flags {
- WIPHY_WOWLAN_DISCONNECT,
- WIPHY_WOWLAN_GTK_REKEY_FAILURE,
- WIPHY_WOWLAN_MAGIC_PKT,
- WIPHY_WOWLAN_SUPPORTS_GTK_REKEY,
- WIPHY_WOWLAN_NET_DETECT,
-};
-
-struct wiphy_wowlan_support {
- /* XXX TODO */
- enum wiphy_wowlan_support_flags flags;
- int max_nd_match_sets, max_pkt_offset, n_patterns, pattern_max_len, pattern_min_len;
-};
-
struct station_del_parameters {
/* XXX TODO */
const uint8_t *mac;
@@ -558,7 +533,8 @@ struct station_info {
int assoc_req_ies_len, connected_time;
int generation, inactive_time, rx_bytes, rx_dropped_misc, rx_packets, signal, tx_bytes, tx_packets;
int filled, rx_beacon, rx_beacon_signal_avg, signal_avg;
- int rx_duration, tx_failed, tx_retries;
+ int rx_duration, tx_duration, tx_failed, tx_retries;
+ int ack_signal, avg_ack_signal;
int chains;
uint8_t chain_signal[IEEE80211_MAX_CHAINS];
@@ -603,6 +579,7 @@ struct mac_address {
struct ieee80211_reg_rule {
/* TODO FIXME */
uint32_t flags;
+ int dfs_cac_ms;
struct freq_range {
int start_freq_khz;
int end_freq_khz;
@@ -641,15 +618,14 @@ struct linuxkpi_ieee80211_regdomain {
#define IEEE80211_HE_MAC_CAP2_MU_CASCADING 0x40
#define IEEE80211_HE_MAC_CAP2_TRS 0x80
-#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2 0x1
-#define IEEE80211_HE_MAC_CAP3_OMI_CONTROL 0x2
-#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_1 0x10
-#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2 0x20
-#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3 0x40
-#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK 0x70
+#define IEEE80211_HE_MAC_CAP3_OMI_CONTROL 0x02
+#define IEEE80211_HE_MAC_CAP3_OFDMA_RA 0x04
+#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_1 0x08
+#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2 0x10
+#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3 0x18
+#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK 0x18
+#define IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED 0x40
#define IEEE80211_HE_MAC_CAP3_RX_CTRL_FRAME_TO_MULTIBSS 0x80
-#define IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED 0x80
-#define IEEE80211_HE_MAC_CAP3_OFDMA_RA 0x80
#define IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU 0x1
#define IEEE80211_HE_MAC_CAP4_BQR 0x2
@@ -678,7 +654,6 @@ struct linuxkpi_ieee80211_regdomain {
#define IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN 0x08
#define IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP 0x10
#define IEEE80211_HE_6GHZ_CAP_SM_PS 0x20
-#define IEEE80211_HE_6GHZ_MAX_AMPDU_FACTOR 0x40
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G 0x1
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G 0x2
@@ -687,6 +662,7 @@ struct linuxkpi_ieee80211_regdomain {
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G 0x10
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G 0x20
#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK 0x40
+#define IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL 0xff
#define IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A 0x1
#define IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD 0x2
@@ -782,6 +758,97 @@ struct linuxkpi_ieee80211_regdomain {
#define IEEE80211_HE_PHY_CAP10_HE_MU_M1RU_MAX_LTF 0x1
+#define IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED 0x1
+#define IEEE80211_HE_OPERATION_BSS_COLOR_OFFSET 0x2
+#define IEEE80211_HE_OPERATION_ER_SU_DISABLE 0x4
+
+#define IEEE80211_HE_SPR_HESIGA_SR_VAL15_ALLOWED 0x01
+#define IEEE80211_HE_SPR_NON_SRG_OBSS_PD_SR_DISALLOWED 0x02
+#define IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT 0x04
+#define IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT 0x08
+
+#define IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS 0x01
+#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454 0x02
+#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK 0x03
+#define IEEE80211_EHT_MAC_CAP0_OM_CONTROL 0x04
+#define IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 0x05
+#define IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2 0x06
+#define IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_7991 0x07
+
+#define IEEE80211_EHT_MAC_CAP1_MAX_AMPDU_LEN_MASK 0x01
+
+#define IEEE80211_EHT_MCS_NSS_RX 0x01
+#define IEEE80211_EHT_MCS_NSS_TX 0x02
+
+#define IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ 0x01
+#define IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ 0x02
+#define IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK 0x03
+#define IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI 0x04
+#define IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO 0x05
+#define IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE 0x06
+#define IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER 0x07
+
+#define IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK 0x01
+#define IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK 0x02
+#define IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK 0x03
+
+#define IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK 0x01
+#define IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK 0x02
+#define IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK 0x03
+
+#define IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK 0x01
+#define IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK 0x02
+#define IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK 0x03
+#define IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK 0x04
+#define IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK 0x05
+#define IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK 0x06
+#define IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK 0x07
+#define IEEE80211_EHT_PHY_CAP3_SOUNDING_DIM_320MHZ_MASK 0x08
+
+#define IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI 0x01
+#define IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO 0x02
+#define IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP 0x03
+#define IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK 0x04
+
+#define IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_0US 0x01
+#define IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_16US 0x02
+#define IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_20US 0x03
+#define IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_8US 0x04
+#define IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK 0x05
+#define IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK 0x06
+#define IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT 0x07
+#define IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP 0x08
+#define IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP 0x09
+#define IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK 0x0a
+#define IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF 0x0b
+
+#define IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP 0x01
+#define IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK 0x02
+#define IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK 0x03
+
+#define IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ 0x01
+#define IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ 0x02
+#define IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ 0x03
+#define IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ 0x04
+#define IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ 0x05
+#define IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ 0x06
+
+#define IEEE80211_EHT_PHY_CAP8_RX_1024QAM_WIDER_BW_DL_OFDMA 0x01
+#define IEEE80211_EHT_PHY_CAP8_RX_4096QAM_WIDER_BW_DL_OFDMA 0x02
+
+#define IEEE80211_EHT_PPE_THRES_INFO_HEADER_SIZE 0x01
+#define IEEE80211_EHT_PPE_THRES_NSS_MASK 0x02
+#define IEEE80211_EHT_PPE_THRES_RU_INDEX_BITMASK_MASK 0x03
+#define IEEE80211_EHT_PPE_THRES_INFO_PPET_SIZE 0x04
+
+#define IEEE80211_EML_CAP_EMLSR_SUPP 0x01
+#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT 0x02
+#define IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128TU 0x04
+#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY 0x08
+#define IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_32US 0x10
+#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY 0x20
+#define IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_64US 0x40
+
#define VENDOR_CMD_RAW_DATA (void *)(uintptr_t)(-ENOENT)
struct ieee80211_he_cap_elem {
@@ -814,6 +881,12 @@ struct cfg80211_he_bss_color {
struct ieee80211_he_obss_pd {
bool enable;
+ uint8_t min_offset;
+ uint8_t max_offset;
+ uint8_t non_srg_max_offset;
+ uint8_t sr_ctrl;
+ uint8_t bss_color_bitmap[8];
+ uint8_t partial_bssid_bitmap[8];
};
struct ieee80211_sta_he_6ghz_capa {
@@ -821,11 +894,51 @@ struct ieee80211_sta_he_6ghz_capa {
int capa;
};
+struct ieee80211_eht_mcs_nss_supp_20mhz_only {
+ uint8_t rx_tx_mcs7_max_nss;
+ uint8_t rx_tx_mcs9_max_nss;
+ uint8_t rx_tx_mcs11_max_nss;
+ uint8_t rx_tx_mcs13_max_nss;
+};
+
+struct ieee80211_eht_mcs_nss_supp_bw {
+ uint8_t rx_tx_mcs9_max_nss;
+ uint8_t rx_tx_mcs11_max_nss;
+ uint8_t rx_tx_mcs13_max_nss;
+};
+
+struct ieee80211_eht_cap_elem_fixed {
+ uint8_t mac_cap_info[2];
+ uint8_t phy_cap_info[9];
+};
+
+struct ieee80211_eht_mcs_nss_supp {
+ /* TODO FIXME */
+ /* Can only have either or... */
+ union {
+ struct ieee80211_eht_mcs_nss_supp_20mhz_only only_20mhz;
+ struct {
+ struct ieee80211_eht_mcs_nss_supp_bw _80;
+ struct ieee80211_eht_mcs_nss_supp_bw _160;
+ struct ieee80211_eht_mcs_nss_supp_bw _320;
+ } bw;
+ };
+};
+
+#define IEEE80211_STA_EHT_PPE_THRES_MAX 32
+struct ieee80211_sta_eht_cap {
+ bool has_eht;
+ struct ieee80211_eht_cap_elem_fixed eht_cap_elem;
+ struct ieee80211_eht_mcs_nss_supp eht_mcs_nss_supp;
+ uint8_t eht_ppe_thres[IEEE80211_STA_EHT_PPE_THRES_MAX];
+};
+
struct ieee80211_sband_iftype_data {
/* TODO FIXME */
enum nl80211_iftype types_mask;
struct ieee80211_sta_he_cap he_cap;
struct ieee80211_sta_he_6ghz_capa he_6ghz_capa;
+ struct ieee80211_sta_eht_cap eht_cap;
struct {
const uint8_t *data;
size_t len;
@@ -853,9 +966,56 @@ struct cfg80211_pkt_pattern {
int pkt_offset;
};
+struct cfg80211_wowlan_nd_match {
+ /* XXX TODO */
+ struct cfg80211_ssid ssid;
+ int n_channels;
+ uint32_t channels[0]; /* freq! = ieee80211_channel_to_frequency() */
+};
+
+struct cfg80211_wowlan_nd_info {
+ /* XXX TODO */
+ int n_matches;
+ struct cfg80211_wowlan_nd_match *matches[0];
+};
+
+enum wiphy_wowlan_support_flags {
+ WIPHY_WOWLAN_DISCONNECT,
+ WIPHY_WOWLAN_GTK_REKEY_FAILURE,
+ WIPHY_WOWLAN_MAGIC_PKT,
+ WIPHY_WOWLAN_SUPPORTS_GTK_REKEY,
+ WIPHY_WOWLAN_NET_DETECT,
+};
+
+struct wiphy_wowlan_support {
+ /* XXX TODO */
+ enum wiphy_wowlan_support_flags flags;
+ int max_nd_match_sets, max_pkt_offset, n_patterns, pattern_max_len, pattern_min_len;
+};
+
+struct cfg80211_wowlan_wakeup {
+ /* XXX TODO */
+ uint16_t pattern_idx;
+ bool disconnect;
+ bool eap_identity_req;
+ bool four_way_handshake;
+ bool gtk_rekey_failure;
+ bool magic_pkt;
+ bool rfkill_release;
+ bool tcp_connlost;
+ bool tcp_nomoretokens;
+ bool tcp_match;
+ bool packet_80211;
+ struct cfg80211_wowlan_nd_info *net_detect;
+ uint8_t *packet;
+ uint16_t packet_len;
+ uint16_t packet_present_len;
+};
+
struct cfg80211_wowlan {
/* XXX TODO */
int disconnect, gtk_rekey_failure, magic_pkt;
+ int eap_identity_req, four_way_handshake, rfkill_release, tcp, any;
int n_patterns;
struct cfg80211_sched_scan_request *nd_config;
struct cfg80211_pkt_pattern *patterns;
@@ -863,12 +1023,14 @@ struct cfg80211_wowlan {
struct cfg80211_gtk_rekey_data {
/* XXX TODO */
- int kck, kek, replay_ctr;
+ const uint8_t *kck, *kek, *replay_ctr;
+ uint32_t akm;
+ uint8_t kck_len, kek_len;
};
struct cfg80211_tid_cfg {
/* XXX TODO */
- int mask, noack, retry_long, rtscts, tids;
+ int mask, noack, retry_long, rtscts, tids, amsdu, ampdu;
enum nl80211_tx_rate_setting txrate_type;
struct cfg80211_bitrate_mask txrate_mask;
};
@@ -901,7 +1063,14 @@ struct iface_combination_params {
struct regulatory_request {
/* XXX TODO */
uint8_t alpha2[2];
+ enum environment_cap country_ie_env;
int initiator, dfs_region;
+ int user_reg_hint_type;
+};
+
+struct cfg80211_set_hw_timestamp {
+ const uint8_t *macaddr;
+ bool enable;
};
enum wiphy_vendor_cmd_need_flags {
@@ -926,6 +1095,7 @@ struct wiphy_iftype_ext_capab {
const uint8_t *extended_capabilities;
const uint8_t *extended_capabilities_mask;
uint8_t extended_capabilities_len;
+ uint16_t eml_capabilities;
};
@@ -962,6 +1132,7 @@ enum wiphy_flags {
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD = BIT(13),
WIPHY_FLAG_4ADDR_AP = BIT(14),
WIPHY_FLAG_4ADDR_STATION = BIT(15),
+ WIPHY_FLAG_SUPPORTS_MLO = BIT(16),
};
struct wiphy {
@@ -972,6 +1143,7 @@ struct wiphy {
uint32_t flags;
struct ieee80211_supported_band *bands[NUM_NL80211_BANDS];
uint8_t perm_addr[ETH_ALEN];
+ uint16_t max_scan_ie_len;
/* XXX TODO */
const struct cfg80211_pmsr_capabilities *pmsr_capa;
@@ -991,16 +1163,19 @@ struct wiphy {
uint32_t rts_threshold;
uint32_t frag_threshold;
struct tid_config_support tid_config_support;
+ uint8_t available_antennas_rx;
+ uint8_t available_antennas_tx;
- int available_antennas_rx, available_antennas_tx;
int features, hw_version;
- int interface_modes, max_match_sets, max_remain_on_channel_duration, max_scan_ie_len, max_scan_ssids, max_sched_scan_ie_len, max_sched_scan_plan_interval, max_sched_scan_plan_iterations, max_sched_scan_plans, max_sched_scan_reqs, max_sched_scan_ssids;
+ int interface_modes, max_match_sets, max_remain_on_channel_duration, max_scan_ssids, max_sched_scan_ie_len, max_sched_scan_plan_interval, max_sched_scan_plan_iterations, max_sched_scan_plans, max_sched_scan_reqs, max_sched_scan_ssids;
int num_iftype_ext_capab;
int max_ap_assoc_sta, probe_resp_offload, software_iftypes;
int bss_select_support, max_num_pmkids, retry_long, retry_short, signal_type;
int max_data_retry_count;
int tx_queue_len, rfkill;
int mbssid_max_interfaces;
+ int hw_timestamp_max_peers;
+ int ema_max_profile_periodicity;
unsigned long ext_features[BITS_TO_LONGS(NUM_NL80211_EXT_FEATURES)];
struct dentry *debugfsdir;
@@ -1080,7 +1255,13 @@ uint32_t linuxkpi_ieee80211_channel_to_frequency(uint32_t, enum nl80211_band);
uint32_t linuxkpi_ieee80211_frequency_to_channel(uint32_t, uint32_t);
struct linuxkpi_ieee80211_channel *
linuxkpi_ieee80211_get_channel(struct wiphy *, uint32_t);
+struct cfg80211_bss *linuxkpi_cfg80211_get_bss(struct wiphy *,
+ struct linuxkpi_ieee80211_channel *, const uint8_t *,
+ const uint8_t *, size_t, enum ieee80211_bss_type, enum ieee80211_privacy);
+void linuxkpi_cfg80211_put_bss(struct wiphy *, struct cfg80211_bss *);
void linuxkpi_cfg80211_bss_flush(struct wiphy *);
+struct linuxkpi_ieee80211_regdomain *
+ lkpi_get_linuxkpi_ieee80211_regdomain(size_t);
/* -------------------------------------------------------------------------- */
@@ -1151,6 +1332,32 @@ wiphy_rfkill_set_hw_state_reason(struct wiphy *wiphy, bool blocked,
/* -------------------------------------------------------------------------- */
+static inline struct cfg80211_bss *
+cfg80211_get_bss(struct wiphy *wiphy, struct linuxkpi_ieee80211_channel *chan,
+ const uint8_t *bssid, const uint8_t *ssid, size_t ssid_len,
+ enum ieee80211_bss_type bss_type, enum ieee80211_privacy privacy)
+{
+
+ return (linuxkpi_cfg80211_get_bss(wiphy, chan, bssid, ssid, ssid_len,
+ bss_type, privacy));
+}
+
+static inline void
+cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *bss)
+{
+
+ linuxkpi_cfg80211_put_bss(wiphy, bss);
+}
+
+static inline void
+cfg80211_bss_flush(struct wiphy *wiphy)
+{
+
+ linuxkpi_cfg80211_bss_flush(wiphy);
+}
+
+/* -------------------------------------------------------------------------- */
+
static __inline bool
rfkill_blocked(int rfkill) /* argument type? */
{
@@ -1224,6 +1431,7 @@ cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
chandef->center_freq1 = chan->center_freq;
break;
default:
+ IMPROVE("Also depends on our manual settings");
if (chan->flags & IEEE80211_CHAN_NO_HT40)
chandef->width = NL80211_CHAN_WIDTH_20;
else if (chan->flags & IEEE80211_CHAN_NO_80MHZ)
@@ -1252,13 +1460,75 @@ struct element {
uint8_t data[0];
} __packed;
-static __inline const struct element *
-cfg80211_find_elem(enum ieee80211_eid eid, uint8_t *data, size_t len)
-{
- TODO();
+static inline const struct element *
+lkpi_cfg80211_find_elem_pattern(enum ieee80211_eid eid,
+ const uint8_t *data, size_t len, uint8_t *pattern, size_t plen)
+{
+ const struct element *elem;
+ const uint8_t *p;
+ size_t ielen;
+
+ p = data;
+ elem = (const struct element *)p;
+ ielen = len;
+ while (elem != NULL && ielen > 1) {
+ if ((2 + elem->datalen) > ielen)
+ /* Element overruns our memory. */
+ return (NULL);
+ if (elem->id == eid) {
+ if (pattern == NULL)
+ return (elem);
+ if (elem->datalen >= plen &&
+ memcmp(elem->data, pattern, plen) == 0)
+ return (elem);
+ }
+ ielen -= 2 + elem->datalen;
+ p += 2 + elem->datalen;
+ elem = (const struct element *)p;
+ }
+
return (NULL);
}
+static inline const struct element *
+cfg80211_find_elem(enum ieee80211_eid eid, const uint8_t *data, size_t len)
+{
+
+ return (lkpi_cfg80211_find_elem_pattern(eid, data, len, NULL, 0));
+}
+
+static inline const struct element *
+ieee80211_bss_get_elem(struct cfg80211_bss *bss, uint32_t eid)
+{
+
+ if (bss->ies == NULL)
+ return (NULL);
+ return (cfg80211_find_elem(eid, bss->ies->data, bss->ies->len));
+}
+
+static inline const uint8_t *
+ieee80211_bss_get_ie(struct cfg80211_bss *bss, uint32_t eid)
+{
+
+ return ((const uint8_t *)ieee80211_bss_get_elem(bss, eid));
+}
+
+static inline uint8_t *
+cfg80211_find_vendor_ie(unsigned int oui, int oui_type,
+ uint8_t *data, size_t len)
+{
+ const struct element *elem;
+ uint8_t pattern[4] = { oui << 16, oui << 8, oui, oui_type };
+ uint8_t plen = 4; /* >= 3? oui_type always part of this? */
+ IMPROVE("plen currently always incl. oui_type");
+
+ elem = lkpi_cfg80211_find_elem_pattern(IEEE80211_ELEMID_VENDOR,
+ data, len, pattern, plen);
+ if (elem == NULL)
+ return (NULL);
+ return (__DECONST(uint8_t *, elem));
+}
+
static __inline uint32_t
cfg80211_calculate_bitrate(struct rate_info *rate)
{
@@ -1319,8 +1589,22 @@ regulatory_set_wiphy_regd(struct wiphy *wiphy,
static __inline int
regulatory_hint(struct wiphy *wiphy, const uint8_t *alpha2)
{
- TODO();
- return (-ENXIO);
+ struct linuxkpi_ieee80211_regdomain *regd;
+
+ if (wiphy->regd != NULL)
+ return (-EBUSY);
+
+ regd = lkpi_get_linuxkpi_ieee80211_regdomain(0);
+ if (regd == NULL)
+ return (-ENOMEM);
+
+ regd->alpha2[0] = alpha2[0];
+ regd->alpha2[1] = alpha2[1];
+ wiphy->regd = regd;
+
+ IMPROVE("are there flags who is managing? update net8011?");
+
+ return (0);
}
static __inline const char *
@@ -1344,20 +1628,6 @@ freq_reg_info(struct wiphy *wiphy, uint32_t center_freq)
return (NULL);
}
-static __inline struct cfg80211_bss *
-cfg80211_get_bss(struct wiphy *wiphy, struct linuxkpi_ieee80211_channel *chan,
- uint8_t *bssid, void *p, int x, uint32_t f1, uint32_t f2)
-{
- TODO();
- return (NULL);
-}
-
-static __inline void
-cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *bss)
-{
- TODO();
-}
-
static __inline void
wiphy_apply_custom_regulatory(struct wiphy *wiphy,
const struct linuxkpi_ieee80211_regdomain *regd)
@@ -1384,14 +1654,6 @@ wiphy_read_of_freq_limits(struct wiphy *wiphy)
#endif
}
-static __inline uint8_t *
-cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
- uint8_t *data, size_t len)
-{
- TODO();
- return (NULL);
-}
-
static __inline void
wiphy_ext_feature_set(struct wiphy *wiphy, enum nl80211_ext_feature ef)
{
@@ -1611,19 +1873,23 @@ ieee80211_get_channel(struct wiphy *wiphy, uint32_t freq)
return (linuxkpi_ieee80211_get_channel(wiphy, freq));
}
-static __inline size_t
+static inline size_t
ieee80211_get_hdrlen_from_skb(struct sk_buff *skb)
{
+ const struct ieee80211_hdr *hdr;
+ size_t len;
- TODO();
- return (-1);
-}
+ if (skb->len < 10) /* sizeof(ieee80211_frame_[ack,cts]) */
+ return (0);
-static __inline void
-cfg80211_bss_flush(struct wiphy *wiphy)
-{
+ hdr = (const struct ieee80211_hdr *)skb->data;
+ len = ieee80211_hdrlen(hdr->frame_control);
- linuxkpi_cfg80211_bss_flush(wiphy);
+ /* If larger than what is in the skb return. */
+ if (len > skb->len)
+ return (0);
+
+ return (len);
}
static __inline bool
@@ -1638,12 +1904,36 @@ cfg80211_channel_is_psc(struct linuxkpi_ieee80211_channel *channel)
return (false);
}
-static __inline int
+static inline int
cfg80211_get_ies_channel_number(const uint8_t *ie, size_t len,
enum nl80211_band band, enum cfg80211_bss_frame_type ftype)
{
+ const struct element *elem;
- TODO();
+ switch (band) {
+ case NL80211_BAND_6GHZ:
+ TODO();
+ break;
+ case NL80211_BAND_5GHZ:
+ case NL80211_BAND_2GHZ:
+ /* DSPARAMS has the channel number. */
+ elem = cfg80211_find_elem(IEEE80211_ELEMID_DSPARMS, ie, len);
+ if (elem != NULL && elem->datalen == 1)
+ return (elem->data[0]);
+ /* HTINFO has the primary center channel. */
+ elem = cfg80211_find_elem(IEEE80211_ELEMID_HTINFO, ie, len);
+ if (elem != NULL &&
+ elem->datalen >= (sizeof(struct ieee80211_ie_htinfo) - 2)) {
+ const struct ieee80211_ie_htinfo *htinfo;
+ htinfo = (const struct ieee80211_ie_htinfo *)elem;
+ return (htinfo->hi_ctrlchannel);
+ }
+ /* What else? */
+ break;
+ default:
+ IMPROVE("Unsupported");
+ break;
+ }
return (-1);
}
@@ -1681,7 +1971,7 @@ cfg80211_background_radar_event(struct wiphy *wiphy,
}
static __inline const u8 *
-cfg80211_find_ext_ie(uint8_t eid, uint8_t *p, size_t len)
+cfg80211_find_ext_ie(uint8_t eid, const uint8_t *p, size_t len)
{
TODO();
return (NULL);
@@ -1694,25 +1984,22 @@ cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
return (false);
}
+static __inline const struct ieee80211_sta_eht_cap *
+ieee80211_get_eht_iftype_cap(const struct ieee80211_supported_band *band,
+ enum nl80211_iftype iftype)
+{
+ TODO();
+ return (NULL);
+}
+
#define wiphy_info(wiphy, fmt, ...) \
printf("%s:%d XXX TODO " fmt, __func__, __LINE__, __VA_ARGS__)
#ifndef LINUXKPI_NET80211
#define ieee80211_channel linuxkpi_ieee80211_channel
#define ieee80211_regdomain linuxkpi_ieee80211_regdomain
-/* net80211::IEEE80211_VHT_MCS_SUPPORT_0_n() conflicts */
-#if defined(IEEE80211_VHT_MCS_SUPPORT_0_7)
-#undef IEEE80211_VHT_MCS_SUPPORT_0_7
-#endif
-#if defined(IEEE80211_VHT_MCS_SUPPORT_0_8)
-#undef IEEE80211_VHT_MCS_SUPPORT_0_8
-#endif
-#if defined(IEEE80211_VHT_MCS_SUPPORT_0_9)
-#undef IEEE80211_VHT_MCS_SUPPORT_0_9
-#endif
-#define IEEE80211_VHT_MCS_SUPPORT_0_7 LKPI_IEEE80211_VHT_MCS_SUPPORT_0_7
-#define IEEE80211_VHT_MCS_SUPPORT_0_8 LKPI_IEEE80211_VHT_MCS_SUPPORT_0_8
-#define IEEE80211_VHT_MCS_SUPPORT_0_9 LKPI_IEEE80211_VHT_MCS_SUPPORT_0_9
#endif
+#include <net/mac80211.h>
+
#endif /* _LINUXKPI_NET_CFG80211_H */
diff --git a/sys/compat/linuxkpi/common/include/net/ieee80211_radiotap.h b/sys/compat/linuxkpi/common/include/net/ieee80211_radiotap.h
index 932c0b037026..82e554f6b96e 100644
--- a/sys/compat/linuxkpi/common/include/net/ieee80211_radiotap.h
+++ b/sys/compat/linuxkpi/common/include/net/ieee80211_radiotap.h
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_NET_IEEE80211_RADIOTAP_H
diff --git a/sys/compat/linuxkpi/common/include/net/if_inet6.h b/sys/compat/linuxkpi/common/include/net/if_inet6.h
index d4a16d967ecf..c340909d7098 100644
--- a/sys/compat/linuxkpi/common/include/net/if_inet6.h
+++ b/sys/compat/linuxkpi/common/include/net/if_inet6.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_NET_IF_INET6_H_
#define _LINUXKPI_NET_IF_INET6_H_
diff --git a/sys/compat/linuxkpi/common/include/net/ip.h b/sys/compat/linuxkpi/common/include/net/ip.h
index 6fadfd92b8e8..3e7baab6cc0b 100644
--- a/sys/compat/linuxkpi/common/include/net/ip.h
+++ b/sys/compat/linuxkpi/common/include/net/ip.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_NET_IP_H_
#define _LINUXKPI_NET_IP_H_
diff --git a/sys/compat/linuxkpi/common/include/net/ipv6.h b/sys/compat/linuxkpi/common/include/net/ipv6.h
index bf29a28a9a46..3a85781e3a49 100644
--- a/sys/compat/linuxkpi/common/include/net/ipv6.h
+++ b/sys/compat/linuxkpi/common/include/net/ipv6.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_NET_IPV6_H_
#define _LINUXKPI_NET_IPV6_H_
diff --git a/sys/compat/linuxkpi/common/include/net/mac80211.h b/sys/compat/linuxkpi/common/include/net/mac80211.h
index 4320edc90eba..fc9d7829dae3 100644
--- a/sys/compat/linuxkpi/common/include/net/mac80211.h
+++ b/sys/compat/linuxkpi/common/include/net/mac80211.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2020-2021 The FreeBSD Foundation
+ * Copyright (c) 2020-2023 The FreeBSD Foundation
* Copyright (c) 2020-2022 Bjoern A. Zeeb
*
* This software was developed by Björn Zeeb under sponsorship from
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_NET_MAC80211_H
@@ -41,6 +39,7 @@
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/workqueue.h>
+#include <linux/dcache.h>
#include <net/cfg80211.h>
#define ARPHRD_IEEE80211_RADIOTAP __LINE__ /* XXX TODO brcmfmac */
@@ -51,6 +50,8 @@
#define WLAN_OUI_TYPE_WFA_P2P (9)
#define WLAN_OUI_WFA (0x506F9A)
+#define IEEE80211_LINK_UNSPECIFIED 0x0f
+
/* hw->conf.flags */
enum ieee80211_hw_conf_flags {
IEEE80211_CONF_IDLE = BIT(0),
@@ -115,6 +116,7 @@ enum ieee80211_bss_changed {
BSS_CHANGED_HE_OBSS_PD = BIT(27),
BSS_CHANGED_TWT = BIT(28),
BSS_CHANGED_UNSOL_BCAST_PROBE_RESP = BIT(30),
+ BSS_CHANGED_EHT_PUNCTURING = BIT(31),
};
/* 802.11 Figure 9-256 Suite selector format. [OUI(3), SUITE TYPE(1)] */
@@ -162,6 +164,8 @@ enum ieee80211_bss_changed {
/* Reserved 14-255 */
/* Apparently 11ax defines more. Seen (19,20) mentioned. */
+#define TKIP_PN_TO_IV16(_x) ((uint16_t)(_x & 0xffff))
+#define TKIP_PN_TO_IV32(_x) ((uint32_t)((_x >> 16) & 0xffffffff))
struct ieee80211_sta;
@@ -171,11 +175,13 @@ struct ieee80211_sta;
#define IEEE80211_HT_AMPDU_PARM_DENSITY (0x7 << IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT)
struct ieee80211_ampdu_params {
- /* TODO FIXME */
struct ieee80211_sta *sta;
- uint8_t tid;
+ enum ieee80211_ampdu_mlme_action action;
+ uint16_t buf_size;
+ uint16_t timeout;
uint16_t ssn;
- int action, amsdu, buf_size, timeout;
+ uint8_t tid;
+ bool amsdu;
};
struct ieee80211_bar {
@@ -210,12 +216,40 @@ struct mac80211_fils_discovery {
uint32_t max_interval;
};
+struct ieee80211_chanctx_conf {
+ /* TODO FIXME */
+ int rx_chains_dynamic, rx_chains_static;
+ bool radar_enabled;
+ struct cfg80211_chan_def def;
+ struct cfg80211_chan_def min_def;
+
+ /* Must stay last. */
+ uint8_t drv_priv[0] __aligned(CACHE_LINE_SIZE);
+};
+
+struct ieee80211_rate_status {
+ struct rate_info rate_idx;
+ uint8_t try_count;
+};
+
+struct ieee80211_ema_beacons {
+ uint8_t cnt;
+ struct {
+ struct sk_buff *skb;
+ struct ieee80211_mutable_offsets offs;
+ } bcn[0];
+};
+
#define WLAN_MEMBERSHIP_LEN (8)
#define WLAN_USER_POSITION_LEN (16)
struct ieee80211_bss_conf {
/* TODO FIXME */
- uint8_t bssid[ETH_ALEN];
+ struct ieee80211_vif *vif;
+ const uint8_t *bssid;
+ uint8_t addr[ETH_ALEN];
+ uint8_t link_id;
+ uint8_t _pad0;
uint8_t transmitter_bssid[ETH_ALEN];
struct ieee80211_ftm_responder_params *ftmr_params;
struct ieee80211_p2p_noa_attr p2p_noa_attr;
@@ -226,34 +260,54 @@ struct ieee80211_bss_conf {
uint8_t membership[WLAN_MEMBERSHIP_LEN];
uint8_t position[WLAN_USER_POSITION_LEN];
} mu_group;
+ struct {
+ uint32_t params;
+ /* single field struct? */
+ } he_oper;
struct cfg80211_he_bss_color he_bss_color;
struct ieee80211_he_obss_pd he_obss_pd;
- size_t ssid_len;
- uint8_t ssid[IEEE80211_NWID_LEN];
- uint16_t aid;
+
+ bool ht_ldpc;
+ bool vht_ldpc;
+ bool he_ldpc;
+ bool vht_mu_beamformee;
+ bool vht_mu_beamformer;
+ bool vht_su_beamformee;
+ bool vht_su_beamformer;
+ bool he_mu_beamformer;
+ bool he_su_beamformee;
+ bool he_su_beamformer;
+ bool he_full_ul_mumimo;
+ bool eht_su_beamformee;
+ bool eht_su_beamformer;
+ bool eht_mu_beamformer;
+
uint16_t ht_operation_mode;
int arp_addr_cnt;
+ uint16_t eht_puncturing;
uint8_t dtim_period;
uint8_t sync_dtim_count;
- bool assoc;
- bool idle;
bool qos;
- bool ps;
bool twt_broadcast;
bool use_cts_prot;
bool use_short_preamble;
bool use_short_slot;
bool he_support;
+ bool eht_support;
bool csa_active;
+ bool mu_mimo_owner;
uint32_t sync_device_ts;
uint64_t sync_tsf;
uint16_t beacon_int;
int16_t txpower;
uint32_t basic_rates;
int mcast_rate[NUM_NL80211_BANDS];
+ enum ieee80211_reg_ap_power power_type;
struct cfg80211_bitrate_mask beacon_tx_rate;
struct mac80211_fils_discovery fils_discovery;
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ struct ieee80211_vif *mbssid_tx_vif;
int ack_enabled, bssid_index, bssid_indicator, cqm_rssi_hyst, cqm_rssi_thold, ema_ap, frame_time_rts_th, ftm_responder;
int htc_trig_based_pkt_ext;
@@ -261,21 +315,10 @@ struct ieee80211_bss_conf {
int profile_periodicity;
int twt_requester, uora_exists, uora_ocw_range;
int assoc_capability, enable_beacon, hidden_ssid, ibss_joined, twt_protected;
- int he_oper, twt_responder, unsol_bcast_probe_resp_interval;
+ int twt_responder, unsol_bcast_probe_resp_interval;
int color_change_active;
};
-struct ieee80211_chanctx_conf {
- /* TODO FIXME */
- int rx_chains_dynamic, rx_chains_static;
- bool radar_enabled;
- struct cfg80211_chan_def def;
- struct cfg80211_chan_def min_def;
-
- /* Must stay last. */
- uint8_t drv_priv[0] __aligned(CACHE_LINE_SIZE);
-};
-
struct ieee80211_channel_switch {
/* TODO FIXME */
int block_tx, count, delay, device_timestamp, timestamp;
@@ -400,6 +443,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_SUPPORTS_RX_DECAP_OFFLOAD,
IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD,
IEEE80211_HW_SUPPORTS_RC_TABLE,
+ IEEE80211_HW_DETECTS_COLOR_COLLISION,
/* Keep last. */
NUM_IEEE80211_HW_FLAGS
@@ -410,7 +454,6 @@ struct ieee80211_hw {
struct wiphy *wiphy;
/* TODO FIXME */
- int max_rx_aggregation_subframes, max_tx_aggregation_subframes;
int extra_tx_headroom, weight_multiplier;
int max_rate_tries, max_rates, max_report_rates;
struct ieee80211_cipher_scheme *cipher_schemes;
@@ -430,8 +473,11 @@ struct ieee80211_hw {
uint16_t offchannel_tx_hw_queue;
uint16_t uapsd_max_sp_len;
uint16_t uapsd_queues;
+ uint16_t max_rx_aggregation_subframes;
+ uint16_t max_tx_aggregation_subframes;
uint16_t max_tx_fragments;
uint16_t max_listen_interval;
+ uint32_t extra_beacon_tailroom;
netdev_features_t netdev_features;
unsigned long flags[BITS_TO_LONGS(NUM_IEEE80211_HW_FLAGS)];
struct ieee80211_conf conf;
@@ -453,6 +499,7 @@ enum ieee802111_key_flag {
IEEE80211_KEY_FLAG_SW_MGMT_TX = BIT(5),
IEEE80211_KEY_FLAG_GENERATE_IV_MGMT = BIT(6),
IEEE80211_KEY_FLAG_GENERATE_MMIE = BIT(7),
+ IEEE80211_KEY_FLAG_RESERVE_TAILROOM = BIT(8),
};
struct ieee80211_key_conf {
@@ -463,8 +510,9 @@ struct ieee80211_key_conf {
uint8_t hw_key_idx; /* Set by drv. */
uint8_t keyidx;
uint16_t flags;
+ int8_t link_id; /* signed! */
uint8_t keylen;
- uint8_t key[0];
+ uint8_t key[0]; /* Must stay last! */
};
struct ieee80211_key_seq {
@@ -481,6 +529,9 @@ struct ieee80211_key_seq {
uint8_t pn[IEEE80211_CCMP_PN_LEN];
} aes_cmac;
struct {
+ uint8_t pn[IEEE80211_CCMP_PN_LEN];
+ } aes_gmac;
+ struct {
uint32_t iv32;
uint16_t iv16;
} tkip;
@@ -517,45 +568,59 @@ enum ieee80211_rx_status_flags {
RX_FLAG_ONLY_MONITOR = BIT(25),
RX_FLAG_SKIP_MONITOR = BIT(26),
RX_FLAG_8023 = BIT(27),
+ RX_FLAG_RADIOTAP_TLV_AT_END = BIT(28),
};
enum mac80211_rx_encoding {
RX_ENC_LEGACY = 0,
RX_ENC_HT,
RX_ENC_VHT,
- RX_ENC_HE
+ RX_ENC_HE,
+ RX_ENC_EHT,
};
struct ieee80211_rx_status {
/* TODO FIXME, this is too large. Over-reduce types to u8 where possible. */
- uint64_t boottime_ns;
+ union {
+ uint64_t boottime_ns;
+ int64_t ack_tx_hwtstamp;
+ };
uint64_t mactime;
uint32_t device_timestamp;
enum ieee80211_rx_status_flags flag;
uint16_t freq;
- uint8_t encoding:2, bw:3, he_ru:3; /* enum mac80211_rx_encoding, rate_info_bw */ /* See mt76.h */
+ uint8_t encoding:3, bw:4; /* enum mac80211_rx_encoding, rate_info_bw */ /* See mt76.h */
uint8_t ampdu_reference;
uint8_t band;
uint8_t chains;
int8_t chain_signal[IEEE80211_MAX_CHAINS];
int8_t signal;
uint8_t enc_flags;
- uint8_t he_dcm;
- uint8_t he_gi;
+ union {
+ struct {
+ uint8_t he_ru:3; /* nl80211::enum nl80211_he_ru_alloc */
+ uint8_t he_gi:2; /* nl80211::enum nl80211_he_gi */
+ uint8_t he_dcm:1;
+ };
+ struct {
+ uint8_t ru:4; /* nl80211::enum nl80211_eht_ru_alloc */
+ uint8_t gi:2; /* nl80211::enum nl80211_eht_gi */
+ } eht;
+ };
+ bool link_valid;
+ uint8_t link_id; /* very incosistent sizes? */
uint8_t zero_length_psdu_type;
uint8_t nss;
uint8_t rate_idx;
};
-struct ieee80211_tx_rate_status {
-};
-
struct ieee80211_tx_status {
struct ieee80211_sta *sta;
struct ieee80211_tx_info *info;
+ int64_t ack_hwtstamp;
u8 n_rates;
- struct ieee80211_tx_rate_status *rates;
+ struct ieee80211_rate_status *rates;
struct sk_buff *skb;
struct list_head *free_list;
@@ -599,29 +664,44 @@ struct ieee80211_sta_txpwr {
short power;
};
+#define IEEE80211_NUM_TIDS 16 /* net80211::WME_NUM_TID */
+struct ieee80211_sta_agg {
+ uint16_t max_amsdu_len;
+ uint16_t max_rc_amsdu_len;
+ uint16_t max_tid_amsdu_len[IEEE80211_NUM_TIDS];
+};
+
struct ieee80211_link_sta {
+ uint8_t addr[ETH_ALEN];
+ uint8_t link_id;
uint32_t supp_rates[NUM_NL80211_BANDS];
struct ieee80211_sta_ht_cap ht_cap;
struct ieee80211_sta_vht_cap vht_cap;
struct ieee80211_sta_he_cap he_cap;
struct ieee80211_sta_he_6ghz_capa he_6ghz_capa;
+ struct ieee80211_sta_eht_cap eht_cap;
uint8_t rx_nss;
enum ieee80211_sta_rx_bw bandwidth;
+ enum ieee80211_smps_mode smps_mode;
+ struct ieee80211_sta_agg agg;
struct ieee80211_sta_txpwr txpwr;
};
-#define IEEE80211_NUM_TIDS 16 /* net80211::WME_NUM_TID */
struct ieee80211_sta {
/* TODO FIXME */
- int max_amsdu_len, max_amsdu_subframes, max_rc_amsdu_len, max_sp;
- int mfp, smps_mode, tdls, tdls_initiator, uapsd_queues, wme;
+ int max_amsdu_subframes;
+ int mfp, smps_mode, tdls, tdls_initiator;
struct ieee80211_txq *txq[IEEE80211_NUM_TIDS + 1]; /* iwlwifi: 8 and adds +1 to tid_data, net80211::IEEE80211_TID_SIZE */
struct ieee80211_sta_rates *rates; /* some rcu thing? */
- uint32_t max_tid_amsdu_len[IEEE80211_NUM_TIDS];
uint8_t addr[ETH_ALEN];
uint16_t aid;
+ bool wme;
+ uint8_t max_sp;
+ uint8_t uapsd_queues;
+ uint16_t valid_links;
struct ieee80211_link_sta deflink;
+ struct ieee80211_link_sta *link[IEEE80211_MLD_MAX_NUM_LINKS]; /* rcu? */
/* Must stay last. */
uint8_t drv_priv[0] __aligned(CACHE_LINE_SIZE);
@@ -662,15 +742,24 @@ enum ieee80211_vif_driver_flags {
IEEE80211_VIF_BEACON_FILTER = BIT(0),
IEEE80211_VIF_SUPPORTS_CQM_RSSI = BIT(1),
IEEE80211_VIF_SUPPORTS_UAPSD = BIT(2),
+ IEEE80211_VIF_DISABLE_SMPS_OVERRIDE = BIT(3),
};
#define IEEE80211_BSS_ARP_ADDR_LIST_LEN 4
struct ieee80211_vif_cfg {
uint16_t aid;
+ uint16_t eml_cap;
+ uint16_t eml_med_sync_delay;
bool assoc;
+ bool ps;
+ bool idle;
+ bool ibss_joined;
int arp_addr_cnt;
+ size_t ssid_len;
uint32_t arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; /* big endian */
+ uint8_t ssid[IEEE80211_NWID_LEN];
+ uint8_t ap_addr[ETH_ALEN];
};
struct ieee80211_vif {
@@ -687,7 +776,15 @@ struct ieee80211_vif {
struct ieee80211_chanctx_conf *chanctx_conf;
struct ieee80211_txq *txq;
struct ieee80211_bss_conf bss_conf;
+ struct ieee80211_bss_conf *link_conf[IEEE80211_MLD_MAX_NUM_LINKS]; /* rcu? */
uint8_t hw_queue[IEEE80211_NUM_ACS];
+ uint16_t active_links;
+ uint16_t valid_links;
+ struct ieee80211_vif *mbssid_tx_vif;
+
+/* #ifdef CONFIG_MAC80211_DEBUGFS */ /* Do not change structure depending on compile-time option. */
+ struct dentry *debugfs_dir;
+/* #endif */
/* Must stay last. */
uint8_t drv_priv[0] __aligned(CACHE_LINE_SIZE);
@@ -696,6 +793,7 @@ struct ieee80211_vif {
struct ieee80211_vif_chanctx_switch {
struct ieee80211_chanctx_conf *old_ctx, *new_ctx;
struct ieee80211_vif *vif;
+ struct ieee80211_bss_conf *link_conf;
};
struct ieee80211_prep_tx_info {
@@ -726,10 +824,10 @@ struct ieee80211_tx_info {
uint8_t ampdu_len;
uint8_t antenna;
uint16_t tx_time;
- bool is_valid_ack_signal;
+ uint8_t flags;
void *status_driver_data[16 / sizeof(void *)]; /* XXX TODO */
} status;
-#define IEEE80211_TX_INFO_DRIVER_DATA_SIZE (5 * sizeof(void *)) /* XXX TODO 5? */
+#define IEEE80211_TX_INFO_DRIVER_DATA_SIZE 40
void *driver_data[IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *)];
};
};
@@ -768,11 +866,11 @@ enum ieee80211_iface_iter {
IEEE80211_IFACE_ITER_NORMAL = BIT(0),
IEEE80211_IFACE_ITER_RESUME_ALL = BIT(1),
IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER = BIT(2), /* seems to be an iter flag */
+ IEEE80211_IFACE_ITER_ACTIVE = BIT(3),
/* Internal flags only. */
- /* ieee80211_iterate_active_interfaces*(). */
IEEE80211_IFACE_ITER__ATOMIC = BIT(6),
- IEEE80211_IFACE_ITER__ACTIVE = BIT(7),
+ IEEE80211_IFACE_ITER__MTX = BIT(8),
};
enum set_key_cmd {
@@ -806,6 +904,8 @@ struct ieee80211_low_level_stats {
enum ieee80211_offload_flags {
IEEE80211_OFFLOAD_ENCAP_4ADDR,
+ IEEE80211_OFFLOAD_ENCAP_ENABLED,
+ IEEE80211_OFFLOAD_DECAP_ENABLED,
};
struct ieee80211_ops {
@@ -827,7 +927,7 @@ struct ieee80211_ops {
int (*hw_scan)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_scan_request *);
void (*cancel_hw_scan)(struct ieee80211_hw *, struct ieee80211_vif *);
- int (*conf_tx)(struct ieee80211_hw *, struct ieee80211_vif *, u16, const struct ieee80211_tx_queue_params *);
+ int (*conf_tx)(struct ieee80211_hw *, struct ieee80211_vif *, u32, u16, const struct ieee80211_tx_queue_params *);
void (*tx)(struct ieee80211_hw *, struct ieee80211_tx_control *, struct sk_buff *);
int (*tx_last_beacon)(struct ieee80211_hw *);
void (*wake_tx_queue)(struct ieee80211_hw *, struct ieee80211_txq *);
@@ -837,6 +937,7 @@ struct ieee80211_ops {
void (*mgd_protect_tdls_discover)(struct ieee80211_hw *, struct ieee80211_vif *);
void (*flush)(struct ieee80211_hw *, struct ieee80211_vif *, u32, bool);
+ void (*flush_sta)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_sta *);
int (*set_frag_threshold)(struct ieee80211_hw *, u32);
@@ -876,8 +977,8 @@ struct ieee80211_ops {
int (*add_chanctx)(struct ieee80211_hw *, struct ieee80211_chanctx_conf *);
void (*remove_chanctx)(struct ieee80211_hw *, struct ieee80211_chanctx_conf *);
void (*change_chanctx)(struct ieee80211_hw *, struct ieee80211_chanctx_conf *, u32);
- int (*assign_vif_chanctx)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_chanctx_conf *);
- void (*unassign_vif_chanctx)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_chanctx_conf *);
+ int (*assign_vif_chanctx)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_bss_conf *, struct ieee80211_chanctx_conf *);
+ void (*unassign_vif_chanctx)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_bss_conf *, struct ieee80211_chanctx_conf *);
int (*switch_vif_chanctx)(struct ieee80211_hw *, struct ieee80211_vif_chanctx_switch *, int, enum ieee80211_chanctx_switch_mode);
int (*get_antenna)(struct ieee80211_hw *, u32 *, u32 *);
@@ -890,6 +991,8 @@ struct ieee80211_ops {
void (*config_iface_filter)(struct ieee80211_hw *, struct ieee80211_vif *, unsigned int, unsigned int);
void (*bss_info_changed)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_bss_conf *, u64);
+ void (*link_info_changed)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_bss_conf *, u64);
+
int (*set_rts_threshold)(struct ieee80211_hw *, u32);
void (*event_callback)(struct ieee80211_hw *, struct ieee80211_vif *, const struct ieee80211_event *);
int (*get_survey)(struct ieee80211_hw *, int, struct survey_info *);
@@ -906,12 +1009,13 @@ struct ieee80211_ops {
int (*set_key)(struct ieee80211_hw *, enum set_key_cmd, struct ieee80211_vif *, struct ieee80211_sta *, struct ieee80211_key_conf *);
void (*set_default_unicast_key)(struct ieee80211_hw *, struct ieee80211_vif *, int);
void (*update_tkip_key)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_key_conf *, struct ieee80211_sta *, u32, u16 *);
+ void (*set_rekey_data)(struct ieee80211_hw *, struct ieee80211_vif *, struct cfg80211_gtk_rekey_data *);
int (*start_pmsr)(struct ieee80211_hw *, struct ieee80211_vif *, struct cfg80211_pmsr_request *);
void (*abort_pmsr)(struct ieee80211_hw *, struct ieee80211_vif *, struct cfg80211_pmsr_request *);
- int (*start_ap)(struct ieee80211_hw *, struct ieee80211_vif *);
- void (*stop_ap)(struct ieee80211_hw *, struct ieee80211_vif *);
+ int (*start_ap)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_bss_conf *link_conf);
+ void (*stop_ap)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_bss_conf *link_conf);
int (*join_ibss)(struct ieee80211_hw *, struct ieee80211_vif *);
void (*leave_ibss)(struct ieee80211_hw *, struct ieee80211_vif *);
@@ -933,6 +1037,17 @@ struct ieee80211_ops {
void (*add_twt_setup)(struct ieee80211_hw *, struct ieee80211_sta *, struct ieee80211_twt_setup *);
void (*twt_teardown_request)(struct ieee80211_hw *, struct ieee80211_sta *, u8);
+
+ int (*set_hw_timestamp)(struct ieee80211_hw *, struct ieee80211_vif *, struct cfg80211_set_hw_timestamp *);
+
+ void (*vif_cfg_changed)(struct ieee80211_hw *, struct ieee80211_vif *, u64);
+
+ int (*change_vif_links)(struct ieee80211_hw *, struct ieee80211_vif *, u16, u16, struct ieee80211_bss_conf *[IEEE80211_MLD_MAX_NUM_LINKS]);
+ int (*change_sta_links)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_sta *, u16, u16);
+
+/* #ifdef CONFIG_MAC80211_DEBUGFS */ /* Do not change depending on compile-time option. */
+ void (*sta_add_debugfs)(struct ieee80211_hw *, struct ieee80211_vif *, struct ieee80211_sta *, struct dentry *);
+/* #endif */
};
@@ -947,7 +1062,9 @@ void linuxkpi_ieee80211_iffree(struct ieee80211_hw *);
void linuxkpi_set_ieee80211_dev(struct ieee80211_hw *, char *);
int linuxkpi_ieee80211_ifattach(struct ieee80211_hw *);
void linuxkpi_ieee80211_ifdetach(struct ieee80211_hw *);
+void linuxkpi_ieee80211_unregister_hw(struct ieee80211_hw *);
struct ieee80211_hw * linuxkpi_wiphy_to_ieee80211_hw(struct wiphy *);
+void linuxkpi_ieee80211_restart_hw(struct ieee80211_hw *);
void linuxkpi_ieee80211_iterate_interfaces(
struct ieee80211_hw *hw, enum ieee80211_iface_iter flags,
void(*iterfunc)(void *, uint8_t *, struct ieee80211_vif *),
@@ -966,8 +1083,8 @@ void linuxkpi_ieee80211_iterate_stations_atomic(struct ieee80211_hw *,
void linuxkpi_ieee80211_scan_completed(struct ieee80211_hw *,
struct cfg80211_scan_info *);
void linuxkpi_ieee80211_rx(struct ieee80211_hw *, struct sk_buff *,
- struct ieee80211_sta *, struct napi_struct *);
-uint8_t linuxkpi_ieee80211_get_tid(struct ieee80211_hdr *);
+ struct ieee80211_sta *, struct napi_struct *, struct list_head *);
+uint8_t linuxkpi_ieee80211_get_tid(struct ieee80211_hdr *, bool);
struct ieee80211_sta *linuxkpi_ieee80211_find_sta(struct ieee80211_vif *,
const u8 *);
struct ieee80211_sta *linuxkpi_ieee80211_find_sta_by_ifaddr(
@@ -984,7 +1101,7 @@ void linuxkpi_ieee80211_queue_work(struct ieee80211_hw *, struct work_struct *);
struct sk_buff *linuxkpi_ieee80211_pspoll_get(struct ieee80211_hw *,
struct ieee80211_vif *);
struct sk_buff *linuxkpi_ieee80211_nullfunc_get(struct ieee80211_hw *,
- struct ieee80211_vif *, bool);
+ struct ieee80211_vif *, int, bool);
void linuxkpi_ieee80211_txq_get_depth(struct ieee80211_txq *, unsigned long *,
unsigned long *);
struct wireless_dev *linuxkpi_ieee80211_vif_to_wdev(struct ieee80211_vif *);
@@ -993,6 +1110,18 @@ void linuxkpi_ieee80211_beacon_loss(struct ieee80211_vif *);
struct sk_buff *linuxkpi_ieee80211_probereq_get(struct ieee80211_hw *,
uint8_t *, uint8_t *, size_t, size_t);
void linuxkpi_ieee80211_tx_status(struct ieee80211_hw *, struct sk_buff *);
+void linuxkpi_ieee80211_tx_status_ext(struct ieee80211_hw *,
+ struct ieee80211_tx_status *);
+void linuxkpi_ieee80211_stop_queues(struct ieee80211_hw *);
+void linuxkpi_ieee80211_wake_queues(struct ieee80211_hw *);
+void linuxkpi_ieee80211_stop_queue(struct ieee80211_hw *, int);
+void linuxkpi_ieee80211_wake_queue(struct ieee80211_hw *, int);
+void linuxkpi_ieee80211_txq_schedule_start(struct ieee80211_hw *, uint8_t);
+struct ieee80211_txq *linuxkpi_ieee80211_next_txq(struct ieee80211_hw *, uint8_t);
+void linuxkpi_ieee80211_schedule_txq(struct ieee80211_hw *,
+ struct ieee80211_txq *, bool);
+void linuxkpi_ieee80211_handle_wake_tx_queue(struct ieee80211_hw *,
+ struct ieee80211_txq *);
/* -------------------------------------------------------------------------- */
@@ -1077,14 +1206,11 @@ ieee80211_register_hw(struct ieee80211_hw *hw)
return (error);
}
-static __inline void
+static inline void
ieee80211_unregister_hw(struct ieee80211_hw *hw)
{
- wiphy_unregister(hw->wiphy);
- linuxkpi_ieee80211_ifdetach(hw);
-
- IMPROVE();
+ linuxkpi_ieee80211_unregister_hw(hw);
}
static __inline struct ieee80211_hw *
@@ -1094,6 +1220,44 @@ wiphy_to_ieee80211_hw(struct wiphy *wiphy)
return (linuxkpi_wiphy_to_ieee80211_hw(wiphy));
}
+static inline void
+ieee80211_restart_hw(struct ieee80211_hw *hw)
+{
+ linuxkpi_ieee80211_restart_hw(hw);
+}
+
+static inline void
+ieee80211_hw_restart_disconnect(struct ieee80211_vif *vif)
+{
+ TODO();
+}
+
+/* -------------------------------------------------------------------------- */
+
+#define link_conf_dereference_check(_vif, _linkid) \
+ rcu_dereference_check((_vif)->link_conf[_linkid], true)
+
+#define link_conf_dereference_protected(_vif, _linkid) \
+ rcu_dereference_protected((_vif)->link_conf[_linkid], true)
+
+#define link_sta_dereference_check(_sta, _linkid) \
+ rcu_dereference_check((_sta)->link[_linkid], true)
+
+#define link_sta_dereference_protected(_sta, _linkid) \
+ rcu_dereference_protected((_sta)->link[_linkid], true)
+
+#define for_each_vif_active_link(_vif, _link, _linkid) \
+ for (_linkid = 0; _linkid < nitems((_vif)->link_conf); _linkid++) \
+ if ( ((_vif)->active_links == 0 /* no MLO */ || \
+ ((_vif)->active_links & BIT(_linkid)) != 0) && \
+ (_link = rcu_dereference((_vif)->link_conf[_linkid])) )
+
+#define for_each_sta_active_link(_vif, _sta, _linksta, _linkid) \
+ for (_linkid = 0; _linkid < nitems((_vif)->link_conf); _linkid++) \
+ if ( ((_vif)->active_links == 0 /* no MLO */ || \
+ ((_vif)->active_links & BIT(_linkid)) != 0) && \
+ (_linksta = link_sta_dereference_protected((_sta), (_linkid))) )
+
/* -------------------------------------------------------------------------- */
static __inline bool
@@ -1254,8 +1418,13 @@ ieee80211_is_back_req(__le16 fc)
}
static __inline bool
-ieee80211_is_bufferable_mmpdu(__le16 fc)
+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. */
@@ -1263,12 +1432,14 @@ ieee80211_is_bufferable_mmpdu(__le16 fc)
if (!ieee80211_is_mgmt(fc))
return (false);
if (ieee80211_is_action(fc)) /* XXX FTM? */
- return (true);
+ return (true); /* XXX false? */
if (ieee80211_is_disassoc(fc))
return (true);
if (ieee80211_is_deauth(fc))
return (true);
+ TODO();
+
return (false);
}
@@ -1301,6 +1472,17 @@ 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_vif_is_mesh(struct ieee80211_vif *vif)
{
@@ -1323,14 +1505,21 @@ ieee80211_is_first_frag(__le16 fc)
}
static __inline bool
-ieee80211_is_pspoll(__le16 fc)
+ieee80211_is_robust_mgmt_frame(struct sk_buff *skb)
{
TODO();
return (false);
}
static __inline bool
-ieee80211_is_robust_mgmt_frame(struct sk_buff *skb)
+ieee80211_is_ftm(struct sk_buff *skb)
+{
+ TODO();
+ return (false);
+}
+
+static __inline bool
+ieee80211_is_timing_measurement(struct sk_buff *skb)
{
TODO();
return (false);
@@ -1429,21 +1618,100 @@ ieee80211_rx_napi(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
struct sk_buff *skb, struct napi_struct *napi)
{
- linuxkpi_ieee80211_rx(hw, skb, sta, napi);
+ linuxkpi_ieee80211_rx(hw, skb, sta, napi, NULL);
+}
+
+static __inline void
+ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+ struct sk_buff *skb, struct list_head *list)
+{
+
+ linuxkpi_ieee80211_rx(hw, skb, sta, NULL, list);
}
static __inline void
ieee80211_rx_ni(struct ieee80211_hw *hw, struct sk_buff *skb)
{
- linuxkpi_ieee80211_rx(hw, skb, NULL, NULL);
+ linuxkpi_ieee80211_rx(hw, skb, NULL, NULL, NULL);
}
static __inline void
ieee80211_rx_irqsafe(struct ieee80211_hw *hw, struct sk_buff *skb)
{
- linuxkpi_ieee80211_rx(hw, skb, NULL, NULL);
+ linuxkpi_ieee80211_rx(hw, skb, NULL, NULL, NULL);
+}
+
+static __inline void
+ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+
+ linuxkpi_ieee80211_rx(hw, skb, NULL, NULL, NULL);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static inline void
+ieee80211_stop_queues(struct ieee80211_hw *hw)
+{
+ linuxkpi_ieee80211_stop_queues(hw);
+}
+
+static inline void
+ieee80211_wake_queues(struct ieee80211_hw *hw)
+{
+ linuxkpi_ieee80211_wake_queues(hw);
+}
+
+static inline void
+ieee80211_stop_queue(struct ieee80211_hw *hw, int qnum)
+{
+ linuxkpi_ieee80211_stop_queue(hw, qnum);
+}
+
+static inline void
+ieee80211_wake_queue(struct ieee80211_hw *hw, int qnum)
+{
+ linuxkpi_ieee80211_wake_queue(hw, qnum);
+}
+
+static inline void
+ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
+{
+ linuxkpi_ieee80211_schedule_txq(hw, txq, true);
+}
+
+static inline void
+ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq,
+ bool withoutpkts)
+{
+ linuxkpi_ieee80211_schedule_txq(hw, txq, withoutpkts);
+}
+
+static inline void
+ieee80211_txq_schedule_start(struct ieee80211_hw *hw, uint8_t ac)
+{
+ linuxkpi_ieee80211_txq_schedule_start(hw, ac);
+}
+
+static inline void
+ieee80211_txq_schedule_end(struct ieee80211_hw *hw, uint8_t ac)
+{
+ /* DO_NADA; */
+}
+
+static inline struct ieee80211_txq *
+ieee80211_next_txq(struct ieee80211_hw *hw, uint8_t ac)
+{
+ return (linuxkpi_ieee80211_next_txq(hw, ac));
+}
+
+static inline void
+ieee80211_handle_wake_tx_queue(struct ieee80211_hw *hw,
+ struct ieee80211_txq *txq)
+{
+ linuxkpi_ieee80211_handle_wake_tx_queue(hw, txq);
}
/* -------------------------------------------------------------------------- */
@@ -1452,12 +1720,12 @@ static __inline uint8_t
ieee80211_get_tid(struct ieee80211_hdr *hdr)
{
- return (linuxkpi_ieee80211_get_tid(hdr));
+ return (linuxkpi_ieee80211_get_tid(hdr, false));
}
static __inline struct sk_buff *
ieee80211_beacon_get_tim(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- uint16_t *tim_offset, uint16_t *tim_len)
+ uint16_t *tim_offset, uint16_t *tim_len, uint32_t link_id)
{
if (tim_offset != NULL)
@@ -1476,7 +1744,7 @@ ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw,
{
flags |= IEEE80211_IFACE_ITER__ATOMIC;
- flags |= IEEE80211_IFACE_ITER__ACTIVE;
+ flags |= IEEE80211_IFACE_ITER_ACTIVE;
linuxkpi_ieee80211_iterate_interfaces(hw, flags, iterfunc, arg);
}
@@ -1487,7 +1755,18 @@ ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw,
void *arg)
{
- flags |= IEEE80211_IFACE_ITER__ACTIVE;
+ flags |= IEEE80211_IFACE_ITER_ACTIVE;
+ linuxkpi_ieee80211_iterate_interfaces(hw, flags, iterfunc, arg);
+}
+
+static __inline void
+ieee80211_iterate_active_interfaces_mtx(struct ieee80211_hw *hw,
+ enum ieee80211_iface_iter flags,
+ void(*iterfunc)(void *, uint8_t *, struct ieee80211_vif *),
+ void *arg)
+{
+ flags |= IEEE80211_IFACE_ITER_ACTIVE;
+ flags |= IEEE80211_IFACE_ITER__MTX;
linuxkpi_ieee80211_iterate_interfaces(hw, flags, iterfunc, arg);
}
@@ -1549,7 +1828,7 @@ ieee80211_vif_to_wdev(struct ieee80211_vif *vif)
static __inline struct sk_buff *
ieee80211_beacon_get_template(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_mutable_offsets *offs,
- int x)
+ uint32_t link_id)
{
TODO();
return (NULL);
@@ -1620,12 +1899,53 @@ ieee80211_tu_to_usec(unsigned long tu)
return (tu * IEEE80211_DUR_TU);
}
+/*
+ * Below we assume that the two values from different emums are the same.
+ * Make sure this does not accidentally change.
+ */
+CTASSERT((int)IEEE80211_ACTION_SM_TPCREP == (int)IEEE80211_ACTION_RADIO_MEASUREMENT_LMREP);
-static __inline int
+static __inline bool
ieee80211_action_contains_tpc(struct sk_buff *skb)
{
- TODO();
- return (0);
+ struct ieee80211_mgmt *mgmt;
+
+ mgmt = (struct ieee80211_mgmt *)skb->data;
+
+ /* Check that this is a mgmt/action frame? */
+ if (!ieee80211_is_action(mgmt->frame_control))
+ return (false);
+
+ /*
+ * This is a bit convoluted but according to docs both actions
+ * are checked for this. Kind-of makes sense for the only consumer
+ * (iwlwifi) I am aware off given the txpower fields are at the
+ * same location so firmware can update the value.
+ */
+ /* 80211-2020 9.6.2 Spectrum Management Action frames */
+ /* 80211-2020 9.6.2.5 TPC Report frame format */
+ /* 80211-2020 9.6.6 Radio Measurement action details */
+ /* 80211-2020 9.6.6.4 Link Measurement Report frame format */
+ /* Check that it is Spectrum Management or Radio Measurement? */
+ if (mgmt->u.action.category != IEEE80211_ACTION_CAT_SM &&
+ mgmt->u.action.category != IEEE80211_ACTION_CAT_RADIO_MEASUREMENT)
+ return (false);
+
+ /*
+ * Check that it is TPC Report or Link Measurement Report?
+ * The values of each are the same (see CTASSERT above function).
+ */
+ if (mgmt->u.action.u.tpc_report.spec_mgmt != IEEE80211_ACTION_SM_TPCREP)
+ return (false);
+
+ /* 80211-2020 9.4.2.16 TPC Report element */
+ /* Check that the ELEMID and length are correct? */
+ if (mgmt->u.action.u.tpc_report.tpc_elem_id != IEEE80211_ELEMID_TPCREP ||
+ mgmt->u.action.u.tpc_report.tpc_elem_length != 4)
+ return (false);
+
+ /* All the right fields in the right place. */
+ return (true);
}
static __inline void
@@ -1662,7 +1982,12 @@ static __inline void
ieee80211_get_tkip_rx_p1k(struct ieee80211_key_conf *keyconf,
const u8 *addr, uint32_t iv32, u16 *p1k)
{
+
+ KASSERT(keyconf != NULL && addr != NULL && p1k != NULL,
+ ("%s: keyconf %p addr %p p1k %p\n", __func__, keyconf, addr, p1k));
+
TODO();
+ memset(p1k, 0xfa, 5 * sizeof(*p1k)); /* Just initializing. */
}
static __inline size_t
@@ -1689,7 +2014,8 @@ ieee80211_ie_split(const u8 *ies, size_t ies_len,
}
static __inline void
-ieee80211_request_smps(struct ieee80211_vif *vif, enum ieee80211_smps_mode smps)
+ieee80211_request_smps(struct ieee80211_vif *vif, u_int link_id,
+ enum ieee80211_smps_mode smps)
{
static const char *smps_mode_name[] = {
"SMPS_OFF",
@@ -1713,18 +2039,6 @@ ieee80211_tdls_oper_request(struct ieee80211_vif *vif, uint8_t *addr,
}
static __inline void
-ieee80211_stop_queues(struct ieee80211_hw *hw)
-{
- TODO();
-}
-
-static __inline void
-ieee80211_wake_queues(struct ieee80211_hw *hw)
-{
- TODO();
-}
-
-static __inline void
wiphy_rfkill_set_hw_state(struct wiphy *wiphy, bool state)
{
TODO();
@@ -1744,12 +2058,6 @@ ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
}
static __inline void
-ieee80211_restart_hw(struct ieee80211_hw *hw)
-{
- TODO();
-}
-
-static __inline void
ieee80211_ready_on_channel(struct ieee80211_hw *hw)
{
TODO();
@@ -1809,6 +2117,20 @@ ieee80211_rate_set_vht(struct ieee80211_tx_rate *r, uint32_t f1, uint32_t f2)
TODO();
}
+static __inline uint8_t
+ieee80211_rate_get_vht_nss(struct ieee80211_tx_rate *r)
+{
+ TODO();
+ return (0);
+}
+
+static __inline uint8_t
+ieee80211_rate_get_vht_mcs(struct ieee80211_tx_rate *r)
+{
+ TODO();
+ return (0);
+}
+
static __inline void
ieee80211_reserve_tid(struct ieee80211_sta *sta, uint8_t tid)
{
@@ -1862,14 +2184,13 @@ ieee80211_sta_pspoll(struct ieee80211_sta *sta)
}
static __inline void
-ieee80211_sta_uapsd_trigger(struct ieee80211_sta *sta, int ntids)
+ieee80211_sta_recalc_aggregates(struct ieee80211_sta *sta)
{
TODO();
}
static __inline void
-ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, uint8_t *addr,
- uint8_t tid)
+ieee80211_sta_uapsd_trigger(struct ieee80211_sta *sta, int ntids)
{
TODO();
}
@@ -1881,37 +2202,63 @@ ieee80211_tkip_add_iv(u8 *crypto_hdr, struct ieee80211_key_conf *keyconf,
TODO();
}
-static __inline struct sk_buff *
+static inline struct sk_buff *
ieee80211_tx_dequeue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
{
return (linuxkpi_ieee80211_tx_dequeue(hw, txq));
}
-static __inline void
-ieee80211_update_mu_groups(struct ieee80211_vif *vif, uint8_t *ms, uint8_t *up)
+static inline struct sk_buff *
+ieee80211_tx_dequeue_ni(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
{
- TODO();
+ struct sk_buff *skb;
+
+ local_bh_disable();
+ skb = linuxkpi_ieee80211_tx_dequeue(hw, txq);
+ local_bh_enable();
+
+ return (skb);
}
static __inline void
-ieee80211_sta_set_buffered(struct ieee80211_sta *sta, uint8_t tid, bool t)
+ieee80211_update_mu_groups(struct ieee80211_vif *vif,
+ u_int _i, uint8_t *ms, uint8_t *up)
{
TODO();
}
static __inline void
-ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
+ieee80211_sta_set_buffered(struct ieee80211_sta *sta, uint8_t tid, bool t)
{
-
- linuxkpi_ieee80211_tx_status(hw, skb);
+ TODO();
}
static __inline void
ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf, uint8_t tid,
struct ieee80211_key_seq *seq)
{
+
+ KASSERT(keyconf != NULL && seq != NULL, ("%s: keyconf %p seq %p\n",
+ __func__, keyconf, seq));
+
TODO();
+ switch (keyconf->cipher) {
+ case WLAN_CIPHER_SUITE_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP_256:
+ memset(seq->ccmp.pn, 0xfa, sizeof(seq->ccmp.pn)); /* XXX TODO */
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ memset(seq->aes_cmac.pn, 0xfa, sizeof(seq->aes_cmac.pn)); /* XXX TODO */
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ seq->tkip.iv32 = 0xfa; /* XXX TODO */
+ seq->tkip.iv16 = 0xfa; /* XXX TODO */
+ break;
+ default:
+ pr_debug("%s: unsupported cipher suite %d\n", __func__, keyconf->cipher);
+ break;
+ }
}
static __inline void
@@ -1926,11 +2273,32 @@ ieee80211_sta_eosp(struct ieee80211_sta *sta)
TODO();
}
+static __inline int
+ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, uint8_t tid, int x)
+{
+ TODO("rtw8x");
+ return (-EINVAL);
+}
+
+static __inline int
+ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, uint8_t tid)
+{
+ TODO("rtw89");
+ return (-EINVAL);
+}
+
+static __inline void
+ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, uint8_t *addr,
+ uint8_t tid)
+{
+ TODO("iwlwifi");
+}
+
static __inline void
ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, uint8_t *addr,
uint8_t tid)
{
- TODO();
+ TODO("iwlwifi/rtw8x/...");
}
static __inline void
@@ -1948,7 +2316,8 @@ ieee80211_scan_completed(struct ieee80211_hw *hw,
}
static __inline struct sk_buff *
-ieee80211_beacon_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+ieee80211_beacon_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ uint32_t link_id)
{
TODO();
return (NULL);
@@ -1974,14 +2343,14 @@ ieee80211_proberesp_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
static __inline struct sk_buff *
ieee80211_nullfunc_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- bool qos)
+ int linkid, bool qos)
{
/* Only STA needs this. Otherwise return NULL and panic bad drivers. */
if (vif->type != NL80211_IFTYPE_STATION)
return (NULL);
- return (linuxkpi_ieee80211_nullfunc_get(hw, vif, qos));
+ return (linuxkpi_ieee80211_nullfunc_get(hw, vif, linkid, qos));
}
static __inline struct sk_buff *
@@ -2009,15 +2378,10 @@ ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *w)
}
static __inline void
-ieee80211_stop_queue(struct ieee80211_hw *hw, uint16_t q)
+ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
{
- TODO();
-}
-static __inline void
-ieee80211_wake_queue(struct ieee80211_hw *hw, uint16_t q)
-{
- TODO();
+ linuxkpi_ieee80211_tx_status(hw, skb);
}
static __inline void
@@ -2034,11 +2398,12 @@ ieee80211_tx_status_ni(struct ieee80211_hw *hw, struct sk_buff *skb)
ieee80211_tx_status(hw, skb);
}
-static __inline int
-ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, uint8_t tid, int x)
+static __inline void
+ieee80211_tx_status_ext(struct ieee80211_hw *hw,
+ struct ieee80211_tx_status *txstat)
{
- TODO();
- return (-EINVAL);
+
+ linuxkpi_ieee80211_tx_status_ext(hw, txstat);
}
static __inline void
@@ -2088,13 +2453,6 @@ SET_IEEE80211_PERM_ADDR (struct ieee80211_hw *hw, uint8_t *addr)
ether_addr_copy(hw->wiphy->perm_addr, addr);
}
-static __inline uint8_t *
-ieee80211_bss_get_ie(struct cfg80211_bss *bss, uint32_t eid)
-{
- TODO();
- return (NULL);
-}
-
static __inline void
ieee80211_report_low_ack(struct ieee80211_sta *sta, int x)
{
@@ -2115,13 +2473,6 @@ ieee80211_stop_rx_ba_session_offl(struct ieee80211_vif *vif, uint8_t *addr,
TODO();
}
-static __inline struct sk_buff *
-ieee80211_tx_dequeue_ni(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
-{
- TODO();
- return (NULL);
-}
-
static __inline void
ieee80211_tx_rate_update(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
struct ieee80211_tx_info *info)
@@ -2136,13 +2487,6 @@ ieee80211_txq_may_transmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
return (false);
}
-static __inline struct ieee80211_txq *
-ieee80211_next_txq(struct ieee80211_hw *hw, uint32_t ac)
-{
- TODO();
- return (NULL);
-}
-
static __inline void
ieee80211_radar_detected(struct ieee80211_hw *hw)
{
@@ -2156,32 +2500,6 @@ ieee80211_sta_register_airtime(struct ieee80211_sta *sta,
TODO();
}
-
-static __inline void
-ieee80211_return_txq(struct ieee80211_hw *hw,
- struct ieee80211_txq *txq, bool _t)
-{
- TODO();
-}
-
-static __inline void
-ieee80211_txq_schedule_end(struct ieee80211_hw *hw, uint32_t ac)
-{
- TODO();
-}
-
-static __inline void
-ieee80211_txq_schedule_start(struct ieee80211_hw *hw, uint32_t ac)
-{
- TODO();
-}
-
-static __inline void
-ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
-{
- TODO();
-}
-
static __inline void
ieee80211_beacon_set_cntdwn(struct ieee80211_vif *vif, u8 counter)
{
@@ -2258,53 +2576,140 @@ ieee80211_get_tx_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
}
static __inline void
-ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
- struct sk_buff *skb, struct list_head *list)
+ieee80211_color_change_finish(struct ieee80211_vif *vif)
{
TODO();
}
-static __inline void
-ieee80211_tx_status_ext(struct ieee80211_hw *hw,
- struct ieee80211_tx_status *txstat)
+static __inline struct sk_buff *
+ieee80211_get_fils_discovery_tmpl(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
{
TODO();
+ return (NULL);
}
-static __inline const struct element *
-ieee80211_bss_get_elem(struct cfg80211_bss *bss, uint32_t eid)
+static __inline struct sk_buff *
+ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
{
TODO();
return (NULL);
}
static __inline void
-ieee80211_color_change_finish(struct ieee80211_vif *vif)
+linuxkpi_ieee80211_send_bar(struct ieee80211_vif *vif, uint8_t *ra, uint16_t tid,
+ uint16_t ssn)
{
TODO();
}
-static __inline struct sk_buff *
-ieee80211_get_fils_discovery_tmpl(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+static __inline void
+ieee80211_resume_disconnect(struct ieee80211_vif *vif)
+{
+ TODO();
+}
+
+static __inline int
+ieee80211_data_to_8023(struct sk_buff *skb, const uint8_t *addr,
+ enum nl80211_iftype iftype)
+{
+ TODO();
+ return (-1);
+}
+
+static __inline void
+ieee80211_get_tkip_p1k_iv(struct ieee80211_key_conf *key,
+ uint32_t iv32, uint16_t *p1k)
+{
+ TODO();
+}
+
+static __inline struct ieee80211_key_conf *
+ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
+ struct ieee80211_key_conf *key)
+{
+ TODO();
+ return (NULL);
+}
+
+static __inline void
+ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const uint8_t *bssid,
+ const uint8_t *replay_ctr, gfp_t gfp)
+{
+ TODO();
+}
+
+static __inline void
+ieee80211_remove_key(struct ieee80211_key_conf *key)
+{
+ TODO();
+}
+
+static __inline void
+ieee80211_set_key_rx_seq(struct ieee80211_key_conf *key, int tid,
+ struct ieee80211_key_seq *seq)
+{
+ TODO();
+}
+
+static __inline void
+ieee80211_report_wowlan_wakeup(struct ieee80211_vif *vif,
+ struct cfg80211_wowlan_wakeup *wakeup, gfp_t gfp)
+{
+ TODO();
+}
+
+static __inline void
+ieee80211_obss_color_collision_notify(struct ieee80211_vif *vif,
+ uint64_t obss_color_bitmap, gfp_t gfp)
+{
+ TODO();
+}
+
+static __inline void
+ieee80211_refresh_tx_agg_session_timer(struct ieee80211_sta *sta,
+ uint8_t tid)
+{
+ TODO();
+}
+
+static __inline struct ieee80211_ema_beacons *
+ieee80211_beacon_get_template_ema_list(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, uint32_t link_id)
{
TODO();
return (NULL);
}
-static __inline struct sk_buff *
-ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw,
+static __inline void
+ieee80211_beacon_free_ema_list(struct ieee80211_ema_beacons *bcns)
+{
+ TODO();
+}
+
+static inline bool
+ieee80211_vif_is_mld(const struct ieee80211_vif *vif)
+{
+
+ /* If valid_links is non-zero, the vif is an MLD. */
+ return (vif->valid_links != 0);
+}
+
+static __inline const struct ieee80211_sta_he_cap *
+ieee80211_get_he_iftype_cap_vif(const struct ieee80211_supported_band *band,
struct ieee80211_vif *vif)
{
TODO();
return (NULL);
}
-static __inline void
-linuxkpi_ieee80211_send_bar(struct ieee80211_vif *vif, uint8_t *ra, uint16_t tid,
- uint16_t ssn)
+static __inline const struct ieee80211_sta_eht_cap *
+ieee80211_get_eht_iftype_cap_vif(const struct ieee80211_supported_band *band,
+ struct ieee80211_vif *vif)
{
TODO();
+ return (NULL);
}
#define ieee80211_send_bar(_v, _r, _t, _s) \
diff --git a/sys/compat/linuxkpi/common/include/net/netevent.h b/sys/compat/linuxkpi/common/include/net/netevent.h
index 40df26705c7b..c1c39af3a772 100644
--- a/sys/compat/linuxkpi/common/include/net/netevent.h
+++ b/sys/compat/linuxkpi/common/include/net/netevent.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_NET_NETEVENT_H_
#define _LINUXKPI_NET_NETEVENT_H_
diff --git a/sys/compat/linuxkpi/common/include/net/netlink.h b/sys/compat/linuxkpi/common/include/net/netlink.h
new file mode 100644
index 000000000000..ae250177d18b
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/net/netlink.h
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2020,2022 Bjoern A. Zeeb
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_NET_NETLINK_H
+#define _LINUXKPI_NET_NETLINK_H
+
+#include <netlink/netlink.h>
+
+struct nla_policy {
+};
+
+struct netlink_callback {
+ int args[8];
+};
+
+static __inline int
+nla_put(struct sk_buff *skb, int attr, size_t len, void *data)
+{
+
+ pr_debug("%s: TODO -- now native?\n", __func__);
+ return (-ENXIO);
+}
+
+static __inline int
+nla_put_u16(struct sk_buff *skb, int attr, uint32_t val)
+{
+
+ return (nla_put(skb, attr, sizeof(uint32_t), &val));
+}
+
+#endif /* _LINUXKPI_NET_NETLINK_H */
diff --git a/sys/compat/linuxkpi/common/include/net/page_pool.h b/sys/compat/linuxkpi/common/include/net/page_pool.h
new file mode 100644
index 000000000000..82dbeff82167
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/net/page_pool.h
@@ -0,0 +1,117 @@
+/*-
+ * Copyright (c) 2023 Bjoern A. Zeeb
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _LINUXKPI_NET_PAGE_POOL_H
+#define _LINUXKPI_NET_PAGE_POOL_H
+
+#include <linux/kernel.h> /* pr_debug */
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+
+struct device;
+
+struct page_pool_params {
+ struct device *dev;
+ uint32_t flags;
+ uint32_t order;
+ uint32_t pool_size;
+ uint32_t max_len;
+ uint32_t offset;
+ int nid; /* NUMA */
+ enum dma_data_direction dma_dir;
+};
+
+struct page_pool {
+};
+
+#define PP_FLAG_DMA_MAP BIT(0)
+#define PP_FLAG_DMA_SYNC_DEV BIT(1)
+#define PP_FLAG_PAGE_FRAG BIT(2)
+
+static inline struct page_pool *
+page_pool_create(const struct page_pool_params *ppparams)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (NULL);
+}
+
+static inline void
+page_pool_destroy(struct page_pool *ppool)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static inline struct page *
+page_pool_dev_alloc_frag(struct page_pool *ppool, uint32_t *offset,
+ size_t size)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (NULL);
+}
+
+static inline dma_addr_t
+page_pool_get_dma_addr(struct page *page)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (0);
+}
+
+static inline enum dma_data_direction
+page_pool_get_dma_dir(const struct page_pool *ppool)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (DMA_BIDIRECTIONAL);
+}
+
+static inline void
+page_pool_put_full_page(struct page_pool *ppool, struct page *page,
+ bool allow_direct)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+}
+
+static inline int
+page_pool_ethtool_stats_get_count(void)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (0);
+}
+
+static inline uint8_t *
+page_pool_ethtool_stats_get_strings(uint8_t *x)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+ return (x);
+}
+
+#endif /* _LINUXKPI_NET_PAGE_POOL_H */
diff --git a/sys/compat/linuxkpi/common/include/net/regulatory.h b/sys/compat/linuxkpi/common/include/net/regulatory.h
index a7b31812e308..0a538f1531f9 100644
--- a/sys/compat/linuxkpi/common/include/net/regulatory.h
+++ b/sys/compat/linuxkpi/common/include/net/regulatory.h
@@ -25,13 +25,15 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_NET_REGULATORY_H
#define _LINUXKPI_NET_REGULATORY_H
+enum environment_cap {
+ ENVIRON_INDOOR = 1, /* keep != 0 */
+};
+
#define REG_RULE(_begin, _end, _bw, _mag, _meirp, _flags) \
{ \
.flags = (_flags), \
diff --git a/sys/compat/linuxkpi/common/include/net/tcp.h b/sys/compat/linuxkpi/common/include/net/tcp.h
index f083cebd3505..4804a2b09b9d 100644
--- a/sys/compat/linuxkpi/common/include/net/tcp.h
+++ b/sys/compat/linuxkpi/common/include/net/tcp.h
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#ifndef _LINUXKPI_NET_TCP_H_
#define _LINUXKPI_NET_TCP_H_
diff --git a/sys/compat/linuxkpi/common/include/stdarg.h b/sys/compat/linuxkpi/common/include/stdarg.h
index b6141038d69a..ab2fdf7534e5 100644
--- a/sys/compat/linuxkpi/common/include/stdarg.h
+++ b/sys/compat/linuxkpi/common/include/stdarg.h
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Vladimir Kondratyev <wulf@FreeBSD.org>
*
diff --git a/sys/compat/linuxkpi/common/include/video/mipi_display.h b/sys/compat/linuxkpi/common/include/video/mipi_display.h
new file mode 100644
index 000000000000..ea079a57d39f
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/video/mipi_display.h
@@ -0,0 +1,64 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_VIDEO_MIPI_DISPLAY_H_
+#define _LINUXKPI_VIDEO_MIPI_DISPLAY_H_
+
+#define MIPI_DSI_V_SYNC_START 0x01
+#define MIPI_DSI_V_SYNC_END 0x11
+#define MIPI_DSI_H_SYNC_START 0x21
+#define MIPI_DSI_H_SYNC_END 0x31
+#define MIPI_DSI_COMPRESSION_MODE 0x07
+#define MIPI_DSI_END_OF_TRANSMISSION 0x08
+#define MIPI_DSI_COLOR_MODE_OFF 0x02
+#define MIPI_DSI_COLOR_MODE_ON 0x12
+#define MIPI_DSI_SHUTDOWN_PERIPHERAL 0x22
+#define MIPI_DSI_TURN_ON_PERIPHERAL 0x32
+#define MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM 0x03
+#define MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM 0x13
+#define MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM 0x23
+#define MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM 0x04
+#define MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM 0x14
+#define MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM 0x24
+#define MIPI_DSI_DCS_SHORT_WRITE 0x05
+#define MIPI_DSI_DCS_SHORT_WRITE_PARAM 0x15
+#define MIPI_DSI_DCS_READ 0x06
+#define MIPI_DSI_EXECUTE_QUEUE 0x16
+#define MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE 0x37
+#define MIPI_DSI_NULL_PACKET 0x09
+#define MIPI_DSI_BLANKING_PACKET 0x19
+#define MIPI_DSI_GENERIC_LONG_WRITE 0x29
+#define MIPI_DSI_DCS_LONG_WRITE 0x39
+#define MIPI_DSI_PICTURE_PARAMETER_SET 0x0a
+#define MIPI_DSI_COMPRESSED_PIXEL_STREAM 0x0b
+#define MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20 0x0c
+#define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24 0x1c
+#define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16 0x2c
+#define MIPI_DSI_PACKED_PIXEL_STREAM_30 0x0d
+#define MIPI_DSI_PACKED_PIXEL_STREAM_36 0x1d
+#define MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12 0x3d
+#define MIPI_DSI_PACKED_PIXEL_STREAM_16 0x0e
+#define MIPI_DSI_PACKED_PIXEL_STREAM_18 0x1e
+#define MIPI_DSI_PIXEL_STREAM_3BYTE_18 0x2e
+#define MIPI_DSI_PACKED_PIXEL_STREAM_24 0x3e
+
+#define MIPI_DCS_NOP 0x00
+#define MIPI_DCS_SOFT_RESET 0x01
+#define MIPI_DCS_GET_POWER_MODE 0x0a
+#define MIPI_DCS_GET_PIXEL_FORMAT 0x0c
+#define MIPI_DCS_ENTER_SLEEP_MODE 0x10
+#define MIPI_DCS_EXIT_SLEEP_MODE 0x11
+#define MIPI_DCS_SET_DISPLAY_OFF 0x28
+#define MIPI_DCS_SET_DISPLAY_ON 0x29
+#define MIPI_DCS_SET_COLUMN_ADDRESS 0x2a
+#define MIPI_DCS_SET_PAGE_ADDRESS 0x2b
+#define MIPI_DCS_SET_TEAR_OFF 0x34
+#define MIPI_DCS_SET_TEAR_ON 0x35
+#define MIPI_DCS_SET_PIXEL_FORMAT 0x3a
+#define MIPI_DCS_SET_TEAR_SCANLINE 0x44
+#define MIPI_DCS_SET_DISPLAY_BRIGHTNESS 0x51
+#define MIPI_DCS_GET_DISPLAY_BRIGHTNESS 0x52
+#define MIPI_DCS_WRITE_CONTROL_DISPLAY 0x53
+#define MIPI_DCS_GET_CONTROL_DISPLAY 0x54
+#define MIPI_DCS_WRITE_POWER_SAVE 0x55
+
+#endif /* _LINUXKPI_VIDEO_MIPI_DISPLAY_H_ */
diff --git a/sys/compat/linuxkpi/common/include/video/vga.h b/sys/compat/linuxkpi/common/include/video/vga.h
new file mode 100644
index 000000000000..e327246cc457
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/video/vga.h
@@ -0,0 +1,16 @@
+/* Public domain. */
+
+#ifndef _LINUXKPI_VIDEO_VGA_H
+#define _LINUXKPI_VIDEO_VGA_H
+
+#define VGA_MIS_W 0x3c2
+#define VGA_SEQ_I 0x3c4
+#define VGA_SEQ_D 0x3c5
+#define VGA_MIS_R 0x3cc
+
+#define VGA_SR01_SCREEN_OFF (1 << 5)
+
+#define VGA_FB_PHYS_BASE 0xA0000
+#define VGA_FB_PHYS_SIZE 65536
+
+#endif
diff --git a/sys/compat/linuxkpi/common/include/xen/xen.h b/sys/compat/linuxkpi/common/include/xen/xen.h
new file mode 100644
index 000000000000..16e77724111d
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/xen/xen.h
@@ -0,0 +1,37 @@
+/*-
+ * 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_XEN_XEN_H_
+#define _LINUXKPI_XEN_XEN_H_
+
+#define xen_initial_domain() lkpi_xen_initial_domain()
+#define xen_pv_domain() lkpi_xen_pv_domain()
+
+bool lkpi_xen_initial_domain(void);
+bool lkpi_xen_pv_domain(void);
+
+#endif /* _LINUXKPI_XEN_XEN_H_ */
diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c
index a98ed56fcdad..d598e9af0050 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2020-2022 The FreeBSD Foundation
+ * Copyright (c) 2020-2023 The FreeBSD Foundation
* Copyright (c) 2020-2022 Bjoern A. Zeeb
*
* This software was developed by Björn Zeeb under sponsorship from
@@ -39,9 +39,6 @@
* We call the internal versions lxxx (e.g., hw -> lhw, sta -> lsta).
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/types.h>
#include <sys/kernel.h>
@@ -53,6 +50,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <sys/queue.h>
#include <sys/taskqueue.h>
+#include <sys/libkern.h>
#include <net/if.h>
#include <net/if_var.h>
@@ -63,6 +61,7 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_proto.h>
#include <net80211/ieee80211_ratectl.h>
#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_vht.h>
#define LINUXKPI_NET80211
#include <net/mac80211.h>
@@ -70,8 +69,22 @@ __FBSDID("$FreeBSD$");
#include <linux/workqueue.h>
#include "linux_80211.h"
+#define LKPI_80211_WME
+/* #define LKPI_80211_HW_CRYPTO */
+/* #define LKPI_80211_VHT */
+/* #define LKPI_80211_HT */
+#if defined(LKPI_80211_VHT) && !defined(LKPI_80211_HT)
+#define LKPI_80211_HT
+#endif
+
static MALLOC_DEFINE(M_LKPI80211, "lkpi80211", "LinuxKPI 80211 compat");
+/* XXX-BZ really want this and others in queue.h */
+#define TAILQ_ELEM_INIT(elm, field) do { \
+ (elm)->field.tqe_next = NULL; \
+ (elm)->field.tqe_prev = NULL; \
+} while (0)
+
/* -------------------------------------------------------------------------- */
/* Keep public for as long as header files are using it too. */
@@ -85,22 +98,6 @@ SYSCTL_NODE(_compat_linuxkpi, OID_AUTO, 80211, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
SYSCTL_INT(_compat_linuxkpi_80211, OID_AUTO, debug, CTLFLAG_RWTUN,
&linuxkpi_debug_80211, 0, "LinuxKPI 802.11 debug level");
-#ifndef D80211_TODO
-#define D80211_TODO 0x1
-#endif
-#ifndef D80211_IMPROVE
-#define D80211_IMPROVE 0x2
-#endif
-#define D80211_TRACE 0x10
-#define D80211_TRACEOK 0x20
-#define D80211_TRACE_TX 0x100
-#define D80211_TRACE_TX_DUMP 0x200
-#define D80211_TRACE_RX 0x1000
-#define D80211_TRACE_RX_DUMP 0x2000
-#define D80211_TRACE_RX_BEACONS 0x4000
-#define D80211_TRACEX (D80211_TRACE_TX|D80211_TRACE_RX)
-#define D80211_TRACEX_DUMP (D80211_TRACE_TX_DUMP|D80211_TRACE_RX_DUMP)
-#define D80211_TRACE_STA 0x10000
#define UNIMPLEMENTED if (linuxkpi_debug_80211 & D80211_TODO) \
printf("XXX-TODO %s:%d: UNIMPLEMENTED\n", __func__, __LINE__)
#define TRACEOK() if (linuxkpi_debug_80211 & D80211_TRACEOK) \
@@ -121,7 +118,8 @@ const uint8_t rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
/* IEEE 802.11-05/0257r1 */
const uint8_t bridge_tunnel_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
-const uint8_t tid_to_mac80211_ac[] = {
+/* IEEE 802.11e Table 20i-UP-to-AC mappings. */
+static const uint8_t ieee80211e_up_to_ac[] = {
IEEE80211_AC_BE,
IEEE80211_AC_BK,
IEEE80211_AC_BK,
@@ -143,10 +141,89 @@ const struct cfg80211_ops linuxkpi_mac80211cfgops = {
*/
};
+#if 0
static struct lkpi_sta *lkpi_find_lsta_by_ni(struct lkpi_vif *,
struct ieee80211_node *);
+#endif
static void lkpi_80211_txq_task(void *, int);
+static void lkpi_80211_lhw_rxq_task(void *, int);
static void lkpi_ieee80211_free_skb_mbuf(void *);
+#ifdef LKPI_80211_WME
+static int lkpi_wme_update(struct lkpi_hw *, struct ieee80211vap *, bool);
+#endif
+
+#if defined(LKPI_80211_HT)
+static void
+lkpi_sta_sync_ht_from_ni(struct ieee80211_sta *sta, struct ieee80211_node *ni, int *ht_rx_nss)
+{
+ struct ieee80211vap *vap;
+ uint8_t *ie;
+ struct ieee80211_ht_cap *htcap;
+ int i, rx_nss;
+
+ if ((ni->ni_flags & IEEE80211_NODE_HT) == 0)
+ return;
+
+ if (IEEE80211_IS_CHAN_HT(ni->ni_chan) &&
+ IEEE80211_IS_CHAN_HT40(ni->ni_chan))
+ sta->deflink.bandwidth = IEEE80211_STA_RX_BW_40;
+
+ sta->deflink.ht_cap.ht_supported = true;
+
+ /* htcap->ampdu_params_info */
+ vap = ni->ni_vap;
+ sta->deflink.ht_cap.ampdu_density = _IEEE80211_MASKSHIFT(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY);
+ if (sta->deflink.ht_cap.ampdu_density > vap->iv_ampdu_density)
+ sta->deflink.ht_cap.ampdu_density = vap->iv_ampdu_density;
+ sta->deflink.ht_cap.ampdu_factor = _IEEE80211_MASKSHIFT(ni->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU);
+ if (sta->deflink.ht_cap.ampdu_factor > vap->iv_ampdu_rxmax)
+ sta->deflink.ht_cap.ampdu_factor = vap->iv_ampdu_rxmax;
+
+ ie = ni->ni_ies.htcap_ie;
+ KASSERT(ie != NULL, ("%s: HT but no htcap_ie on ni %p\n", __func__, ni));
+ if (ie[0] == IEEE80211_ELEMID_VENDOR)
+ ie += 4;
+ ie += 2;
+ htcap = (struct ieee80211_ht_cap *)ie;
+ sta->deflink.ht_cap.cap = htcap->cap_info;
+ sta->deflink.ht_cap.mcs = htcap->mcs;
+
+ rx_nss = 0;
+ for (i = 0; i < nitems(htcap->mcs.rx_mask); i++) {
+ if (htcap->mcs.rx_mask[i])
+ rx_nss++;
+ }
+ if (ht_rx_nss != NULL)
+ *ht_rx_nss = rx_nss;
+
+ IMPROVE("sta->wme, sta->deflink.agg.max*");
+}
+#endif
+
+#if defined(LKPI_80211_VHT)
+static void
+lkpi_sta_sync_vht_from_ni(struct ieee80211_sta *sta, struct ieee80211_node *ni, int *vht_rx_nss)
+{
+
+ if ((ni->ni_flags & IEEE80211_NODE_VHT) == 0)
+ return;
+
+ if (IEEE80211_IS_CHAN_VHT(ni->ni_chan)) {
+#ifdef __notyet__
+ if (IEEE80211_IS_CHAN_VHT80P80(ni->ni_chan)) {
+ sta->deflink.bandwidth = IEEE80211_STA_RX_BW_160; /* XXX? */
+ } else
+#endif
+ if (IEEE80211_IS_CHAN_VHT160(ni->ni_chan))
+ sta->deflink.bandwidth = IEEE80211_STA_RX_BW_160;
+ else if (IEEE80211_IS_CHAN_VHT80(ni->ni_chan))
+ sta->deflink.bandwidth = IEEE80211_STA_RX_BW_80;
+ }
+
+ IMPROVE("VHT sync ni to sta");
+ return;
+}
+#endif
static void
lkpi_lsta_dump(struct lkpi_sta *lsta, struct ieee80211_node *ni,
@@ -172,22 +249,14 @@ lkpi_lsta_dump(struct lkpi_sta *lsta, struct ieee80211_node *ni,
static void
lkpi_lsta_remove(struct lkpi_sta *lsta, struct lkpi_vif *lvif)
{
- struct ieee80211_node *ni;
- ni = lsta->ni;
LKPI_80211_LVIF_LOCK(lvif);
+ KASSERT(lsta->lsta_entry.tqe_prev != NULL,
+ ("%s: lsta %p lsta_entry.tqe_prev %p ni %p\n", __func__,
+ lsta, lsta->lsta_entry.tqe_prev, lsta->ni));
TAILQ_REMOVE(&lvif->lsta_head, lsta, lsta_entry);
LKPI_80211_LVIF_UNLOCK(lvif);
-
- lsta->ni = NULL;
- ni->ni_drv_data = NULL;
- if (ni != NULL)
- ieee80211_free_node(ni);
-
- IMPROVE("more from lkpi_ic_node_free() should happen here.");
-
- free(lsta, M_LKPI80211);
}
static struct lkpi_sta *
@@ -198,7 +267,9 @@ lkpi_lsta_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN],
struct lkpi_vif *lvif;
struct ieee80211_vif *vif;
struct ieee80211_sta *sta;
- int tid;
+ int band, i, tid;
+ int ht_rx_nss;
+ int vht_rx_nss;
lsta = malloc(sizeof(*lsta) + hw->sta_data_size, M_LKPI80211,
M_NOWAIT | M_ZERO);
@@ -207,13 +278,16 @@ lkpi_lsta_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN],
lsta->added_to_drv = false;
lsta->state = IEEE80211_STA_NOTEXIST;
-#if 0
/*
- * This needs to be done in node_init() as ieee80211_alloc_node()
- * will initialise the refcount after us.
+ * Link the ni to the lsta here without taking a reference.
+ * For one we would have to take the reference in node_init()
+ * as ieee80211_alloc_node() will initialise the refcount after us.
+ * For the other a ni and an lsta are 1:1 mapped and always together
+ * from [ic_]node_alloc() to [ic_]node_free() so we are essentally
+ * using the ni references for the lsta as well despite it being
+ * two separate allocations.
*/
- lsta->ni = ieee80211_ref_node(ni);
-#endif
+ lsta->ni = ni;
/* The back-pointer "drv_data" to net80211_node let's us get lsta. */
ni->ni_drv_data = lsta;
@@ -222,6 +296,8 @@ lkpi_lsta_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN],
sta = LSTA_TO_STA(lsta);
IEEE80211_ADDR_COPY(sta->addr, mac);
+
+ /* TXQ */
for (tid = 0; tid < nitems(sta->txq); tid++) {
struct lkpi_txq *ltxq;
@@ -239,30 +315,128 @@ lkpi_lsta_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN],
IMPROVE("AP/if we support non-STA here too");
ltxq->txq.ac = IEEE80211_AC_VO;
} else {
- ltxq->txq.ac = tid_to_mac80211_ac[tid & 7];
+ ltxq->txq.ac = ieee80211e_up_to_ac[tid & 7];
}
ltxq->seen_dequeue = false;
+ ltxq->stopped = false;
ltxq->txq.vif = vif;
ltxq->txq.tid = tid;
ltxq->txq.sta = sta;
+ TAILQ_ELEM_INIT(ltxq, txq_entry);
skb_queue_head_init(&ltxq->skbq);
+ LKPI_80211_LTXQ_LOCK_INIT(ltxq);
sta->txq[tid] = &ltxq->txq;
}
+ /* Deflink information. */
+ for (band = 0; band < NUM_NL80211_BANDS; band++) {
+ struct ieee80211_supported_band *supband;
+
+ supband = hw->wiphy->bands[band];
+ if (supband == NULL)
+ continue;
+
+ for (i = 0; i < supband->n_bitrates; i++) {
+
+ IMPROVE("Further supband->bitrates[i]* checks?");
+ /* or should we get them from the ni? */
+ sta->deflink.supp_rates[band] |= BIT(i);
+ }
+ }
+
+ sta->deflink.smps_mode = IEEE80211_SMPS_OFF;
+ sta->deflink.bandwidth = IEEE80211_STA_RX_BW_20;
+ sta->deflink.rx_nss = 0;
+
+ ht_rx_nss = 0;
+#if defined(LKPI_80211_HT)
+ lkpi_sta_sync_ht_from_ni(sta, ni, &ht_rx_nss);
+#endif
+ vht_rx_nss = 0;
+#if defined(LKPI_80211_VHT)
+ lkpi_sta_sync_vht_from_ni(sta, ni, &vht_rx_nss);
+#endif
+
+ sta->deflink.rx_nss = MAX(ht_rx_nss, sta->deflink.rx_nss);
+ sta->deflink.rx_nss = MAX(vht_rx_nss, sta->deflink.rx_nss);
+ IMPROVE("he, ... smps_mode, ..");
+
+ /* Link configuration. */
+ IEEE80211_ADDR_COPY(sta->deflink.addr, sta->addr);
+ sta->link[0] = &sta->deflink;
+ for (i = 1; i < nitems(sta->link); i++) {
+ IMPROVE("more links; only link[0] = deflink currently.");
+ }
+
/* Deferred TX path. */
- mtx_init(&lsta->txq_mtx, "lsta_txq", NULL, MTX_DEF);
+ LKPI_80211_LSTA_TXQ_LOCK_INIT(lsta);
TASK_INIT(&lsta->txq_task, 0, lkpi_80211_txq_task, lsta);
mbufq_init(&lsta->txq, IFQ_MAXLEN);
+ lsta->txq_ready = true;
return (lsta);
cleanup:
- for (; tid >= 0; tid--)
+ for (; tid >= 0; tid--) {
+ struct lkpi_txq *ltxq;
+
+ ltxq = TXQ_TO_LTXQ(sta->txq[tid]);
+ LKPI_80211_LTXQ_LOCK_DESTROY(ltxq);
free(sta->txq[tid], M_LKPI80211);
+ }
free(lsta, M_LKPI80211);
return (NULL);
}
+static void
+lkpi_lsta_free(struct lkpi_sta *lsta, struct ieee80211_node *ni)
+{
+ struct mbuf *m;
+
+ if (lsta->added_to_drv)
+ panic("%s: Trying to free an lsta still known to firmware: "
+ "lsta %p ni %p added_to_drv %d\n",
+ __func__, lsta, ni, lsta->added_to_drv);
+
+ /* XXX-BZ free resources, ... */
+ IMPROVE();
+
+ /* Drain sta->txq[] */
+
+ LKPI_80211_LSTA_TXQ_LOCK(lsta);
+ lsta->txq_ready = false;
+ LKPI_80211_LSTA_TXQ_UNLOCK(lsta);
+
+ /* Drain taskq, won't be restarted until added_to_drv is set again. */
+ while (taskqueue_cancel(taskqueue_thread, &lsta->txq_task, NULL) != 0)
+ taskqueue_drain(taskqueue_thread, &lsta->txq_task);
+
+ /* Flush mbufq (make sure to release ni refs!). */
+ m = mbufq_dequeue(&lsta->txq);
+ while (m != NULL) {
+ struct ieee80211_node *nim;
+
+ nim = (struct ieee80211_node *)m->m_pkthdr.rcvif;
+ if (nim != NULL)
+ ieee80211_free_node(nim);
+ m_freem(m);
+ m = mbufq_dequeue(&lsta->txq);
+ }
+ KASSERT(mbufq_empty(&lsta->txq), ("%s: lsta %p has txq len %d != 0\n",
+ __func__, lsta, mbufq_len(&lsta->txq)));
+ LKPI_80211_LSTA_TXQ_LOCK_DESTROY(lsta);
+
+ /* Remove lsta from vif; that is done by the state machine. Should assert it? */
+
+ IMPROVE("Make sure everything is cleaned up.");
+
+ /* Free lsta. */
+ lsta->ni = NULL;
+ ni->ni_drv_data = NULL;
+ free(lsta, M_LKPI80211);
+}
+
+
static enum nl80211_band
lkpi_net80211_chan_to_nl80211_band(struct ieee80211_channel *c)
{
@@ -310,6 +484,7 @@ lkpi_nl80211_band_to_net80211_band(enum nl80211_band band)
return (0x00);
}
+#if 0
static enum ieee80211_ac_numbers
lkpi_ac_net_to_l80211(int ac)
{
@@ -328,6 +503,7 @@ lkpi_ac_net_to_l80211(int ac)
return (IEEE80211_AC_BE);
}
}
+#endif
static enum nl80211_iftype
lkpi_opmode_to_vif_type(enum ieee80211_opmode opmode)
@@ -361,7 +537,7 @@ lkpi_opmode_to_vif_type(enum ieee80211_opmode opmode)
return (NL80211_IFTYPE_UNSPECIFIED);
}
-#ifdef __notyet__
+#ifdef LKPI_80211_HW_CRYPTO
static uint32_t
lkpi_l80211_to_net80211_cyphers(uint32_t wlan_cipher_suite)
{
@@ -372,7 +548,7 @@ lkpi_l80211_to_net80211_cyphers(uint32_t wlan_cipher_suite)
case WLAN_CIPHER_SUITE_TKIP:
return (IEEE80211_CRYPTO_TKIP);
case WLAN_CIPHER_SUITE_CCMP:
- return (IEEE80211_CIPHER_AES_CCM);
+ return (IEEE80211_CRYPTO_AES_CCM);
case WLAN_CIPHER_SUITE_WEP104:
return (IEEE80211_CRYPTO_WEP);
case WLAN_CIPHER_SUITE_AES_CMAC:
@@ -392,9 +568,7 @@ lkpi_l80211_to_net80211_cyphers(uint32_t wlan_cipher_suite)
return (0);
}
-#endif
-#ifdef TRY_HW_CRYPTO
static uint32_t
lkpi_net80211_to_l80211_cipher_suite(uint32_t cipher, uint8_t keylen)
{
@@ -481,6 +655,7 @@ lkpi_find_lkpi80211_chan(struct lkpi_hw *lhw,
return (NULL);
}
+#if 0
static struct linuxkpi_ieee80211_channel *
lkpi_get_lkpi80211_chan(struct ieee80211com *ic, struct ieee80211_node *ni)
{
@@ -505,6 +680,7 @@ lkpi_get_lkpi80211_chan(struct ieee80211com *ic, struct ieee80211_node *ni)
return (chan);
}
+#endif
struct linuxkpi_ieee80211_channel *
linuxkpi_ieee80211_get_channel(struct wiphy *wiphy, uint32_t freq)
@@ -530,32 +706,7 @@ linuxkpi_ieee80211_get_channel(struct wiphy *wiphy, uint32_t freq)
return (NULL);
}
-void
-linuxkpi_cfg80211_bss_flush(struct wiphy *wiphy)
-{
- struct lkpi_hw *lhw;
- struct ieee80211com *ic;
- struct ieee80211vap *vap;
-
- lhw = wiphy_priv(wiphy);
- ic = lhw->ic;
-
- /*
- * If we haven't called ieee80211_ifattach() yet
- * or there is no VAP, there are no scans to flush.
- */
- if (ic == NULL ||
- (lhw->sc_flags & LKPI_MAC80211_DRV_STARTED) == 0)
- return;
-
- /* Should only happen on the current one? Not seen it late enough. */
- IEEE80211_LOCK(ic);
- TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
- ieee80211_scan_flush(vap);
- IEEE80211_UNLOCK(ic);
-}
-
-#ifdef TRY_HW_CRYPTO
+#ifdef LKPI_80211_HW_CRYPTO
static int
_lkpi_iv_key_set_delete(struct ieee80211vap *vap, const struct ieee80211_key *k,
enum set_key_cmd cmd)
@@ -745,7 +896,7 @@ lkpi_update_dtim_tsf(struct ieee80211_vif *vif, struct ieee80211_node *ni,
"dtim_period %u sync_dtim_count %u sync_tsf %ju "
"sync_device_ts %u bss_changed %#08x\n",
__func__, __LINE__, _f, _l,
- vif->bss_conf.assoc, vif->bss_conf.aid,
+ vif->cfg.assoc, vif->cfg.aid,
vif->bss_conf.beacon_int, vif->bss_conf.dtim_period,
vif->bss_conf.sync_dtim_count,
(uintmax_t)vif->bss_conf.sync_tsf,
@@ -776,7 +927,7 @@ lkpi_update_dtim_tsf(struct ieee80211_vif *vif, struct ieee80211_node *ni,
"dtim_period %u sync_dtim_count %u sync_tsf %ju "
"sync_device_ts %u bss_changed %#08x\n",
__func__, __LINE__, _f, _l,
- vif->bss_conf.assoc, vif->bss_conf.aid,
+ vif->cfg.assoc, vif->cfg.aid,
vif->bss_conf.beacon_int, vif->bss_conf.dtim_period,
vif->bss_conf.sync_dtim_count,
(uintmax_t)vif->bss_conf.sync_tsf,
@@ -792,8 +943,12 @@ lkpi_stop_hw_scan(struct lkpi_hw *lhw, struct ieee80211_vif *vif)
{
struct ieee80211_hw *hw;
int error;
+ bool cancel;
- if ((lhw->scan_flags & LKPI_SCAN_RUNNING) == 0)
+ LKPI_80211_LHW_SCAN_LOCK(lhw);
+ cancel = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0;
+ LKPI_80211_LHW_SCAN_UNLOCK(lhw);
+ if (!cancel)
return;
hw = LHW_TO_HW(lhw);
@@ -802,13 +957,18 @@ lkpi_stop_hw_scan(struct lkpi_hw *lhw, struct ieee80211_vif *vif)
LKPI_80211_LHW_LOCK(lhw);
/* Need to cancel the scan. */
lkpi_80211_mo_cancel_hw_scan(hw, vif);
+ LKPI_80211_LHW_UNLOCK(lhw);
/* Need to make sure we see ieee80211_scan_completed. */
- error = msleep(lhw, &lhw->mtx, 0, "lhwscanstop", hz/2);
- LKPI_80211_LHW_UNLOCK(lhw);
+ LKPI_80211_LHW_SCAN_LOCK(lhw);
+ if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0)
+ error = msleep(lhw, &lhw->scan_mtx, 0, "lhwscanstop", hz/2);
+ cancel = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0;
+ LKPI_80211_LHW_SCAN_UNLOCK(lhw);
+
IEEE80211_LOCK(lhw->ic);
- if ((lhw->scan_flags & LKPI_SCAN_RUNNING) != 0)
+ if (cancel)
ic_printf(lhw->ic, "%s: failed to cancel scan: %d (%p, %p)\n",
__func__, error, lhw, vif);
}
@@ -838,7 +998,7 @@ lkpi_disassoc(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
struct lkpi_hw *lhw)
{
sta->aid = 0;
- if (vif->bss_conf.assoc) {
+ if (vif->cfg.assoc) {
struct ieee80211_hw *hw;
enum ieee80211_bss_changed changed;
@@ -846,8 +1006,8 @@ lkpi_disassoc(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
lkpi_update_mcast_filter(lhw->ic, true);
changed = 0;
- vif->bss_conf.assoc = false;
- vif->bss_conf.aid = 0;
+ vif->cfg.assoc = false;
+ vif->cfg.aid = 0;
changed |= BSS_CHANGED_ASSOC;
/*
* This will remove the sta from firmware for iwlwifi.
@@ -868,28 +1028,32 @@ lkpi_wake_tx_queues(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
{
struct lkpi_txq *ltxq;
int tid;
+ bool ltxq_empty;
/* Wake up all queues to know they are allocated in the driver. */
for (tid = 0; tid < nitems(sta->txq); tid++) {
- if (tid == IEEE80211_NUM_TIDS) {
- IMPROVE("station specific?");
- if (!ieee80211_hw_check(hw, STA_MMPDU_TXQ))
- continue;
- } else if (tid >= hw->queues)
+ if (tid == IEEE80211_NUM_TIDS) {
+ IMPROVE("station specific?");
+ if (!ieee80211_hw_check(hw, STA_MMPDU_TXQ))
continue;
+ } else if (tid >= hw->queues)
+ continue;
- if (sta->txq[tid] == NULL)
- continue;
+ if (sta->txq[tid] == NULL)
+ continue;
- ltxq = TXQ_TO_LTXQ(sta->txq[tid]);
- if (dequeue_seen && !ltxq->seen_dequeue)
- continue;
+ ltxq = TXQ_TO_LTXQ(sta->txq[tid]);
+ if (dequeue_seen && !ltxq->seen_dequeue)
+ continue;
- if (no_emptyq && skb_queue_empty(&ltxq->skbq))
- continue;
+ LKPI_80211_LTXQ_LOCK(ltxq);
+ ltxq_empty = skb_queue_empty(&ltxq->skbq);
+ LKPI_80211_LTXQ_UNLOCK(ltxq);
+ if (no_emptyq && ltxq_empty)
+ continue;
- lkpi_80211_mo_wake_tx_queue(hw, sta->txq[tid]);
+ lkpi_80211_mo_wake_tx_queue(hw, sta->txq[tid]);
}
}
@@ -909,6 +1073,7 @@ static int
lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
{
struct linuxkpi_ieee80211_channel *chan;
+ struct lkpi_chanctx *lchanctx;
struct ieee80211_chanctx_conf *conf;
struct lkpi_hw *lhw;
struct ieee80211_hw *hw;
@@ -916,35 +1081,73 @@ lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int
struct ieee80211_vif *vif;
struct ieee80211_node *ni;
struct lkpi_sta *lsta;
- struct ieee80211_sta *sta;
enum ieee80211_bss_changed bss_changed;
struct ieee80211_prep_tx_info prep_tx_info;
uint32_t changed;
int error;
- chan = lkpi_get_lkpi80211_chan(vap->iv_ic, vap->iv_bss);
+ /*
+ * In here we use vap->iv_bss until lvif->lvif_bss is set.
+ * For all later (STATE >= AUTH) functions we need to use the lvif
+ * cache which will be tracked even through (*iv_update_bss)().
+ */
+
+ if (vap->iv_bss == NULL) {
+ ic_printf(vap->iv_ic, "%s: no iv_bss for vap %p\n", __func__, vap);
+ return (EINVAL);
+ }
+ /*
+ * Keep the ni alive locally. In theory (and practice) iv_bss can change
+ * once we unlock here. This is due to net80211 allowing state changes
+ * and new join1() despite having an active node as well as due to
+ * the fact that the iv_bss can be swapped under the hood in (*iv_update_bss).
+ */
+ ni = ieee80211_ref_node(vap->iv_bss);
+ if (ni->ni_chan == NULL || ni->ni_chan == IEEE80211_CHAN_ANYC) {
+ ic_printf(vap->iv_ic, "%s: no channel set for iv_bss ni %p "
+ "on vap %p\n", __func__, ni, vap);
+ ieee80211_free_node(ni); /* Error handling for the local ni. */
+ return (EINVAL);
+ }
+
+ lhw = vap->iv_ic->ic_softc;
+ chan = lkpi_find_lkpi80211_chan(lhw, ni->ni_chan);
if (chan == NULL) {
- ic_printf(vap->iv_ic, "%s: failed to get channel\n", __func__);
+ ic_printf(vap->iv_ic, "%s: failed to get LKPI channel from "
+ "iv_bss ni %p on vap %p\n", __func__, ni, vap);
+ ieee80211_free_node(ni); /* Error handling for the local ni. */
return (ESRCH);
}
- lhw = vap->iv_ic->ic_softc;
hw = LHW_TO_HW(lhw);
lvif = VAP_TO_LVIF(vap);
vif = LVIF_TO_VIF(lvif);
- ni = ieee80211_ref_node(vap->iv_bss);
+ LKPI_80211_LVIF_LOCK(lvif);
+ /* XXX-BZ KASSERT later? */
+ if (lvif->lvif_bss_synched || lvif->lvif_bss != NULL) {
+ ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
+ "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
+ lvif, vap, vap->iv_bss, lvif->lvif_bss,
+ (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
+ lvif->lvif_bss_synched);
+ return (EBUSY);
+ }
+ LKPI_80211_LVIF_UNLOCK(lvif);
IEEE80211_UNLOCK(vap->iv_ic);
+ LKPI_80211_LHW_LOCK(lhw);
/* Add chanctx (or if exists, change it). */
if (vif->chanctx_conf != NULL) {
conf = vif->chanctx_conf;
+ lchanctx = CHANCTX_CONF_TO_LCHANCTX(conf);
IMPROVE("diff changes for changed, working on live copy, rcu");
} else {
/* Keep separate alloc as in Linux this is rcu managed? */
- conf = malloc(sizeof(*conf) + hw->chanctx_data_size,
+ lchanctx = malloc(sizeof(*lchanctx) + hw->chanctx_data_size,
M_LKPI80211, M_WAITOK | M_ZERO);
+ conf = &lchanctx->conf;
}
conf->rx_chains_dynamic = 1;
@@ -955,12 +1158,54 @@ lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int
conf->def.width = NL80211_CHAN_WIDTH_20_NOHT;
conf->def.center_freq1 = chan->center_freq;
conf->def.center_freq2 = 0;
+ IMPROVE("Check vht_cap from band not just chan?");
+ KASSERT(ni->ni_chan != NULL && ni->ni_chan != IEEE80211_CHAN_ANYC,
+ ("%s:%d: ni %p ni_chan %p\n", __func__, __LINE__, ni, ni->ni_chan));
+#ifdef LKPI_80211_HT
+ if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) {
+ if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
+ conf->def.width = NL80211_CHAN_WIDTH_40;
+ } else
+ conf->def.width = NL80211_CHAN_WIDTH_20;
+ }
+#endif
+#ifdef LKPI_80211_VHT
+ if (IEEE80211_IS_CHAN_VHT(ni->ni_chan)) {
+#ifdef __notyet__
+ if (IEEE80211_IS_CHAN_VHT80P80(ni->ni_chan)) {
+ conf->def.width = NL80211_CHAN_WIDTH_80P80;
+ conf->def.center_freq2 = 0; /* XXX */
+ } else
+#endif
+ if (IEEE80211_IS_CHAN_VHT160(ni->ni_chan))
+ conf->def.width = NL80211_CHAN_WIDTH_160;
+ else if (IEEE80211_IS_CHAN_VHT80(ni->ni_chan))
+ conf->def.width = NL80211_CHAN_WIDTH_80;
+ }
+#endif
/* Responder ... */
conf->min_def.chan = chan;
conf->min_def.width = NL80211_CHAN_WIDTH_20_NOHT;
conf->min_def.center_freq1 = chan->center_freq;
conf->min_def.center_freq2 = 0;
- IMPROVE("currently 20_NOHT only");
+ IMPROVE("currently 20_NOHT min_def only");
+
+ /* Set bss info (bss_info_changed). */
+ bss_changed = 0;
+ vif->bss_conf.bssid = ni->ni_bssid;
+ bss_changed |= BSS_CHANGED_BSSID;
+ vif->bss_conf.txpower = ni->ni_txpower;
+ bss_changed |= BSS_CHANGED_TXPOWER;
+ vif->cfg.idle = false;
+ bss_changed |= BSS_CHANGED_IDLE;
+
+ /* vif->bss_conf.basic_rates ? Where exactly? */
+
+ /* Should almost assert it is this. */
+ vif->cfg.assoc = false;
+ vif->cfg.aid = 0;
+
+ bss_changed |= lkpi_update_dtim_tsf(vif, ni, vap, __func__, __LINE__);
error = 0;
if (vif->chanctx_conf != NULL) {
@@ -976,65 +1221,76 @@ lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int
vif->bss_conf.chandef.width = conf->def.width;
vif->bss_conf.chandef.center_freq1 =
conf->def.center_freq1;
+#ifdef LKPI_80211_HT
+ if (vif->bss_conf.chandef.width == NL80211_CHAN_WIDTH_40) {
+ /* Note: it is 10 not 20. */
+ if (IEEE80211_IS_CHAN_HT40U(ni->ni_chan))
+ vif->bss_conf.chandef.center_freq1 += 10;
+ else if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan))
+ vif->bss_conf.chandef.center_freq1 -= 10;
+ }
+#endif
vif->bss_conf.chandef.center_freq2 =
conf->def.center_freq2;
} else {
+ ic_printf(vap->iv_ic, "%s:%d: mo_add_chanctx "
+ "failed: %d\n", __func__, __LINE__, error);
goto out;
}
+
+ vif->bss_conf.chanctx_conf = conf;
+
/* Assign vif chanctx. */
if (error == 0)
- error = lkpi_80211_mo_assign_vif_chanctx(hw, vif, conf);
+ error = lkpi_80211_mo_assign_vif_chanctx(hw, vif,
+ &vif->bss_conf, conf);
if (error == EOPNOTSUPP)
error = 0;
if (error != 0) {
+ ic_printf(vap->iv_ic, "%s:%d: mo_assign_vif_chanctx "
+ "failed: %d\n", __func__, __LINE__, error);
lkpi_80211_mo_remove_chanctx(hw, conf);
- free(conf, M_LKPI80211);
+ lchanctx = CHANCTX_CONF_TO_LCHANCTX(conf);
+ free(lchanctx, M_LKPI80211);
goto out;
}
}
IMPROVE("update radiotap chan fields too");
- /* Set bss info (bss_info_changed). */
- bss_changed = 0;
- IEEE80211_ADDR_COPY(vif->bss_conf.bssid, ni->ni_bssid);
- bss_changed |= BSS_CHANGED_BSSID;
- vif->bss_conf.txpower = ni->ni_txpower;
- bss_changed |= BSS_CHANGED_TXPOWER;
- vif->bss_conf.idle = false;
- bss_changed |= BSS_CHANGED_IDLE;
-
- /* Should almost assert it is this. */
- vif->bss_conf.assoc = false;
- vif->bss_conf.aid = 0;
-
- bss_changed |= lkpi_update_dtim_tsf(vif, ni, vap, __func__, __LINE__);
-
/* RATES */
IMPROVE("bss info: not all needs to come now and rates are missing");
lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);
/*
- * This is a bandaid for now. If we went through (*iv_update_bss)()
- * and then removed the lsta we end up here without a lsta and have
- * to manually allocate and link it in as lkpi_ic_node_alloc()/init()
- * would normally do.
- * XXX-BZ I do not like this but currently we have no good way of
- * intercepting the bss swap and state changes and packets going out
- * workflow so live with this. It is a compat layer after all.
+ * Given ni and lsta are 1:1 from alloc to free we can assert that
+ * ni always has lsta data attach despite net80211 node swapping
+ * under the hoods.
*/
- if (ni->ni_drv_data == NULL) {
- lsta = lkpi_lsta_alloc(vap, ni->ni_macaddr, hw, ni);
- if (lsta == NULL) {
- error = ENOMEM;
- goto out;
- }
- lsta->ni = ieee80211_ref_node(ni);
- } else {
- lsta = ni->ni_drv_data;
- }
+ KASSERT(ni->ni_drv_data != NULL, ("%s: ni %p ni_drv_data %p\n",
+ __func__, ni, ni->ni_drv_data));
+ lsta = ni->ni_drv_data;
- /* Insert the [l]sta into the list of known stations. */
LKPI_80211_LVIF_LOCK(lvif);
+ /* Re-check given (*iv_update_bss) could have happened. */
+ /* XXX-BZ KASSERT later? or deal as error? */
+ if (lvif->lvif_bss_synched || lvif->lvif_bss != NULL)
+ ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
+ "lvif_bss->ni %p synched %d, ni %p lsta %p\n", __func__, __LINE__,
+ lvif, vap, vap->iv_bss, lvif->lvif_bss,
+ (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
+ lvif->lvif_bss_synched, ni, lsta);
+
+ /*
+ * Reference the ni for this cache of lsta/ni on lvif->lvif_bss
+ * essentially out lsta version of the iv_bss.
+ * Do NOT use iv_bss here anymore as that may have diverged from our
+ * function local ni already and would lead to inconsistencies.
+ */
+ ieee80211_ref_node(ni);
+ lvif->lvif_bss = lsta;
+ lvif->lvif_bss_synched = true;
+
+ /* Insert the [l]sta into the list of known stations. */
TAILQ_INSERT_TAIL(&lvif->lsta_head, lsta, lsta_entry);
LKPI_80211_LVIF_UNLOCK(lvif);
@@ -1042,10 +1298,11 @@ lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int
KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
KASSERT(lsta->state == IEEE80211_STA_NOTEXIST, ("%s: lsta %p state not "
"NOTEXIST: %#x\n", __func__, lsta, lsta->state));
- sta = LSTA_TO_STA(lsta);
- error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_NONE);
+ error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NONE);
if (error != 0) {
IMPROVE("do we need to undo the chan ctx?");
+ ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NONE) "
+ "failed: %d\n", __func__, __LINE__, error);
goto out;
}
#if 0
@@ -1054,6 +1311,7 @@ lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
+#if 0
/*
* Wakeup all queues now that sta is there so we have as much time to
* possibly prepare the queue in the driver to be ready for the 1st
@@ -1062,7 +1320,8 @@ lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int
* XXX-BZ and by now we know that this does not work on all drivers
* for all queues.
*/
- lkpi_wake_tx_queues(hw, sta, false, false);
+ lkpi_wake_tx_queues(hw, LSTA_TO_STA(lsta), false, false);
+#endif
/* Start mgd_prepare_tx. */
memset(&prep_tx_info, 0, sizeof(prep_tx_info));
@@ -1080,7 +1339,12 @@ lkpi_sta_scan_to_auth(struct ieee80211vap *vap, enum ieee80211_state nstate, int
*/
out:
+ LKPI_80211_LHW_UNLOCK(lhw);
IEEE80211_LOCK(vap->iv_ic);
+ /*
+ * Release the reference that keop the ni stable locally
+ * during the work of this function.
+ */
if (ni != NULL)
ieee80211_free_node(ni);
return (error);
@@ -1104,14 +1368,29 @@ lkpi_sta_auth_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int
lvif = VAP_TO_LVIF(vap);
vif = LVIF_TO_VIF(lvif);
- /* Keep ni around. */
- ni = ieee80211_ref_node(vap->iv_bss);
- lsta = ni->ni_drv_data;
+ LKPI_80211_LVIF_LOCK(lvif);
+#ifdef LINUXKPI_DEBUG_80211
+ /* XXX-BZ KASSERT later; state going down so no action. */
+ if (lvif->lvif_bss == NULL)
+ ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
+ "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
+ lvif, vap, vap->iv_bss, lvif->lvif_bss,
+ (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
+ lvif->lvif_bss_synched);
+#endif
+
+ lsta = lvif->lvif_bss;
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "
+ "lvif %p vap %p\n", __func__,
+ lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));
+ ni = lsta->ni; /* Reference held for lvif_bss. */
sta = LSTA_TO_STA(lsta);
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
IEEE80211_UNLOCK(vap->iv_ic);
+ LKPI_80211_LHW_LOCK(lhw);
/* flush, drop. */
lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), true);
@@ -1142,9 +1421,11 @@ lkpi_sta_auth_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int
KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
KASSERT(lsta->state == IEEE80211_STA_NONE, ("%s: lsta %p state not "
"NONE: %#x, nstate %d arg %d\n", __func__, lsta, lsta->state, nstate, arg));
- error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST);
+ error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NOTEXIST);
if (error != 0) {
IMPROVE("do we need to undo the chan ctx?");
+ ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NOTEXIST) "
+ "failed: %d\n", __func__, __LINE__, error);
goto out;
}
#if 0
@@ -1153,28 +1434,40 @@ lkpi_sta_auth_to_scan(struct ieee80211vap *vap, enum ieee80211_state nstate, int
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
+ LKPI_80211_LVIF_LOCK(lvif);
+ /* Remove ni reference for this cache of lsta. */
+ lvif->lvif_bss = NULL;
+ lvif->lvif_bss_synched = false;
+ LKPI_80211_LVIF_UNLOCK(lvif);
lkpi_lsta_remove(lsta, lvif);
+ /*
+ * The very last release the reference on the ni for the ni/lsta on
+ * lvif->lvif_bss. Upon return from this both ni and lsta are invalid
+ * and potentially freed.
+ */
+ ieee80211_free_node(ni);
/* conf_tx */
/* Take the chan ctx down. */
if (vif->chanctx_conf != NULL) {
+ struct lkpi_chanctx *lchanctx;
struct ieee80211_chanctx_conf *conf;
conf = vif->chanctx_conf;
/* Remove vif context. */
- lkpi_80211_mo_unassign_vif_chanctx(hw, vif, &vif->chanctx_conf);
+ lkpi_80211_mo_unassign_vif_chanctx(hw, vif, &vif->bss_conf, &vif->chanctx_conf);
/* NB: vif->chanctx_conf is NULL now. */
/* Remove chan ctx. */
lkpi_80211_mo_remove_chanctx(hw, conf);
- free(conf, M_LKPI80211);
+ lchanctx = CHANCTX_CONF_TO_LCHANCTX(conf);
+ free(lchanctx, M_LKPI80211);
}
out:
+ LKPI_80211_LHW_UNLOCK(lhw);
IEEE80211_LOCK(vap->iv_ic);
- if (ni != NULL)
- ieee80211_free_node(ni);
return (error);
}
@@ -1196,9 +1489,7 @@ lkpi_sta_auth_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, in
struct ieee80211_hw *hw;
struct lkpi_vif *lvif;
struct ieee80211_vif *vif;
- struct ieee80211_node *ni;
struct lkpi_sta *lsta;
- struct ieee80211_sta *sta;
struct ieee80211_prep_tx_info prep_tx_info;
int error;
@@ -1208,21 +1499,39 @@ lkpi_sta_auth_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, in
vif = LVIF_TO_VIF(lvif);
IEEE80211_UNLOCK(vap->iv_ic);
- ni = NULL;
+ LKPI_80211_LHW_LOCK(lhw);
+
+ LKPI_80211_LVIF_LOCK(lvif);
+ /* XXX-BZ KASSERT later? */
+ if (!lvif->lvif_bss_synched || lvif->lvif_bss == NULL) {
+#ifdef LINUXKPI_DEBUG_80211
+ ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
+ "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
+ lvif, vap, vap->iv_bss, lvif->lvif_bss,
+ (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
+ lvif->lvif_bss_synched);
+#endif
+ error = ENOTRECOVERABLE;
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ goto out;
+ }
+ lsta = lvif->lvif_bss;
+ LKPI_80211_LVIF_UNLOCK(lvif);
+
+ KASSERT(lsta != NULL, ("%s: lsta %p\n", __func__, lsta));
/* Finish auth. */
IMPROVE("event callback");
/* Update sta_state (NONE to AUTH). */
- ni = ieee80211_ref_node(vap->iv_bss);
- lsta = ni->ni_drv_data;
- KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
KASSERT(lsta->state == IEEE80211_STA_NONE, ("%s: lsta %p state not "
"NONE: %#x\n", __func__, lsta, lsta->state));
- sta = LSTA_TO_STA(lsta);
- error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_AUTH);
- if (error != 0)
+ error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_AUTH);
+ if (error != 0) {
+ ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(AUTH) "
+ "failed: %d\n", __func__, __LINE__, error);
goto out;
+ }
/* End mgd_complete_tx. */
if (lsta->in_mgd) {
@@ -1243,7 +1552,7 @@ lkpi_sta_auth_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, in
}
/* Wake tx queue to get packet out. */
- lkpi_wake_tx_queues(hw, sta, true, true);
+ lkpi_wake_tx_queues(hw, LSTA_TO_STA(lsta), true, true);
/*
* <twiddle> .. we end up in "assoc_to_run"
@@ -1256,9 +1565,8 @@ lkpi_sta_auth_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, in
*/
out:
+ LKPI_80211_LHW_UNLOCK(lhw);
IEEE80211_LOCK(vap->iv_ic);
- if (ni != NULL)
- ieee80211_free_node(ni);
return (error);
}
@@ -1270,19 +1578,37 @@ lkpi_sta_a_to_a(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
struct ieee80211_hw *hw;
struct lkpi_vif *lvif;
struct ieee80211_vif *vif;
- struct ieee80211_node *ni;
struct lkpi_sta *lsta;
struct ieee80211_prep_tx_info prep_tx_info;
+ int error;
lhw = vap->iv_ic->ic_softc;
hw = LHW_TO_HW(lhw);
lvif = VAP_TO_LVIF(vap);
vif = LVIF_TO_VIF(lvif);
- ni = ieee80211_ref_node(vap->iv_bss);
-
IEEE80211_UNLOCK(vap->iv_ic);
- lsta = ni->ni_drv_data;
+ LKPI_80211_LHW_LOCK(lhw);
+
+ LKPI_80211_LVIF_LOCK(lvif);
+ /* XXX-BZ KASSERT later? */
+ if (!lvif->lvif_bss_synched || lvif->lvif_bss == NULL) {
+#ifdef LINUXKPI_DEBUG_80211
+ ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
+ "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
+ lvif, vap, vap->iv_bss, lvif->lvif_bss,
+ (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
+ lvif->lvif_bss_synched);
+#endif
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ error = ENOTRECOVERABLE;
+ goto out;
+ }
+ lsta = lvif->lvif_bss;
+ LKPI_80211_LVIF_UNLOCK(lvif);
+
+ KASSERT(lsta != NULL, ("%s: lsta %p! lvif %p vap %p\n", __func__,
+ lsta, lvif, vap));
IMPROVE("event callback?");
@@ -1304,11 +1630,12 @@ lkpi_sta_a_to_a(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
lsta->in_mgd = true;
}
+ error = 0;
+out:
+ LKPI_80211_LHW_UNLOCK(lhw);
IEEE80211_LOCK(vap->iv_ic);
- if (ni != NULL)
- ieee80211_free_node(ni);
- return (0);
+ return (error);
}
static int
@@ -1330,15 +1657,30 @@ _lkpi_sta_assoc_to_down(struct ieee80211vap *vap, enum ieee80211_state nstate, i
lvif = VAP_TO_LVIF(vap);
vif = LVIF_TO_VIF(lvif);
- /* Keep ni around. */
- ni = ieee80211_ref_node(vap->iv_bss);
- lsta = ni->ni_drv_data;
+ IEEE80211_UNLOCK(vap->iv_ic);
+ LKPI_80211_LHW_LOCK(lhw);
+
+ LKPI_80211_LVIF_LOCK(lvif);
+#ifdef LINUXKPI_DEBUG_80211
+ /* XXX-BZ KASSERT later; state going down so no action. */
+ if (lvif->lvif_bss == NULL)
+ ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
+ "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
+ lvif, vap, vap->iv_bss, lvif->lvif_bss,
+ (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
+ lvif->lvif_bss_synched);
+#endif
+ lsta = lvif->lvif_bss;
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "
+ "lvif %p vap %p\n", __func__,
+ lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));
+
+ ni = lsta->ni; /* Reference held for lvif_bss. */
sta = LSTA_TO_STA(lsta);
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
- IEEE80211_UNLOCK(vap->iv_ic);
-
/* flush, drop. */
lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), true);
@@ -1351,14 +1693,19 @@ _lkpi_sta_assoc_to_down(struct ieee80211vap *vap, enum ieee80211_state nstate, i
lsta->in_mgd = true;
}
+ LKPI_80211_LHW_UNLOCK(lhw);
IEEE80211_LOCK(vap->iv_ic);
/* Call iv_newstate first so we get potential DISASSOC packet out. */
error = lvif->iv_newstate(vap, nstate, arg);
- if (error != 0)
+ if (error != 0) {
+ ic_printf(vap->iv_ic, "%s:%d: iv_newstate(%p, %d, %d) "
+ "failed: %d\n", __func__, __LINE__, vap, nstate, arg, error);
goto outni;
+ }
IEEE80211_UNLOCK(vap->iv_ic);
+ LKPI_80211_LHW_LOCK(lhw);
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
@@ -1388,64 +1735,83 @@ _lkpi_sta_assoc_to_down(struct ieee80211vap *vap, enum ieee80211_state nstate, i
KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
KASSERT(lsta->state == IEEE80211_STA_AUTH, ("%s: lsta %p state not "
"AUTH: %#x\n", __func__, lsta, lsta->state));
- error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_NONE);
- if (error != 0)
+ error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NONE);
+ if (error != 0) {
+ ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NONE) "
+ "failed: %d\n", __func__, __LINE__, error);
goto out;
+ }
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
+ /* Update bss info (bss_info_changed) (assoc, aid, ..). */
+ /*
+ * We need to do this now, before sta changes to IEEE80211_STA_NOTEXIST
+ * as otherwise drivers (iwlwifi at least) will silently not remove
+ * the sta from the firmware and when we will add a new one trigger
+ * a fw assert.
+ */
+ lkpi_disassoc(sta, vif, lhw);
+
/* Adjust sta and change state (from NONE) to NOTEXIST. */
KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
KASSERT(lsta->state == IEEE80211_STA_NONE, ("%s: lsta %p state not "
"NONE: %#x, nstate %d arg %d\n", __func__, lsta, lsta->state, nstate, arg));
- error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST);
+ error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NOTEXIST);
if (error != 0) {
IMPROVE("do we need to undo the chan ctx?");
+ ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NOTEXIST) "
+ "failed: %d\n", __func__, __LINE__, error);
goto out;
}
-#if 0
- lsta->added_to_drv = false; /* mo manages. */
-#endif
- lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
-
- /* Update bss info (bss_info_changed) (assoc, aid, ..). */
- /* We need to do this now, can only do after sta is IEEE80211_STA_NOTEXIST. */
- lkpi_disassoc(sta, vif, lhw);
+ lkpi_lsta_dump(lsta, ni, __func__, __LINE__); /* sta no longer save to use. */
IMPROVE("Any bss_info changes to announce?");
bss_changed = 0;
vif->bss_conf.qos = 0;
bss_changed |= BSS_CHANGED_QOS;
- vif->bss_conf.ssid_len = 0;
- memset(vif->bss_conf.ssid, '\0', sizeof(vif->bss_conf.ssid));
+ vif->cfg.ssid_len = 0;
+ memset(vif->cfg.ssid, '\0', sizeof(vif->cfg.ssid));
bss_changed |= BSS_CHANGED_BSSID;
lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);
+ LKPI_80211_LVIF_LOCK(lvif);
+ /* Remove ni reference for this cache of lsta. */
+ lvif->lvif_bss = NULL;
+ lvif->lvif_bss_synched = false;
+ LKPI_80211_LVIF_UNLOCK(lvif);
lkpi_lsta_remove(lsta, lvif);
+ /*
+ * The very last release the reference on the ni for the ni/lsta on
+ * lvif->lvif_bss. Upon return from this both ni and lsta are invalid
+ * and potentially freed.
+ */
+ ieee80211_free_node(ni);
/* conf_tx */
/* Take the chan ctx down. */
if (vif->chanctx_conf != NULL) {
+ struct lkpi_chanctx *lchanctx;
struct ieee80211_chanctx_conf *conf;
conf = vif->chanctx_conf;
/* Remove vif context. */
- lkpi_80211_mo_unassign_vif_chanctx(hw, vif, &vif->chanctx_conf);
+ lkpi_80211_mo_unassign_vif_chanctx(hw, vif, &vif->bss_conf, &vif->chanctx_conf);
/* NB: vif->chanctx_conf is NULL now. */
/* Remove chan ctx. */
lkpi_80211_mo_remove_chanctx(hw, conf);
- free(conf, M_LKPI80211);
+ lchanctx = CHANCTX_CONF_TO_LCHANCTX(conf);
+ free(lchanctx, M_LKPI80211);
}
error = EALREADY;
out:
+ LKPI_80211_LHW_UNLOCK(lhw);
IEEE80211_LOCK(vap->iv_ic);
outni:
- if (ni != NULL)
- ieee80211_free_node(ni);
return (error);
}
@@ -1502,36 +1868,65 @@ lkpi_sta_assoc_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int
vif = LVIF_TO_VIF(lvif);
IEEE80211_UNLOCK(vap->iv_ic);
- ni = NULL;
+ LKPI_80211_LHW_LOCK(lhw);
+
+ LKPI_80211_LVIF_LOCK(lvif);
+ /* XXX-BZ KASSERT later? */
+ if (!lvif->lvif_bss_synched || lvif->lvif_bss == NULL) {
+#ifdef LINUXKPI_DEBUG_80211
+ ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
+ "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
+ lvif, vap, vap->iv_bss, lvif->lvif_bss,
+ (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
+ lvif->lvif_bss_synched);
+#endif
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ error = ENOTRECOVERABLE;
+ goto out;
+ }
+ lsta = lvif->lvif_bss;
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "
+ "lvif %p vap %p\n", __func__,
+ lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));
+
+ ni = lsta->ni; /* Reference held for lvif_bss. */
IMPROVE("ponder some of this moved to ic_newassoc, scan_assoc_success, "
"and to lesser extend ieee80211_notify_node_join");
/* Finish assoc. */
/* Update sta_state (AUTH to ASSOC) and set aid. */
- ni = ieee80211_ref_node(vap->iv_bss);
- lsta = ni->ni_drv_data;
- KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
KASSERT(lsta->state == IEEE80211_STA_AUTH, ("%s: lsta %p state not "
"AUTH: %#x\n", __func__, lsta, lsta->state));
sta = LSTA_TO_STA(lsta);
sta->aid = IEEE80211_NODE_AID(ni);
- error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_ASSOC);
- if (error != 0)
+#ifdef LKPI_80211_WME
+ if (vap->iv_flags & IEEE80211_F_WME)
+ sta->wme = true;
+#endif
+ error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_ASSOC);
+ if (error != 0) {
+ ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(ASSOC) "
+ "failed: %d\n", __func__, __LINE__, error);
goto out;
+ }
IMPROVE("wme / conf_tx [all]");
/* Update bss info (bss_info_changed) (assoc, aid, ..). */
bss_changed = 0;
- if (!vif->bss_conf.assoc || vif->bss_conf.aid != IEEE80211_NODE_AID(ni)) {
- vif->bss_conf.assoc = true;
- vif->bss_conf.aid = IEEE80211_NODE_AID(ni);
+#ifdef LKPI_80211_WME
+ bss_changed |= lkpi_wme_update(lhw, vap, true);
+#endif
+ if (!vif->cfg.assoc || vif->cfg.aid != IEEE80211_NODE_AID(ni)) {
+ vif->cfg.assoc = true;
+ vif->cfg.aid = IEEE80211_NODE_AID(ni);
bss_changed |= BSS_CHANGED_ASSOC;
}
/* We set SSID but this is not BSSID! */
- vif->bss_conf.ssid_len = ni->ni_esslen;
- memcpy(vif->bss_conf.ssid, ni->ni_essid, ni->ni_esslen);
+ vif->cfg.ssid_len = ni->ni_esslen;
+ memcpy(vif->cfg.ssid, ni->ni_essid, ni->ni_esslen);
if ((vap->iv_flags & IEEE80211_F_SHPREAMBLE) !=
vif->bss_conf.use_short_preamble) {
vif->bss_conf.use_short_preamble ^= 1;
@@ -1582,13 +1977,20 @@ lkpi_sta_assoc_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int
IMPROVE("net80211 does not consider node authorized");
}
+#if defined(LKPI_80211_HT)
+ IMPROVE("Is this the right spot, has net80211 done all updates already?");
+ lkpi_sta_sync_ht_from_ni(sta, ni, NULL);
+#endif
+
/* Update sta_state (ASSOC to AUTHORIZED). */
KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
KASSERT(lsta->state == IEEE80211_STA_ASSOC, ("%s: lsta %p state not "
"ASSOC: %#x\n", __func__, lsta, lsta->state));
- error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_AUTHORIZED);
+ error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_AUTHORIZED);
if (error != 0) {
IMPROVE("undo some changes?");
+ ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(AUTHORIZED) "
+ "failed: %d\n", __func__, __LINE__, error);
goto out;
}
@@ -1605,9 +2007,8 @@ lkpi_sta_assoc_to_run(struct ieee80211vap *vap, enum ieee80211_state nstate, int
lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);
out:
+ LKPI_80211_LHW_UNLOCK(lhw);
IEEE80211_LOCK(vap->iv_ic);
- if (ni != NULL)
- ieee80211_free_node(ni);
return (error);
}
@@ -1643,14 +2044,29 @@ lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int
lvif = VAP_TO_LVIF(vap);
vif = LVIF_TO_VIF(lvif);
- /* Keep ni around. */
- ni = ieee80211_ref_node(vap->iv_bss);
- lsta = ni->ni_drv_data;
+ LKPI_80211_LVIF_LOCK(lvif);
+#ifdef LINUXKPI_DEBUG_80211
+ /* XXX-BZ KASSERT later; state going down so no action. */
+ if (lvif->lvif_bss == NULL)
+ ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
+ "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
+ lvif, vap, vap->iv_bss, lvif->lvif_bss,
+ (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
+ lvif->lvif_bss_synched);
+#endif
+ lsta = lvif->lvif_bss;
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "
+ "lvif %p vap %p\n", __func__,
+ lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));
+
+ ni = lsta->ni; /* Reference held for lvif_bss. */
sta = LSTA_TO_STA(lsta);
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
IEEE80211_UNLOCK(vap->iv_ic);
+ LKPI_80211_LHW_LOCK(lhw);
/* flush, drop. */
lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), true);
@@ -1664,14 +2080,19 @@ lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int
lsta->in_mgd = true;
}
+ LKPI_80211_LHW_UNLOCK(lhw);
IEEE80211_LOCK(vap->iv_ic);
/* Call iv_newstate first so we get potential DISASSOC packet out. */
error = lvif->iv_newstate(vap, nstate, arg);
- if (error != 0)
+ if (error != 0) {
+ ic_printf(vap->iv_ic, "%s:%d: iv_newstate(%p, %d, %d) "
+ "failed: %d\n", __func__, __LINE__, vap, nstate, arg, error);
goto outni;
+ }
IEEE80211_UNLOCK(vap->iv_ic);
+ LKPI_80211_LHW_LOCK(lhw);
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
@@ -1703,9 +2124,12 @@ lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int
KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
KASSERT(lsta->state == IEEE80211_STA_AUTHORIZED, ("%s: lsta %p state not "
"AUTHORIZED: %#x\n", __func__, lsta, lsta->state));
- error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_ASSOC);
- if (error != 0)
+ error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_ASSOC);
+ if (error != 0) {
+ ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(ASSOC) "
+ "failed: %d\n", __func__, __LINE__, error);
goto out;
+ }
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
@@ -1713,9 +2137,12 @@ lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int
KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
KASSERT(lsta->state == IEEE80211_STA_ASSOC, ("%s: lsta %p state not "
"ASSOC: %#x\n", __func__, lsta, lsta->state));
- error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_AUTH);
- if (error != 0)
+ error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_AUTH);
+ if (error != 0) {
+ ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(AUTH) "
+ "failed: %d\n", __func__, __LINE__, error);
goto out;
+ }
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
@@ -1726,10 +2153,9 @@ lkpi_sta_run_to_assoc(struct ieee80211vap *vap, enum ieee80211_state nstate, int
error = EALREADY;
out:
+ LKPI_80211_LHW_UNLOCK(lhw);
IEEE80211_LOCK(vap->iv_ic);
outni:
- if (ni != NULL)
- ieee80211_free_node(ni);
return (error);
}
@@ -1752,15 +2178,30 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int
lvif = VAP_TO_LVIF(vap);
vif = LVIF_TO_VIF(lvif);
- /* Keep ni around. */
- ni = ieee80211_ref_node(vap->iv_bss);
- lsta = ni->ni_drv_data;
+ IEEE80211_UNLOCK(vap->iv_ic);
+ LKPI_80211_LHW_LOCK(lhw);
+
+ LKPI_80211_LVIF_LOCK(lvif);
+#ifdef LINUXKPI_DEBUG_80211
+ /* XXX-BZ KASSERT later; state going down so no action. */
+ if (lvif->lvif_bss == NULL)
+ ic_printf(vap->iv_ic, "%s:%d: lvif %p vap %p iv_bss %p lvif_bss %p "
+ "lvif_bss->ni %p synched %d\n", __func__, __LINE__,
+ lvif, vap, vap->iv_bss, lvif->lvif_bss,
+ (lvif->lvif_bss != NULL) ? lvif->lvif_bss->ni : NULL,
+ lvif->lvif_bss_synched);
+#endif
+ lsta = lvif->lvif_bss;
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ KASSERT(lsta != NULL && lsta->ni != NULL, ("%s: lsta %p ni %p "
+ "lvif %p vap %p\n", __func__,
+ lsta, (lsta != NULL) ? lsta->ni : NULL, lvif, vap));
+
+ ni = lsta->ni; /* Reference held for lvif_bss. */
sta = LSTA_TO_STA(lsta);
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
- IEEE80211_UNLOCK(vap->iv_ic);
-
/* flush, drop. */
lkpi_80211_mo_flush(hw, vif, nitems(sta->txq), true);
@@ -1773,14 +2214,19 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int
lsta->in_mgd = true;
}
+ LKPI_80211_LHW_UNLOCK(lhw);
IEEE80211_LOCK(vap->iv_ic);
/* Call iv_newstate first so we get potential DISASSOC packet out. */
error = lvif->iv_newstate(vap, nstate, arg);
- if (error != 0)
+ if (error != 0) {
+ ic_printf(vap->iv_ic, "%s:%d: iv_newstate(%p, %d, %d) "
+ "failed: %d\n", __func__, __LINE__, vap, nstate, arg, error);
goto outni;
+ }
IEEE80211_UNLOCK(vap->iv_ic);
+ LKPI_80211_LHW_LOCK(lhw);
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
@@ -1810,9 +2256,12 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int
KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
KASSERT(lsta->state == IEEE80211_STA_AUTHORIZED, ("%s: lsta %p state not "
"AUTHORIZED: %#x\n", __func__, lsta, lsta->state));
- error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_ASSOC);
- if (error != 0)
+ error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_ASSOC);
+ if (error != 0) {
+ ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(ASSOC) "
+ "failed: %d\n", __func__, __LINE__, error);
goto out;
+ }
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
@@ -1820,9 +2269,12 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int
KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
KASSERT(lsta->state == IEEE80211_STA_ASSOC, ("%s: lsta %p state not "
"ASSOC: %#x\n", __func__, lsta, lsta->state));
- error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_AUTH);
- if (error != 0)
+ error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_AUTH);
+ if (error != 0) {
+ ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(AUTH) "
+ "failed: %d\n", __func__, __LINE__, error);
goto out;
+ }
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
@@ -1830,67 +2282,81 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int
KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
KASSERT(lsta->state == IEEE80211_STA_AUTH, ("%s: lsta %p state not "
"AUTH: %#x\n", __func__, lsta, lsta->state));
- error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_NONE);
- if (error != 0)
+ error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NONE);
+ if (error != 0) {
+ ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NONE) "
+ "failed: %d\n", __func__, __LINE__, error);
goto out;
+ }
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
+ /* Update bss info (bss_info_changed) (assoc, aid, ..). */
+ /*
+ * One would expect this to happen when going off AUTHORIZED.
+ * See comment there; removes the sta from fw.
+ */
+ lkpi_disassoc(sta, vif, lhw);
+
/* Adjust sta and change state (from NONE) to NOTEXIST. */
KASSERT(lsta != NULL, ("%s: ni %p lsta is NULL\n", __func__, ni));
KASSERT(lsta->state == IEEE80211_STA_NONE, ("%s: lsta %p state not "
"NONE: %#x, nstate %d arg %d\n", __func__, lsta, lsta->state, nstate, arg));
- error = lkpi_80211_mo_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST);
+ error = lkpi_80211_mo_sta_state(hw, vif, lsta, IEEE80211_STA_NOTEXIST);
if (error != 0) {
IMPROVE("do we need to undo the chan ctx?");
+ ic_printf(vap->iv_ic, "%s:%d: mo_sta_state(NOTEXIST) "
+ "failed: %d\n", __func__, __LINE__, error);
goto out;
}
-#if 0
- lsta->added_to_drv = false; /* mo manages. */
-#endif
- lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
-
- /* Update bss info (bss_info_changed) (assoc, aid, ..). */
- /*
- * One would expect this to happen when going off AUTHORIZED.
- * See comment there; removes the sta from fw.
- */
- lkpi_disassoc(sta, vif, lhw);
+ lkpi_lsta_dump(lsta, ni, __func__, __LINE__); /* sta no longer save to use. */
IMPROVE("Any bss_info changes to announce?");
bss_changed = 0;
vif->bss_conf.qos = 0;
bss_changed |= BSS_CHANGED_QOS;
- vif->bss_conf.ssid_len = 0;
- memset(vif->bss_conf.ssid, '\0', sizeof(vif->bss_conf.ssid));
+ vif->cfg.ssid_len = 0;
+ memset(vif->cfg.ssid, '\0', sizeof(vif->cfg.ssid));
bss_changed |= BSS_CHANGED_BSSID;
lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, bss_changed);
+ LKPI_80211_LVIF_LOCK(lvif);
+ /* Remove ni reference for this cache of lsta. */
+ lvif->lvif_bss = NULL;
+ lvif->lvif_bss_synched = false;
+ LKPI_80211_LVIF_UNLOCK(lvif);
lkpi_lsta_remove(lsta, lvif);
+ /*
+ * The very last release the reference on the ni for the ni/lsta on
+ * lvif->lvif_bss. Upon return from this both ni and lsta are invalid
+ * and potentially freed.
+ */
+ ieee80211_free_node(ni);
/* conf_tx */
/* Take the chan ctx down. */
if (vif->chanctx_conf != NULL) {
+ struct lkpi_chanctx *lchanctx;
struct ieee80211_chanctx_conf *conf;
conf = vif->chanctx_conf;
/* Remove vif context. */
- lkpi_80211_mo_unassign_vif_chanctx(hw, vif, &vif->chanctx_conf);
+ lkpi_80211_mo_unassign_vif_chanctx(hw, vif, &vif->bss_conf, &vif->chanctx_conf);
/* NB: vif->chanctx_conf is NULL now. */
/* Remove chan ctx. */
lkpi_80211_mo_remove_chanctx(hw, conf);
- free(conf, M_LKPI80211);
+ lchanctx = CHANCTX_CONF_TO_LCHANCTX(conf);
+ free(lchanctx, M_LKPI80211);
}
error = EALREADY;
out:
+ LKPI_80211_LHW_UNLOCK(lhw);
IEEE80211_LOCK(vap->iv_ic);
outni:
- if (ni != NULL)
- ieee80211_free_node(ni);
return (error);
}
@@ -2035,12 +2501,11 @@ lkpi_iv_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
}
if (error != 0) {
- /* XXX-BZ currently expected so ignore. */
ic_printf(vap->iv_ic, "%s: error %d during state transition "
"%d (%s) -> %d (%s)\n", __func__, error,
ostate, ieee80211_state_name[ostate],
nstate, ieee80211_state_name[nstate]);
- /* return (error); */
+ return (error);
}
#ifdef LINUXKPI_DEBUG_80211
@@ -2064,60 +2529,25 @@ static struct ieee80211_node *
lkpi_iv_update_bss(struct ieee80211vap *vap, struct ieee80211_node *ni)
{
struct lkpi_vif *lvif;
- struct ieee80211_node *obss;
- struct lkpi_sta *lsta;
- struct ieee80211_sta *sta;
+ struct ieee80211_node *rni;
- obss = vap->iv_bss;
-
-#ifdef LINUXKPI_DEBUG_80211
- if (linuxkpi_debug_80211 & D80211_TRACE)
- ic_printf(vap->iv_ic, "%s: obss %p ni_drv_data %p "
- "ni %p ni_drv_data %p\n", __func__,
- obss, (obss != NULL) ? obss->ni_drv_data : NULL,
- ni, (ni != NULL) ? ni->ni_drv_data : NULL);
-#endif
-
- /* Nothing to copy from. Just return. */
- if (obss == NULL || obss->ni_drv_data == NULL)
- goto out;
-
- /* Nothing to copy to. Just return. */
- IMPROVE("clearing the obss might still be needed?");
- if (ni == NULL)
- goto out;
+ IEEE80211_LOCK_ASSERT(vap->iv_ic);
- /* Nothing changed? panic? */
- if (obss == ni)
- goto out;
+ lvif = VAP_TO_LVIF(vap);
- lsta = obss->ni_drv_data;
- obss->ni_drv_data = ni->ni_drv_data;
- ni->ni_drv_data = lsta;
- if (lsta != NULL) {
- lsta->ni = ni;
- sta = LSTA_TO_STA(lsta);
- IEEE80211_ADDR_COPY(sta->addr, lsta->ni->ni_macaddr);
- }
- lsta = obss->ni_drv_data;
- if (lsta != NULL) {
- lsta->ni = obss;
- sta = LSTA_TO_STA(lsta);
- IEEE80211_ADDR_COPY(sta->addr, lsta->ni->ni_macaddr);
- }
+ LKPI_80211_LVIF_LOCK(lvif);
+ lvif->lvif_bss_synched = false;
+ LKPI_80211_LVIF_UNLOCK(lvif);
-out:
- lvif = VAP_TO_LVIF(vap);
- return (lvif->iv_update_bss(vap, ni));
+ rni = lvif->iv_update_bss(vap, ni);
+ return (rni);
}
+#ifdef LKPI_80211_WME
static int
-lkpi_ic_wme_update(struct ieee80211com *ic)
+lkpi_wme_update(struct lkpi_hw *lhw, struct ieee80211vap *vap, bool planned)
{
- /* This needs queuing and go at the right moment. */
-#ifdef WITH_WME_UPDATE
- struct ieee80211vap *vap;
- struct lkpi_hw *lhw;
+ struct ieee80211com *ic;
struct ieee80211_hw *hw;
struct lkpi_vif *lvif;
struct ieee80211_vif *vif;
@@ -2127,56 +2557,79 @@ lkpi_ic_wme_update(struct ieee80211com *ic)
enum ieee80211_bss_changed changed;
int error;
uint16_t ac;
-#endif
IMPROVE();
KASSERT(WME_NUM_AC == IEEE80211_NUM_ACS, ("%s: WME_NUM_AC %d != "
"IEEE80211_NUM_ACS %d\n", __func__, WME_NUM_AC, IEEE80211_NUM_ACS));
-#ifdef WITH_WME_UPDATE
- vap = TAILQ_FIRST(&ic->ic_vaps);
if (vap == NULL)
return (0);
- /* We should factor this out into per-vap (*wme_update). */
- lhw = ic->ic_softc;
+ if ((vap->iv_flags & IEEE80211_F_WME) == 0)
+ return (0);
+
if (lhw->ops->conf_tx == NULL)
return (0);
- /* XXX-BZ check amount of hw queues */
- hw = LHW_TO_HW(lhw);
- lvif = VAP_TO_LVIF(vap);
- vif = LVIF_TO_VIF(lvif);
+ if (!planned && (vap->iv_state != IEEE80211_S_RUN)) {
+ lhw->update_wme = true;
+ return (0);
+ }
+ lhw->update_wme = false;
+ ic = lhw->ic;
ieee80211_wme_ic_getparams(ic, &chp);
IEEE80211_LOCK(ic);
for (ac = 0; ac < WME_NUM_AC; ac++)
wmeparr[ac] = chp.cap_wmeParams[ac];
IEEE80211_UNLOCK(ic);
+ hw = LHW_TO_HW(lhw);
+ lvif = VAP_TO_LVIF(vap);
+ vif = LVIF_TO_VIF(lvif);
+
/* Configure tx queues (conf_tx) & send BSS_CHANGED_QOS. */
LKPI_80211_LHW_LOCK(lhw);
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
struct wmeParams *wmep;
- /* XXX-BZ should keep this in lvif? */
wmep = &wmeparr[ac];
bzero(&txqp, sizeof(txqp));
txqp.cw_min = wmep->wmep_logcwmin;
txqp.cw_max = wmep->wmep_logcwmax;
txqp.txop = wmep->wmep_txopLimit;
txqp.aifs = wmep->wmep_aifsn;
- error = lkpi_80211_mo_conf_tx(hw, vif, ac, &txqp);
+ error = lkpi_80211_mo_conf_tx(hw, vif, /* link_id */0, ac, &txqp);
if (error != 0)
- printf("%s: conf_tx ac %u failed %d\n",
+ ic_printf(ic, "%s: conf_tx ac %u failed %d\n",
__func__, ac, error);
}
LKPI_80211_LHW_UNLOCK(lhw);
changed = BSS_CHANGED_QOS;
- lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, changed);
+ if (!planned)
+ lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, changed);
+
+ return (changed);
+}
#endif
- return (0);
+static int
+lkpi_ic_wme_update(struct ieee80211com *ic)
+{
+#ifdef LKPI_80211_WME
+ struct ieee80211vap *vap;
+ struct lkpi_hw *lhw;
+
+ IMPROVE("Use the per-VAP callback in net80211.");
+ vap = TAILQ_FIRST(&ic->ic_vaps);
+ if (vap == NULL)
+ return (0);
+
+ lhw = ic->ic_softc;
+
+ lkpi_wme_update(lhw, vap, false);
+#endif
+ return (0); /* unused */
}
static struct ieee80211vap *
@@ -2190,9 +2643,11 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ],
struct lkpi_vif *lvif;
struct ieee80211vap *vap;
struct ieee80211_vif *vif;
+ struct ieee80211_tx_queue_params txqp;
enum ieee80211_bss_changed changed;
size_t len;
- int error;
+ int error, i;
+ uint16_t ac;
if (!TAILQ_EMPTY(&ic->ic_vaps)) /* 1 so far. Add <n> once this works. */
return (NULL);
@@ -2206,6 +2661,8 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ],
lvif = malloc(len, M_80211_VAP, M_WAITOK | M_ZERO);
mtx_init(&lvif->mtx, "lvif", NULL, MTX_DEF);
TAILQ_INIT(&lvif->lsta_head);
+ lvif->lvif_bss = NULL;
+ lvif->lvif_bss_synched = false;
vap = LVIF_TO_VAP(lvif);
vif = LVIF_TO_VIF(lvif);
@@ -2220,16 +2677,27 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ],
/* XXX-BZ hardcoded for now! */
#if 1
vif->chanctx_conf = NULL;
- vif->bss_conf.idle = true;
- vif->bss_conf.ps = false;
+ vif->bss_conf.vif = vif;
+ /* vap->iv_myaddr is not set until net80211::vap_setup or vap_attach. */
+ IEEE80211_ADDR_COPY(vif->bss_conf.addr, mac);
+ vif->bss_conf.link_id = 0; /* Non-MLO operation. */
vif->bss_conf.chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
vif->bss_conf.use_short_preamble = false; /* vap->iv_flags IEEE80211_F_SHPREAMBLE */
vif->bss_conf.use_short_slot = false; /* vap->iv_flags IEEE80211_F_SHSLOT */
vif->bss_conf.qos = false;
vif->bss_conf.use_cts_prot = false; /* vap->iv_protmode */
vif->bss_conf.ht_operation_mode = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
- vif->bss_conf.assoc = false;
- vif->bss_conf.aid = 0;
+ vif->cfg.aid = 0;
+ vif->cfg.assoc = false;
+ vif->cfg.idle = true;
+ vif->cfg.ps = false;
+ IMPROVE("Check other fields and then figure out whats is left elsewhere of them");
+ /*
+ * We need to initialize it to something as the bss_info_changed call
+ * will try to copy from it in iwlwifi and NULL is a panic.
+ * We will set the proper one in scan_to_auth() before being assoc.
+ */
+ vif->bss_conf.bssid = ieee80211broadcastaddr;
#endif
#if 0
vif->bss_conf.dtim_period = 0; /* IEEE80211_DTIM_DEFAULT ; must stay 0. */
@@ -2239,11 +2707,32 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ],
if (vif->bss_conf.beacon_int < 16)
vif->bss_conf.beacon_int = 16;
#endif
+
+ /* Link Config */
+ vif->link_conf[0] = &vif->bss_conf;
+ for (i = 0; i < nitems(vif->link_conf); i++) {
+ IMPROVE("more than 1 link one day");
+ }
+
+ /* Setup queue defaults; driver may override in (*add_interface). */
+ for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+ if (ieee80211_hw_check(hw, QUEUE_CONTROL))
+ vif->hw_queue[i] = IEEE80211_INVAL_HW_QUEUE;
+ else if (hw->queues >= IEEE80211_NUM_ACS)
+ vif->hw_queue[i] = i;
+ else
+ vif->hw_queue[i] = 0;
+
+ /* Initialize the queue to running. Stopped? */
+ lvif->hw_queue_stopped[i] = false;
+ }
+ vif->cab_queue = IEEE80211_INVAL_HW_QUEUE;
+
IMPROVE();
error = lkpi_80211_mo_start(hw);
if (error != 0) {
- printf("%s: failed to start hw: %d\n", __func__, error);
+ ic_printf(ic, "%s: failed to start hw: %d\n", __func__, error);
mtx_destroy(&lvif->mtx);
free(lvif, M_80211_VAP);
return (NULL);
@@ -2252,7 +2741,7 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ],
error = lkpi_80211_mo_add_interface(hw, vif);
if (error != 0) {
IMPROVE(); /* XXX-BZ mo_stop()? */
- printf("%s: failed to add interface: %d\n", __func__, error);
+ ic_printf(ic, "%s: failed to add interface: %d\n", __func__, error);
mtx_destroy(&lvif->mtx);
free(lvif, M_80211_VAP);
return (NULL);
@@ -2266,7 +2755,24 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ],
changed = 0;
lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, changed);
- /* conf_tx setup; default WME? */
+ /* Configure tx queues (conf_tx), default WME & send BSS_CHANGED_QOS. */
+ IMPROVE("Hardcoded values; to fix see 802.11-2016, 9.4.2.29 EDCA Parameter Set element");
+ LKPI_80211_LHW_LOCK(lhw);
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+
+ bzero(&txqp, sizeof(txqp));
+ txqp.cw_min = 15;
+ txqp.cw_max = 1023;
+ txqp.txop = 0;
+ txqp.aifs = 2;
+ error = lkpi_80211_mo_conf_tx(hw, vif, /* link_id */0, ac, &txqp);
+ if (error != 0)
+ ic_printf(ic, "%s: conf_tx ac %u failed %d\n",
+ __func__, ac, error);
+ }
+ LKPI_80211_LHW_UNLOCK(lhw);
+ changed = BSS_CHANGED_QOS;
+ lkpi_80211_mo_bss_info_changed(hw, vif, &vif->bss_conf, changed);
/* Force MC init. */
lkpi_update_mcast_filter(ic, true);
@@ -2283,12 +2789,16 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ],
/* Key management. */
if (lhw->ops->set_key != NULL) {
-#ifdef TRY_HW_CRYPTO
+#ifdef LKPI_80211_HW_CRYPTO
vap->iv_key_set = lkpi_iv_key_set;
vap->iv_key_delete = lkpi_iv_key_delete;
#endif
}
+#ifdef LKPI_80211_HT
+ /* Stay with the iv_ampdu_rxmax,limit / iv_ampdu_density defaults until later. */
+#endif
+
ieee80211_ratectl_init(vap);
/* Complete setup. */
@@ -2301,9 +2811,9 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ],
ic->ic_set_channel(ic);
/* XXX-BZ do we need to be able to update these? */
- hw->wiphy->frag_threshold = vap->iv_fragthreshold;
+ hw->wiphy->frag_threshold = vap->iv_fragthreshold;
lkpi_80211_mo_set_frag_threshold(hw, vap->iv_fragthreshold);
- hw->wiphy->rts_threshold = vap->iv_rtsthreshold;
+ hw->wiphy->rts_threshold = vap->iv_rtsthreshold;
lkpi_80211_mo_set_rts_threshold(hw, vap->iv_rtsthreshold);
/* any others? */
IMPROVE();
@@ -2311,6 +2821,23 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ],
return (vap);
}
+void
+linuxkpi_ieee80211_unregister_hw(struct ieee80211_hw *hw)
+{
+
+ wiphy_unregister(hw->wiphy);
+ linuxkpi_ieee80211_ifdetach(hw);
+
+ IMPROVE();
+}
+
+void
+linuxkpi_ieee80211_restart_hw(struct ieee80211_hw *hw)
+{
+
+ TODO();
+}
+
static void
lkpi_ic_vap_delete(struct ieee80211vap *vap)
{
@@ -2329,10 +2856,17 @@ lkpi_ic_vap_delete(struct ieee80211vap *vap)
LKPI_80211_LHW_LVIF_LOCK(lhw);
TAILQ_REMOVE(&lhw->lvif_head, lvif, lvif_entry);
LKPI_80211_LHW_LVIF_UNLOCK(lhw);
- lkpi_80211_mo_remove_interface(hw, vif);
ieee80211_ratectl_deinit(vap);
ieee80211_vap_detach(vap);
+
+ IMPROVE("clear up other bits in this state");
+
+ lkpi_80211_mo_remove_interface(hw, vif);
+
+ /* Single VAP, so we can do this here. */
+ lkpi_80211_mo_stop(hw);
+
mtx_destroy(&lvif->mtx);
free(lvif, M_80211_VAP);
}
@@ -2364,23 +2898,35 @@ static void
lkpi_ic_parent(struct ieee80211com *ic)
{
struct lkpi_hw *lhw;
+#ifdef HW_START_STOP
struct ieee80211_hw *hw;
int error;
+#endif
bool start_all;
IMPROVE();
lhw = ic->ic_softc;
+#ifdef HW_START_STOP
hw = LHW_TO_HW(lhw);
+#endif
start_all = false;
+ /* IEEE80211_UNLOCK(ic); */
+ LKPI_80211_LHW_LOCK(lhw);
if (ic->ic_nrunning > 0) {
+#ifdef HW_START_STOP
error = lkpi_80211_mo_start(hw);
if (error == 0)
+#endif
start_all = true;
} else {
+#ifdef HW_START_STOP
lkpi_80211_mo_stop(hw);
+#endif
}
+ LKPI_80211_LHW_UNLOCK(lhw);
+ /* IEEE80211_LOCK(ic); */
if (start_all)
ieee80211_start_all(ic);
@@ -2427,11 +2973,13 @@ lkpi_scan_ies_add(uint8_t *p, struct ieee80211_scan_ies *scan_ies,
{
struct ieee80211_supported_band *supband;
struct linuxkpi_ieee80211_channel *channels;
+ struct ieee80211com *ic;
const struct ieee80211_channel *chan;
const struct ieee80211_rateset *rs;
uint8_t *pb;
int band, i;
+ ic = vap->iv_ic;
for (band = 0; band < NUM_NL80211_BANDS; band++) {
if ((band_mask & (1 << band)) == 0)
continue;
@@ -2452,7 +3000,7 @@ lkpi_scan_ies_add(uint8_t *p, struct ieee80211_scan_ies *scan_ies,
if (channels[i].flags & IEEE80211_CHAN_DISABLED)
continue;
- chan = ieee80211_find_channel(vap->iv_ic,
+ chan = ieee80211_find_channel(ic,
channels[i].center_freq, 0);
if (chan != NULL)
break;
@@ -2463,10 +3011,31 @@ lkpi_scan_ies_add(uint8_t *p, struct ieee80211_scan_ies *scan_ies,
continue;
pb = p;
- rs = ieee80211_get_suprates(vap->iv_ic, chan); /* calls chan2mode */
+ rs = ieee80211_get_suprates(ic, chan); /* calls chan2mode */
p = ieee80211_add_rates(p, rs);
p = ieee80211_add_xrates(p, rs);
+#if defined(LKPI_80211_HT)
+ if ((vap->iv_flags_ht & IEEE80211_FHT_HT) != 0) {
+ struct ieee80211_channel *c;
+
+ c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan,
+ vap->iv_flags_ht);
+ p = ieee80211_add_htcap_ch(p, vap, c);
+ }
+#endif
+#if defined(LKPI_80211_VHT)
+ if ((vap->iv_vht_flags & IEEE80211_FVHT_VHT) != 0) {
+ struct ieee80211_channel *c;
+
+ c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan,
+ vap->iv_flags_ht);
+ c = ieee80211_vht_adjust_channel(ic, c,
+ vap->iv_vht_flags);
+ p = ieee80211_add_vhtcap_ch(p, vap, c);
+ }
+#endif
+
scan_ies->ies[band] = pb;
scan_ies->len[band] = p - pb;
}
@@ -2499,12 +3068,17 @@ lkpi_ic_scan_start(struct ieee80211com *ic)
struct ieee80211_scan_state *ss;
struct ieee80211vap *vap;
int error;
+ bool is_hw_scan;
lhw = ic->ic_softc;
- if ((lhw->scan_flags & LKPI_SCAN_RUNNING) != 0) {
+ LKPI_80211_LHW_SCAN_LOCK(lhw);
+ if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0) {
/* A scan is still running. */
+ LKPI_80211_LHW_SCAN_UNLOCK(lhw);
return;
}
+ is_hw_scan = (lhw->scan_flags & LKPI_LHW_SCAN_HW) != 0;
+ LKPI_80211_LHW_SCAN_UNLOCK(lhw);
ss = ic->ic_scan;
vap = ss->ss_vap;
@@ -2514,7 +3088,9 @@ lkpi_ic_scan_start(struct ieee80211com *ic)
}
hw = LHW_TO_HW(lhw);
- if ((vap->iv_flags_ext & IEEE80211_FEXT_SCAN_OFFLOAD) == 0) {
+ if (!is_hw_scan) {
+ /* If hw_scan is cleared clear FEXT_SCAN_OFFLOAD too. */
+ vap->iv_flags_ext &= ~IEEE80211_FEXT_SCAN_OFFLOAD;
sw_scan:
lvif = VAP_TO_LVIF(vap);
vif = LVIF_TO_VIF(lvif);
@@ -2539,12 +3115,7 @@ sw_scan:
int band, i, ssid_count, common_ie_len;
uint32_t band_mask;
uint8_t *ie, *ieend;
-
- if (!ieee80211_hw_check(hw, SINGLE_SCAN_ON_ALL_BANDS)) {
- IMPROVE("individual band scans not yet supported");
- /* In theory net80211 would have to drive this. */
- return;
- }
+ bool running;
ssid_count = min(ss->ss_nssid, hw->wiphy->max_scan_ssids);
ssids_len = ssid_count * sizeof(*ssids);
@@ -2558,6 +3129,18 @@ sw_scan:
ss->ss_chans[ss->ss_next + i]);
band_mask |= (1 << band);
}
+
+ if (!ieee80211_hw_check(hw, SINGLE_SCAN_ON_ALL_BANDS)) {
+ IMPROVE("individual band scans not yet supported, only scanning first band");
+ /* In theory net80211 should drive this. */
+ /* Probably we need to add local logic for now;
+ * need to deal with scan_complete
+ * and cancel_scan and keep local state.
+ * Also cut the nchan down above.
+ */
+ /* XXX-BZ ath10k does not set this but still does it? &$%^ */
+ }
+
chan_len = nchan * (sizeof(lc) + sizeof(*lc));
common_ie_len = 0;
@@ -2574,10 +3157,7 @@ sw_scan:
common_ie_len, hw->wiphy->max_scan_ie_len);
}
- KASSERT(lhw->hw_req == NULL, ("%s: ic %p lhw %p hw_req %p "
- "!= NULL\n", __func__, ic, lhw, lhw->hw_req));
-
- lhw->hw_req = hw_req = malloc(sizeof(*hw_req) + ssids_len +
+ hw_req = malloc(sizeof(*hw_req) + ssids_len +
s6ghzlen + chan_len + lhw->supbands * lhw->scan_ie_len +
common_ie_len, M_LKPI80211, M_WAITOK | M_ZERO);
@@ -2595,6 +3175,7 @@ sw_scan:
memcpy(hw_req->req.mac_addr, xxx, IEEE80211_ADDR_LEN);
memset(hw_req->req.mac_addr_mask, 0xxx, IEEE80211_ADDR_LEN);
#endif
+ eth_broadcast_addr(hw_req->req.bssid);
hw_req->req.n_channels = nchan;
cpp = (struct linuxkpi_ieee80211_channel **)(hw_req + 1);
@@ -2607,7 +3188,7 @@ sw_scan:
c = ss->ss_chans[ss->ss_next + i];
lc->hw_value = c->ic_ieee;
- lc->center_freq = c->ic_freq;
+ lc->center_freq = c->ic_freq; /* XXX */
/* lc->flags */
lc->band = lkpi_net80211_chan_to_nl80211_band(c);
lc->max_power = c->ic_maxpower;
@@ -2644,12 +3225,48 @@ sw_scan:
lvif = VAP_TO_LVIF(vap);
vif = LVIF_TO_VIF(lvif);
+
+ LKPI_80211_LHW_SCAN_LOCK(lhw);
+ /* Re-check under lock. */
+ running = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0;
+ if (!running) {
+ KASSERT(lhw->hw_req == NULL, ("%s: ic %p lhw %p hw_req %p "
+ "!= NULL\n", __func__, ic, lhw, lhw->hw_req));
+
+ lhw->scan_flags |= LKPI_LHW_SCAN_RUNNING;
+ lhw->hw_req = hw_req;
+ }
+ LKPI_80211_LHW_SCAN_UNLOCK(lhw);
+ if (running) {
+ free(hw_req, M_LKPI80211);
+ return;
+ }
+
error = lkpi_80211_mo_hw_scan(hw, vif, hw_req);
if (error != 0) {
ieee80211_cancel_scan(vap);
- free(hw_req, M_LKPI80211);
- lhw->hw_req = NULL;
+ /*
+ * ieee80211_scan_completed must be called in either
+ * case of error or none. So let the free happen there
+ * and only there.
+ * That would be fine in theory but in practice drivers
+ * behave differently:
+ * ath10k does not return hw_scan until after scan_complete
+ * and can then still return an error.
+ * rtw88 can return 1 or -EBUSY without scan_complete
+ * iwlwifi can return various errors before scan starts
+ * ...
+ * So we cannot rely on that behaviour and have to check
+ * and balance between both code paths.
+ */
+ LKPI_80211_LHW_SCAN_LOCK(lhw);
+ if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0) {
+ free(lhw->hw_req, M_LKPI80211);
+ lhw->hw_req = NULL;
+ lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING;
+ }
+ LKPI_80211_LHW_SCAN_UNLOCK(lhw);
/*
* XXX-SIGH magic number.
@@ -2657,6 +3274,14 @@ sw_scan:
* not possible. Fall back to sw scan in that case.
*/
if (error == 1) {
+ LKPI_80211_LHW_SCAN_LOCK(lhw);
+ lhw->scan_flags &= ~LKPI_LHW_SCAN_HW;
+ LKPI_80211_LHW_SCAN_UNLOCK(lhw);
+ /*
+ * XXX If we clear this now and later a driver
+ * thinks it * can do a hw_scan again, we will
+ * currently not re-enable it?
+ */
vap->iv_flags_ext &= ~IEEE80211_FEXT_SCAN_OFFLOAD;
ieee80211_start_scan(vap,
IEEE80211_SCAN_ACTIVE |
@@ -2679,26 +3304,30 @@ static void
lkpi_ic_scan_end(struct ieee80211com *ic)
{
struct lkpi_hw *lhw;
- struct ieee80211_scan_state *ss;
- struct ieee80211vap *vap;
+ bool is_hw_scan;
lhw = ic->ic_softc;
- if ((lhw->scan_flags & LKPI_SCAN_RUNNING) == 0) {
+ LKPI_80211_LHW_SCAN_LOCK(lhw);
+ if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) == 0) {
+ LKPI_80211_LHW_SCAN_UNLOCK(lhw);
return;
}
+ is_hw_scan = (lhw->scan_flags & LKPI_LHW_SCAN_HW) != 0;
+ LKPI_80211_LHW_SCAN_UNLOCK(lhw);
- ss = ic->ic_scan;
- vap = ss->ss_vap;
- if (vap->iv_flags_ext & IEEE80211_FEXT_SCAN_OFFLOAD) {
- /* Nothing to do. */
- } else {
+ if (!is_hw_scan) {
+ struct ieee80211_scan_state *ss;
+ struct ieee80211vap *vap;
struct ieee80211_hw *hw;
struct lkpi_vif *lvif;
struct ieee80211_vif *vif;
+ ss = ic->ic_scan;
+ vap = ss->ss_vap;
hw = LHW_TO_HW(lhw);
lvif = VAP_TO_LVIF(vap);
vif = LVIF_TO_VIF(lvif);
+
lkpi_80211_mo_sw_scan_complete(hw, vif);
/* Send PS to stop buffering if n80211 does not for us? */
@@ -2709,6 +3338,35 @@ lkpi_ic_scan_end(struct ieee80211com *ic)
}
static void
+lkpi_ic_scan_curchan(struct ieee80211_scan_state *ss,
+ unsigned long maxdwell)
+{
+ struct lkpi_hw *lhw;
+ bool is_hw_scan;
+
+ lhw = ss->ss_ic->ic_softc;
+ LKPI_80211_LHW_SCAN_LOCK(lhw);
+ is_hw_scan = (lhw->scan_flags & LKPI_LHW_SCAN_HW) != 0;
+ LKPI_80211_LHW_SCAN_UNLOCK(lhw);
+ if (!is_hw_scan)
+ lhw->ic_scan_curchan(ss, maxdwell);
+}
+
+static void
+lkpi_ic_scan_mindwell(struct ieee80211_scan_state *ss)
+{
+ struct lkpi_hw *lhw;
+ bool is_hw_scan;
+
+ lhw = ss->ss_ic->ic_softc;
+ LKPI_80211_LHW_SCAN_LOCK(lhw);
+ is_hw_scan = (lhw->scan_flags & LKPI_LHW_SCAN_HW) != 0;
+ LKPI_80211_LHW_SCAN_UNLOCK(lhw);
+ if (!is_hw_scan)
+ lhw->ic_scan_mindwell(ss);
+}
+
+static void
lkpi_ic_set_channel(struct ieee80211com *ic)
{
struct lkpi_hw *lhw;
@@ -2716,6 +3374,7 @@ lkpi_ic_set_channel(struct ieee80211com *ic)
struct ieee80211_channel *c;
struct linuxkpi_ieee80211_channel *chan;
int error;
+ bool hw_scan_running;
lhw = ic->ic_softc;
@@ -2723,6 +3382,15 @@ lkpi_ic_set_channel(struct ieee80211com *ic)
if (lhw->ops->config == NULL)
return;
+ /* If we have a hw_scan running do not switch channels. */
+ LKPI_80211_LHW_SCAN_LOCK(lhw);
+ hw_scan_running =
+ (lhw->scan_flags & (LKPI_LHW_SCAN_RUNNING|LKPI_LHW_SCAN_HW)) ==
+ (LKPI_LHW_SCAN_RUNNING|LKPI_LHW_SCAN_HW);
+ LKPI_80211_LHW_SCAN_UNLOCK(lhw);
+ if (hw_scan_running)
+ return;
+
c = ic->ic_curchan;
if (c == NULL || c == IEEE80211_CHAN_ANYC) {
ic_printf(ic, "%s: c %p ops->config %p\n", __func__,
@@ -2742,6 +3410,9 @@ lkpi_ic_set_channel(struct ieee80211com *ic)
hw = LHW_TO_HW(lhw);
cfg80211_chandef_create(&hw->conf.chandef, chan,
+#ifdef LKPI_80211_HT
+ (ic->ic_htcaps & IEEE80211_HTC_HT) ? 0 :
+#endif
NL80211_CHAN_NO_HT);
error = lkpi_80211_mo_config(hw, IEEE80211_CONF_CHANGE_CHANNEL);
@@ -2808,7 +3479,6 @@ lkpi_ic_node_init(struct ieee80211_node *ni)
{
struct ieee80211com *ic;
struct lkpi_hw *lhw;
- struct lkpi_sta *lsta;
int error;
ic = ni->ni_ic;
@@ -2820,11 +3490,6 @@ lkpi_ic_node_init(struct ieee80211_node *ni)
return (error);
}
- lsta = ni->ni_drv_data;
-
- /* Now take the reference before linking it to the table. */
- lsta->ni = ieee80211_ref_node(ni);
-
/* XXX-BZ Sync other state over. */
IMPROVE();
@@ -2857,30 +3522,15 @@ lkpi_ic_node_free(struct ieee80211_node *ni)
ic = ni->ni_ic;
lhw = ic->ic_softc;
lsta = ni->ni_drv_data;
- if (lsta == NULL)
- goto out;
- /* XXX-BZ free resources, ... */
- IMPROVE();
+ /* KASSERT lsta is not NULL here. Print ni/ni__refcnt. */
- /* Flush mbufq (make sure to release ni refs!). */
-#ifdef __notyet__
- KASSERT(mbufq_len(&lsta->txq) == 0, ("%s: lsta %p has txq len %d != 0\n",
- __func__, lsta, mbufq_len(&lsta->txq)));
-#endif
- /* Drain taskq. */
-
- /* Drain sta->txq[] */
- mtx_destroy(&lsta->txq_mtx);
-
- /* Remove lsta if added_to_drv. */
-
- /* Remove lsta from vif */
- /* Remove ref from lsta node... */
- /* Free lsta. */
- lkpi_lsta_remove(lsta, VAP_TO_LVIF(ni->ni_vap));
+ /*
+ * Pass in the original ni just in case of error we could check that
+ * it is the same as lsta->ni.
+ */
+ lkpi_lsta_free(lsta, ni);
-out:
if (lhw->ic_node_free != NULL)
lhw->ic_node_free(ni);
}
@@ -2892,11 +3542,21 @@ lkpi_ic_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
struct lkpi_sta *lsta;
lsta = ni->ni_drv_data;
+ LKPI_80211_LSTA_TXQ_LOCK(lsta);
+ if (!lsta->txq_ready) {
+ LKPI_80211_LSTA_TXQ_UNLOCK(lsta);
+ /*
+ * Free the mbuf (do NOT release ni ref for the m_pkthdr.rcvif!
+ * ieee80211_raw_output() does that in case of error).
+ */
+ m_free(m);
+ return (ENETDOWN);
+ }
/* Queue the packet and enqueue the task to handle it. */
- LKPI_80211_LSTA_LOCK(lsta);
mbufq_enqueue(&lsta->txq, m);
- LKPI_80211_LSTA_UNLOCK(lsta);
+ taskqueue_enqueue(taskqueue_thread, &lsta->txq_task);
+ LKPI_80211_LSTA_TXQ_UNLOCK(lsta);
#ifdef LINUXKPI_DEBUG_80211
if (linuxkpi_debug_80211 & D80211_TRACE_TX)
@@ -2905,7 +3565,6 @@ lkpi_ic_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
mbufq_len(&lsta->txq));
#endif
- taskqueue_enqueue(taskqueue_thread, &lsta->txq_task);
return (0);
}
@@ -2913,7 +3572,9 @@ static void
lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m)
{
struct ieee80211_node *ni;
+#ifndef LKPI_80211_HW_CRYPTO
struct ieee80211_frame *wh;
+#endif
struct ieee80211_key *k;
struct sk_buff *skb;
struct ieee80211com *ic;
@@ -2925,8 +3586,10 @@ lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m)
struct ieee80211_tx_control control;
struct ieee80211_tx_info *info;
struct ieee80211_sta *sta;
+ struct ieee80211_hdr *hdr;
+ struct lkpi_txq *ltxq;
void *buf;
- int ac;
+ uint8_t ac, tid;
M_ASSERTPKTHDR(m);
#ifdef LINUXKPI_DEBUG_80211
@@ -2935,7 +3598,8 @@ lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m)
#endif
ni = lsta->ni;
-#ifndef TRY_HW_CRYPTO
+ k = NULL;
+#ifndef LKPI_80211_HW_CRYPTO
/* Encrypt the frame if need be; XXX-BZ info->control.hw_key. */
wh = mtod(m, struct ieee80211_frame *);
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
@@ -2981,7 +3645,7 @@ lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m)
*/
skb = dev_alloc_skb(hw->extra_tx_headroom + m->m_pkthdr.len);
if (skb == NULL) {
- printf("XXX ERROR %s: skb alloc failed\n", __func__);
+ ic_printf(ic, "ERROR %s: skb alloc failed\n", __func__);
ieee80211_free_node(ni);
m_freem(m);
return;
@@ -3004,10 +3668,23 @@ lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m)
lvif = VAP_TO_LVIF(ni->ni_vap);
vif = LVIF_TO_VIF(lvif);
- /* XXX-BZ review this at some point [4] vs. [8] vs. [16](TID). */
- ac = M_WME_GETAC(m);
- skb->priority = WME_AC_TO_TID(ac);
- ac = lkpi_ac_net_to_l80211(ac);
+ hdr = (void *)skb->data;
+ tid = linuxkpi_ieee80211_get_tid(hdr, true);
+ if (tid == IEEE80211_NONQOS_TID) { /* == IEEE80211_NUM_TIDS */
+ if (!ieee80211_is_data(hdr->frame_control)) {
+ /* MGMT and CTRL frames go on TID 7/VO. */
+ skb->priority = 7;
+ ac = IEEE80211_AC_VO;
+ } else {
+ /* Other non-QOS traffic goes to BE. */
+ /* Contrary to net80211 we MUST NOT promote M_EAPOL. */
+ skb->priority = 0;
+ ac = IEEE80211_AC_BE;
+ }
+ } else {
+ skb->priority = tid & IEEE80211_QOS_CTL_TID_MASK;
+ ac = ieee80211e_up_to_ac[tid & 7];
+ }
skb_set_queue_mapping(skb, ac);
info = IEEE80211_SKB_CB(skb);
@@ -3016,85 +3693,58 @@ lkpi_80211_txq_tx_one(struct lkpi_sta *lsta, struct mbuf *m)
if (c == NULL || c == IEEE80211_CHAN_ANYC)
c = ic->ic_curchan;
info->band = lkpi_net80211_chan_to_nl80211_band(c);
- info->hw_queue = ac; /* XXX-BZ is this correct? */
+ info->hw_queue = vif->hw_queue[ac];
if (m->m_flags & M_EAPOL)
info->control.flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO;
info->control.vif = vif;
/* XXX-BZ info->control.rates */
+#ifdef __notyet__
+#ifdef LKPI_80211_HT
+ info->control.rts_cts_rate_idx=
+ info->control.use_rts= /* RTS */
+ info->control.use_cts_prot= /* RTS/CTS*/
+#endif
+#endif
- lsta = lkpi_find_lsta_by_ni(lvif, ni);
- if (lsta != NULL) {
- sta = LSTA_TO_STA(lsta);
-#ifdef TRY_HW_CRYPTO
- info->control.hw_key = lsta->kc;
+ sta = LSTA_TO_STA(lsta);
+#ifdef LKPI_80211_HW_CRYPTO
+ info->control.hw_key = lsta->kc;
#endif
- } else {
- sta = NULL;
- }
IMPROVE();
- if (sta != NULL) {
- struct lkpi_txq *ltxq;
- struct ieee80211_hdr *hdr;
-
- hdr = (void *)skb->data;
- if (lsta->added_to_drv &&
- !ieee80211_is_data_present(hdr->frame_control)) {
- if (sta->txq[IEEE80211_NUM_TIDS] != NULL)
- ltxq = TXQ_TO_LTXQ(sta->txq[IEEE80211_NUM_TIDS]);
- else
- goto ops_tx;
- } else if (lsta->added_to_drv) {
- ltxq = TXQ_TO_LTXQ(sta->txq[ac]); /* XXX-BZ re-check */
- } else
- goto ops_tx;
- KASSERT(ltxq != NULL, ("%s: lsta %p sta %p m %p skb %p "
- "ltxq %p != NULL\n", __func__, lsta, sta, m, skb, ltxq));
-
- /*
- * We currently do not use queues but do direct TX.
- * The exception to the rule is initial packets, as we cannot
- * TX until queues are allocated (at least for iwlwifi).
- * So we wake_tx_queue in newstate and register any dequeue
- * calls. In the time until then we queue packets and
- * let the driver deal with them.
- */
-#if 0
- if (!ltxq->seen_dequeue) {
+ ltxq = NULL;
+ if (!ieee80211_is_data_present(hdr->frame_control)) {
+ if (vif->type == NL80211_IFTYPE_STATION &&
+ lsta->added_to_drv &&
+ sta->txq[IEEE80211_NUM_TIDS] != NULL)
+ ltxq = TXQ_TO_LTXQ(sta->txq[IEEE80211_NUM_TIDS]);
+ } else if (lsta->added_to_drv &&
+ sta->txq[skb->priority] != NULL) {
+ ltxq = TXQ_TO_LTXQ(sta->txq[skb->priority]);
+ }
+ if (ltxq == NULL)
+ goto ops_tx;
- /* Prevent an ordering problem, likely other issues. */
- while (!skb_queue_empty(&ltxq->skbq)) {
- struct sk_buff *skb2;
+ KASSERT(ltxq != NULL, ("%s: lsta %p sta %p m %p skb %p "
+ "ltxq %p != NULL\n", __func__, lsta, sta, m, skb, ltxq));
- skb2 = skb_dequeue(&ltxq->skbq);
- if (skb2 != NULL) {
- memset(&control, 0, sizeof(control));
- control.sta = sta;
- lkpi_80211_mo_tx(hw, &control, skb2);
- }
- }
- goto ops_tx;
- }
- if (0 && ltxq->seen_dequeue && skb_queue_empty(&ltxq->skbq))
- goto ops_tx;
-#endif
-
- skb_queue_tail(&ltxq->skbq, skb);
+ LKPI_80211_LTXQ_LOCK(ltxq);
+ skb_queue_tail(&ltxq->skbq, skb);
#ifdef LINUXKPI_DEBUG_80211
- if (linuxkpi_debug_80211 & D80211_TRACE_TX)
- printf("%s:%d mo_wake_tx_queue :: %d %u lsta %p sta %p "
- "ni %p %6D skb %p lxtq %p { qlen %u, ac %d tid %u } "
- "WAKE_TX_Q ac %d prio %u qmap %u\n",
- __func__, __LINE__,
- curthread->td_tid, (unsigned int)ticks,
- lsta, sta, ni, ni->ni_macaddr, ":", skb, ltxq,
- skb_queue_len(&ltxq->skbq), ltxq->txq.ac,
- ltxq->txq.tid, ac, skb->priority, skb->qmap);
+ if (linuxkpi_debug_80211 & D80211_TRACE_TX)
+ printf("%s:%d mo_wake_tx_queue :: %d %u lsta %p sta %p "
+ "ni %p %6D skb %p lxtq %p { qlen %u, ac %d tid %u } "
+ "WAKE_TX_Q ac %d prio %u qmap %u\n",
+ __func__, __LINE__,
+ curthread->td_tid, (unsigned int)ticks,
+ lsta, sta, ni, ni->ni_macaddr, ":", skb, ltxq,
+ skb_queue_len(&ltxq->skbq), ltxq->txq.ac,
+ ltxq->txq.tid, ac, skb->priority, skb->qmap);
#endif
- lkpi_80211_mo_wake_tx_queue(hw, &ltxq->txq);
- return;
- }
+ LKPI_80211_LTXQ_UNLOCK(ltxq);
+ lkpi_80211_mo_wake_tx_queue(hw, &ltxq->txq);
+ return;
ops_tx:
#ifdef LINUXKPI_DEBUG_80211
@@ -3106,9 +3756,7 @@ ops_tx:
#endif
memset(&control, 0, sizeof(control));
control.sta = sta;
-
lkpi_80211_mo_tx(hw, &control, skb);
- return;
}
static void
@@ -3129,9 +3777,13 @@ lkpi_80211_txq_task(void *ctx, int pending)
mbufq_init(&mq, IFQ_MAXLEN);
- LKPI_80211_LSTA_LOCK(lsta);
+ LKPI_80211_LSTA_TXQ_LOCK(lsta);
+ /*
+ * Do not re-check lsta->txq_ready here; we may have a pending
+ * disassoc frame still.
+ */
mbufq_concat(&mq, &lsta->txq);
- LKPI_80211_LSTA_UNLOCK(lsta);
+ LKPI_80211_LSTA_TXQ_UNLOCK(lsta);
m = mbufq_dequeue(&mq);
while (m != NULL) {
@@ -3154,6 +3806,291 @@ lkpi_ic_transmit(struct ieee80211com *ic, struct mbuf *m)
return (lkpi_ic_raw_xmit(ni, m, NULL));
}
+#ifdef LKPI_80211_HT
+static int
+lkpi_ic_recv_action(struct ieee80211_node *ni, const struct ieee80211_frame *wh,
+ const uint8_t *frm, const uint8_t *efrm)
+{
+ struct ieee80211com *ic;
+ struct lkpi_hw *lhw;
+
+ ic = ni->ni_ic;
+ lhw = ic->ic_softc;
+
+ IMPROVE_HT();
+
+ return (lhw->ic_recv_action(ni, wh, frm, efrm));
+}
+
+static int
+lkpi_ic_send_action(struct ieee80211_node *ni, int category, int action, void *sa)
+{
+ struct ieee80211com *ic;
+ struct lkpi_hw *lhw;
+
+ ic = ni->ni_ic;
+ lhw = ic->ic_softc;
+
+ IMPROVE_HT();
+
+ return (lhw->ic_send_action(ni, category, action, sa));
+}
+
+
+static int
+lkpi_ic_ampdu_enable(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
+{
+ struct ieee80211com *ic;
+ struct lkpi_hw *lhw;
+
+ ic = ni->ni_ic;
+ lhw = ic->ic_softc;
+
+ IMPROVE_HT();
+
+ return (lhw->ic_ampdu_enable(ni, tap));
+}
+
+static int
+lkpi_ic_addba_request(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,
+ int dialogtoken, int baparamset, int batimeout)
+{
+ struct ieee80211com *ic;
+ struct lkpi_hw *lhw;
+
+ ic = ni->ni_ic;
+ lhw = ic->ic_softc;
+
+ IMPROVE_HT();
+
+ return (lhw->ic_addba_request(ni, tap, dialogtoken, baparamset, batimeout));
+}
+
+static int
+lkpi_ic_addba_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,
+ int status, int baparamset, int batimeout)
+{
+ struct ieee80211com *ic;
+ struct lkpi_hw *lhw;
+
+ ic = ni->ni_ic;
+ lhw = ic->ic_softc;
+
+ IMPROVE_HT();
+
+ return (lhw->ic_addba_response(ni, tap, status, baparamset, batimeout));
+}
+
+static void
+lkpi_ic_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
+{
+ struct ieee80211com *ic;
+ struct lkpi_hw *lhw;
+
+ ic = ni->ni_ic;
+ lhw = ic->ic_softc;
+
+ IMPROVE_HT();
+
+ lhw->ic_addba_stop(ni, tap);
+}
+
+static void
+lkpi_ic_addba_response_timeout(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
+{
+ struct ieee80211com *ic;
+ struct lkpi_hw *lhw;
+
+ ic = ni->ni_ic;
+ lhw = ic->ic_softc;
+
+ IMPROVE_HT();
+
+ lhw->ic_addba_response_timeout(ni, tap);
+}
+
+static void
+lkpi_ic_bar_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,
+ int status)
+{
+ struct ieee80211com *ic;
+ struct lkpi_hw *lhw;
+
+ ic = ni->ni_ic;
+ lhw = ic->ic_softc;
+
+ IMPROVE_HT();
+
+ lhw->ic_bar_response(ni, tap, status);
+}
+
+static int
+lkpi_ic_ampdu_rx_start(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap,
+ int baparamset, int batimeout, int baseqctl)
+{
+ struct ieee80211com *ic;
+ struct lkpi_hw *lhw;
+ struct ieee80211_hw *hw;
+ struct ieee80211vap *vap;
+ struct lkpi_vif *lvif;
+ struct ieee80211_vif *vif;
+ struct lkpi_sta *lsta;
+ struct ieee80211_sta *sta;
+ struct ieee80211_ampdu_params params;
+ int error;
+
+ ic = ni->ni_ic;
+ lhw = ic->ic_softc;
+ hw = LHW_TO_HW(lhw);
+ vap = ni->ni_vap;
+ lvif = VAP_TO_LVIF(vap);
+ vif = LVIF_TO_VIF(lvif);
+ lsta = ni->ni_drv_data;
+ sta = LSTA_TO_STA(lsta);
+
+ params.sta = sta;
+ params.action = IEEE80211_AMPDU_RX_START;
+ params.buf_size = _IEEE80211_MASKSHIFT(le16toh(baparamset), IEEE80211_BAPS_BUFSIZ);
+ if (params.buf_size == 0)
+ params.buf_size = IEEE80211_MAX_AMPDU_BUF_HT;
+ else
+ params.buf_size = min(params.buf_size, IEEE80211_MAX_AMPDU_BUF_HT);
+ if (params.buf_size > hw->max_rx_aggregation_subframes)
+ params.buf_size = hw->max_rx_aggregation_subframes;
+ params.timeout = le16toh(batimeout);
+ params.ssn = _IEEE80211_MASKSHIFT(le16toh(baseqctl), IEEE80211_BASEQ_START);
+ params.tid = _IEEE80211_MASKSHIFT(le16toh(baparamset), IEEE80211_BAPS_TID);
+ params.amsdu = false;
+
+ IMPROVE_HT("Do we need to distinguish based on SUPPORTS_REORDERING_BUFFER?");
+
+ /* This may call kalloc. Make sure we can sleep. */
+ error = lkpi_80211_mo_ampdu_action(hw, vif, &params);
+ if (error != 0) {
+ ic_printf(ic, "%s: mo_ampdu_action returned %d. ni %p rap %p\n",
+ __func__, error, ni, rap);
+ return (error);
+ }
+ IMPROVE_HT("net80211 is missing the error check on return and assumes success");
+
+ error = lhw->ic_ampdu_rx_start(ni, rap, baparamset, batimeout, baseqctl);
+ return (error);
+}
+
+static void
+lkpi_ic_ampdu_rx_stop(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap)
+{
+ struct ieee80211com *ic;
+ struct lkpi_hw *lhw;
+ struct ieee80211_hw *hw;
+ struct ieee80211vap *vap;
+ struct lkpi_vif *lvif;
+ struct ieee80211_vif *vif;
+ struct lkpi_sta *lsta;
+ struct ieee80211_sta *sta;
+ struct ieee80211_ampdu_params params;
+ int error;
+ uint8_t tid;
+
+ ic = ni->ni_ic;
+ lhw = ic->ic_softc;
+
+ /*
+ * We should not (cannot) call into mac80211 ops with AMPDU_RX_STOP if
+ * we did not START. Some drivers pass it down to firmware which will
+ * simply barf and net80211 calls ieee80211_ht_node_cleanup() from
+ * ieee80211_ht_node_init() amongst others which will iterate over all
+ * tid and call ic_ampdu_rx_stop() unconditionally.
+ * XXX net80211 should probably be more "gentle" in these cases and
+ * track some state itself.
+ */
+ if ((rap->rxa_flags & IEEE80211_AGGR_RUNNING) == 0)
+ goto net80211_only;
+
+ hw = LHW_TO_HW(lhw);
+ vap = ni->ni_vap;
+ lvif = VAP_TO_LVIF(vap);
+ vif = LVIF_TO_VIF(lvif);
+ lsta = ni->ni_drv_data;
+ sta = LSTA_TO_STA(lsta);
+
+ IMPROVE_HT("This really should be passed from ht_recv_action_ba_delba.");
+ for (tid = 0; tid < WME_NUM_TID; tid++) {
+ if (&ni->ni_rx_ampdu[tid] == rap)
+ break;
+ }
+
+ params.sta = sta;
+ params.action = IEEE80211_AMPDU_RX_STOP;
+ params.buf_size = 0;
+ params.timeout = 0;
+ params.ssn = 0;
+ params.tid = tid;
+ params.amsdu = false;
+
+ error = lkpi_80211_mo_ampdu_action(hw, vif, &params);
+ if (error != 0)
+ ic_printf(ic, "%s: mo_ampdu_action returned %d. ni %p rap %p\n",
+ __func__, error, ni, rap);
+
+net80211_only:
+ lhw->ic_ampdu_rx_stop(ni, rap);
+}
+#endif
+
+static void
+lkpi_ic_getradiocaps_ht(struct ieee80211com *ic, struct ieee80211_hw *hw,
+ uint8_t *bands, int *chan_flags, enum nl80211_band band)
+{
+#ifdef LKPI_80211_HT
+ struct ieee80211_sta_ht_cap *ht_cap;
+
+ ht_cap = &hw->wiphy->bands[band]->ht_cap;
+ if (!ht_cap->ht_supported)
+ return;
+
+ switch (band) {
+ case NL80211_BAND_2GHZ:
+ setbit(bands, IEEE80211_MODE_11NG);
+ break;
+ case NL80211_BAND_5GHZ:
+ setbit(bands, IEEE80211_MODE_11NA);
+ break;
+ default:
+ IMPROVE("Unsupported band %d", band);
+ return;
+ }
+
+ ic->ic_htcaps = IEEE80211_HTC_HT; /* HT operation */
+
+ /*
+ * Rather than manually checking each flag and
+ * translating IEEE80211_HT_CAP_ to IEEE80211_HTCAP_,
+ * simply copy the 16bits.
+ */
+ ic->ic_htcaps |= ht_cap->cap;
+
+ /* Then deal with the other flags. */
+ if (ieee80211_hw_check(hw, AMPDU_AGGREGATION))
+ ic->ic_htcaps |= IEEE80211_HTC_AMPDU;
+#ifdef __notyet__
+ if (ieee80211_hw_check(hw, TX_AMSDU))
+ ic->ic_htcaps |= IEEE80211_HTC_AMSDU;
+ if (ieee80211_hw_check(hw, SUPPORTS_AMSDU_IN_AMPDU))
+ ic->ic_htcaps |= (IEEE80211_HTC_RX_AMSDU_AMPDU |
+ IEEE80211_HTC_TX_AMSDU_AMPDU);
+#endif
+
+ IMPROVE("PS, ampdu_*, ht_cap.mcs.tx_params, ...");
+ ic->ic_htcaps |= IEEE80211_HTCAP_SMPS_OFF;
+
+ /* Only add HT40 channels if supported. */
+ if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) != 0 &&
+ chan_flags != NULL)
+ *chan_flags |= NET80211_CBW_FLAG_HT40;
+#endif
+}
+
static void
lkpi_ic_getradiocaps(struct ieee80211com *ic, int maxchan,
int *n, struct ieee80211_channel *c)
@@ -3177,13 +4114,12 @@ lkpi_ic_getradiocaps(struct ieee80211com *ic, int maxchan,
chan_flags = 0;
setbit(bands, IEEE80211_MODE_11B);
/* XXX-BZ unclear how to check for 11g. */
+
+ IMPROVE("the bitrates may have flags?");
setbit(bands, IEEE80211_MODE_11G);
-#ifdef __notyet__
- if (hw->wiphy->bands[NL80211_BAND_2GHZ]->ht_cap.ht_supported) {
- setbit(bands, IEEE80211_MODE_11NG);
- chan_flags |= NET80211_CBW_FLAG_HT40;
- }
-#endif
+
+ lkpi_ic_getradiocaps_ht(ic, hw, bands, &chan_flags,
+ NL80211_BAND_2GHZ);
channels = hw->wiphy->bands[NL80211_BAND_2GHZ]->channels;
for (i = 0; i < nchans && *n < maxchan; i++) {
@@ -3191,8 +4127,8 @@ lkpi_ic_getradiocaps(struct ieee80211com *ic, int maxchan,
int cflags = chan_flags;
if (channels[i].flags & IEEE80211_CHAN_DISABLED) {
- printf("%s: %s: Skipping disabled chan "
- "[%u/%u/%#x]\n", ic->ic_name, __func__,
+ ic_printf(ic, "%s: Skipping disabled chan "
+ "[%u/%u/%#x]\n", __func__,
channels[i].hw_value,
channels[i].center_freq, channels[i].flags);
continue;
@@ -3212,11 +4148,11 @@ lkpi_ic_getradiocaps(struct ieee80211com *ic, int maxchan,
error = ieee80211_add_channel_cbw(c, maxchan, n,
channels[i].hw_value, channels[i].center_freq,
channels[i].max_power,
- nflags, bands, chan_flags);
+ nflags, bands, cflags);
/* net80211::ENOBUFS: *n >= maxchans */
if (error != 0 && error != ENOBUFS)
- printf("%s: %s: Adding chan %u/%u/%#x/%#x/%#x/%#x "
- "returned error %d\n", ic->ic_name,
+ ic_printf(ic, "%s: Adding chan %u/%u/%#x/%#x/%#x/%#x "
+ "returned error %d\n",
__func__, channels[i].hw_value,
channels[i].center_freq, channels[i].flags,
nflags, chan_flags, cflags, error);
@@ -3233,24 +4169,24 @@ lkpi_ic_getradiocaps(struct ieee80211com *ic, int maxchan,
memset(bands, 0, sizeof(bands));
chan_flags = 0;
setbit(bands, IEEE80211_MODE_11A);
-#ifdef __not_yet__
- if (hw->wiphy->bands[NL80211_BAND_5GHZ]->ht_cap.ht_supported) {
- setbit(bands, IEEE80211_MODE_11NA);
- chan_flags |= NET80211_CBW_FLAG_HT40;
- }
+
+ lkpi_ic_getradiocaps_ht(ic, hw, bands, &chan_flags,
+ NL80211_BAND_5GHZ);
+
+#ifdef LKPI_80211_VHT
if (hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap.vht_supported){
ic->ic_flags_ext |= IEEE80211_FEXT_VHT;
- ic->ic_vhtcaps =
+ ic->ic_vht_cap.vht_cap_info =
hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap.cap;
setbit(bands, IEEE80211_MODE_VHT_5GHZ);
chan_flags |= NET80211_CBW_FLAG_VHT80;
if (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160MHZ(
- ic->ic_vhtcaps))
+ ic->ic_vht_cap.vht_cap_info))
chan_flags |= NET80211_CBW_FLAG_VHT160;
if (IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160_80P80MHZ(
- ic->ic_vhtcaps))
+ ic->ic_vht_cap.vht_cap_info))
chan_flags |= NET80211_CBW_FLAG_VHT80P80;
}
#endif
@@ -3261,8 +4197,8 @@ lkpi_ic_getradiocaps(struct ieee80211com *ic, int maxchan,
int cflags = chan_flags;
if (channels[i].flags & IEEE80211_CHAN_DISABLED) {
- printf("%s: %s: Skipping disabled chan "
- "[%u/%u/%#x]\n", ic->ic_name, __func__,
+ ic_printf(ic, "%s: Skipping disabled chan "
+ "[%u/%u/%#x]\n", __func__,
channels[i].hw_value,
channels[i].center_freq, channels[i].flags);
continue;
@@ -3282,11 +4218,11 @@ lkpi_ic_getradiocaps(struct ieee80211com *ic, int maxchan,
error = ieee80211_add_channel_cbw(c, maxchan, n,
channels[i].hw_value, channels[i].center_freq,
channels[i].max_power,
- nflags, bands, chan_flags);
+ nflags, bands, cflags);
/* net80211::ENOBUFS: *n >= maxchans */
if (error != 0 && error != ENOBUFS)
- printf("%s: %s: Adding chan %u/%u/%#x/%#x/%#x/%#x "
- "returned error %d\n", ic->ic_name,
+ ic_printf(ic, "%s: Adding chan %u/%u/%#x/%#x/%#x/%#x "
+ "returned error %d\n",
__func__, channels[i].hw_value,
channels[i].center_freq, channels[i].flags,
nflags, chan_flags, cflags, error);
@@ -3318,6 +4254,7 @@ linuxkpi_ieee80211_alloc_hw(size_t priv_len, const struct ieee80211_ops *ops)
struct ieee80211_hw *hw;
struct lkpi_hw *lhw;
struct wiphy *wiphy;
+ int ac;
/* Get us and the driver data also allocated. */
wiphy = wiphy_new(&linuxkpi_mac80211cfgops, sizeof(*lhw) + priv_len);
@@ -3327,9 +4264,21 @@ linuxkpi_ieee80211_alloc_hw(size_t priv_len, const struct ieee80211_ops *ops)
lhw = wiphy_priv(wiphy);
lhw->ops = ops;
- mtx_init(&lhw->mtx, "lhw", NULL, MTX_DEF | MTX_RECURSE);
+ LKPI_80211_LHW_LOCK_INIT(lhw);
+ LKPI_80211_LHW_SCAN_LOCK_INIT(lhw);
+ LKPI_80211_LHW_TXQ_LOCK_INIT(lhw);
sx_init_flags(&lhw->lvif_sx, "lhw-lvif", SX_RECURSE | SX_DUPOK);
TAILQ_INIT(&lhw->lvif_head);
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ lhw->txq_generation[ac] = 1;
+ TAILQ_INIT(&lhw->scheduled_txqs[ac]);
+ }
+
+ /* Deferred RX path. */
+ LKPI_80211_LHW_RXQ_LOCK_INIT(lhw);
+ TASK_INIT(&lhw->rxq_task, 0, lkpi_80211_lhw_rxq_task, lhw);
+ mbufq_init(&lhw->rxq, IFQ_MAXLEN);
+ lhw->rxq_stopped = false;
/*
* XXX-BZ TODO make sure there is a "_null" function to all ops
@@ -3356,14 +4305,47 @@ void
linuxkpi_ieee80211_iffree(struct ieee80211_hw *hw)
{
struct lkpi_hw *lhw;
+ struct mbuf *m;
lhw = HW_TO_LHW(hw);
free(lhw->ic, M_LKPI80211);
lhw->ic = NULL;
+ /*
+ * Drain the deferred RX path.
+ */
+ LKPI_80211_LHW_RXQ_LOCK(lhw);
+ lhw->rxq_stopped = true;
+ LKPI_80211_LHW_RXQ_UNLOCK(lhw);
+
+ /* Drain taskq, won't be restarted due to rxq_stopped being set. */
+ while (taskqueue_cancel(taskqueue_thread, &lhw->rxq_task, NULL) != 0)
+ taskqueue_drain(taskqueue_thread, &lhw->rxq_task);
+
+ /* Flush mbufq (make sure to release ni refs!). */
+ m = mbufq_dequeue(&lhw->rxq);
+ while (m != NULL) {
+ struct m_tag *mtag;
+
+ mtag = m_tag_locate(m, MTAG_ABI_LKPI80211, LKPI80211_TAG_RXNI, NULL);
+ if (mtag != NULL) {
+ struct lkpi_80211_tag_rxni *rxni;
+
+ rxni = (struct lkpi_80211_tag_rxni *)(mtag + 1);
+ ieee80211_free_node(rxni->ni);
+ }
+ m_freem(m);
+ m = mbufq_dequeue(&lhw->rxq);
+ }
+ KASSERT(mbufq_empty(&lhw->rxq), ("%s: lhw %p has rxq len %d != 0\n",
+ __func__, lhw, mbufq_len(&lhw->rxq)));
+ LKPI_80211_LHW_RXQ_LOCK_DESTROY(lhw);
+
/* Cleanup more of lhw here or in wiphy_free()? */
+ LKPI_80211_LHW_TXQ_LOCK_DESTROY(lhw);
+ LKPI_80211_LHW_SCAN_LOCK_DESTROY(lhw);
+ LKPI_80211_LHW_LOCK_DESTROY(lhw);
sx_destroy(&lhw->lvif_sx);
- mtx_destroy(&lhw->mtx);
IMPROVE();
}
@@ -3446,7 +4428,9 @@ linuxkpi_ieee80211_ifattach(struct ieee80211_hw *hw)
IEEE80211_C_STA |
IEEE80211_C_MONITOR |
IEEE80211_C_WPA | /* WPA/RSN */
+#ifdef LKPI_80211_WME
IEEE80211_C_WME |
+#endif
#if 0
IEEE80211_C_PMGT |
#endif
@@ -3466,22 +4450,27 @@ linuxkpi_ieee80211_ifattach(struct ieee80211_hw *hw)
* the flag.
*/
ic->ic_flags_ext |= IEEE80211_FEXT_SCAN_OFFLOAD;
+ lhw->scan_flags |= LKPI_LHW_SCAN_HW;
}
-#ifdef __notyet__
- ic->ic_htcaps = IEEE80211_HTC_HT /* HT operation */
- | IEEE80211_HTC_AMPDU /* A-MPDU tx/rx */
- | IEEE80211_HTC_AMSDU /* A-MSDU tx/rx */
- | IEEE80211_HTCAP_MAXAMSDU_3839
- /* max A-MSDU length */
- | IEEE80211_HTCAP_SMPS_OFF; /* SM power save off */
- ic->ic_htcaps |= IEEE80211_HTCAP_SHORTGI20;
- ic->ic_htcaps |= IEEE80211_HTCAP_CHWIDTH40 | IEEE80211_HTCAP_SHORTGI40;
- ic->ic_htcaps |= IEEE80211_HTCAP_TXSTBC;
-#endif
+ /*
+ * The wiphy variables report bitmasks of avail antennas.
+ * (*get_antenna) get the current bitmask sets which can be
+ * altered by (*set_antenna) for some drivers.
+ * XXX-BZ will the count alone do us much good long-term in net80211?
+ */
+ if (hw->wiphy->available_antennas_rx ||
+ hw->wiphy->available_antennas_tx) {
+ uint32_t rxs, txs;
+
+ if (lkpi_80211_mo_get_antenna(hw, &txs, &rxs) == 0) {
+ ic->ic_rxstream = bitcount32(rxs);
+ ic->ic_txstream = bitcount32(txs);
+ }
+ }
ic->ic_cryptocaps = 0;
-#ifdef TRY_HW_CRYPTO
+#ifdef LKPI_80211_HW_CRYPTO
if (hw->wiphy->n_cipher_suites > 0) {
for (i = 0; i < hw->wiphy->n_cipher_suites; i++)
ic->ic_cryptocaps |= lkpi_l80211_to_net80211_cyphers(
@@ -3508,6 +4497,11 @@ linuxkpi_ieee80211_ifattach(struct ieee80211_hw *hw)
ic->ic_getradiocaps = lkpi_ic_getradiocaps;
ic->ic_wme.wme_update = lkpi_ic_wme_update;
+ lhw->ic_scan_curchan = ic->ic_scan_curchan;
+ ic->ic_scan_curchan = lkpi_ic_scan_curchan;
+ lhw->ic_scan_mindwell = ic->ic_scan_mindwell;
+ ic->ic_scan_mindwell = lkpi_ic_scan_mindwell;
+
lhw->ic_node_alloc = ic->ic_node_alloc;
ic->ic_node_alloc = lkpi_ic_node_alloc;
lhw->ic_node_init = ic->ic_node_init;
@@ -3517,6 +4511,33 @@ linuxkpi_ieee80211_ifattach(struct ieee80211_hw *hw)
lhw->ic_node_free = ic->ic_node_free;
ic->ic_node_free = lkpi_ic_node_free;
+#ifdef LKPI_80211_HT
+ lhw->ic_recv_action = ic->ic_recv_action;
+ ic->ic_recv_action = lkpi_ic_recv_action;
+ lhw->ic_send_action = ic->ic_send_action;
+ ic->ic_send_action = lkpi_ic_send_action;
+
+ lhw->ic_ampdu_enable = ic->ic_ampdu_enable;
+ ic->ic_ampdu_enable = lkpi_ic_ampdu_enable;
+
+ lhw->ic_addba_request = ic->ic_addba_request;
+ ic->ic_addba_request = lkpi_ic_addba_request;
+ lhw->ic_addba_response = ic->ic_addba_response;
+ ic->ic_addba_response = lkpi_ic_addba_response;
+ lhw->ic_addba_stop = ic->ic_addba_stop;
+ ic->ic_addba_stop = lkpi_ic_addba_stop;
+ lhw->ic_addba_response_timeout = ic->ic_addba_response_timeout;
+ ic->ic_addba_response_timeout = lkpi_ic_addba_response_timeout;
+
+ lhw->ic_bar_response = ic->ic_bar_response;
+ ic->ic_bar_response = lkpi_ic_bar_response;
+
+ lhw->ic_ampdu_rx_start = ic->ic_ampdu_rx_start;
+ ic->ic_ampdu_rx_start = lkpi_ic_ampdu_rx_start;
+ lhw->ic_ampdu_rx_stop = ic->ic_ampdu_rx_stop;
+ ic->ic_ampdu_rx_stop = lkpi_ic_ampdu_rx_stop;
+#endif
+
lkpi_radiotap_attach(lhw);
/*
@@ -3526,8 +4547,7 @@ linuxkpi_ieee80211_ifattach(struct ieee80211_hw *hw)
* in any band so we can scale [(ext) sup rates] IE(s) accordingly.
*/
lhw->supbands = lhw->max_rates = 0;
- for (band = 0; band < NUM_NL80211_BANDS &&
- hw->conf.chandef.chan == NULL; band++) {
+ for (band = 0; band < NUM_NL80211_BANDS; band++) {
struct ieee80211_supported_band *supband;
struct linuxkpi_ieee80211_channel *channels;
@@ -3538,6 +4558,10 @@ linuxkpi_ieee80211_ifattach(struct ieee80211_hw *hw)
lhw->supbands++;
lhw->max_rates = max(lhw->max_rates, supband->n_bitrates);
+ /* If we have a channel, we need to keep counting supbands. */
+ if (hw->conf.chandef.chan != NULL)
+ continue;
+
channels = supband->channels;
for (i = 0; i < supband->n_channels; i++) {
@@ -3545,6 +4569,9 @@ linuxkpi_ieee80211_ifattach(struct ieee80211_hw *hw)
continue;
cfg80211_chandef_create(&hw->conf.chandef, &channels[i],
+#ifdef LKPI_80211_HT
+ (ic->ic_htcaps & IEEE80211_HTC_HT) ? 0 :
+#endif
NL80211_CHAN_NO_HT);
break;
}
@@ -3562,7 +4589,6 @@ linuxkpi_ieee80211_ifattach(struct ieee80211_hw *hw)
/*
* The maximum supported bitrates on any band + size for
* DSSS Parameter Set give our per-band IE size.
- * XXX-BZ FIXME add HT VHT ... later
* SSID is the responsibility of the driver and goes on the side.
* The user specified bits coming from the vap go into the
* "common ies" fields.
@@ -3570,20 +4596,39 @@ linuxkpi_ieee80211_ifattach(struct ieee80211_hw *hw)
lhw->scan_ie_len = 2 + IEEE80211_RATE_SIZE;
if (lhw->max_rates > IEEE80211_RATE_SIZE)
lhw->scan_ie_len += 2 + (lhw->max_rates - IEEE80211_RATE_SIZE);
- /*
- * net80211 does not seem to support the DSSS Parameter Set but some of
- * the drivers insert it so calculate the extra fixed space in.
- */
- lhw->scan_ie_len += 2 + 1;
+
+ if (hw->wiphy->features & NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) {
+ /*
+ * net80211 does not seem to support the DSSS Parameter Set but
+ * some of the drivers insert it so calculate the extra fixed
+ * space in.
+ */
+ lhw->scan_ie_len += 2 + 1;
+ }
+
+#if defined(LKPI_80211_HT)
+ if ((ic->ic_htcaps & IEEE80211_HTC_HT) != 0)
+ lhw->scan_ie_len += sizeof(struct ieee80211_ie_htcap);
+#endif
+#if defined(LKPI_80211_VHT)
+ if ((ic->ic_flags_ext & IEEE80211_FEXT_VHT) != 0)
+ lhw->scan_ie_len += 2 + sizeof(struct ieee80211_vht_cap);
+#endif
/* Reduce the max_scan_ie_len "left" by the amount we consume already. */
- if (hw->wiphy->max_scan_ie_len > 0)
+ if (hw->wiphy->max_scan_ie_len > 0) {
+ if (lhw->scan_ie_len > hw->wiphy->max_scan_ie_len)
+ goto err;
hw->wiphy->max_scan_ie_len -= lhw->scan_ie_len;
+ }
if (bootverbose)
ieee80211_announce(ic);
return (0);
+err:
+ IMPROVE("TODO FIXME CLEANUP");
+ return (-EAGAIN);
}
void
@@ -3613,12 +4658,12 @@ linuxkpi_ieee80211_iterate_interfaces(struct ieee80211_hw *hw,
if (flags & ~(IEEE80211_IFACE_ITER_NORMAL|
IEEE80211_IFACE_ITER_RESUME_ALL|
IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER|
- IEEE80211_IFACE_ITER__ACTIVE|IEEE80211_IFACE_ITER__ATOMIC)) {
+ IEEE80211_IFACE_ITER_ACTIVE|IEEE80211_IFACE_ITER__ATOMIC)) {
ic_printf(lhw->ic, "XXX TODO %s flags(%#x) not yet supported.\n",
__func__, flags);
}
- active = (flags & IEEE80211_IFACE_ITER__ACTIVE) != 0;
+ active = (flags & IEEE80211_IFACE_ITER_ACTIVE) != 0;
atomic = (flags & IEEE80211_IFACE_ITER__ATOMIC) != 0;
nin_drv = (flags & IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER) != 0;
@@ -3676,8 +4721,32 @@ linuxkpi_ieee80211_iterate_chan_contexts(struct ieee80211_hw *hw,
void *),
void *arg)
{
+ struct lkpi_hw *lhw;
+ struct lkpi_vif *lvif;
+ struct ieee80211_vif *vif;
+ struct lkpi_chanctx *lchanctx;
- UNIMPLEMENTED;
+ KASSERT(hw != NULL && iterfunc != NULL,
+ ("%s: hw %p iterfunc %p arg %p\n", __func__, hw, iterfunc, arg));
+
+ lhw = HW_TO_LHW(hw);
+
+ IMPROVE("lchanctx should be its own list somewhere");
+
+ LKPI_80211_LHW_LVIF_LOCK(lhw);
+ TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) {
+
+ vif = LVIF_TO_VIF(lvif);
+ if (vif->chanctx_conf == NULL)
+ continue;
+
+ lchanctx = CHANCTX_CONF_TO_LCHANCTX(vif->chanctx_conf);
+ if (!lchanctx->added_to_drv)
+ continue;
+
+ iterfunc(hw, &lchanctx->conf, arg);
+ }
+ LKPI_80211_LHW_LVIF_UNLOCK(lhw);
}
void
@@ -3709,6 +4778,16 @@ linuxkpi_ieee80211_iterate_stations_atomic(struct ieee80211_hw *hw,
LKPI_80211_LHW_LVIF_UNLOCK(lhw);
}
+struct linuxkpi_ieee80211_regdomain *
+lkpi_get_linuxkpi_ieee80211_regdomain(size_t n)
+{
+ struct linuxkpi_ieee80211_regdomain *regd;
+
+ regd = kzalloc(sizeof(*regd) + n * sizeof(struct ieee80211_reg_rule),
+ GFP_KERNEL);
+ return (regd);
+}
+
int
linuxkpi_regulatory_set_wiphy_regd_sync(struct wiphy *wiphy,
struct linuxkpi_ieee80211_regdomain *regd)
@@ -3746,21 +4825,82 @@ linuxkpi_ieee80211_scan_completed(struct ieee80211_hw *hw,
ieee80211_scan_done(ss->ss_vap);
- LKPI_80211_LHW_LOCK(lhw);
+ LKPI_80211_LHW_SCAN_LOCK(lhw);
free(lhw->hw_req, M_LKPI80211);
lhw->hw_req = NULL;
- lhw->scan_flags &= ~LKPI_SCAN_RUNNING;
+ lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING;
wakeup(lhw);
- LKPI_80211_LHW_UNLOCK(lhw);
+ LKPI_80211_LHW_SCAN_UNLOCK(lhw);
return;
}
+static void
+lkpi_80211_lhw_rxq_rx_one(struct lkpi_hw *lhw, struct mbuf *m)
+{
+ struct ieee80211_node *ni;
+ struct m_tag *mtag;
+ int ok;
+
+ ni = NULL;
+ mtag = m_tag_locate(m, MTAG_ABI_LKPI80211, LKPI80211_TAG_RXNI, NULL);
+ if (mtag != NULL) {
+ struct lkpi_80211_tag_rxni *rxni;
+
+ rxni = (struct lkpi_80211_tag_rxni *)(mtag + 1);
+ ni = rxni->ni;
+ }
+
+ if (ni != NULL) {
+ ok = ieee80211_input_mimo(ni, m);
+ ieee80211_free_node(ni); /* Release the reference. */
+ if (ok < 0)
+ m_freem(m);
+ } else {
+ ok = ieee80211_input_mimo_all(lhw->ic, m);
+ /* mbuf got consumed. */
+ }
+
+#ifdef LINUXKPI_DEBUG_80211
+ if (linuxkpi_debug_80211 & D80211_TRACE_RX)
+ printf("TRACE %s: handled frame type %#0x\n", __func__, ok);
+#endif
+}
+
+static void
+lkpi_80211_lhw_rxq_task(void *ctx, int pending)
+{
+ struct lkpi_hw *lhw;
+ struct mbufq mq;
+ struct mbuf *m;
+
+ lhw = ctx;
+
+#ifdef LINUXKPI_DEBUG_80211
+ if (linuxkpi_debug_80211 & D80211_TRACE_RX)
+ printf("%s:%d lhw %p pending %d mbuf_qlen %d\n",
+ __func__, __LINE__, lhw, pending, mbufq_len(&lhw->rxq));
+#endif
+
+ mbufq_init(&mq, IFQ_MAXLEN);
+
+ LKPI_80211_LHW_RXQ_LOCK(lhw);
+ mbufq_concat(&mq, &lhw->rxq);
+ LKPI_80211_LHW_RXQ_UNLOCK(lhw);
+
+ m = mbufq_dequeue(&mq);
+ while (m != NULL) {
+ lkpi_80211_lhw_rxq_rx_one(lhw, m);
+ m = mbufq_dequeue(&mq);
+ }
+}
+
+/* For %list see comment towards the end of the function. */
void
linuxkpi_ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_sta *sta, struct napi_struct *napi __unused)
+ struct ieee80211_sta *sta, struct napi_struct *napi __unused,
+ struct list_head *list __unused)
{
- struct epoch_tracker et;
struct lkpi_hw *lhw;
struct ieee80211com *ic;
struct mbuf *m;
@@ -3933,8 +5073,9 @@ no_trace_beacons:
* net80211 should take care of the other information (sync_tsf,
* sync_dtim_count) as otherwise we need to parse the beacon.
*/
- }
skip_device_ts:
+ ;
+ }
if (vap != NULL && vap->iv_state > IEEE80211_S_INIT &&
ieee80211_radiotap_active_vap(vap)) {
@@ -3966,22 +5107,45 @@ skip_device_ts:
if (ieee80211_hw_check(hw, RX_INCLUDES_FCS))
m_adj(m, -IEEE80211_CRC_LEN);
- NET_EPOCH_ENTER(et);
+#if 0
+ if (list != NULL) {
+ /*
+ * Normally this would be queued up and delivered by
+ * netif_receive_skb_list(), napi_gro_receive(), or the like.
+ * See mt76::mac80211.c as only current possible consumer.
+ */
+ IMPROVE("we simply pass the packet to net80211 to deal with.");
+ }
+#endif
+
+ /*
+ * Attach meta-information to the mbuf for the deferred RX path.
+ * Currently this is best-effort. Should we need to be hard,
+ * drop the frame and goto err;
+ */
if (ni != NULL) {
- ok = ieee80211_input_mimo(ni, m);
- ieee80211_free_node(ni);
- if (ok < 0)
- m_freem(m);
- } else {
- ok = ieee80211_input_mimo_all(ic, m);
- /* mbuf got consumed. */
+ struct m_tag *mtag;
+ struct lkpi_80211_tag_rxni *rxni;
+
+ mtag = m_tag_alloc(MTAG_ABI_LKPI80211, LKPI80211_TAG_RXNI,
+ sizeof(*rxni), IEEE80211_M_NOWAIT);
+ if (mtag != NULL) {
+ rxni = (struct lkpi_80211_tag_rxni *)(mtag + 1);
+ rxni->ni = ni; /* We hold a reference. */
+ m_tag_prepend(m, mtag);
+ }
}
- NET_EPOCH_EXIT(et);
-#ifdef LINUXKPI_DEBUG_80211
- if (linuxkpi_debug_80211 & D80211_TRACE_RX)
- printf("TRACE %s: handled frame type %#0x\n", __func__, ok);
-#endif
+ LKPI_80211_LHW_RXQ_LOCK(lhw);
+ if (lhw->rxq_stopped) {
+ LKPI_80211_LHW_RXQ_UNLOCK(lhw);
+ m_freem(m);
+ goto err;
+ }
+
+ mbufq_enqueue(&lhw->rxq, m);
+ taskqueue_enqueue(taskqueue_thread, &lhw->rxq_task);
+ LKPI_80211_LHW_RXQ_UNLOCK(lhw);
IMPROVE();
@@ -3991,12 +5155,22 @@ err:
}
uint8_t
-linuxkpi_ieee80211_get_tid(struct ieee80211_hdr *hdr)
+linuxkpi_ieee80211_get_tid(struct ieee80211_hdr *hdr, bool nonqos_ok)
{
const struct ieee80211_frame *wh;
+ uint8_t tid;
+
+ /* Linux seems to assume this is a QOS-Data-Frame */
+ KASSERT(nonqos_ok || ieee80211_is_data_qos(hdr->frame_control),
+ ("%s: hdr %p fc %#06x not qos_data\n", __func__, hdr,
+ hdr->frame_control));
wh = (const struct ieee80211_frame *)hdr;
- return (ieee80211_gettid(wh));
+ tid = ieee80211_gettid(wh);
+ KASSERT(nonqos_ok || tid == (tid & IEEE80211_QOS_TID), ("%s: tid %u "
+ "not expected (%u?)\n", __func__, tid, IEEE80211_NONQOS_TID));
+
+ return (tid);
}
struct wiphy *
@@ -4052,6 +5226,7 @@ linuxkpi_ieee80211_frequency_to_channel(uint32_t freq, uint32_t flags __unused)
return (ieee80211_mhz2ieee(freq, 0));
}
+#if 0
static struct lkpi_sta *
lkpi_find_lsta_by_ni(struct lkpi_vif *lvif, struct ieee80211_node *ni)
{
@@ -4068,6 +5243,7 @@ lkpi_find_lsta_by_ni(struct lkpi_vif *lvif, struct ieee80211_node *ni)
return (NULL);
}
+#endif
struct ieee80211_sta *
linuxkpi_ieee80211_find_sta(struct ieee80211_vif *vif, const u8 *peer)
@@ -4132,13 +5308,29 @@ linuxkpi_ieee80211_tx_dequeue(struct ieee80211_hw *hw,
struct ieee80211_txq *txq)
{
struct lkpi_txq *ltxq;
+ struct lkpi_vif *lvif;
struct sk_buff *skb;
+ skb = NULL;
ltxq = TXQ_TO_LTXQ(txq);
ltxq->seen_dequeue = true;
+ if (ltxq->stopped)
+ goto stopped;
+
+ lvif = VIF_TO_LVIF(ltxq->txq.vif);
+ if (lvif->hw_queue_stopped[ltxq->txq.ac]) {
+ ltxq->stopped = true;
+ goto stopped;
+ }
+
+ IMPROVE("hw(TX_FRAG_LIST)");
+
+ LKPI_80211_LTXQ_LOCK(ltxq);
skb = skb_dequeue(&ltxq->skbq);
+ LKPI_80211_LTXQ_UNLOCK(ltxq);
+stopped:
return (skb);
}
@@ -4153,10 +5345,12 @@ linuxkpi_ieee80211_txq_get_depth(struct ieee80211_txq *txq,
ltxq = TXQ_TO_LTXQ(txq);
fc = bc = 0;
+ LKPI_80211_LTXQ_LOCK(ltxq);
skb_queue_walk(&ltxq->skbq, skb) {
fc++;
bc += skb->len;
}
+ LKPI_80211_LTXQ_UNLOCK(ltxq);
if (frame_cnt)
*frame_cnt = fc;
if (byte_cnt)
@@ -4173,8 +5367,8 @@ linuxkpi_ieee80211_txq_get_depth(struct ieee80211_txq *txq,
* passed back from the driver. rawx_mit() saves the ni on the m and the
* m on the skb for us to be able to give feedback to net80211.
*/
-void
-linuxkpi_ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb,
+static void
+_lkpi_ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb,
int status)
{
struct ieee80211_node *ni;
@@ -4189,20 +5383,28 @@ linuxkpi_ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb,
ieee80211_tx_complete(ni, m, status);
/* ni & mbuf were consumed. */
}
+}
+void
+linuxkpi_ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb,
+ int status)
+{
+
+ _lkpi_ieee80211_free_txskb(hw, skb, status);
kfree_skb(skb);
}
void
-linuxkpi_ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
+linuxkpi_ieee80211_tx_status_ext(struct ieee80211_hw *hw,
+ struct ieee80211_tx_status *txstat)
{
+ struct sk_buff *skb;
struct ieee80211_tx_info *info;
struct ieee80211_ratectl_tx_status txs;
struct ieee80211_node *ni;
int status;
- info = IEEE80211_SKB_CB(skb);
-
+ skb = txstat->skb;
if (skb->m != NULL) {
struct mbuf *m;
@@ -4213,6 +5415,7 @@ linuxkpi_ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
ni = NULL;
}
+ info = txstat->info;
if (info->flags & IEEE80211_TX_STAT_ACK) {
status = 0; /* No error. */
txs.status = IEEE80211_RATECTL_TX_SUCCESS;
@@ -4235,11 +5438,11 @@ linuxkpi_ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
txs.flags |= IEEE80211_RATECTL_STATUS_LONG_RETRY;
}
#if 0 /* Unused in net80211 currently. */
- /* XXX-BZ conver;t check .flags for MCS/VHT/.. */
+ /* XXX-BZ convert check .flags for MCS/VHT/.. */
txs.final_rate = info->status.rates[0].idx;
txs.flags |= IEEE80211_RATECTL_STATUS_FINAL_RATE;
#endif
- if (info->status.is_valid_ack_signal) {
+ if (info->status.flags & IEEE80211_TX_STATUS_ACK_SIGNAL_VALID) {
txs.rssi = info->status.ack_signal; /* XXX-BZ CONVERT? */
txs.flags |= IEEE80211_RATECTL_STATUS_RSSI;
}
@@ -4264,7 +5467,7 @@ linuxkpi_ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
"band %u hw_queue %u tx_time_est %d : "
"rates [ %u %u %#x, %u %u %#x, %u %u %#x, %u %u %#x ] "
"ack_signal %u ampdu_ack_len %u ampdu_len %u antenna %u "
- "tx_time %u is_valid_ack_signal %u "
+ "tx_time %u flags %#x "
"status_driver_data [ %p %p ]\n",
__func__, hw, skb, status, info->flags,
info->band, info->hw_queue, info->tx_time_est,
@@ -4278,12 +5481,30 @@ linuxkpi_ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
info->status.rates[3].flags,
info->status.ack_signal, info->status.ampdu_ack_len,
info->status.ampdu_len, info->status.antenna,
- info->status.tx_time, info->status.is_valid_ack_signal,
+ info->status.tx_time, info->status.flags,
info->status.status_driver_data[0],
info->status.status_driver_data[1]);
#endif
- linuxkpi_ieee80211_free_txskb(hw, skb, status);
+ if (txstat->free_list) {
+ _lkpi_ieee80211_free_txskb(hw, skb, status);
+ list_add_tail(&skb->list, txstat->free_list);
+ } else {
+ linuxkpi_ieee80211_free_txskb(hw, skb, status);
+ }
+}
+
+void
+linuxkpi_ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+ struct ieee80211_tx_status status;
+
+ memset(&status, 0, sizeof(status));
+ status.info = IEEE80211_SKB_CB(skb);
+ status.skb = skb;
+ /* sta, n_rates, rates, free_list? */
+
+ ieee80211_tx_status_ext(hw, &status);
}
/*
@@ -4394,7 +5615,7 @@ linuxkpi_ieee80211_pspoll_get(struct ieee80211_hw *hw,
psp = skb_put_zero(skb, sizeof(*psp));
psp->i_fc[0] = IEEE80211_FC0_VERSION_0;
psp->i_fc[0] |= IEEE80211_FC0_SUBTYPE_PS_POLL | IEEE80211_FC0_TYPE_CTL;
- v = htole16(vif->bss_conf.aid | 1<<15 | 1<<16);
+ v = htole16(vif->cfg.aid | 1<<15 | 1<<16);
memcpy(&psp->i_aid, &v, sizeof(v));
IEEE80211_ADDR_COPY(psp->i_bssid, vap->iv_bss->ni_macaddr);
IEEE80211_ADDR_COPY(psp->i_ta, vif->addr);
@@ -4404,13 +5625,15 @@ linuxkpi_ieee80211_pspoll_get(struct ieee80211_hw *hw,
struct sk_buff *
linuxkpi_ieee80211_nullfunc_get(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, bool qos)
+ struct ieee80211_vif *vif, int linkid, bool qos)
{
struct lkpi_vif *lvif;
struct ieee80211vap *vap;
struct sk_buff *skb;
struct ieee80211_frame *nullf;
+ IMPROVE("linkid");
+
skb = dev_alloc_skb(hw->extra_tx_headroom + sizeof(*nullf));
if (skb == NULL)
return (NULL);
@@ -4460,10 +5683,8 @@ linuxkpi_ieee80211_connection_loss(struct ieee80211_vif *vif)
nstate = IEEE80211_S_INIT;
arg = 0; /* Not a valid reason. */
-#ifdef LINUXKPI_DEBUG_80211
- if (linuxkpi_debug_80211 & D80211_TRACE)
- ic_printf(vap->iv_ic, "%s: vif %p\n", __func__, vif);
-#endif
+ ic_printf(vap->iv_ic, "%s: vif %p vap %p state %s\n", __func__,
+ vif, vap, ieee80211_state_name[vap->iv_state]);
ieee80211_new_state(vap, nstate, arg);
}
@@ -4476,14 +5697,437 @@ linuxkpi_ieee80211_beacon_loss(struct ieee80211_vif *vif)
lvif = VIF_TO_LVIF(vif);
vap = LVIF_TO_VAP(lvif);
+ ic_printf(vap->iv_ic, "%s: vif %p vap %p state %s\n", __func__,
+ vif, vap, ieee80211_state_name[vap->iv_state]);
+ ieee80211_beacon_miss(vap->iv_ic);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void
+linuxkpi_ieee80211_stop_queue(struct ieee80211_hw *hw, int qnum)
+{
+ struct lkpi_hw *lhw;
+ struct lkpi_vif *lvif;
+ struct ieee80211_vif *vif;
+ int ac_count, ac;
+
+ KASSERT(qnum < hw->queues, ("%s: qnum %d >= hw->queues %d, hw %p\n",
+ __func__, qnum, hw->queues, hw));
+
+ lhw = wiphy_priv(hw->wiphy);
+
+ /* See lkpi_ic_vap_create(). */
+ if (hw->queues >= IEEE80211_NUM_ACS)
+ ac_count = IEEE80211_NUM_ACS;
+ else
+ ac_count = 1;
+
+ LKPI_80211_LHW_LVIF_LOCK(lhw);
+ TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) {
+
+ vif = LVIF_TO_VIF(lvif);
+ for (ac = 0; ac < ac_count; ac++) {
+ IMPROVE_TXQ("LOCKING");
+ if (qnum == vif->hw_queue[ac]) {
#ifdef LINUXKPI_DEBUG_80211
- if (linuxkpi_debug_80211 & D80211_TRACE || vap->iv_state != IEEE80211_S_RUN)
- ic_printf(vap->iv_ic, "%s: vif %p vap %p state %s\n", __func__,
- vif, vap, ieee80211_state_name[vap->iv_state]);
+ /*
+ * For now log this to better understand
+ * how this is supposed to work.
+ */
+ if (lvif->hw_queue_stopped[ac] &&
+ (linuxkpi_debug_80211 & D80211_IMPROVE_TXQ) != 0)
+ ic_printf(lhw->ic, "%s:%d: lhw %p hw %p "
+ "lvif %p vif %p ac %d qnum %d already "
+ "stopped\n", __func__, __LINE__,
+ lhw, hw, lvif, vif, ac, qnum);
#endif
- ieee80211_beacon_miss(vap->iv_ic);
+ lvif->hw_queue_stopped[ac] = true;
+ }
+ }
+ }
+ LKPI_80211_LHW_LVIF_UNLOCK(lhw);
+}
+
+void
+linuxkpi_ieee80211_stop_queues(struct ieee80211_hw *hw)
+{
+ int i;
+
+ IMPROVE_TXQ("Locking; do we need further info?");
+ for (i = 0; i < hw->queues; i++)
+ linuxkpi_ieee80211_stop_queue(hw, i);
+}
+
+
+static void
+lkpi_ieee80211_wake_queues(struct ieee80211_hw *hw, int hwq)
+{
+ struct lkpi_hw *lhw;
+ struct lkpi_vif *lvif;
+ struct lkpi_sta *lsta;
+ int ac_count, ac, tid;
+
+ /* See lkpi_ic_vap_create(). */
+ if (hw->queues >= IEEE80211_NUM_ACS)
+ ac_count = IEEE80211_NUM_ACS;
+ else
+ ac_count = 1;
+
+ lhw = wiphy_priv(hw->wiphy);
+
+ IMPROVE_TXQ("Locking");
+ LKPI_80211_LHW_LVIF_LOCK(lhw);
+ TAILQ_FOREACH(lvif, &lhw->lvif_head, lvif_entry) {
+ struct ieee80211_vif *vif;
+
+ vif = LVIF_TO_VIF(lvif);
+ for (ac = 0; ac < ac_count; ac++) {
+
+ if (hwq == vif->hw_queue[ac]) {
+
+ /* XXX-BZ what about software scan? */
+
+#ifdef LINUXKPI_DEBUG_80211
+ /*
+ * For now log this to better understand
+ * how this is supposed to work.
+ */
+ if (!lvif->hw_queue_stopped[ac] &&
+ (linuxkpi_debug_80211 & D80211_IMPROVE_TXQ) != 0)
+ ic_printf(lhw->ic, "%s:%d: lhw %p hw %p "
+ "lvif %p vif %p ac %d hw_q not stopped\n",
+ __func__, __LINE__,
+ lhw, hw, lvif, vif, ac);
+#endif
+ lvif->hw_queue_stopped[ac] = false;
+
+ LKPI_80211_LVIF_LOCK(lvif);
+ TAILQ_FOREACH(lsta, &lvif->lsta_head, lsta_entry) {
+ struct ieee80211_sta *sta;
+
+ sta = LSTA_TO_STA(lsta);
+ for (tid = 0; tid < nitems(sta->txq); tid++) {
+ struct lkpi_txq *ltxq;
+
+ if (sta->txq[tid] == NULL)
+ continue;
+
+ if (sta->txq[tid]->ac != ac)
+ continue;
+
+ ltxq = TXQ_TO_LTXQ(sta->txq[tid]);
+ if (!ltxq->stopped)
+ continue;
+
+ ltxq->stopped = false;
+
+ /* XXX-BZ see when this explodes with all the locking. taskq? */
+ lkpi_80211_mo_wake_tx_queue(hw, sta->txq[tid]);
+ }
+ }
+ LKPI_80211_LVIF_UNLOCK(lvif);
+ }
+ }
+ }
+ LKPI_80211_LHW_LVIF_UNLOCK(lhw);
+}
+
+void
+linuxkpi_ieee80211_wake_queues(struct ieee80211_hw *hw)
+{
+ int i;
+
+ IMPROVE_TXQ("Is this all/enough here?");
+ for (i = 0; i < hw->queues; i++)
+ lkpi_ieee80211_wake_queues(hw, i);
}
+void
+linuxkpi_ieee80211_wake_queue(struct ieee80211_hw *hw, int qnum)
+{
+
+ KASSERT(qnum < hw->queues, ("%s: qnum %d >= hw->queues %d, hw %p\n",
+ __func__, qnum, hw->queues, hw));
+
+ lkpi_ieee80211_wake_queues(hw, qnum);
+}
+
+/* This is just hardware queues. */
+void
+linuxkpi_ieee80211_txq_schedule_start(struct ieee80211_hw *hw, uint8_t ac)
+{
+ struct lkpi_hw *lhw;
+
+ lhw = HW_TO_LHW(hw);
+
+ IMPROVE_TXQ("Are there reasons why we wouldn't schedule?");
+ IMPROVE_TXQ("LOCKING");
+ if (++lhw->txq_generation[ac] == 0)
+ lhw->txq_generation[ac]++;
+}
+
+struct ieee80211_txq *
+linuxkpi_ieee80211_next_txq(struct ieee80211_hw *hw, uint8_t ac)
+{
+ struct lkpi_hw *lhw;
+ struct ieee80211_txq *txq;
+ struct lkpi_txq *ltxq;
+
+ lhw = HW_TO_LHW(hw);
+ txq = NULL;
+
+ IMPROVE_TXQ("LOCKING");
+
+ /* Check that we are scheduled. */
+ if (lhw->txq_generation[ac] == 0)
+ goto out;
+
+ ltxq = TAILQ_FIRST(&lhw->scheduled_txqs[ac]);
+ if (ltxq == NULL)
+ goto out;
+ if (ltxq->txq_generation == lhw->txq_generation[ac])
+ goto out;
+
+ ltxq->txq_generation = lhw->txq_generation[ac];
+ TAILQ_REMOVE(&lhw->scheduled_txqs[ac], ltxq, txq_entry);
+ txq = &ltxq->txq;
+ TAILQ_ELEM_INIT(ltxq, txq_entry);
+
+out:
+ return (txq);
+}
+
+void linuxkpi_ieee80211_schedule_txq(struct ieee80211_hw *hw,
+ struct ieee80211_txq *txq, bool withoutpkts)
+{
+ struct lkpi_hw *lhw;
+ struct lkpi_txq *ltxq;
+ bool ltxq_empty;
+
+ ltxq = TXQ_TO_LTXQ(txq);
+
+ IMPROVE_TXQ("LOCKING");
+
+ /* Only schedule if work to do or asked to anyway. */
+ LKPI_80211_LTXQ_LOCK(ltxq);
+ ltxq_empty = skb_queue_empty(&ltxq->skbq);
+ LKPI_80211_LTXQ_UNLOCK(ltxq);
+ if (!withoutpkts && ltxq_empty)
+ goto out;
+
+ /* Make sure we do not double-schedule. */
+ if (ltxq->txq_entry.tqe_next != NULL)
+ goto out;
+
+ lhw = HW_TO_LHW(hw);
+ TAILQ_INSERT_TAIL(&lhw->scheduled_txqs[txq->ac], ltxq, txq_entry);
+out:
+ return;
+}
+
+void
+linuxkpi_ieee80211_handle_wake_tx_queue(struct ieee80211_hw *hw,
+ struct ieee80211_txq *txq)
+{
+ struct lkpi_hw *lhw;
+ struct ieee80211_txq *ntxq;
+ struct ieee80211_tx_control control;
+ struct sk_buff *skb;
+
+ lhw = HW_TO_LHW(hw);
+
+ LKPI_80211_LHW_TXQ_LOCK(lhw);
+ ieee80211_txq_schedule_start(hw, txq->ac);
+ do {
+ ntxq = ieee80211_next_txq(hw, txq->ac);
+ if (ntxq == NULL)
+ break;
+
+ memset(&control, 0, sizeof(control));
+ control.sta = ntxq->sta;
+ do {
+ skb = linuxkpi_ieee80211_tx_dequeue(hw, ntxq);
+ if (skb == NULL)
+ break;
+ lkpi_80211_mo_tx(hw, &control, skb);
+ } while(1);
+
+ ieee80211_return_txq(hw, ntxq, false);
+ } while (1);
+ ieee80211_txq_schedule_end(hw, txq->ac);
+ LKPI_80211_LHW_TXQ_UNLOCK(lhw);
+}
+
+/* -------------------------------------------------------------------------- */
+
+struct lkpi_cfg80211_bss {
+ u_int refcnt;
+ struct cfg80211_bss bss;
+};
+
+struct lkpi_cfg80211_get_bss_iter_lookup {
+ struct wiphy *wiphy;
+ struct linuxkpi_ieee80211_channel *chan;
+ const uint8_t *bssid;
+ const uint8_t *ssid;
+ size_t ssid_len;
+ enum ieee80211_bss_type bss_type;
+ enum ieee80211_privacy privacy;
+
+ /*
+ * Something to store a copy of the result as the net80211 scan cache
+ * is not refoucnted so a scan entry might go away any time.
+ */
+ bool match;
+ struct cfg80211_bss *bss;
+};
+
+static void
+lkpi_cfg80211_get_bss_iterf(void *arg, const struct ieee80211_scan_entry *se)
+{
+ struct lkpi_cfg80211_get_bss_iter_lookup *lookup;
+ size_t ielen;
+
+ lookup = arg;
+
+ /* Do not try to find another match. */
+ if (lookup->match)
+ return;
+
+ /* Nothing to store result. */
+ if (lookup->bss == NULL)
+ return;
+
+ if (lookup->privacy != IEEE80211_PRIVACY_ANY) {
+ /* if (se->se_capinfo & IEEE80211_CAPINFO_PRIVACY) */
+ /* We have no idea what to compare to as the drivers only request ANY */
+ return;
+ }
+
+ if (lookup->bss_type != IEEE80211_BSS_TYPE_ANY) {
+ /* if (se->se_capinfo & (IEEE80211_CAPINFO_IBSS|IEEE80211_CAPINFO_ESS)) */
+ /* We have no idea what to compare to as the drivers only request ANY */
+ return;
+ }
+
+ if (lookup->chan != NULL) {
+ struct linuxkpi_ieee80211_channel *chan;
+
+ chan = linuxkpi_ieee80211_get_channel(lookup->wiphy,
+ se->se_chan->ic_freq);
+ if (chan == NULL || chan != lookup->chan)
+ return;
+ }
+
+ if (lookup->bssid && !IEEE80211_ADDR_EQ(lookup->bssid, se->se_bssid))
+ return;
+
+ if (lookup->ssid) {
+ if (lookup->ssid_len != se->se_ssid[1] ||
+ se->se_ssid[1] == 0)
+ return;
+ if (memcmp(lookup->ssid, se->se_ssid+2, lookup->ssid_len) != 0)
+ return;
+ }
+
+ ielen = se->se_ies.len;
+
+ lookup->bss->ies = malloc(sizeof(*lookup->bss->ies) + ielen,
+ M_LKPI80211, M_NOWAIT | M_ZERO);
+ if (lookup->bss->ies == NULL)
+ return;
+
+ lookup->bss->ies->data = (uint8_t *)lookup->bss->ies + sizeof(*lookup->bss->ies);
+ lookup->bss->ies->len = ielen;
+ if (ielen)
+ memcpy(lookup->bss->ies->data, se->se_ies.data, ielen);
+
+ lookup->match = true;
+}
+
+struct cfg80211_bss *
+linuxkpi_cfg80211_get_bss(struct wiphy *wiphy, struct linuxkpi_ieee80211_channel *chan,
+ const uint8_t *bssid, const uint8_t *ssid, size_t ssid_len,
+ enum ieee80211_bss_type bss_type, enum ieee80211_privacy privacy)
+{
+ struct lkpi_cfg80211_bss *lbss;
+ struct lkpi_cfg80211_get_bss_iter_lookup lookup;
+ struct lkpi_hw *lhw;
+ struct ieee80211vap *vap;
+
+ lhw = wiphy_priv(wiphy);
+
+ /* Let's hope we can alloc. */
+ lbss = malloc(sizeof(*lbss), M_LKPI80211, M_NOWAIT | M_ZERO);
+ if (lbss == NULL) {
+ ic_printf(lhw->ic, "%s: alloc failed.\n", __func__);
+ return (NULL);
+ }
+
+ lookup.wiphy = wiphy;
+ lookup.chan = chan;
+ lookup.bssid = bssid;
+ lookup.ssid = ssid;
+ lookup.ssid_len = ssid_len;
+ lookup.bss_type = bss_type;
+ lookup.privacy = privacy;
+ lookup.match = false;
+ lookup.bss = &lbss->bss;
+
+ IMPROVE("Iterate over all VAPs comparing perm_addr and addresses?");
+ vap = TAILQ_FIRST(&lhw->ic->ic_vaps);
+ ieee80211_scan_iterate(vap, lkpi_cfg80211_get_bss_iterf, &lookup);
+ if (!lookup.match) {
+ free(lbss, M_LKPI80211);
+ return (NULL);
+ }
+
+ refcount_init(&lbss->refcnt, 1);
+ return (&lbss->bss);
+}
+
+void
+linuxkpi_cfg80211_put_bss(struct wiphy *wiphy, struct cfg80211_bss *bss)
+{
+ struct lkpi_cfg80211_bss *lbss;
+
+ lbss = container_of(bss, struct lkpi_cfg80211_bss, bss);
+
+ /* Free everything again on refcount ... */
+ if (refcount_release(&lbss->refcnt)) {
+ free(lbss->bss.ies, M_LKPI80211);
+ free(lbss, M_LKPI80211);
+ }
+}
+
+void
+linuxkpi_cfg80211_bss_flush(struct wiphy *wiphy)
+{
+ struct lkpi_hw *lhw;
+ struct ieee80211com *ic;
+ struct ieee80211vap *vap;
+
+ lhw = wiphy_priv(wiphy);
+ ic = lhw->ic;
+
+ /*
+ * If we haven't called ieee80211_ifattach() yet
+ * or there is no VAP, there are no scans to flush.
+ */
+ if (ic == NULL ||
+ (lhw->sc_flags & LKPI_MAC80211_DRV_STARTED) == 0)
+ return;
+
+ /* Should only happen on the current one? Not seen it late enough. */
+ IEEE80211_LOCK(ic);
+ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
+ ieee80211_scan_flush(vap);
+ IEEE80211_UNLOCK(ic);
+}
+
+/* -------------------------------------------------------------------------- */
+
MODULE_VERSION(linuxkpi_wlan, 1);
MODULE_DEPEND(linuxkpi_wlan, linuxkpi, 1, 1, 1);
MODULE_DEPEND(linuxkpi_wlan, wlan, 1, 1, 1);
diff --git a/sys/compat/linuxkpi/common/src/linux_80211.h b/sys/compat/linuxkpi/common/src/linux_80211.h
index 3c107f76de32..b0156a5ade3f 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.h
+++ b/sys/compat/linuxkpi/common/src/linux_80211.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2020-2022 The FreeBSD Foundation
+ * Copyright (c) 2020-2023 The FreeBSD Foundation
* Copyright (c) 2020-2021 Bjoern A. Zeeb
*
* This software was developed by Björn Zeeb under sponsorship from
@@ -42,6 +42,52 @@
#ifndef _LKPI_SRC_LINUX_80211_H
#define _LKPI_SRC_LINUX_80211_H
+/* #define LINUXKPI_DEBUG_80211 */
+
+#ifndef D80211_TODO
+#define D80211_TODO 0x00000001
+#endif
+#ifndef D80211_IMPROVE
+#define D80211_IMPROVE 0x00000002
+#endif
+#define D80211_IMPROVE_TXQ 0x00000004
+#define D80211_TRACE 0x00000010
+#define D80211_TRACEOK 0x00000020
+#define D80211_TRACE_TX 0x00000100
+#define D80211_TRACE_TX_DUMP 0x00000200
+#define D80211_TRACE_RX 0x00001000
+#define D80211_TRACE_RX_DUMP 0x00002000
+#define D80211_TRACE_RX_BEACONS 0x00004000
+#define D80211_TRACEX (D80211_TRACE_TX|D80211_TRACE_RX)
+#define D80211_TRACEX_DUMP (D80211_TRACE_TX_DUMP|D80211_TRACE_RX_DUMP)
+#define D80211_TRACE_STA 0x00010000
+#define D80211_TRACE_MO 0x00100000
+#define D80211_TRACE_MODE 0x0f000000
+#define D80211_TRACE_MODE_HT 0x01000000
+#define D80211_TRACE_MODE_VHT 0x02000000
+#define D80211_TRACE_MODE_HE 0x04000000
+#define D80211_TRACE_MODE_EHT 0x08000000
+
+#define IMPROVE_TXQ(...) \
+ if (linuxkpi_debug_80211 & D80211_IMPROVE_TXQ) \
+ printf("%s:%d: XXX LKPI80211 IMPROVE_TXQ\n", __func__, __LINE__)
+
+#define IMPROVE_HT(...) \
+ if (linuxkpi_debug_80211 & D80211_TRACE_MODE_HT) \
+ printf("%s:%d: XXX LKPI80211 IMPROVE_HT\n", __func__, __LINE__)
+
+#define MTAG_ABI_LKPI80211 1707696513 /* LinuxKPI 802.11 KBI */
+
+/*
+ * Deferred RX path.
+ * We need to pass *ni along (and possibly more in the future so
+ * we use a struct right from the start.
+ */
+#define LKPI80211_TAG_RXNI 0 /* deferred RX path */
+struct lkpi_80211_tag_rxni {
+ struct ieee80211_node *ni; /* MUST hold a reference to it. */
+};
+
struct lkpi_radiotap_tx_hdr {
struct ieee80211_radiotap_header wt_ihdr;
uint8_t wt_flags;
@@ -73,7 +119,12 @@ struct lkpi_radiotap_rx_hdr {
(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE))
struct lkpi_txq {
+ TAILQ_ENTRY(lkpi_txq) txq_entry;
+
+ struct mtx ltxq_mtx;
bool seen_dequeue;
+ bool stopped;
+ uint32_t txq_generation;
struct sk_buff_head skbq;
/* Must be last! */
@@ -95,6 +146,7 @@ struct lkpi_sta {
struct ieee80211_key_conf *kc;
enum ieee80211_sta_state state;
+ bool txq_ready; /* Can we run the taskq? */
bool added_to_drv; /* Driver knows; i.e. we called ...(). */
bool in_mgd; /* XXX-BZ should this be per-vif? */
@@ -117,8 +169,12 @@ struct lkpi_vif {
struct ieee80211_node * (*iv_update_bss)(struct ieee80211vap *,
struct ieee80211_node *);
TAILQ_HEAD(, lkpi_sta) lsta_head;
+ struct lkpi_sta *lvif_bss;
+ bool lvif_bss_synched;
bool added_to_drv; /* Driver knows; i.e. we called add_interface(). */
+ bool hw_queue_stopped[IEEE80211_NUM_ACS];
+
/* Must be last! */
struct ieee80211_vif vif __aligned(CACHE_LINE_SIZE);
};
@@ -142,7 +198,21 @@ struct lkpi_hw { /* name it mac80211_sc? */
TAILQ_HEAD(, lkpi_vif) lvif_head;
struct sx lvif_sx;
- struct mtx mtx;
+ struct sx sx;
+
+ struct mtx txq_mtx;
+ uint32_t txq_generation[IEEE80211_NUM_ACS];
+ TAILQ_HEAD(, lkpi_txq) scheduled_txqs[IEEE80211_NUM_ACS];
+
+ /* Deferred RX path. */
+ struct task rxq_task;
+ struct mbufq rxq;
+ struct mtx rxq_mtx;
+
+ /* Scan functions we overload to handle depending on scan mode. */
+ void (*ic_scan_curchan)(struct ieee80211_scan_state *,
+ unsigned long);
+ void (*ic_scan_mindwell)(struct ieee80211_scan_state *);
/* Node functions we overload to sync state. */
struct ieee80211_node * (*ic_node_alloc)(struct ieee80211vap *,
@@ -151,16 +221,43 @@ struct lkpi_hw { /* name it mac80211_sc? */
void (*ic_node_cleanup)(struct ieee80211_node *);
void (*ic_node_free)(struct ieee80211_node *);
+ /* HT and later functions. */
+ int (*ic_recv_action)(struct ieee80211_node *,
+ const struct ieee80211_frame *,
+ const uint8_t *, const uint8_t *);
+ int (*ic_send_action)(struct ieee80211_node *,
+ int, int, void *);
+ int (*ic_ampdu_enable)(struct ieee80211_node *,
+ struct ieee80211_tx_ampdu *);
+ int (*ic_addba_request)(struct ieee80211_node *,
+ struct ieee80211_tx_ampdu *, int, int, int);
+ int (*ic_addba_response)(struct ieee80211_node *,
+ struct ieee80211_tx_ampdu *, int, int, int);
+ void (*ic_addba_stop)(struct ieee80211_node *,
+ struct ieee80211_tx_ampdu *);
+ void (*ic_addba_response_timeout)(struct ieee80211_node *,
+ struct ieee80211_tx_ampdu *);
+ void (*ic_bar_response)(struct ieee80211_node *,
+ struct ieee80211_tx_ampdu *, int);
+ int (*ic_ampdu_rx_start)(struct ieee80211_node *,
+ struct ieee80211_rx_ampdu *, int, int, int);
+ void (*ic_ampdu_rx_stop)(struct ieee80211_node *,
+ struct ieee80211_rx_ampdu *);
+
#define LKPI_MAC80211_DRV_STARTED 0x00000001
uint32_t sc_flags;
-#define LKPI_SCAN_RUNNING 0x00000001
+#define LKPI_LHW_SCAN_RUNNING 0x00000001
+#define LKPI_LHW_SCAN_HW 0x00000002
uint32_t scan_flags;
+ struct mtx scan_mtx;
int supbands; /* Number of supported bands. */
int max_rates; /* Maximum number of bitrates supported in any channel. */
int scan_ie_len; /* Length of common per-band scan IEs. */
bool update_mc;
+ bool update_wme;
+ bool rxq_stopped;
/* Must be last! */
struct ieee80211_hw hw __aligned(CACHE_LINE_SIZE);
@@ -168,6 +265,15 @@ struct lkpi_hw { /* name it mac80211_sc? */
#define LHW_TO_HW(_lhw) (&(_lhw)->hw)
#define HW_TO_LHW(_hw) container_of(_hw, struct lkpi_hw, hw)
+struct lkpi_chanctx {
+ bool added_to_drv; /* Managed by MO */
+ struct ieee80211_chanctx_conf conf __aligned(CACHE_LINE_SIZE);
+};
+#define LCHANCTX_TO_CHANCTX_CONF(_lchanctx) \
+ (&(_lchanctx)->conf)
+#define CHANCTX_CONF_TO_LCHANCTX(_conf) \
+ container_of(_conf, struct lkpi_chanctx, conf)
+
struct lkpi_wiphy {
const struct cfg80211_ops *ops;
@@ -177,13 +283,57 @@ struct lkpi_wiphy {
#define WIPHY_TO_LWIPHY(_wiphy) container_of(_wiphy, struct lkpi_wiphy, wiphy)
#define LWIPHY_TO_WIPHY(_lwiphy) (&(_lwiphy)->wiphy)
-
-#define LKPI_80211_LHW_LOCK(_lhw) mtx_lock(&(_lhw)->mtx)
-#define LKPI_80211_LHW_UNLOCK(_lhw) mtx_unlock(&(_lhw)->mtx)
-#define LKPI_80211_LHW_LOCK_ASSERT(_lhw) \
- mtx_assert(&(_lhw)->mtx, MA_OWNED)
-#define LKPI_80211_LHW_UNLOCK_ASSERT(_lhw) \
- mtx_assert(&(_lhw)->mtx, MA_NOTOWNED)
+#define LKPI_80211_LHW_LOCK_INIT(_lhw) \
+ sx_init_flags(&(_lhw)->sx, "lhw", SX_RECURSE);
+#define LKPI_80211_LHW_LOCK_DESTROY(_lhw) \
+ sx_destroy(&(_lhw)->sx);
+#define LKPI_80211_LHW_LOCK(_lhw) \
+ sx_xlock(&(_lhw)->sx)
+#define LKPI_80211_LHW_UNLOCK(_lhw) \
+ sx_xunlock(&(_lhw)->sx)
+#define LKPI_80211_LHW_LOCK_ASSERT(_lhw) \
+ sx_assert(&(_lhw)->sx, SA_LOCKED)
+#define LKPI_80211_LHW_UNLOCK_ASSERT(_lhw) \
+ sx_assert(&(_lhw)->sx, SA_UNLOCKED)
+
+#define LKPI_80211_LHW_SCAN_LOCK_INIT(_lhw) \
+ mtx_init(&(_lhw)->scan_mtx, "lhw-scan", NULL, MTX_DEF | MTX_RECURSE);
+#define LKPI_80211_LHW_SCAN_LOCK_DESTROY(_lhw) \
+ mtx_destroy(&(_lhw)->scan_mtx);
+#define LKPI_80211_LHW_SCAN_LOCK(_lhw) \
+ mtx_lock(&(_lhw)->scan_mtx)
+#define LKPI_80211_LHW_SCAN_UNLOCK(_lhw) \
+ mtx_unlock(&(_lhw)->scan_mtx)
+#define LKPI_80211_LHW_SCAN_LOCK_ASSERT(_lhw) \
+ mtx_assert(&(_lhw)->scan_mtx, MA_OWNED)
+#define LKPI_80211_LHW_SCAN_UNLOCK_ASSERT(_lhw) \
+ mtx_assert(&(_lhw)->scan_mtx, MA_NOTOWNED)
+
+#define LKPI_80211_LHW_TXQ_LOCK_INIT(_lhw) \
+ mtx_init(&(_lhw)->txq_mtx, "lhw-txq", NULL, MTX_DEF | MTX_RECURSE);
+#define LKPI_80211_LHW_TXQ_LOCK_DESTROY(_lhw) \
+ mtx_destroy(&(_lhw)->txq_mtx);
+#define LKPI_80211_LHW_TXQ_LOCK(_lhw) \
+ mtx_lock(&(_lhw)->txq_mtx)
+#define LKPI_80211_LHW_TXQ_UNLOCK(_lhw) \
+ mtx_unlock(&(_lhw)->txq_mtx)
+#define LKPI_80211_LHW_TXQ_LOCK_ASSERT(_lhw) \
+ mtx_assert(&(_lhw)->txq_mtx, MA_OWNED)
+#define LKPI_80211_LHW_TXQ_UNLOCK_ASSERT(_lhw) \
+ mtx_assert(&(_lhw)->txq_mtx, MA_NOTOWNED)
+
+#define LKPI_80211_LHW_RXQ_LOCK_INIT(_lhw) \
+ mtx_init(&(_lhw)->rxq_mtx, "lhw-rxq", NULL, MTX_DEF | MTX_RECURSE);
+#define LKPI_80211_LHW_RXQ_LOCK_DESTROY(_lhw) \
+ mtx_destroy(&(_lhw)->rxq_mtx);
+#define LKPI_80211_LHW_RXQ_LOCK(_lhw) \
+ mtx_lock(&(_lhw)->rxq_mtx)
+#define LKPI_80211_LHW_RXQ_UNLOCK(_lhw) \
+ mtx_unlock(&(_lhw)->rxq_mtx)
+#define LKPI_80211_LHW_RXQ_LOCK_ASSERT(_lhw) \
+ mtx_assert(&(_lhw)->rxq_mtx, MA_OWNED)
+#define LKPI_80211_LHW_RXQ_UNLOCK_ASSERT(_lhw) \
+ mtx_assert(&(_lhw)->rxq_mtx, MA_NOTOWNED)
#define LKPI_80211_LHW_LVIF_LOCK(_lhw) sx_xlock(&(_lhw)->lvif_sx)
#define LKPI_80211_LHW_LVIF_UNLOCK(_lhw) sx_xunlock(&(_lhw)->lvif_sx)
@@ -191,12 +341,35 @@ struct lkpi_wiphy {
#define LKPI_80211_LVIF_LOCK(_lvif) mtx_lock(&(_lvif)->mtx)
#define LKPI_80211_LVIF_UNLOCK(_lvif) mtx_unlock(&(_lvif)->mtx)
-#define LKPI_80211_LSTA_LOCK(_lsta) mtx_lock(&(_lsta)->txq_mtx)
-#define LKPI_80211_LSTA_UNLOCK(_lsta) mtx_unlock(&(_lsta)->txq_mtx)
-
+#define LKPI_80211_LSTA_TXQ_LOCK_INIT(_lsta) \
+ mtx_init(&(_lsta)->txq_mtx, "lsta-txq", NULL, MTX_DEF);
+#define LKPI_80211_LSTA_TXQ_LOCK_DESTROY(_lsta) \
+ mtx_destroy(&(_lsta)->txq_mtx);
+#define LKPI_80211_LSTA_TXQ_LOCK(_lsta) \
+ mtx_lock(&(_lsta)->txq_mtx)
+#define LKPI_80211_LSTA_TXQ_UNLOCK(_lsta) \
+ mtx_unlock(&(_lsta)->txq_mtx)
+#define LKPI_80211_LSTA_TXQ_LOCK_ASSERT(_lsta) \
+ mtx_assert(&(_lsta)->txq_mtx, MA_OWNED)
+#define LKPI_80211_LSTA_TXQ_UNLOCK_ASSERT(_lsta) \
+ mtx_assert(&(_lsta)->txq_mtx, MA_NOTOWNED)
+
+#define LKPI_80211_LTXQ_LOCK_INIT(_ltxq) \
+ mtx_init(&(_ltxq)->ltxq_mtx, "ltxq", NULL, MTX_DEF);
+#define LKPI_80211_LTXQ_LOCK_DESTROY(_ltxq) \
+ mtx_destroy(&(_ltxq)->ltxq_mtx);
+#define LKPI_80211_LTXQ_LOCK(_ltxq) \
+ mtx_lock(&(_ltxq)->ltxq_mtx)
+#define LKPI_80211_LTXQ_UNLOCK(_ltxq) \
+ mtx_unlock(&(_ltxq)->ltxq_mtx)
+#define LKPI_80211_LTXQ_LOCK_ASSERT(_ltxq) \
+ mtx_assert(&(_ltxq)->ltxq_mtx, MA_OWNED)
+#define LKPI_80211_LTXQ_UNLOCK_ASSERT(_ltxq) \
+ mtx_assert(&(_ltxq)->ltxq_mtx, MA_NOTOWNED)
int lkpi_80211_mo_start(struct ieee80211_hw *);
void lkpi_80211_mo_stop(struct ieee80211_hw *);
+int lkpi_80211_mo_get_antenna(struct ieee80211_hw *, u32 *, u32 *);
int lkpi_80211_mo_set_frag_threshold(struct ieee80211_hw *, uint32_t);
int lkpi_80211_mo_set_rts_threshold(struct ieee80211_hw *, uint32_t);
int lkpi_80211_mo_add_interface(struct ieee80211_hw *, struct ieee80211_vif *);
@@ -212,12 +385,12 @@ u64 lkpi_80211_mo_prepare_multicast(struct ieee80211_hw *,
void lkpi_80211_mo_configure_filter(struct ieee80211_hw *, unsigned int,
unsigned int *, u64);
int lkpi_80211_mo_sta_state(struct ieee80211_hw *, struct ieee80211_vif *,
- struct ieee80211_sta *, enum ieee80211_sta_state);
+ struct lkpi_sta *, enum ieee80211_sta_state);
int lkpi_80211_mo_config(struct ieee80211_hw *, uint32_t);
int lkpi_80211_mo_assign_vif_chanctx(struct ieee80211_hw *, struct ieee80211_vif *,
- struct ieee80211_chanctx_conf *);
+ struct ieee80211_bss_conf *, struct ieee80211_chanctx_conf *);
void lkpi_80211_mo_unassign_vif_chanctx(struct ieee80211_hw *, struct ieee80211_vif *,
- struct ieee80211_chanctx_conf **);
+ struct ieee80211_bss_conf *, struct ieee80211_chanctx_conf **);
int lkpi_80211_mo_add_chanctx(struct ieee80211_hw *, struct ieee80211_chanctx_conf *);
void lkpi_80211_mo_change_chanctx(struct ieee80211_hw *,
struct ieee80211_chanctx_conf *, uint32_t);
@@ -226,7 +399,7 @@ void lkpi_80211_mo_remove_chanctx(struct ieee80211_hw *,
void lkpi_80211_mo_bss_info_changed(struct ieee80211_hw *, struct ieee80211_vif *,
struct ieee80211_bss_conf *, uint64_t);
int lkpi_80211_mo_conf_tx(struct ieee80211_hw *, struct ieee80211_vif *,
- uint16_t, const struct ieee80211_tx_queue_params *);
+ uint32_t, uint16_t, const struct ieee80211_tx_queue_params *);
void lkpi_80211_mo_flush(struct ieee80211_hw *, struct ieee80211_vif *,
uint32_t, bool);
void lkpi_80211_mo_mgd_prepare_tx(struct ieee80211_hw *, struct ieee80211_vif *,
@@ -242,5 +415,8 @@ void lkpi_80211_mo_sta_pre_rcu_remove(struct ieee80211_hw *,
int lkpi_80211_mo_set_key(struct ieee80211_hw *, enum set_key_cmd,
struct ieee80211_vif *, struct ieee80211_sta *,
struct ieee80211_key_conf *);
+int lkpi_80211_mo_ampdu_action(struct ieee80211_hw *, struct ieee80211_vif *,
+ struct ieee80211_ampdu_params *);
+
#endif /* _LKPI_SRC_LINUX_80211_H */
diff --git a/sys/compat/linuxkpi/common/src/linux_80211_macops.c b/sys/compat/linuxkpi/common/src/linux_80211_macops.c
index b3e01780e1ce..8cc885c037e3 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211_macops.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211_macops.c
@@ -26,9 +26,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/types.h>
#include <sys/kernel.h>
@@ -39,6 +36,17 @@ __FBSDID("$FreeBSD$");
#include "linux_80211.h"
+/* Could be a different tracing framework later. */
+#ifdef LINUXKPI_DEBUG_80211
+#define LKPI_80211_TRACE_MO(fmt, ...) \
+ if (linuxkpi_debug_80211 & D80211_TRACE_MO) \
+ printf("LKPI_80211_TRACE_MO %s:%d: %d %d %u_" fmt "\n", \
+ __func__, __LINE__, curcpu, curthread->td_tid, \
+ (unsigned int)ticks, __VA_ARGS__)
+#else
+#define LKPI_80211_TRACE_MO(...) do { } while(0)
+#endif
+
int
lkpi_80211_mo_start(struct ieee80211_hw *hw)
{
@@ -56,6 +64,7 @@ lkpi_80211_mo_start(struct ieee80211_hw *hw)
error = EEXIST;
goto out;
}
+ LKPI_80211_TRACE_MO("hw %p", hw);
error = lhw->ops->start(hw);
if (error == 0)
lhw->sc_flags |= LKPI_MAC80211_DRV_STARTED;
@@ -73,11 +82,31 @@ lkpi_80211_mo_stop(struct ieee80211_hw *hw)
if (lhw->ops->stop == NULL)
return;
+ LKPI_80211_TRACE_MO("hw %p", hw);
lhw->ops->stop(hw);
lhw->sc_flags &= ~LKPI_MAC80211_DRV_STARTED;
}
int
+lkpi_80211_mo_get_antenna(struct ieee80211_hw *hw, u32 *txs, u32 *rxs)
+{
+ struct lkpi_hw *lhw;
+ int error;
+
+ lhw = HW_TO_LHW(hw);
+ if (lhw->ops->get_antenna == NULL) {
+ error = EOPNOTSUPP;
+ goto out;
+ }
+
+ LKPI_80211_TRACE_MO("hw %p", hw);
+ error = lhw->ops->get_antenna(hw, txs, rxs);
+
+out:
+ return (error);
+}
+
+int
lkpi_80211_mo_set_frag_threshold(struct ieee80211_hw *hw, uint32_t frag_th)
{
struct lkpi_hw *lhw;
@@ -89,6 +118,7 @@ lkpi_80211_mo_set_frag_threshold(struct ieee80211_hw *hw, uint32_t frag_th)
goto out;
}
+ LKPI_80211_TRACE_MO("hw %p frag_th %u", hw, frag_th);
error = lhw->ops->set_frag_threshold(hw, frag_th);
out:
@@ -107,6 +137,7 @@ lkpi_80211_mo_set_rts_threshold(struct ieee80211_hw *hw, uint32_t rts_th)
goto out;
}
+ LKPI_80211_TRACE_MO("hw %p rts_th %u", hw, rts_th);
error = lhw->ops->set_rts_threshold(hw, rts_th);
out:
@@ -137,6 +168,7 @@ lkpi_80211_mo_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
}
LKPI_80211_LVIF_UNLOCK(lvif);
+ LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
error = lhw->ops->add_interface(hw, vif);
if (error == 0) {
LKPI_80211_LVIF_LOCK(lvif);
@@ -166,6 +198,7 @@ lkpi_80211_mo_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vi
}
LKPI_80211_LVIF_UNLOCK(lvif);
+ LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
lhw->ops->remove_interface(hw, vif);
LKPI_80211_LVIF_LOCK(lvif);
lvif->added_to_drv = false;
@@ -180,17 +213,22 @@ lkpi_80211_mo_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct lkpi_hw *lhw;
int error;
+ /*
+ * MUST NOT return EPERM as that is a "magic number 1" based on rtw88
+ * driver indicating hw_scan is not supported despite the ops call
+ * being available.
+ */
+
lhw = HW_TO_LHW(hw);
if (lhw->ops->hw_scan == NULL) {
- /* XXX-BZ can we hide other scans like we can for sta_add..? */
- error = EOPNOTSUPP;
+ /* Return magic number to use sw scan. */
+ error = 1;
goto out;
}
- lhw->scan_flags |= LKPI_SCAN_RUNNING;
+ LKPI_80211_TRACE_MO("CALLING hw %p vif %p sr %p", hw, vif, sr);
error = lhw->ops->hw_scan(hw, vif, sr);
- if (error != 0)
- lhw->scan_flags &= ~LKPI_SCAN_RUNNING;
+ LKPI_80211_TRACE_MO("RETURNING hw %p vif %p sr %p error %d", hw, vif, sr, error);
out:
return (error);
@@ -205,6 +243,7 @@ lkpi_80211_mo_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
if (lhw->ops->cancel_hw_scan == NULL)
return;
+ LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
lhw->ops->cancel_hw_scan(hw, vif);
}
@@ -217,8 +256,9 @@ lkpi_80211_mo_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vi
if (lhw->ops->sw_scan_complete == NULL)
return;
+ LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
lhw->ops->sw_scan_complete(hw, vif);
- lhw->scan_flags &= ~LKPI_SCAN_RUNNING;
+ lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING;
}
void
@@ -231,6 +271,7 @@ lkpi_80211_mo_sw_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (lhw->ops->sw_scan_start == NULL)
return;
+ LKPI_80211_TRACE_MO("hw %p vif %p", hw, vif);
lhw->ops->sw_scan_start(hw, vif, addr);
}
@@ -249,6 +290,7 @@ lkpi_80211_mo_prepare_multicast(struct ieee80211_hw *hw,
if (lhw->ops->prepare_multicast == NULL)
return (0);
+ LKPI_80211_TRACE_MO("hw %p mc_list %p", hw, mc_list);
ptr = lhw->ops->prepare_multicast(hw, mc_list);
return (ptr);
}
@@ -266,6 +308,7 @@ lkpi_80211_mo_configure_filter(struct ieee80211_hw *hw, unsigned int changed_fla
if (mc_ptr == 0)
return;
+ LKPI_80211_TRACE_MO("hw %p changed_flags %#x total_flags %p mc_ptr %ju", hw, changed_flags, total_flags, (uintmax_t)mc_ptr);
lhw->ops->configure_filter(hw, changed_flags, total_flags, mc_ptr);
}
@@ -295,6 +338,7 @@ lkpi_80211_mo_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
goto out;
}
+ LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta);
error = lhw->ops->sta_add(hw, vif, sta);
if (error == 0)
lsta->added_to_drv = true;
@@ -324,6 +368,7 @@ lkpi_80211_mo_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
goto out;
}
+ LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta);
error = lhw->ops->sta_remove(hw, vif, sta);
if (error == 0)
lsta->added_to_drv = false;
@@ -334,15 +379,16 @@ out:
int
lkpi_80211_mo_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, enum ieee80211_sta_state nstate)
+ struct lkpi_sta *lsta, enum ieee80211_sta_state nstate)
{
struct lkpi_hw *lhw;
- struct lkpi_sta *lsta;
+ struct ieee80211_sta *sta;
int error;
lhw = HW_TO_LHW(hw);
- lsta = STA_TO_LSTA(sta);
+ sta = LSTA_TO_STA(lsta);
if (lhw->ops->sta_state != NULL) {
+ LKPI_80211_TRACE_MO("hw %p vif %p sta %p nstate %d", hw, vif, sta, nstate);
error = lhw->ops->sta_state(hw, vif, sta, lsta->state, nstate);
if (error == 0) {
if (nstate == IEEE80211_STA_NOTEXIST)
@@ -387,6 +433,7 @@ lkpi_80211_mo_config(struct ieee80211_hw *hw, uint32_t changed)
goto out;
}
+ LKPI_80211_TRACE_MO("hw %p changed %u", hw, changed);
error = lhw->ops->config(hw, changed);
out:
@@ -396,7 +443,7 @@ out:
int
lkpi_80211_mo_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_chanctx_conf *chanctx_conf)
+ struct ieee80211_bss_conf *conf, struct ieee80211_chanctx_conf *chanctx_conf)
{
struct lkpi_hw *lhw;
int error;
@@ -407,7 +454,9 @@ lkpi_80211_mo_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *
goto out;
}
- error = lhw->ops->assign_vif_chanctx(hw, vif, chanctx_conf);
+ LKPI_80211_TRACE_MO("hw %p vif %p bss_conf %p chanctx_conf %p",
+ hw, vif, conf, chanctx_conf);
+ error = lhw->ops->assign_vif_chanctx(hw, vif, conf, chanctx_conf);
if (error == 0)
vif->chanctx_conf = chanctx_conf;
@@ -417,7 +466,7 @@ out:
void
lkpi_80211_mo_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_chanctx_conf **chanctx_conf)
+ struct ieee80211_bss_conf *conf, struct ieee80211_chanctx_conf **chanctx_conf)
{
struct lkpi_hw *lhw;
@@ -428,7 +477,9 @@ lkpi_80211_mo_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif
if (*chanctx_conf == NULL)
return;
- lhw->ops->unassign_vif_chanctx(hw, vif, *chanctx_conf);
+ LKPI_80211_TRACE_MO("hw %p vif %p bss_conf %p chanctx_conf %p",
+ hw, vif, conf, *chanctx_conf);
+ lhw->ops->unassign_vif_chanctx(hw, vif, conf, *chanctx_conf);
*chanctx_conf = NULL;
}
@@ -438,6 +489,7 @@ lkpi_80211_mo_add_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *chanctx_conf)
{
struct lkpi_hw *lhw;
+ struct lkpi_chanctx *lchanctx;
int error;
lhw = HW_TO_LHW(hw);
@@ -446,7 +498,12 @@ lkpi_80211_mo_add_chanctx(struct ieee80211_hw *hw,
goto out;
}
+ LKPI_80211_TRACE_MO("hw %p chanctx_conf %p", hw, chanctx_conf);
error = lhw->ops->add_chanctx(hw, chanctx_conf);
+ if (error == 0) {
+ lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);
+ lchanctx->added_to_drv = true;
+ }
out:
return (error);
@@ -462,6 +519,7 @@ lkpi_80211_mo_change_chanctx(struct ieee80211_hw *hw,
if (lhw->ops->change_chanctx == NULL)
return;
+ LKPI_80211_TRACE_MO("hw %p chanctx_conf %p changed %u", hw, chanctx_conf, changed);
lhw->ops->change_chanctx(hw, chanctx_conf, changed);
}
@@ -470,12 +528,16 @@ lkpi_80211_mo_remove_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *chanctx_conf)
{
struct lkpi_hw *lhw;
+ struct lkpi_chanctx *lchanctx;
lhw = HW_TO_LHW(hw);
if (lhw->ops->remove_chanctx == NULL)
return;
+ LKPI_80211_TRACE_MO("hw %p chanctx_conf %p", hw, chanctx_conf);
lhw->ops->remove_chanctx(hw, chanctx_conf);
+ lchanctx = CHANCTX_CONF_TO_LCHANCTX(chanctx_conf);
+ lchanctx->added_to_drv = false;
}
void
@@ -485,16 +547,20 @@ lkpi_80211_mo_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vi
struct lkpi_hw *lhw;
lhw = HW_TO_LHW(hw);
- if (lhw->ops->bss_info_changed == NULL)
+ if (lhw->ops->link_info_changed == NULL &&
+ lhw->ops->bss_info_changed == NULL)
return;
- lhw->ops->bss_info_changed(hw, vif, conf, changed);
+ LKPI_80211_TRACE_MO("hw %p vif %p conf %p changed %#jx", hw, vif, conf, (uintmax_t)changed);
+ if (lhw->ops->link_info_changed != NULL)
+ lhw->ops->link_info_changed(hw, vif, conf, changed);
+ else
+ lhw->ops->bss_info_changed(hw, vif, conf, changed);
}
-
int
lkpi_80211_mo_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- uint16_t ac, const struct ieee80211_tx_queue_params *txqp)
+ uint32_t link_id, uint16_t ac, const struct ieee80211_tx_queue_params *txqp)
{
struct lkpi_hw *lhw;
int error;
@@ -505,7 +571,9 @@ lkpi_80211_mo_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
goto out;
}
- error = lhw->ops->conf_tx(hw, vif, ac, txqp);
+ LKPI_80211_TRACE_MO("hw %p vif %p link_id %u ac %u txpq %p",
+ hw, vif, link_id, ac, txqp);
+ error = lhw->ops->conf_tx(hw, vif, link_id, ac, txqp);
out:
return (error);
@@ -521,6 +589,7 @@ lkpi_80211_mo_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (lhw->ops->flush == NULL)
return;
+ LKPI_80211_TRACE_MO("hw %p vif %p nqueues %u drop %d", hw, vif, nqueues, drop);
lhw->ops->flush(hw, vif, nqueues, drop);
}
@@ -534,6 +603,7 @@ lkpi_80211_mo_mgd_prepare_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (lhw->ops->mgd_prepare_tx == NULL)
return;
+ LKPI_80211_TRACE_MO("hw %p vif %p txinfo %p", hw, vif, txinfo);
lhw->ops->mgd_prepare_tx(hw, vif, txinfo);
}
@@ -547,6 +617,7 @@ lkpi_80211_mo_mgd_complete_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif
if (lhw->ops->mgd_complete_tx == NULL)
return;
+ LKPI_80211_TRACE_MO("hw %p vif %p txinfo %p", hw, vif, txinfo);
lhw->ops->mgd_complete_tx(hw, vif, txinfo);
}
@@ -560,6 +631,7 @@ lkpi_80211_mo_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *txctrl,
if (lhw->ops->tx == NULL)
return;
+ LKPI_80211_TRACE_MO("hw %p txctrl %p skb %p", hw, txctrl, skb);
lhw->ops->tx(hw, txctrl, skb);
}
@@ -572,6 +644,7 @@ lkpi_80211_mo_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
if (lhw->ops->wake_tx_queue == NULL)
return;
+ LKPI_80211_TRACE_MO("hw %p txq %p", hw, txq);
lhw->ops->wake_tx_queue(hw, txq);
}
@@ -584,6 +657,7 @@ lkpi_80211_mo_sync_rx_queues(struct ieee80211_hw *hw)
if (lhw->ops->sync_rx_queues == NULL)
return;
+ LKPI_80211_TRACE_MO("hw %p", hw);
lhw->ops->sync_rx_queues(hw);
}
@@ -597,6 +671,7 @@ lkpi_80211_mo_sta_pre_rcu_remove(struct ieee80211_hw *hw,
if (lhw->ops->sta_pre_rcu_remove == NULL)
return;
+ LKPI_80211_TRACE_MO("hw %p vif %p sta %p", hw, vif, sta);
lhw->ops->sta_pre_rcu_remove(hw, vif, sta);
}
@@ -614,8 +689,31 @@ lkpi_80211_mo_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
goto out;
}
+ LKPI_80211_TRACE_MO("hw %p cmd %d vif %p sta %p kc %p", hw, cmd, vif, sta, kc);
error = lhw->ops->set_key(hw, cmd, vif, sta, kc);
out:
return (error);
}
+
+int
+lkpi_80211_mo_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_ampdu_params *params)
+{
+ struct lkpi_hw *lhw;
+ int error;
+
+ lhw = HW_TO_LHW(hw);
+ if (lhw->ops->ampdu_action == NULL) {
+ error = EOPNOTSUPP;
+ goto out;
+ }
+
+ LKPI_80211_TRACE_MO("hw %p vif %p params %p { %p, %d, %u, %u, %u, %u, %d }",
+ hw, vif, params, params->sta, params->action, params->buf_size,
+ params->timeout, params->ssn, params->tid, params->amsdu);
+ error = lhw->ops->ampdu_action(hw, vif, params);
+
+out:
+ return (error);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_acpi.c b/sys/compat/linuxkpi/common/src/linux_acpi.c
index 5eb60941abac..60ec838e9da7 100644
--- a/sys/compat/linuxkpi/common/src/linux_acpi.c
+++ b/sys/compat/linuxkpi/common/src/linux_acpi.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2018 Johannes Lundberg <johalun@FreeBSD.org>
* Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org>
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#include "opt_acpi.h"
@@ -40,6 +38,7 @@
#include <dev/acpica/acpivar.h>
#include <linux/notifier.h>
+#include <linux/suspend.h>
#include <acpi/acpi_bus.h>
#include <acpi/video.h>
@@ -58,6 +57,8 @@ _Static_assert(LINUX_ACPI_TAGS <= LINUX_NOTIFY_TAGS,
#ifdef DEV_ACPI
+suspend_state_t pm_suspend_target_state = PM_SUSPEND_ON;
+
static uint32_t linux_acpi_target_sleep_state = ACPI_STATE_S0;
static eventhandler_tag resume_tag;
@@ -108,12 +109,14 @@ linux_handle_power_suspend_event(void *arg __unused)
* TODO: Make acpi_sleep_event consistent
*/
linux_acpi_target_sleep_state = ACPI_STATE_S3;
+ pm_suspend_target_state = PM_SUSPEND_MEM;
}
static void
linux_handle_power_resume_event(void *arg __unused)
{
linux_acpi_target_sleep_state = ACPI_STATE_S0;
+ pm_suspend_target_state = PM_SUSPEND_ON;
}
static void
@@ -173,6 +176,79 @@ acpi_target_system_state(void)
return (linux_acpi_target_sleep_state);
}
+struct acpi_dev_present_ctx {
+ const char *hid;
+ const char *uid;
+ int64_t hrv;
+};
+
+static ACPI_STATUS
+acpi_dev_present_cb(ACPI_HANDLE handle, UINT32 level, void *context,
+ void **result)
+{
+ ACPI_DEVICE_INFO *devinfo;
+ struct acpi_dev_present_ctx *match = context;
+ bool present = false;
+ UINT32 sta, hrv;
+ int i;
+
+ if (handle == NULL)
+ return (AE_OK);
+
+ if (!ACPI_FAILURE(acpi_GetInteger(handle, "_STA", &sta)) &&
+ !ACPI_DEVICE_PRESENT(sta))
+ return (AE_OK);
+
+ if (ACPI_FAILURE(AcpiGetObjectInfo(handle, &devinfo)))
+ return (AE_OK);
+
+ if ((devinfo->Valid & ACPI_VALID_HID) != 0 &&
+ strcmp(match->hid, devinfo->HardwareId.String) == 0) {
+ present = true;
+ } else if ((devinfo->Valid & ACPI_VALID_CID) != 0) {
+ for (i = 0; i < devinfo->CompatibleIdList.Count; i++) {
+ if (strcmp(match->hid,
+ devinfo->CompatibleIdList.Ids[i].String) == 0) {
+ present = true;
+ break;
+ }
+ }
+ }
+ if (present && match->uid != NULL &&
+ ((devinfo->Valid & ACPI_VALID_UID) == 0 ||
+ strcmp(match->uid, devinfo->UniqueId.String) != 0))
+ present = false;
+
+ AcpiOsFree(devinfo);
+ if (!present)
+ return (AE_OK);
+
+ if (match->hrv != -1) {
+ if (ACPI_FAILURE(acpi_GetInteger(handle, "_HRV", &hrv)))
+ return (AE_OK);
+ if (hrv != match->hrv)
+ return (AE_OK);
+ }
+
+ return (AE_ERROR);
+}
+
+bool
+lkpi_acpi_dev_present(const char *hid, const char *uid, int64_t hrv)
+{
+ struct acpi_dev_present_ctx match;
+ int rv;
+
+ match.hid = hid;
+ match.uid = uid;
+ match.hrv = hrv;
+
+ rv = AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, acpi_dev_present_cb, NULL, &match, NULL);
+
+ return (rv == AE_ERROR);
+}
+
static void
linux_register_acpi_event_handlers(void *arg __unused)
{
@@ -240,4 +316,10 @@ acpi_target_system_state(void)
return (ACPI_STATE_S0);
}
+bool
+lkpi_acpi_dev_present(const char *hid, const char *uid, int64_t hrv)
+{
+ return (false);
+}
+
#endif /* !DEV_ACPI */
diff --git a/sys/compat/linuxkpi/common/src/linux_compat.c b/sys/compat/linuxkpi/common/src/linux_compat.c
index 8644f67762d9..a6eb7bb17e16 100644
--- a/sys/compat/linuxkpi/common/src/linux_compat.c
+++ b/sys/compat/linuxkpi/common/src/linux_compat.c
@@ -28,8 +28,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
+#include "opt_global.h"
#include "opt_stack.h"
#include <sys/param.h>
@@ -64,6 +63,7 @@ __FBSDID("$FreeBSD$");
#include <machine/stdarg.h>
#if defined(__i386__) || defined(__amd64__)
+#include <machine/cputypes.h>
#include <machine/md_var.h>
#endif
@@ -83,6 +83,7 @@ __FBSDID("$FreeBSD$");
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>
+#include <linux/utsname.h>
#include <linux/list.h>
#include <linux/kthread.h>
#include <linux/kernel.h>
@@ -97,6 +98,16 @@ __FBSDID("$FreeBSD$");
#if defined(__i386__) || defined(__amd64__)
#include <asm/smp.h>
+#include <asm/processor.h>
+#endif
+
+#include <xen/xen.h>
+#ifdef XENHVM
+#undef xen_pv_domain
+#undef xen_initial_domain
+/* xen/xen-os.h redefines __must_check */
+#undef __must_check
+#include <xen/xen-os.h>
#endif
SYSCTL_NODE(_compat, OID_AUTO, linuxkpi, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
@@ -131,12 +142,15 @@ static void linux_cdev_deref(struct linux_cdev *ldev);
static struct vm_area_struct *linux_cdev_handle_find(void *handle);
cpumask_t cpu_online_mask;
+static cpumask_t **static_single_cpu_mask;
+static cpumask_t *static_single_cpu_mask_lcs;
struct kobject linux_class_root;
struct device linux_root_device;
struct class linux_class_misc;
struct list_head pci_drivers;
struct list_head pci_devices;
spinlock_t pci_lock;
+struct uts_namespace init_uts_ns;
unsigned long linux_timer_hz_mask;
@@ -157,176 +171,6 @@ RB_GENERATE(linux_root, rb_node, __entry, panic_cmp);
INTERVAL_TREE_DEFINE(struct interval_tree_node, rb, unsigned long,, START,
LAST,, lkpi_interval_tree)
-struct kobject *
-kobject_create(void)
-{
- struct kobject *kobj;
-
- kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
- if (kobj == NULL)
- return (NULL);
- kobject_init(kobj, &linux_kfree_type);
-
- return (kobj);
-}
-
-
-int
-kobject_set_name_vargs(struct kobject *kobj, const char *fmt, va_list args)
-{
- va_list tmp_va;
- int len;
- char *old;
- char *name;
- char dummy;
-
- old = kobj->name;
-
- if (old && fmt == NULL)
- return (0);
-
- /* compute length of string */
- va_copy(tmp_va, args);
- len = vsnprintf(&dummy, 0, fmt, tmp_va);
- va_end(tmp_va);
-
- /* account for zero termination */
- len++;
-
- /* check for error */
- if (len < 1)
- return (-EINVAL);
-
- /* allocate memory for string */
- name = kzalloc(len, GFP_KERNEL);
- if (name == NULL)
- return (-ENOMEM);
- vsnprintf(name, len, fmt, args);
- kobj->name = name;
-
- /* free old string */
- kfree(old);
-
- /* filter new string */
- for (; *name != '\0'; name++)
- if (*name == '/')
- *name = '!';
- return (0);
-}
-
-int
-kobject_set_name(struct kobject *kobj, const char *fmt, ...)
-{
- va_list args;
- int error;
-
- va_start(args, fmt);
- error = kobject_set_name_vargs(kobj, fmt, args);
- va_end(args);
-
- return (error);
-}
-
-static int
-kobject_add_complete(struct kobject *kobj, struct kobject *parent)
-{
- const struct kobj_type *t;
- int error;
-
- kobj->parent = parent;
- error = sysfs_create_dir(kobj);
- if (error == 0 && kobj->ktype && kobj->ktype->default_attrs) {
- struct attribute **attr;
- t = kobj->ktype;
-
- for (attr = t->default_attrs; *attr != NULL; attr++) {
- error = sysfs_create_file(kobj, *attr);
- if (error)
- break;
- }
- if (error)
- sysfs_remove_dir(kobj);
- }
- return (error);
-}
-
-int
-kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...)
-{
- va_list args;
- int error;
-
- va_start(args, fmt);
- error = kobject_set_name_vargs(kobj, fmt, args);
- va_end(args);
- if (error)
- return (error);
-
- return kobject_add_complete(kobj, parent);
-}
-
-void
-linux_kobject_release(struct kref *kref)
-{
- struct kobject *kobj;
- char *name;
-
- kobj = container_of(kref, struct kobject, kref);
- sysfs_remove_dir(kobj);
- name = kobj->name;
- if (kobj->ktype && kobj->ktype->release)
- kobj->ktype->release(kobj);
- kfree(name);
-}
-
-static void
-linux_kobject_kfree(struct kobject *kobj)
-{
- kfree(kobj);
-}
-
-static void
-linux_kobject_kfree_name(struct kobject *kobj)
-{
- if (kobj) {
- kfree(kobj->name);
- }
-}
-
-const struct kobj_type linux_kfree_type = {
- .release = linux_kobject_kfree
-};
-
-static ssize_t
-lkpi_kobj_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
-{
- struct kobj_attribute *ka =
- container_of(attr, struct kobj_attribute, attr);
-
- if (ka->show == NULL)
- return (-EIO);
-
- return (ka->show(kobj, ka, buf));
-}
-
-static ssize_t
-lkpi_kobj_attr_store(struct kobject *kobj, struct attribute *attr,
- const char *buf, size_t count)
-{
- struct kobj_attribute *ka =
- container_of(attr, struct kobj_attribute, attr);
-
- if (ka->store == NULL)
- return (-EIO);
-
- return (ka->store(kobj, ka, buf, count));
-}
-
-const struct sysfs_ops kobj_sysfs_ops = {
- .show = lkpi_kobj_attr_show,
- .store = lkpi_kobj_attr_store,
-};
-
static void
linux_device_release(struct device *dev)
{
@@ -516,26 +360,6 @@ class_create(struct module *owner, const char *name)
return (class);
}
-int
-kobject_init_and_add(struct kobject *kobj, const struct kobj_type *ktype,
- struct kobject *parent, const char *fmt, ...)
-{
- va_list args;
- int error;
-
- kobject_init(kobj, ktype);
- kobj->ktype = ktype;
- kobj->parent = parent;
- kobj->name = NULL;
-
- va_start(args, fmt);
- error = kobject_set_name_vargs(kobj, fmt, args);
- va_end(args);
- if (error)
- return (error);
- return kobject_add_complete(kobj, parent);
-}
-
static void
linux_kq_lock(void *arg)
{
@@ -832,6 +656,18 @@ zap_vma_ptes(struct vm_area_struct *vma, unsigned long address,
return (0);
}
+void
+vma_set_file(struct vm_area_struct *vma, struct linux_file *file)
+{
+ struct linux_file *tmp;
+
+ /* Changing an anonymous vma with this is illegal */
+ get_file(file);
+ tmp = vma->vm_file;
+ vma->vm_file = file;
+ fput(tmp);
+}
+
static struct file_operations dummy_ldev_ops = {
/* XXXKIB */
};
@@ -1885,6 +1721,19 @@ linux_iminor(struct inode *inode)
return (minor(ldev->dev));
}
+static int
+linux_file_kcmp(struct file *fp1, struct file *fp2, struct thread *td)
+{
+ struct linux_file *filp1, *filp2;
+
+ if (fp2->f_type != DTYPE_DEV)
+ return (3);
+
+ filp1 = fp1->f_data;
+ filp2 = fp2->f_data;
+ return (kcmp_cmp((uintptr_t)filp1->f_cdev, (uintptr_t)filp2->f_cdev));
+}
+
struct fileops linuxfileops = {
.fo_read = linux_file_read,
.fo_write = linux_file_write,
@@ -1899,6 +1748,7 @@ struct fileops linuxfileops = {
.fo_chmod = invfo_chmod,
.fo_chown = invfo_chown,
.fo_sendfile = invfo_sendfile,
+ .fo_cmp = linux_file_kcmp,
.fo_flags = DFLAG_PASSABLE,
};
@@ -1975,7 +1825,7 @@ iounmap(void *addr)
if (vmmap == NULL)
return;
#if defined(__i386__) || defined(__amd64__) || defined(__powerpc__) || defined(__aarch64__) || defined(__riscv)
- pmap_unmapdev((vm_offset_t)addr, vmmap->vm_size);
+ pmap_unmapdev(addr, vmmap->vm_size);
#endif
kfree(vmmap);
}
@@ -2070,6 +1920,10 @@ linux_timer_callback_wrapper(void *context)
timer = context;
+ /* the timer is about to be shutdown permanently */
+ if (timer->function == NULL)
+ return;
+
if (linux_set_current_flags(curthread, M_NOWAIT)) {
/* try again later */
callout_reset(&timer->callout, 1,
@@ -2131,6 +1985,21 @@ del_timer_sync(struct timer_list *timer)
return (1);
}
+int
+timer_delete_sync(struct timer_list *timer)
+{
+
+ return (del_timer_sync(timer));
+}
+
+int
+timer_shutdown_sync(struct timer_list *timer)
+{
+
+ timer->function = NULL;
+ return (del_timer_sync(timer));
+}
+
/* greatest common divisor, Euclid equation */
static uint64_t
lkpi_gcd_64(uint64_t a, uint64_t b)
@@ -2561,7 +2430,7 @@ struct list_sort_thunk {
};
static inline int
-linux_le_cmp(void *priv, const void *d1, const void *d2)
+linux_le_cmp(const void *d1, const void *d2, void *priv)
{
struct list_head *le1, *le2;
struct list_sort_thunk *thunk;
@@ -2589,7 +2458,7 @@ list_sort(void *priv, struct list_head *head, int (*cmp)(void *priv,
ar[i++] = le;
thunk.cmp = cmp;
thunk.priv = priv;
- qsort_r(ar, count, sizeof(struct list_head *), &thunk, linux_le_cmp);
+ qsort_r(ar, count, sizeof(struct list_head *), linux_le_cmp, &thunk);
INIT_LIST_HEAD(head);
for (i = 0; i < count; i++)
list_add_tail(ar[i], head);
@@ -2730,7 +2599,41 @@ io_mapping_create_wc(resource_size_t base, unsigned long size)
#if defined(__i386__) || defined(__amd64__)
bool linux_cpu_has_clflush;
+struct cpuinfo_x86 boot_cpu_data;
+struct cpuinfo_x86 *__cpu_data;
+#endif
+
+cpumask_t *
+lkpi_get_static_single_cpu_mask(int cpuid)
+{
+
+ KASSERT((cpuid >= 0 && cpuid <= mp_maxid), ("%s: invalid cpuid %d\n",
+ __func__, cpuid));
+ KASSERT(!CPU_ABSENT(cpuid), ("%s: cpu with cpuid %d is absent\n",
+ __func__, cpuid));
+
+ return (static_single_cpu_mask[cpuid]);
+}
+
+bool
+lkpi_xen_initial_domain(void)
+{
+#ifdef XENHVM
+ return (xen_initial_domain());
+#else
+ return (false);
#endif
+}
+
+bool
+lkpi_xen_pv_domain(void)
+{
+#ifdef XENHVM
+ return (xen_pv_domain());
+#else
+ return (false);
+#endif
+}
static void
linux_compat_init(void *arg)
@@ -2739,7 +2642,40 @@ linux_compat_init(void *arg)
int i;
#if defined(__i386__) || defined(__amd64__)
+ static const uint32_t x86_vendors[X86_VENDOR_NUM] = {
+ [X86_VENDOR_INTEL] = CPU_VENDOR_INTEL,
+ [X86_VENDOR_CYRIX] = CPU_VENDOR_CYRIX,
+ [X86_VENDOR_AMD] = CPU_VENDOR_AMD,
+ [X86_VENDOR_UMC] = CPU_VENDOR_UMC,
+ [X86_VENDOR_CENTAUR] = CPU_VENDOR_CENTAUR,
+ [X86_VENDOR_TRANSMETA] = CPU_VENDOR_TRANSMETA,
+ [X86_VENDOR_NSC] = CPU_VENDOR_NSC,
+ [X86_VENDOR_HYGON] = CPU_VENDOR_HYGON,
+ };
+ uint8_t x86_vendor = X86_VENDOR_UNKNOWN;
+
+ for (i = 0; i < X86_VENDOR_NUM; i++) {
+ if (cpu_vendor_id != 0 && cpu_vendor_id == x86_vendors[i]) {
+ x86_vendor = i;
+ break;
+ }
+ }
linux_cpu_has_clflush = (cpu_feature & CPUID_CLFSH);
+ boot_cpu_data.x86_clflush_size = cpu_clflush_line_size;
+ boot_cpu_data.x86_max_cores = mp_ncpus;
+ boot_cpu_data.x86 = CPUID_TO_FAMILY(cpu_id);
+ boot_cpu_data.x86_model = CPUID_TO_MODEL(cpu_id);
+ boot_cpu_data.x86_vendor = x86_vendor;
+
+ __cpu_data = mallocarray(mp_maxid + 1,
+ sizeof(*__cpu_data), M_KMALLOC, M_WAITOK | M_ZERO);
+ CPU_FOREACH(i) {
+ __cpu_data[i].x86_clflush_size = cpu_clflush_line_size;
+ __cpu_data[i].x86_max_cores = mp_ncpus;
+ __cpu_data[i].x86 = CPUID_TO_FAMILY(cpu_id);
+ __cpu_data[i].x86_model = CPUID_TO_MODEL(cpu_id);
+ __cpu_data[i].x86_vendor = x86_vendor;
+ }
#endif
rw_init(&linux_vma_lock, "lkpi-vma-lock");
@@ -2767,6 +2703,96 @@ linux_compat_init(void *arg)
init_waitqueue_head(&linux_var_waitq);
CPU_COPY(&all_cpus, &cpu_online_mask);
+ /*
+ * Generate a single-CPU cpumask_t for each CPU (possibly) in the system.
+ * CPUs are indexed from 0..(mp_maxid). The entry for cpuid 0 will only
+ * have itself in the cpumask, cupid 1 only itself on entry 1, and so on.
+ * This is used by cpumask_of() (and possibly others in the future) for,
+ * e.g., drivers to pass hints to irq_set_affinity_hint().
+ */
+ static_single_cpu_mask = mallocarray(mp_maxid + 1,
+ sizeof(static_single_cpu_mask), M_KMALLOC, M_WAITOK | M_ZERO);
+
+ /*
+ * When the number of CPUs reach a threshold, we start to save memory
+ * given the sets are static by overlapping those having their single
+ * bit set at same position in a bitset word. Asymptotically, this
+ * regular scheme is in O(n²) whereas the overlapping one is in O(n)
+ * only with n being the maximum number of CPUs, so the gain will become
+ * huge quite quickly. The threshold for 64-bit architectures is 128
+ * CPUs.
+ */
+ if (mp_ncpus < (2 * _BITSET_BITS)) {
+ cpumask_t *sscm_ptr;
+
+ /*
+ * This represents 'mp_ncpus * __bitset_words(CPU_SETSIZE) *
+ * (_BITSET_BITS / 8)' bytes (for comparison with the
+ * overlapping scheme).
+ */
+ static_single_cpu_mask_lcs = mallocarray(mp_ncpus,
+ sizeof(*static_single_cpu_mask_lcs),
+ M_KMALLOC, M_WAITOK | M_ZERO);
+
+ sscm_ptr = static_single_cpu_mask_lcs;
+ CPU_FOREACH(i) {
+ static_single_cpu_mask[i] = sscm_ptr++;
+ CPU_SET(i, static_single_cpu_mask[i]);
+ }
+ } else {
+ /* Pointer to a bitset word. */
+ __typeof(((cpuset_t *)NULL)->__bits[0]) *bwp;
+
+ /*
+ * Allocate memory for (static) spans of 'cpumask_t' ('cpuset_t'
+ * really) with a single bit set that can be reused for all
+ * single CPU masks by making them start at different offsets.
+ * We need '__bitset_words(CPU_SETSIZE) - 1' bitset words before
+ * the word having its single bit set, and the same amount
+ * after.
+ */
+ static_single_cpu_mask_lcs = mallocarray(_BITSET_BITS,
+ (2 * __bitset_words(CPU_SETSIZE) - 1) * (_BITSET_BITS / 8),
+ M_KMALLOC, M_WAITOK | M_ZERO);
+
+ /*
+ * We rely below on cpuset_t and the bitset generic
+ * implementation assigning words in the '__bits' array in the
+ * same order of bits (i.e., little-endian ordering, not to be
+ * confused with machine endianness, which concerns bits in
+ * words and other integers). This is an imperfect test, but it
+ * will detect a change to big-endian ordering.
+ */
+ _Static_assert(
+ __bitset_word(_BITSET_BITS + 1, _BITSET_BITS) == 1,
+ "Assumes a bitset implementation that is little-endian "
+ "on its words");
+
+ /* Initialize the single bit of each static span. */
+ bwp = (__typeof(bwp))static_single_cpu_mask_lcs +
+ (__bitset_words(CPU_SETSIZE) - 1);
+ for (i = 0; i < _BITSET_BITS; i++) {
+ CPU_SET(i, (cpuset_t *)bwp);
+ bwp += (2 * __bitset_words(CPU_SETSIZE) - 1);
+ }
+
+ /*
+ * Finally set all CPU masks to the proper word in their
+ * relevant span.
+ */
+ CPU_FOREACH(i) {
+ bwp = (__typeof(bwp))static_single_cpu_mask_lcs;
+ /* Find the non-zero word of the relevant span. */
+ bwp += (2 * __bitset_words(CPU_SETSIZE) - 1) *
+ (i % _BITSET_BITS) +
+ __bitset_words(CPU_SETSIZE) - 1;
+ /* Shift to find the CPU mask start. */
+ bwp -= (i / _BITSET_BITS);
+ static_single_cpu_mask[i] = (cpuset_t *)bwp;
+ }
+ }
+
+ strlcpy(init_uts_ns.name.release, osrelease, sizeof(init_uts_ns.name.release));
}
SYSINIT(linux_compat, SI_SUB_DRIVERS, SI_ORDER_SECOND, linux_compat_init, NULL);
@@ -2777,6 +2803,12 @@ linux_compat_uninit(void *arg)
linux_kobject_kfree_name(&linux_root_device.kobj);
linux_kobject_kfree_name(&linux_class_misc.kobj);
+ free(static_single_cpu_mask_lcs, M_KMALLOC);
+ free(static_single_cpu_mask, M_KMALLOC);
+#if defined(__i386__) || defined(__amd64__)
+ free(__cpu_data, M_KMALLOC);
+#endif
+
mtx_destroy(&vmmaplock);
spin_lock_destroy(&pci_lock);
rw_destroy(&linux_vma_lock);
diff --git a/sys/compat/linuxkpi/common/src/linux_current.c b/sys/compat/linuxkpi/common/src/linux_current.c
index 925d96770cc2..c342eb279caa 100644
--- a/sys/compat/linuxkpi/common/src/linux_current.c
+++ b/sys/compat/linuxkpi/common/src/linux_current.c
@@ -25,7 +25,11 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+#ifdef __amd64__
+#define DEV_APIC
+#elif defined(__i386__)
+#include "opt_apic.h"
+#endif
#include <linux/compat.h>
#include <linux/completion.h>
@@ -39,7 +43,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <vm/uma.h>
-#if defined(__i386__) || defined(__amd64__)
+#ifdef DEV_APIC
extern u_int first_msi_irq, num_msi_irqs;
#endif
@@ -274,7 +278,7 @@ linux_current_init(void *arg __unused)
TUNABLE_INT_FETCH("compat.linuxkpi.task_struct_reserve",
&lkpi_task_resrv);
if (lkpi_task_resrv == 0) {
-#if defined(__i386__) || defined(__amd64__)
+#ifdef DEV_APIC
/*
* Number of interrupt threads plus per-cpu callout
* SWI threads.
@@ -290,7 +294,7 @@ linux_current_init(void *arg __unused)
uma_zone_reserve(linux_current_zone, lkpi_task_resrv);
uma_prealloc(linux_current_zone, lkpi_task_resrv);
linux_mm_zone = uma_zcreate("lkpimm",
- sizeof(struct task_struct), NULL, NULL, NULL, NULL,
+ sizeof(struct mm_struct), NULL, NULL, NULL, NULL,
UMA_ALIGN_PTR, 0);
uma_zone_reserve(linux_mm_zone, lkpi_task_resrv);
uma_prealloc(linux_mm_zone, lkpi_task_resrv);
@@ -301,7 +305,7 @@ linux_current_init(void *arg __unused)
linuxkpi_thread_dtor, NULL, EVENTHANDLER_PRI_ANY);
lkpi_alloc_current = linux_alloc_current;
}
-SYSINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND,
+SYSINIT(linux_current, SI_SUB_EVENTHANDLER + 1, SI_ORDER_SECOND,
linux_current_init, NULL);
static void
@@ -335,5 +339,5 @@ linux_current_uninit(void *arg __unused)
uma_zdestroy(linux_current_zone);
uma_zdestroy(linux_mm_zone);
}
-SYSUNINIT(linux_current, SI_SUB_EVENTHANDLER, SI_ORDER_SECOND,
+SYSUNINIT(linux_current, SI_SUB_EVENTHANDLER + 1, SI_ORDER_SECOND,
linux_current_uninit, NULL);
diff --git a/sys/compat/linuxkpi/common/src/linux_devres.c b/sys/compat/linuxkpi/common/src/linux_devres.c
index 96ff3e486d1d..84f03ba0dd7d 100644
--- a/sys/compat/linuxkpi/common/src/linux_devres.c
+++ b/sys/compat/linuxkpi/common/src/linux_devres.c
@@ -29,8 +29,6 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/slab.h>
@@ -224,3 +222,46 @@ lkpi_devm_kmalloc_release(struct device *dev __unused, void *p __unused)
/* Nothing to do. Freed with the devres. */
}
+
+struct devres_action {
+ void *data;
+ void (*action)(void *);
+};
+
+static void
+lkpi_devm_action_release(struct device *dev, void *res)
+{
+ struct devres_action *devres;
+
+ devres = (struct devres_action *)res;
+ devres->action(devres->data);
+}
+
+int
+lkpi_devm_add_action(struct device *dev, void (*action)(void *), void *data)
+{
+ struct devres_action *devres;
+
+ KASSERT(action != NULL, ("%s: action is NULL\n", __func__));
+ devres = lkpi_devres_alloc(lkpi_devm_action_release,
+ sizeof(struct devres_action), GFP_KERNEL);
+ if (devres == NULL)
+ return (-ENOMEM);
+ devres->data = data;
+ devres->action = action;
+ devres_add(dev, devres);
+
+ return (0);
+}
+
+int
+lkpi_devm_add_action_or_reset(struct device *dev, void (*action)(void *), void *data)
+{
+ int rv;
+
+ rv = lkpi_devm_add_action(dev, action, data);
+ if (rv != 0)
+ action(data);
+
+ return (rv);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_dmi.c b/sys/compat/linuxkpi/common/src/linux_dmi.c
index 70d56c246c10..9e3faaeddeb9 100644
--- a/sys/compat/linuxkpi/common/src/linux_dmi.c
+++ b/sys/compat/linuxkpi/common/src/linux_dmi.c
@@ -24,8 +24,6 @@
* 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.
- *
- * $FreeBSD$
*/
#include <sys/param.h>
diff --git a/sys/compat/linuxkpi/common/src/linux_domain.c b/sys/compat/linuxkpi/common/src/linux_domain.c
index acbf8821d42b..8e936aac4719 100644
--- a/sys/compat/linuxkpi/common/src/linux_domain.c
+++ b/sys/compat/linuxkpi/common/src/linux_domain.c
@@ -24,9 +24,6 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/domainset.h>
diff --git a/sys/compat/linuxkpi/common/src/linux_firmware.c b/sys/compat/linuxkpi/common/src/linux_firmware.c
index 47cccd42da20..17da91381280 100644
--- a/sys/compat/linuxkpi/common/src/linux_firmware.c
+++ b/sys/compat/linuxkpi/common/src/linux_firmware.c
@@ -2,6 +2,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020-2021 The FreeBSD Foundation
+ * Copyright (c) 2022 Bjoern A. Zeeb
*
* This software was developed by Björn Zeeb under sponsorship from
* the FreeBSD Foundation.
@@ -26,8 +27,6 @@
* 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.
- *
- * $FreeBSD$
*/
#include <sys/param.h>
@@ -223,3 +222,26 @@ linuxkpi_release_firmware(const struct linuxkpi_firmware *fw)
firmware_put(fw->fbdfw, FIRMWARE_UNLOAD);
free(__DECONST(void *, fw), M_LKPI_FW);
}
+
+int
+linuxkpi_request_partial_firmware_into_buf(const struct linuxkpi_firmware **fw,
+ const char *fw_name, struct device *dev, uint8_t *buf, size_t buflen,
+ size_t offset)
+{
+ const struct linuxkpi_firmware *lfw;
+ int error;
+
+ error = linuxkpi_request_firmware(fw, fw_name, dev);
+ if (error != 0)
+ return (error);
+
+ lfw = *fw;
+ if ((offset + buflen) >= lfw->size) {
+ linuxkpi_release_firmware(lfw);
+ return (-ERANGE);
+ }
+
+ memcpy(buf, lfw->data + offset, buflen);
+
+ return (0);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_fpu.c b/sys/compat/linuxkpi/common/src/linux_fpu.c
index 08f7e075d827..4e40a2b004bb 100644
--- a/sys/compat/linuxkpi/common/src/linux_fpu.c
+++ b/sys/compat/linuxkpi/common/src/linux_fpu.c
@@ -1,7 +1,7 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2020 Greg V <greg@unrelenting.technology>
+ * Copyright (c) 2020 Val Packett <val@packett.cool>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,11 +30,13 @@
#include <sys/proc.h>
#include <sys/kernel.h>
+#include <linux/compat.h>
#include <linux/sched.h>
#include <asm/fpu/api.h>
-#if defined(__aarch64__) || defined(__amd64__) || defined(__i386__)
+#if defined(__aarch64__) || defined(__arm__) || defined(__amd64__) || \
+ defined(__i386__) || defined(__powerpc64__)
#include <machine/fpu.h>
@@ -58,6 +60,24 @@ lkpi_kernel_fpu_end(void)
fpu_kern_leave(curthread, NULL);
}
+void
+lkpi_fpu_safe_exec(fpu_safe_exec_cb_t func, void *ctx)
+{
+ unsigned int save_fpu_level;
+
+ save_fpu_level =
+ __current_unallocated(curthread) ? 0 : current->fpu_ctx_level;
+ if (__predict_false(save_fpu_level != 0)) {
+ current->fpu_ctx_level = 1;
+ kernel_fpu_end();
+ }
+ func(ctx);
+ if (__predict_false(save_fpu_level != 0)) {
+ kernel_fpu_begin();
+ current->fpu_ctx_level = save_fpu_level;
+ }
+}
+
#else
void
@@ -70,4 +90,10 @@ lkpi_kernel_fpu_end(void)
{
}
+void
+lkpi_fpu_safe_exec(fpu_safe_exec_cb_t func, void *ctx)
+{
+ func(ctx);
+}
+
#endif
diff --git a/sys/compat/linuxkpi/common/src/linux_hdmi.c b/sys/compat/linuxkpi/common/src/linux_hdmi.c
new file mode 100644
index 000000000000..ec4ac7568c7c
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_hdmi.c
@@ -0,0 +1,1921 @@
+/*
+ * Copyright (C) 2012 Avionic Design GmbH
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef __FreeBSD__
+
+#include <sys/param.h>
+#include <sys/module.h>
+#endif
+
+#include <linux/bitops.h>
+#include <linux/bug.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/hdmi.h>
+#include <linux/string.h>
+#include <linux/device.h>
+
+#define hdmi_log(fmt, ...) dev_printk(level, dev, fmt, ##__VA_ARGS__)
+
+static u8 hdmi_infoframe_checksum(const u8 *ptr, size_t size)
+{
+ u8 csum = 0;
+ size_t i;
+
+ /* compute checksum */
+ for (i = 0; i < size; i++)
+ csum += ptr[i];
+
+ return 256 - csum;
+}
+
+static void hdmi_infoframe_set_checksum(void *buffer, size_t size)
+{
+ u8 *ptr = buffer;
+
+ ptr[3] = hdmi_infoframe_checksum(buffer, size);
+}
+
+/**
+ * hdmi_avi_infoframe_init() - initialize an HDMI AVI infoframe
+ * @frame: HDMI AVI infoframe
+ */
+void hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame)
+{
+ memset(frame, 0, sizeof(*frame));
+
+ frame->type = HDMI_INFOFRAME_TYPE_AVI;
+ frame->version = 2;
+ frame->length = HDMI_AVI_INFOFRAME_SIZE;
+}
+EXPORT_SYMBOL(hdmi_avi_infoframe_init);
+
+static int hdmi_avi_infoframe_check_only(const struct hdmi_avi_infoframe *frame)
+{
+ if (frame->type != HDMI_INFOFRAME_TYPE_AVI ||
+ frame->version != 2 ||
+ frame->length != HDMI_AVI_INFOFRAME_SIZE)
+ return -EINVAL;
+
+ if (frame->picture_aspect > HDMI_PICTURE_ASPECT_16_9)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * hdmi_avi_infoframe_check() - check a HDMI AVI infoframe
+ * @frame: HDMI AVI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_avi_infoframe_check(struct hdmi_avi_infoframe *frame)
+{
+ return hdmi_avi_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_avi_infoframe_check);
+
+/**
+ * hdmi_avi_infoframe_pack_only() - write HDMI AVI infoframe to binary buffer
+ * @frame: HDMI AVI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Packs the information contained in the @frame structure into a binary
+ * representation that can be written into the corresponding controller
+ * registers. Also computes the checksum as required by section 5.3.5 of
+ * the HDMI 1.4 specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_avi_infoframe_pack_only(const struct hdmi_avi_infoframe *frame,
+ void *buffer, size_t size)
+{
+ u8 *ptr = buffer;
+ size_t length;
+ int ret;
+
+ ret = hdmi_avi_infoframe_check_only(frame);
+ if (ret)
+ return ret;
+
+ length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
+
+ if (size < length)
+ return -ENOSPC;
+
+ memset(buffer, 0, size);
+
+ ptr[0] = frame->type;
+ ptr[1] = frame->version;
+ ptr[2] = frame->length;
+ ptr[3] = 0; /* checksum */
+
+ /* start infoframe payload */
+ ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+ ptr[0] = ((frame->colorspace & 0x3) << 5) | (frame->scan_mode & 0x3);
+
+ /*
+ * Data byte 1, bit 4 has to be set if we provide the active format
+ * aspect ratio
+ */
+ if (frame->active_aspect & 0xf)
+ ptr[0] |= BIT(4);
+
+ /* Bit 3 and 2 indicate if we transmit horizontal/vertical bar data */
+ if (frame->top_bar || frame->bottom_bar)
+ ptr[0] |= BIT(3);
+
+ if (frame->left_bar || frame->right_bar)
+ ptr[0] |= BIT(2);
+
+ ptr[1] = ((frame->colorimetry & 0x3) << 6) |
+ ((frame->picture_aspect & 0x3) << 4) |
+ (frame->active_aspect & 0xf);
+
+ ptr[2] = ((frame->extended_colorimetry & 0x7) << 4) |
+ ((frame->quantization_range & 0x3) << 2) |
+ (frame->nups & 0x3);
+
+ if (frame->itc)
+ ptr[2] |= BIT(7);
+
+ ptr[3] = frame->video_code & 0x7f;
+
+ ptr[4] = ((frame->ycc_quantization_range & 0x3) << 6) |
+ ((frame->content_type & 0x3) << 4) |
+ (frame->pixel_repeat & 0xf);
+
+ ptr[5] = frame->top_bar & 0xff;
+ ptr[6] = (frame->top_bar >> 8) & 0xff;
+ ptr[7] = frame->bottom_bar & 0xff;
+ ptr[8] = (frame->bottom_bar >> 8) & 0xff;
+ ptr[9] = frame->left_bar & 0xff;
+ ptr[10] = (frame->left_bar >> 8) & 0xff;
+ ptr[11] = frame->right_bar & 0xff;
+ ptr[12] = (frame->right_bar >> 8) & 0xff;
+
+ hdmi_infoframe_set_checksum(buffer, length);
+
+ return length;
+}
+EXPORT_SYMBOL(hdmi_avi_infoframe_pack_only);
+
+/**
+ * hdmi_avi_infoframe_pack() - check a HDMI AVI infoframe,
+ * and write it to binary buffer
+ * @frame: HDMI AVI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame,
+ void *buffer, size_t size)
+{
+ int ret;
+
+ ret = hdmi_avi_infoframe_check(frame);
+ if (ret)
+ return ret;
+
+ return hdmi_avi_infoframe_pack_only(frame, buffer, size);
+}
+EXPORT_SYMBOL(hdmi_avi_infoframe_pack);
+
+/**
+ * hdmi_spd_infoframe_init() - initialize an HDMI SPD infoframe
+ * @frame: HDMI SPD infoframe
+ * @vendor: vendor string
+ * @product: product string
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
+ const char *vendor, const char *product)
+{
+ size_t len;
+
+ memset(frame, 0, sizeof(*frame));
+
+ frame->type = HDMI_INFOFRAME_TYPE_SPD;
+ frame->version = 1;
+ frame->length = HDMI_SPD_INFOFRAME_SIZE;
+
+ len = strlen(vendor);
+ memcpy(frame->vendor, vendor, min(len, sizeof(frame->vendor)));
+ len = strlen(product);
+ memcpy(frame->product, product, min(len, sizeof(frame->product)));
+
+ return 0;
+}
+EXPORT_SYMBOL(hdmi_spd_infoframe_init);
+
+static int hdmi_spd_infoframe_check_only(const struct hdmi_spd_infoframe *frame)
+{
+ if (frame->type != HDMI_INFOFRAME_TYPE_SPD ||
+ frame->version != 1 ||
+ frame->length != HDMI_SPD_INFOFRAME_SIZE)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * hdmi_spd_infoframe_check() - check a HDMI SPD infoframe
+ * @frame: HDMI SPD infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_spd_infoframe_check(struct hdmi_spd_infoframe *frame)
+{
+ return hdmi_spd_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_spd_infoframe_check);
+
+/**
+ * hdmi_spd_infoframe_pack_only() - write HDMI SPD infoframe to binary buffer
+ * @frame: HDMI SPD infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Packs the information contained in the @frame structure into a binary
+ * representation that can be written into the corresponding controller
+ * registers. Also computes the checksum as required by section 5.3.5 of
+ * the HDMI 1.4 specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_spd_infoframe_pack_only(const struct hdmi_spd_infoframe *frame,
+ void *buffer, size_t size)
+{
+ u8 *ptr = buffer;
+ size_t length;
+ int ret;
+
+ ret = hdmi_spd_infoframe_check_only(frame);
+ if (ret)
+ return ret;
+
+ length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
+
+ if (size < length)
+ return -ENOSPC;
+
+ memset(buffer, 0, size);
+
+ ptr[0] = frame->type;
+ ptr[1] = frame->version;
+ ptr[2] = frame->length;
+ ptr[3] = 0; /* checksum */
+
+ /* start infoframe payload */
+ ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+ memcpy(ptr, frame->vendor, sizeof(frame->vendor));
+ memcpy(ptr + 8, frame->product, sizeof(frame->product));
+
+ ptr[24] = frame->sdi;
+
+ hdmi_infoframe_set_checksum(buffer, length);
+
+ return length;
+}
+EXPORT_SYMBOL(hdmi_spd_infoframe_pack_only);
+
+/**
+ * hdmi_spd_infoframe_pack() - check a HDMI SPD infoframe,
+ * and write it to binary buffer
+ * @frame: HDMI SPD infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame,
+ void *buffer, size_t size)
+{
+ int ret;
+
+ ret = hdmi_spd_infoframe_check(frame);
+ if (ret)
+ return ret;
+
+ return hdmi_spd_infoframe_pack_only(frame, buffer, size);
+}
+EXPORT_SYMBOL(hdmi_spd_infoframe_pack);
+
+/**
+ * hdmi_audio_infoframe_init() - initialize an HDMI audio infoframe
+ * @frame: HDMI audio infoframe
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame)
+{
+ memset(frame, 0, sizeof(*frame));
+
+ frame->type = HDMI_INFOFRAME_TYPE_AUDIO;
+ frame->version = 1;
+ frame->length = HDMI_AUDIO_INFOFRAME_SIZE;
+
+ return 0;
+}
+EXPORT_SYMBOL(hdmi_audio_infoframe_init);
+
+static int hdmi_audio_infoframe_check_only(const struct hdmi_audio_infoframe *frame)
+{
+ if (frame->type != HDMI_INFOFRAME_TYPE_AUDIO ||
+ frame->version != 1 ||
+ frame->length != HDMI_AUDIO_INFOFRAME_SIZE)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * hdmi_audio_infoframe_check() - check a HDMI audio infoframe
+ * @frame: HDMI audio infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_audio_infoframe_check(struct hdmi_audio_infoframe *frame)
+{
+ return hdmi_audio_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_audio_infoframe_check);
+
+/**
+ * hdmi_audio_infoframe_pack_only() - write HDMI audio infoframe to binary buffer
+ * @frame: HDMI audio infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Packs the information contained in the @frame structure into a binary
+ * representation that can be written into the corresponding controller
+ * registers. Also computes the checksum as required by section 5.3.5 of
+ * the HDMI 1.4 specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_audio_infoframe_pack_only(const struct hdmi_audio_infoframe *frame,
+ void *buffer, size_t size)
+{
+ unsigned char channels;
+ u8 *ptr = buffer;
+ size_t length;
+ int ret;
+
+ ret = hdmi_audio_infoframe_check_only(frame);
+ if (ret)
+ return ret;
+
+ length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
+
+ if (size < length)
+ return -ENOSPC;
+
+ memset(buffer, 0, size);
+
+ if (frame->channels >= 2)
+ channels = frame->channels - 1;
+ else
+ channels = 0;
+
+ ptr[0] = frame->type;
+ ptr[1] = frame->version;
+ ptr[2] = frame->length;
+ ptr[3] = 0; /* checksum */
+
+ /* start infoframe payload */
+ ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+ ptr[0] = ((frame->coding_type & 0xf) << 4) | (channels & 0x7);
+ ptr[1] = ((frame->sample_frequency & 0x7) << 2) |
+ (frame->sample_size & 0x3);
+ ptr[2] = frame->coding_type_ext & 0x1f;
+ ptr[3] = frame->channel_allocation;
+ ptr[4] = (frame->level_shift_value & 0xf) << 3;
+
+ if (frame->downmix_inhibit)
+ ptr[4] |= BIT(7);
+
+ hdmi_infoframe_set_checksum(buffer, length);
+
+ return length;
+}
+EXPORT_SYMBOL(hdmi_audio_infoframe_pack_only);
+
+/**
+ * hdmi_audio_infoframe_pack() - check a HDMI Audio infoframe,
+ * and write it to binary buffer
+ * @frame: HDMI Audio infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
+ void *buffer, size_t size)
+{
+ int ret;
+
+ ret = hdmi_audio_infoframe_check(frame);
+ if (ret)
+ return ret;
+
+ return hdmi_audio_infoframe_pack_only(frame, buffer, size);
+}
+EXPORT_SYMBOL(hdmi_audio_infoframe_pack);
+
+/**
+ * hdmi_vendor_infoframe_init() - initialize an HDMI vendor infoframe
+ * @frame: HDMI vendor infoframe
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
+{
+ memset(frame, 0, sizeof(*frame));
+
+ frame->type = HDMI_INFOFRAME_TYPE_VENDOR;
+ frame->version = 1;
+
+ frame->oui = HDMI_IEEE_OUI;
+
+ /*
+ * 0 is a valid value for s3d_struct, so we use a special "not set"
+ * value
+ */
+ frame->s3d_struct = HDMI_3D_STRUCTURE_INVALID;
+ frame->length = HDMI_VENDOR_INFOFRAME_SIZE;
+
+ return 0;
+}
+EXPORT_SYMBOL(hdmi_vendor_infoframe_init);
+
+static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *frame)
+{
+ /* for side by side (half) we also need to provide 3D_Ext_Data */
+ if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
+ return 6;
+ else if (frame->vic != 0 || frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
+ return 5;
+ else
+ return 4;
+}
+
+static int hdmi_vendor_infoframe_check_only(const struct hdmi_vendor_infoframe *frame)
+{
+ if (frame->type != HDMI_INFOFRAME_TYPE_VENDOR ||
+ frame->version != 1 ||
+ frame->oui != HDMI_IEEE_OUI)
+ return -EINVAL;
+
+ /* only one of those can be supplied */
+ if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID)
+ return -EINVAL;
+
+ if (frame->length != hdmi_vendor_infoframe_length(frame))
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * hdmi_vendor_infoframe_check() - check a HDMI vendor infoframe
+ * @frame: HDMI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_vendor_infoframe_check(struct hdmi_vendor_infoframe *frame)
+{
+ frame->length = hdmi_vendor_infoframe_length(frame);
+
+ return hdmi_vendor_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_vendor_infoframe_check);
+
+/**
+ * hdmi_vendor_infoframe_pack_only() - write a HDMI vendor infoframe to binary buffer
+ * @frame: HDMI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Packs the information contained in the @frame structure into a binary
+ * representation that can be written into the corresponding controller
+ * registers. Also computes the checksum as required by section 5.3.5 of
+ * the HDMI 1.4 specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_vendor_infoframe_pack_only(const struct hdmi_vendor_infoframe *frame,
+ void *buffer, size_t size)
+{
+ u8 *ptr = buffer;
+ size_t length;
+ int ret;
+
+ ret = hdmi_vendor_infoframe_check_only(frame);
+ if (ret)
+ return ret;
+
+ length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
+
+ if (size < length)
+ return -ENOSPC;
+
+ memset(buffer, 0, size);
+
+ ptr[0] = frame->type;
+ ptr[1] = frame->version;
+ ptr[2] = frame->length;
+ ptr[3] = 0; /* checksum */
+
+ /* HDMI OUI */
+ ptr[4] = 0x03;
+ ptr[5] = 0x0c;
+ ptr[6] = 0x00;
+
+ if (frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
+ ptr[7] = 0x2 << 5; /* video format */
+ ptr[8] = (frame->s3d_struct & 0xf) << 4;
+ if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
+ ptr[9] = (frame->s3d_ext_data & 0xf) << 4;
+ } else if (frame->vic) {
+ ptr[7] = 0x1 << 5; /* video format */
+ ptr[8] = frame->vic;
+ } else {
+ ptr[7] = 0x0 << 5; /* video format */
+ }
+
+ hdmi_infoframe_set_checksum(buffer, length);
+
+ return length;
+}
+EXPORT_SYMBOL(hdmi_vendor_infoframe_pack_only);
+
+/**
+ * hdmi_vendor_infoframe_pack() - check a HDMI Vendor infoframe,
+ * and write it to binary buffer
+ * @frame: HDMI Vendor infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
+ void *buffer, size_t size)
+{
+ int ret;
+
+ ret = hdmi_vendor_infoframe_check(frame);
+ if (ret)
+ return ret;
+
+ return hdmi_vendor_infoframe_pack_only(frame, buffer, size);
+}
+EXPORT_SYMBOL(hdmi_vendor_infoframe_pack);
+
+static int
+hdmi_vendor_any_infoframe_check_only(const union hdmi_vendor_any_infoframe *frame)
+{
+ if (frame->any.type != HDMI_INFOFRAME_TYPE_VENDOR ||
+ frame->any.version != 1)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * hdmi_drm_infoframe_init() - initialize an HDMI Dynaminc Range and
+ * mastering infoframe
+ * @frame: HDMI DRM infoframe
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_drm_infoframe_init(struct hdmi_drm_infoframe *frame)
+{
+ memset(frame, 0, sizeof(*frame));
+
+ frame->type = HDMI_INFOFRAME_TYPE_DRM;
+ frame->version = 1;
+ frame->length = HDMI_DRM_INFOFRAME_SIZE;
+
+ return 0;
+}
+EXPORT_SYMBOL(hdmi_drm_infoframe_init);
+
+static int hdmi_drm_infoframe_check_only(const struct hdmi_drm_infoframe *frame)
+{
+ if (frame->type != HDMI_INFOFRAME_TYPE_DRM ||
+ frame->version != 1)
+ return -EINVAL;
+
+ if (frame->length != HDMI_DRM_INFOFRAME_SIZE)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * hdmi_drm_infoframe_check() - check a HDMI DRM infoframe
+ * @frame: HDMI DRM infoframe
+ *
+ * Validates that the infoframe is consistent.
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_drm_infoframe_check(struct hdmi_drm_infoframe *frame)
+{
+ return hdmi_drm_infoframe_check_only(frame);
+}
+EXPORT_SYMBOL(hdmi_drm_infoframe_check);
+
+/**
+ * hdmi_drm_infoframe_pack_only() - write HDMI DRM infoframe to binary buffer
+ * @frame: HDMI DRM infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Packs the information contained in the @frame structure into a binary
+ * representation that can be written into the corresponding controller
+ * registers. Also computes the checksum as required by section 5.3.5 of
+ * the HDMI 1.4 specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_drm_infoframe_pack_only(const struct hdmi_drm_infoframe *frame,
+ void *buffer, size_t size)
+{
+ u8 *ptr = buffer;
+ size_t length;
+ int i;
+
+ length = HDMI_INFOFRAME_HEADER_SIZE + frame->length;
+
+ if (size < length)
+ return -ENOSPC;
+
+ memset(buffer, 0, size);
+
+ ptr[0] = frame->type;
+ ptr[1] = frame->version;
+ ptr[2] = frame->length;
+ ptr[3] = 0; /* checksum */
+
+ /* start infoframe payload */
+ ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+ *ptr++ = frame->eotf;
+ *ptr++ = frame->metadata_type;
+
+ for (i = 0; i < 3; i++) {
+ *ptr++ = frame->display_primaries[i].x;
+ *ptr++ = frame->display_primaries[i].x >> 8;
+ *ptr++ = frame->display_primaries[i].y;
+ *ptr++ = frame->display_primaries[i].y >> 8;
+ }
+
+ *ptr++ = frame->white_point.x;
+ *ptr++ = frame->white_point.x >> 8;
+
+ *ptr++ = frame->white_point.y;
+ *ptr++ = frame->white_point.y >> 8;
+
+ *ptr++ = frame->max_display_mastering_luminance;
+ *ptr++ = frame->max_display_mastering_luminance >> 8;
+
+ *ptr++ = frame->min_display_mastering_luminance;
+ *ptr++ = frame->min_display_mastering_luminance >> 8;
+
+ *ptr++ = frame->max_cll;
+ *ptr++ = frame->max_cll >> 8;
+
+ *ptr++ = frame->max_fall;
+ *ptr++ = frame->max_fall >> 8;
+
+ hdmi_infoframe_set_checksum(buffer, length);
+
+ return length;
+}
+EXPORT_SYMBOL(hdmi_drm_infoframe_pack_only);
+
+/**
+ * hdmi_drm_infoframe_pack() - check a HDMI DRM infoframe,
+ * and write it to binary buffer
+ * @frame: HDMI DRM infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t hdmi_drm_infoframe_pack(struct hdmi_drm_infoframe *frame,
+ void *buffer, size_t size)
+{
+ int ret;
+
+ ret = hdmi_drm_infoframe_check(frame);
+ if (ret)
+ return ret;
+
+ return hdmi_drm_infoframe_pack_only(frame, buffer, size);
+}
+EXPORT_SYMBOL(hdmi_drm_infoframe_pack);
+
+/*
+ * hdmi_vendor_any_infoframe_check() - check a vendor infoframe
+ */
+static int
+hdmi_vendor_any_infoframe_check(union hdmi_vendor_any_infoframe *frame)
+{
+ int ret;
+
+ ret = hdmi_vendor_any_infoframe_check_only(frame);
+ if (ret)
+ return ret;
+
+ /* we only know about HDMI vendor infoframes */
+ if (frame->any.oui != HDMI_IEEE_OUI)
+ return -EINVAL;
+
+ return hdmi_vendor_infoframe_check(&frame->hdmi);
+}
+
+/*
+ * hdmi_vendor_any_infoframe_pack_only() - write a vendor infoframe to binary buffer
+ */
+static ssize_t
+hdmi_vendor_any_infoframe_pack_only(const union hdmi_vendor_any_infoframe *frame,
+ void *buffer, size_t size)
+{
+ int ret;
+
+ ret = hdmi_vendor_any_infoframe_check_only(frame);
+ if (ret)
+ return ret;
+
+ /* we only know about HDMI vendor infoframes */
+ if (frame->any.oui != HDMI_IEEE_OUI)
+ return -EINVAL;
+
+ return hdmi_vendor_infoframe_pack_only(&frame->hdmi, buffer, size);
+}
+
+/*
+ * hdmi_vendor_any_infoframe_pack() - check a vendor infoframe,
+ * and write it to binary buffer
+ */
+static ssize_t
+hdmi_vendor_any_infoframe_pack(union hdmi_vendor_any_infoframe *frame,
+ void *buffer, size_t size)
+{
+ int ret;
+
+ ret = hdmi_vendor_any_infoframe_check(frame);
+ if (ret)
+ return ret;
+
+ return hdmi_vendor_any_infoframe_pack_only(frame, buffer, size);
+}
+
+/**
+ * hdmi_infoframe_check() - check a HDMI infoframe
+ * @frame: HDMI infoframe
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int
+hdmi_infoframe_check(union hdmi_infoframe *frame)
+{
+ switch (frame->any.type) {
+ case HDMI_INFOFRAME_TYPE_AVI:
+ return hdmi_avi_infoframe_check(&frame->avi);
+ case HDMI_INFOFRAME_TYPE_SPD:
+ return hdmi_spd_infoframe_check(&frame->spd);
+ case HDMI_INFOFRAME_TYPE_AUDIO:
+ return hdmi_audio_infoframe_check(&frame->audio);
+ case HDMI_INFOFRAME_TYPE_VENDOR:
+ return hdmi_vendor_any_infoframe_check(&frame->vendor);
+ default:
+ WARN(1, "Bad infoframe type %d\n", frame->any.type);
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(hdmi_infoframe_check);
+
+/**
+ * hdmi_infoframe_pack_only() - write a HDMI infoframe to binary buffer
+ * @frame: HDMI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Packs the information contained in the @frame structure into a binary
+ * representation that can be written into the corresponding controller
+ * registers. Also computes the checksum as required by section 5.3.5 of
+ * the HDMI 1.4 specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t
+hdmi_infoframe_pack_only(const union hdmi_infoframe *frame, void *buffer, size_t size)
+{
+ ssize_t length;
+
+ switch (frame->any.type) {
+ case HDMI_INFOFRAME_TYPE_AVI:
+ length = hdmi_avi_infoframe_pack_only(&frame->avi,
+ buffer, size);
+ break;
+ case HDMI_INFOFRAME_TYPE_DRM:
+ length = hdmi_drm_infoframe_pack_only(&frame->drm,
+ buffer, size);
+ break;
+ case HDMI_INFOFRAME_TYPE_SPD:
+ length = hdmi_spd_infoframe_pack_only(&frame->spd,
+ buffer, size);
+ break;
+ case HDMI_INFOFRAME_TYPE_AUDIO:
+ length = hdmi_audio_infoframe_pack_only(&frame->audio,
+ buffer, size);
+ break;
+ case HDMI_INFOFRAME_TYPE_VENDOR:
+ length = hdmi_vendor_any_infoframe_pack_only(&frame->vendor,
+ buffer, size);
+ break;
+ default:
+ WARN(1, "Bad infoframe type %d\n", frame->any.type);
+ length = -EINVAL;
+ }
+
+ return length;
+}
+EXPORT_SYMBOL(hdmi_infoframe_pack_only);
+
+/**
+ * hdmi_infoframe_pack() - check a HDMI infoframe,
+ * and write it to binary buffer
+ * @frame: HDMI infoframe
+ * @buffer: destination buffer
+ * @size: size of buffer
+ *
+ * Validates that the infoframe is consistent and updates derived fields
+ * (eg. length) based on other fields, after which it packs the information
+ * contained in the @frame structure into a binary representation that
+ * can be written into the corresponding controller registers. This function
+ * also computes the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns the number of bytes packed into the binary buffer or a negative
+ * error code on failure.
+ */
+ssize_t
+hdmi_infoframe_pack(union hdmi_infoframe *frame,
+ void *buffer, size_t size)
+{
+ ssize_t length;
+
+ switch (frame->any.type) {
+ case HDMI_INFOFRAME_TYPE_AVI:
+ length = hdmi_avi_infoframe_pack(&frame->avi, buffer, size);
+ break;
+ case HDMI_INFOFRAME_TYPE_DRM:
+ length = hdmi_drm_infoframe_pack(&frame->drm, buffer, size);
+ break;
+ case HDMI_INFOFRAME_TYPE_SPD:
+ length = hdmi_spd_infoframe_pack(&frame->spd, buffer, size);
+ break;
+ case HDMI_INFOFRAME_TYPE_AUDIO:
+ length = hdmi_audio_infoframe_pack(&frame->audio, buffer, size);
+ break;
+ case HDMI_INFOFRAME_TYPE_VENDOR:
+ length = hdmi_vendor_any_infoframe_pack(&frame->vendor,
+ buffer, size);
+ break;
+ default:
+ WARN(1, "Bad infoframe type %d\n", frame->any.type);
+ length = -EINVAL;
+ }
+
+ return length;
+}
+EXPORT_SYMBOL(hdmi_infoframe_pack);
+
+static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
+{
+ if (type < 0x80 || type > 0x9f)
+ return "Invalid";
+ switch (type) {
+ case HDMI_INFOFRAME_TYPE_VENDOR:
+ return "Vendor";
+ case HDMI_INFOFRAME_TYPE_AVI:
+ return "Auxiliary Video Information (AVI)";
+ case HDMI_INFOFRAME_TYPE_SPD:
+ return "Source Product Description (SPD)";
+ case HDMI_INFOFRAME_TYPE_AUDIO:
+ return "Audio";
+ case HDMI_INFOFRAME_TYPE_DRM:
+ return "Dynamic Range and Mastering";
+ }
+ return "Reserved";
+}
+
+static void hdmi_infoframe_log_header(const char *level,
+ struct device *dev,
+ const struct hdmi_any_infoframe *frame)
+{
+ hdmi_log("HDMI infoframe: %s, version %u, length %u\n",
+ hdmi_infoframe_type_get_name(frame->type),
+ frame->version, frame->length);
+}
+
+static const char *hdmi_colorspace_get_name(enum hdmi_colorspace colorspace)
+{
+ switch (colorspace) {
+ case HDMI_COLORSPACE_RGB:
+ return "RGB";
+ case HDMI_COLORSPACE_YUV422:
+ return "YCbCr 4:2:2";
+ case HDMI_COLORSPACE_YUV444:
+ return "YCbCr 4:4:4";
+ case HDMI_COLORSPACE_YUV420:
+ return "YCbCr 4:2:0";
+ case HDMI_COLORSPACE_RESERVED4:
+ return "Reserved (4)";
+ case HDMI_COLORSPACE_RESERVED5:
+ return "Reserved (5)";
+ case HDMI_COLORSPACE_RESERVED6:
+ return "Reserved (6)";
+ case HDMI_COLORSPACE_IDO_DEFINED:
+ return "IDO Defined";
+ }
+ return "Invalid";
+}
+
+static const char *hdmi_scan_mode_get_name(enum hdmi_scan_mode scan_mode)
+{
+ switch (scan_mode) {
+ case HDMI_SCAN_MODE_NONE:
+ return "No Data";
+ case HDMI_SCAN_MODE_OVERSCAN:
+ return "Overscan";
+ case HDMI_SCAN_MODE_UNDERSCAN:
+ return "Underscan";
+ case HDMI_SCAN_MODE_RESERVED:
+ return "Reserved";
+ }
+ return "Invalid";
+}
+
+static const char *hdmi_colorimetry_get_name(enum hdmi_colorimetry colorimetry)
+{
+ switch (colorimetry) {
+ case HDMI_COLORIMETRY_NONE:
+ return "No Data";
+ case HDMI_COLORIMETRY_ITU_601:
+ return "ITU601";
+ case HDMI_COLORIMETRY_ITU_709:
+ return "ITU709";
+ case HDMI_COLORIMETRY_EXTENDED:
+ return "Extended";
+ }
+ return "Invalid";
+}
+
+static const char *
+hdmi_picture_aspect_get_name(enum hdmi_picture_aspect picture_aspect)
+{
+ switch (picture_aspect) {
+ case HDMI_PICTURE_ASPECT_NONE:
+ return "No Data";
+ case HDMI_PICTURE_ASPECT_4_3:
+ return "4:3";
+ case HDMI_PICTURE_ASPECT_16_9:
+ return "16:9";
+ case HDMI_PICTURE_ASPECT_64_27:
+ return "64:27";
+ case HDMI_PICTURE_ASPECT_256_135:
+ return "256:135";
+ case HDMI_PICTURE_ASPECT_RESERVED:
+ return "Reserved";
+ }
+ return "Invalid";
+}
+
+static const char *
+hdmi_active_aspect_get_name(enum hdmi_active_aspect active_aspect)
+{
+ if (active_aspect < 0 || active_aspect > 0xf)
+ return "Invalid";
+
+ switch (active_aspect) {
+ case HDMI_ACTIVE_ASPECT_16_9_TOP:
+ return "16:9 Top";
+ case HDMI_ACTIVE_ASPECT_14_9_TOP:
+ return "14:9 Top";
+ case HDMI_ACTIVE_ASPECT_16_9_CENTER:
+ return "16:9 Center";
+ case HDMI_ACTIVE_ASPECT_PICTURE:
+ return "Same as Picture";
+ case HDMI_ACTIVE_ASPECT_4_3:
+ return "4:3";
+ case HDMI_ACTIVE_ASPECT_16_9:
+ return "16:9";
+ case HDMI_ACTIVE_ASPECT_14_9:
+ return "14:9";
+ case HDMI_ACTIVE_ASPECT_4_3_SP_14_9:
+ return "4:3 SP 14:9";
+ case HDMI_ACTIVE_ASPECT_16_9_SP_14_9:
+ return "16:9 SP 14:9";
+ case HDMI_ACTIVE_ASPECT_16_9_SP_4_3:
+ return "16:9 SP 4:3";
+ }
+ return "Reserved";
+}
+
+static const char *
+hdmi_extended_colorimetry_get_name(enum hdmi_extended_colorimetry ext_col)
+{
+ switch (ext_col) {
+ case HDMI_EXTENDED_COLORIMETRY_XV_YCC_601:
+ return "xvYCC 601";
+ case HDMI_EXTENDED_COLORIMETRY_XV_YCC_709:
+ return "xvYCC 709";
+ case HDMI_EXTENDED_COLORIMETRY_S_YCC_601:
+ return "sYCC 601";
+ case HDMI_EXTENDED_COLORIMETRY_OPYCC_601:
+ return "opYCC 601";
+ case HDMI_EXTENDED_COLORIMETRY_OPRGB:
+ return "opRGB";
+ case HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM:
+ return "BT.2020 Constant Luminance";
+ case HDMI_EXTENDED_COLORIMETRY_BT2020:
+ return "BT.2020";
+ case HDMI_EXTENDED_COLORIMETRY_RESERVED:
+ return "Reserved";
+ }
+ return "Invalid";
+}
+
+static const char *
+hdmi_quantization_range_get_name(enum hdmi_quantization_range qrange)
+{
+ switch (qrange) {
+ case HDMI_QUANTIZATION_RANGE_DEFAULT:
+ return "Default";
+ case HDMI_QUANTIZATION_RANGE_LIMITED:
+ return "Limited";
+ case HDMI_QUANTIZATION_RANGE_FULL:
+ return "Full";
+ case HDMI_QUANTIZATION_RANGE_RESERVED:
+ return "Reserved";
+ }
+ return "Invalid";
+}
+
+static const char *hdmi_nups_get_name(enum hdmi_nups nups)
+{
+ switch (nups) {
+ case HDMI_NUPS_UNKNOWN:
+ return "Unknown Non-uniform Scaling";
+ case HDMI_NUPS_HORIZONTAL:
+ return "Horizontally Scaled";
+ case HDMI_NUPS_VERTICAL:
+ return "Vertically Scaled";
+ case HDMI_NUPS_BOTH:
+ return "Horizontally and Vertically Scaled";
+ }
+ return "Invalid";
+}
+
+static const char *
+hdmi_ycc_quantization_range_get_name(enum hdmi_ycc_quantization_range qrange)
+{
+ switch (qrange) {
+ case HDMI_YCC_QUANTIZATION_RANGE_LIMITED:
+ return "Limited";
+ case HDMI_YCC_QUANTIZATION_RANGE_FULL:
+ return "Full";
+ }
+ return "Invalid";
+}
+
+static const char *
+hdmi_content_type_get_name(enum hdmi_content_type content_type)
+{
+ switch (content_type) {
+ case HDMI_CONTENT_TYPE_GRAPHICS:
+ return "Graphics";
+ case HDMI_CONTENT_TYPE_PHOTO:
+ return "Photo";
+ case HDMI_CONTENT_TYPE_CINEMA:
+ return "Cinema";
+ case HDMI_CONTENT_TYPE_GAME:
+ return "Game";
+ }
+ return "Invalid";
+}
+
+static void hdmi_avi_infoframe_log(const char *level,
+ struct device *dev,
+ const struct hdmi_avi_infoframe *frame)
+{
+ hdmi_infoframe_log_header(level, dev,
+ (const struct hdmi_any_infoframe *)frame);
+
+ hdmi_log(" colorspace: %s\n",
+ hdmi_colorspace_get_name(frame->colorspace));
+ hdmi_log(" scan mode: %s\n",
+ hdmi_scan_mode_get_name(frame->scan_mode));
+ hdmi_log(" colorimetry: %s\n",
+ hdmi_colorimetry_get_name(frame->colorimetry));
+ hdmi_log(" picture aspect: %s\n",
+ hdmi_picture_aspect_get_name(frame->picture_aspect));
+ hdmi_log(" active aspect: %s\n",
+ hdmi_active_aspect_get_name(frame->active_aspect));
+ hdmi_log(" itc: %s\n", frame->itc ? "IT Content" : "No Data");
+ hdmi_log(" extended colorimetry: %s\n",
+ hdmi_extended_colorimetry_get_name(frame->extended_colorimetry));
+ hdmi_log(" quantization range: %s\n",
+ hdmi_quantization_range_get_name(frame->quantization_range));
+ hdmi_log(" nups: %s\n", hdmi_nups_get_name(frame->nups));
+ hdmi_log(" video code: %u\n", frame->video_code);
+ hdmi_log(" ycc quantization range: %s\n",
+ hdmi_ycc_quantization_range_get_name(frame->ycc_quantization_range));
+ hdmi_log(" hdmi content type: %s\n",
+ hdmi_content_type_get_name(frame->content_type));
+ hdmi_log(" pixel repeat: %u\n", frame->pixel_repeat);
+ hdmi_log(" bar top %u, bottom %u, left %u, right %u\n",
+ frame->top_bar, frame->bottom_bar,
+ frame->left_bar, frame->right_bar);
+}
+
+static const char *hdmi_spd_sdi_get_name(enum hdmi_spd_sdi sdi)
+{
+ if (sdi < 0 || sdi > 0xff)
+ return "Invalid";
+ switch (sdi) {
+ case HDMI_SPD_SDI_UNKNOWN:
+ return "Unknown";
+ case HDMI_SPD_SDI_DSTB:
+ return "Digital STB";
+ case HDMI_SPD_SDI_DVDP:
+ return "DVD Player";
+ case HDMI_SPD_SDI_DVHS:
+ return "D-VHS";
+ case HDMI_SPD_SDI_HDDVR:
+ return "HDD Videorecorder";
+ case HDMI_SPD_SDI_DVC:
+ return "DVC";
+ case HDMI_SPD_SDI_DSC:
+ return "DSC";
+ case HDMI_SPD_SDI_VCD:
+ return "Video CD";
+ case HDMI_SPD_SDI_GAME:
+ return "Game";
+ case HDMI_SPD_SDI_PC:
+ return "PC General";
+ case HDMI_SPD_SDI_BD:
+ return "Blu-Ray Disc (BD)";
+ case HDMI_SPD_SDI_SACD:
+ return "Super Audio CD";
+ case HDMI_SPD_SDI_HDDVD:
+ return "HD DVD";
+ case HDMI_SPD_SDI_PMP:
+ return "PMP";
+ }
+ return "Reserved";
+}
+
+static void hdmi_spd_infoframe_log(const char *level,
+ struct device *dev,
+ const struct hdmi_spd_infoframe *frame)
+{
+ u8 buf[17];
+
+ hdmi_infoframe_log_header(level, dev,
+ (const struct hdmi_any_infoframe *)frame);
+
+ memset(buf, 0, sizeof(buf));
+
+ strncpy(buf, frame->vendor, 8);
+ hdmi_log(" vendor: %s\n", buf);
+ strncpy(buf, frame->product, 16);
+ hdmi_log(" product: %s\n", buf);
+ hdmi_log(" source device information: %s (0x%x)\n",
+ hdmi_spd_sdi_get_name(frame->sdi), frame->sdi);
+}
+
+static const char *
+hdmi_audio_coding_type_get_name(enum hdmi_audio_coding_type coding_type)
+{
+ switch (coding_type) {
+ case HDMI_AUDIO_CODING_TYPE_STREAM:
+ return "Refer to Stream Header";
+ case HDMI_AUDIO_CODING_TYPE_PCM:
+ return "PCM";
+ case HDMI_AUDIO_CODING_TYPE_AC3:
+ return "AC-3";
+ case HDMI_AUDIO_CODING_TYPE_MPEG1:
+ return "MPEG1";
+ case HDMI_AUDIO_CODING_TYPE_MP3:
+ return "MP3";
+ case HDMI_AUDIO_CODING_TYPE_MPEG2:
+ return "MPEG2";
+ case HDMI_AUDIO_CODING_TYPE_AAC_LC:
+ return "AAC";
+ case HDMI_AUDIO_CODING_TYPE_DTS:
+ return "DTS";
+ case HDMI_AUDIO_CODING_TYPE_ATRAC:
+ return "ATRAC";
+ case HDMI_AUDIO_CODING_TYPE_DSD:
+ return "One Bit Audio";
+ case HDMI_AUDIO_CODING_TYPE_EAC3:
+ return "Dolby Digital +";
+ case HDMI_AUDIO_CODING_TYPE_DTS_HD:
+ return "DTS-HD";
+ case HDMI_AUDIO_CODING_TYPE_MLP:
+ return "MAT (MLP)";
+ case HDMI_AUDIO_CODING_TYPE_DST:
+ return "DST";
+ case HDMI_AUDIO_CODING_TYPE_WMA_PRO:
+ return "WMA PRO";
+ case HDMI_AUDIO_CODING_TYPE_CXT:
+ return "Refer to CXT";
+ }
+ return "Invalid";
+}
+
+static const char *
+hdmi_audio_sample_size_get_name(enum hdmi_audio_sample_size sample_size)
+{
+ switch (sample_size) {
+ case HDMI_AUDIO_SAMPLE_SIZE_STREAM:
+ return "Refer to Stream Header";
+ case HDMI_AUDIO_SAMPLE_SIZE_16:
+ return "16 bit";
+ case HDMI_AUDIO_SAMPLE_SIZE_20:
+ return "20 bit";
+ case HDMI_AUDIO_SAMPLE_SIZE_24:
+ return "24 bit";
+ }
+ return "Invalid";
+}
+
+static const char *
+hdmi_audio_sample_frequency_get_name(enum hdmi_audio_sample_frequency freq)
+{
+ switch (freq) {
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM:
+ return "Refer to Stream Header";
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_32000:
+ return "32 kHz";
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_44100:
+ return "44.1 kHz (CD)";
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_48000:
+ return "48 kHz";
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_88200:
+ return "88.2 kHz";
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_96000:
+ return "96 kHz";
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_176400:
+ return "176.4 kHz";
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_192000:
+ return "192 kHz";
+ }
+ return "Invalid";
+}
+
+static const char *
+hdmi_audio_coding_type_ext_get_name(enum hdmi_audio_coding_type_ext ctx)
+{
+ if (ctx < 0 || ctx > 0x1f)
+ return "Invalid";
+
+ switch (ctx) {
+ case HDMI_AUDIO_CODING_TYPE_EXT_CT:
+ return "Refer to CT";
+ case HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC:
+ return "HE AAC";
+ case HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC_V2:
+ return "HE AAC v2";
+ case HDMI_AUDIO_CODING_TYPE_EXT_MPEG_SURROUND:
+ return "MPEG SURROUND";
+ case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC:
+ return "MPEG-4 HE AAC";
+ case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_V2:
+ return "MPEG-4 HE AAC v2";
+ case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC:
+ return "MPEG-4 AAC LC";
+ case HDMI_AUDIO_CODING_TYPE_EXT_DRA:
+ return "DRA";
+ case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_SURROUND:
+ return "MPEG-4 HE AAC + MPEG Surround";
+ case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC_SURROUND:
+ return "MPEG-4 AAC LC + MPEG Surround";
+ }
+ return "Reserved";
+}
+
+static void hdmi_audio_infoframe_log(const char *level,
+ struct device *dev,
+ const struct hdmi_audio_infoframe *frame)
+{
+ hdmi_infoframe_log_header(level, dev,
+ (const struct hdmi_any_infoframe *)frame);
+
+ if (frame->channels)
+ hdmi_log(" channels: %u\n", frame->channels - 1);
+ else
+ hdmi_log(" channels: Refer to stream header\n");
+ hdmi_log(" coding type: %s\n",
+ hdmi_audio_coding_type_get_name(frame->coding_type));
+ hdmi_log(" sample size: %s\n",
+ hdmi_audio_sample_size_get_name(frame->sample_size));
+ hdmi_log(" sample frequency: %s\n",
+ hdmi_audio_sample_frequency_get_name(frame->sample_frequency));
+ hdmi_log(" coding type ext: %s\n",
+ hdmi_audio_coding_type_ext_get_name(frame->coding_type_ext));
+ hdmi_log(" channel allocation: 0x%x\n",
+ frame->channel_allocation);
+ hdmi_log(" level shift value: %u dB\n",
+ frame->level_shift_value);
+ hdmi_log(" downmix inhibit: %s\n",
+ frame->downmix_inhibit ? "Yes" : "No");
+}
+
+static void hdmi_drm_infoframe_log(const char *level,
+ struct device *dev,
+ const struct hdmi_drm_infoframe *frame)
+{
+ int i;
+
+ hdmi_infoframe_log_header(level, dev,
+ (struct hdmi_any_infoframe *)frame);
+ hdmi_log("length: %d\n", frame->length);
+ hdmi_log("metadata type: %d\n", frame->metadata_type);
+ hdmi_log("eotf: %d\n", frame->eotf);
+ for (i = 0; i < 3; i++) {
+ hdmi_log("x[%d]: %d\n", i, frame->display_primaries[i].x);
+ hdmi_log("y[%d]: %d\n", i, frame->display_primaries[i].y);
+ }
+
+ hdmi_log("white point x: %d\n", frame->white_point.x);
+ hdmi_log("white point y: %d\n", frame->white_point.y);
+
+ hdmi_log("max_display_mastering_luminance: %d\n",
+ frame->max_display_mastering_luminance);
+ hdmi_log("min_display_mastering_luminance: %d\n",
+ frame->min_display_mastering_luminance);
+
+ hdmi_log("max_cll: %d\n", frame->max_cll);
+ hdmi_log("max_fall: %d\n", frame->max_fall);
+}
+
+static const char *
+hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct)
+{
+ if (s3d_struct < 0 || s3d_struct > 0xf)
+ return "Invalid";
+
+ switch (s3d_struct) {
+ case HDMI_3D_STRUCTURE_FRAME_PACKING:
+ return "Frame Packing";
+ case HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE:
+ return "Field Alternative";
+ case HDMI_3D_STRUCTURE_LINE_ALTERNATIVE:
+ return "Line Alternative";
+ case HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL:
+ return "Side-by-side (Full)";
+ case HDMI_3D_STRUCTURE_L_DEPTH:
+ return "L + Depth";
+ case HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH:
+ return "L + Depth + Graphics + Graphics-depth";
+ case HDMI_3D_STRUCTURE_TOP_AND_BOTTOM:
+ return "Top-and-Bottom";
+ case HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF:
+ return "Side-by-side (Half)";
+ default:
+ break;
+ }
+ return "Reserved";
+}
+
+static void
+hdmi_vendor_any_infoframe_log(const char *level,
+ struct device *dev,
+ const union hdmi_vendor_any_infoframe *frame)
+{
+ const struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
+
+ hdmi_infoframe_log_header(level, dev,
+ (const struct hdmi_any_infoframe *)frame);
+
+ if (frame->any.oui != HDMI_IEEE_OUI) {
+ hdmi_log(" not a HDMI vendor infoframe\n");
+ return;
+ }
+ if (hvf->vic == 0 && hvf->s3d_struct == HDMI_3D_STRUCTURE_INVALID) {
+ hdmi_log(" empty frame\n");
+ return;
+ }
+
+ if (hvf->vic)
+ hdmi_log(" HDMI VIC: %u\n", hvf->vic);
+ if (hvf->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
+ hdmi_log(" 3D structure: %s\n",
+ hdmi_3d_structure_get_name(hvf->s3d_struct));
+ if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
+ hdmi_log(" 3D extension data: %d\n",
+ hvf->s3d_ext_data);
+ }
+}
+
+/**
+ * hdmi_infoframe_log() - log info of HDMI infoframe
+ * @level: logging level
+ * @dev: device
+ * @frame: HDMI infoframe
+ */
+void hdmi_infoframe_log(const char *level,
+ struct device *dev,
+ const union hdmi_infoframe *frame)
+{
+ switch (frame->any.type) {
+ case HDMI_INFOFRAME_TYPE_AVI:
+ hdmi_avi_infoframe_log(level, dev, &frame->avi);
+ break;
+ case HDMI_INFOFRAME_TYPE_SPD:
+ hdmi_spd_infoframe_log(level, dev, &frame->spd);
+ break;
+ case HDMI_INFOFRAME_TYPE_AUDIO:
+ hdmi_audio_infoframe_log(level, dev, &frame->audio);
+ break;
+ case HDMI_INFOFRAME_TYPE_VENDOR:
+ hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
+ break;
+ case HDMI_INFOFRAME_TYPE_DRM:
+ hdmi_drm_infoframe_log(level, dev, &frame->drm);
+ break;
+ }
+}
+EXPORT_SYMBOL(hdmi_infoframe_log);
+
+/**
+ * hdmi_avi_infoframe_unpack() - unpack binary buffer to a HDMI AVI infoframe
+ * @frame: HDMI AVI infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI Auxiliary Video (AVI) information frame.
+ * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
+ const void *buffer, size_t size)
+{
+ const u8 *ptr = buffer;
+
+ if (size < HDMI_INFOFRAME_SIZE(AVI))
+ return -EINVAL;
+
+ if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
+ ptr[1] != 2 ||
+ ptr[2] != HDMI_AVI_INFOFRAME_SIZE)
+ return -EINVAL;
+
+ if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(AVI)) != 0)
+ return -EINVAL;
+
+ hdmi_avi_infoframe_init(frame);
+
+ ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+ frame->colorspace = (ptr[0] >> 5) & 0x3;
+ if (ptr[0] & 0x10)
+ frame->active_aspect = ptr[1] & 0xf;
+ if (ptr[0] & 0x8) {
+ frame->top_bar = (ptr[6] << 8) | ptr[5];
+ frame->bottom_bar = (ptr[8] << 8) | ptr[7];
+ }
+ if (ptr[0] & 0x4) {
+ frame->left_bar = (ptr[10] << 8) | ptr[9];
+ frame->right_bar = (ptr[12] << 8) | ptr[11];
+ }
+ frame->scan_mode = ptr[0] & 0x3;
+
+ frame->colorimetry = (ptr[1] >> 6) & 0x3;
+ frame->picture_aspect = (ptr[1] >> 4) & 0x3;
+ frame->active_aspect = ptr[1] & 0xf;
+
+ frame->itc = ptr[2] & 0x80 ? true : false;
+ frame->extended_colorimetry = (ptr[2] >> 4) & 0x7;
+ frame->quantization_range = (ptr[2] >> 2) & 0x3;
+ frame->nups = ptr[2] & 0x3;
+
+ frame->video_code = ptr[3] & 0x7f;
+ frame->ycc_quantization_range = (ptr[4] >> 6) & 0x3;
+ frame->content_type = (ptr[4] >> 4) & 0x3;
+
+ frame->pixel_repeat = ptr[4] & 0xf;
+
+ return 0;
+}
+
+/**
+ * hdmi_spd_infoframe_unpack() - unpack binary buffer to a HDMI SPD infoframe
+ * @frame: HDMI SPD infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI Source Product Description (SPD) information frame.
+ * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
+ const void *buffer, size_t size)
+{
+ const u8 *ptr = buffer;
+ int ret;
+
+ if (size < HDMI_INFOFRAME_SIZE(SPD))
+ return -EINVAL;
+
+ if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
+ ptr[1] != 1 ||
+ ptr[2] != HDMI_SPD_INFOFRAME_SIZE) {
+ return -EINVAL;
+ }
+
+ if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(SPD)) != 0)
+ return -EINVAL;
+
+ ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+ ret = hdmi_spd_infoframe_init(frame, ptr, ptr + 8);
+ if (ret)
+ return ret;
+
+ frame->sdi = ptr[24];
+
+ return 0;
+}
+
+/**
+ * hdmi_audio_infoframe_unpack() - unpack binary buffer to a HDMI AUDIO infoframe
+ * @frame: HDMI Audio infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI Audio information frame.
+ * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
+ const void *buffer, size_t size)
+{
+ const u8 *ptr = buffer;
+ int ret;
+
+ if (size < HDMI_INFOFRAME_SIZE(AUDIO))
+ return -EINVAL;
+
+ if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
+ ptr[1] != 1 ||
+ ptr[2] != HDMI_AUDIO_INFOFRAME_SIZE) {
+ return -EINVAL;
+ }
+
+ if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(AUDIO)) != 0)
+ return -EINVAL;
+
+ ret = hdmi_audio_infoframe_init(frame);
+ if (ret)
+ return ret;
+
+ ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+ frame->channels = ptr[0] & 0x7;
+ frame->coding_type = (ptr[0] >> 4) & 0xf;
+ frame->sample_size = ptr[1] & 0x3;
+ frame->sample_frequency = (ptr[1] >> 2) & 0x7;
+ frame->coding_type_ext = ptr[2] & 0x1f;
+ frame->channel_allocation = ptr[3];
+ frame->level_shift_value = (ptr[4] >> 3) & 0xf;
+ frame->downmix_inhibit = ptr[4] & 0x80 ? true : false;
+
+ return 0;
+}
+
+/**
+ * hdmi_vendor_any_infoframe_unpack() - unpack binary buffer to a HDMI
+ * vendor infoframe
+ * @frame: HDMI Vendor infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI Vendor information frame.
+ * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int
+hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
+ const void *buffer, size_t size)
+{
+ const u8 *ptr = buffer;
+ size_t length;
+ int ret;
+ u8 hdmi_video_format;
+ struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
+
+ if (size < HDMI_INFOFRAME_HEADER_SIZE)
+ return -EINVAL;
+
+ if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR ||
+ ptr[1] != 1 ||
+ (ptr[2] != 4 && ptr[2] != 5 && ptr[2] != 6))
+ return -EINVAL;
+
+ length = ptr[2];
+
+ if (size < HDMI_INFOFRAME_HEADER_SIZE + length)
+ return -EINVAL;
+
+ if (hdmi_infoframe_checksum(buffer,
+ HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
+ return -EINVAL;
+
+ ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+ /* HDMI OUI */
+ if ((ptr[0] != 0x03) ||
+ (ptr[1] != 0x0c) ||
+ (ptr[2] != 0x00))
+ return -EINVAL;
+
+ hdmi_video_format = ptr[3] >> 5;
+
+ if (hdmi_video_format > 0x2)
+ return -EINVAL;
+
+ ret = hdmi_vendor_infoframe_init(hvf);
+ if (ret)
+ return ret;
+
+ hvf->length = length;
+
+ if (hdmi_video_format == 0x2) {
+ if (length != 5 && length != 6)
+ return -EINVAL;
+ hvf->s3d_struct = ptr[4] >> 4;
+ if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) {
+ if (length != 6)
+ return -EINVAL;
+ hvf->s3d_ext_data = ptr[5] >> 4;
+ }
+ } else if (hdmi_video_format == 0x1) {
+ if (length != 5)
+ return -EINVAL;
+ hvf->vic = ptr[4];
+ } else {
+ if (length != 4)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * hdmi_drm_infoframe_unpack_only() - unpack binary buffer of CTA-861-G DRM
+ * infoframe DataBytes to a HDMI DRM
+ * infoframe
+ * @frame: HDMI DRM infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
+ *
+ * Unpacks CTA-861-G DRM infoframe DataBytes contained in the binary @buffer
+ * into a structured @frame of the HDMI Dynamic Range and Mastering (DRM)
+ * infoframe.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_drm_infoframe_unpack_only(struct hdmi_drm_infoframe *frame,
+ const void *buffer, size_t size)
+{
+ const u8 *ptr = buffer;
+ const u8 *temp;
+ u8 x_lsb, x_msb;
+ u8 y_lsb, y_msb;
+ int ret;
+ int i;
+
+ if (size < HDMI_DRM_INFOFRAME_SIZE)
+ return -EINVAL;
+
+ ret = hdmi_drm_infoframe_init(frame);
+ if (ret)
+ return ret;
+
+ frame->eotf = ptr[0] & 0x7;
+ frame->metadata_type = ptr[1] & 0x7;
+
+ temp = ptr + 2;
+ for (i = 0; i < 3; i++) {
+ x_lsb = *temp++;
+ x_msb = *temp++;
+ frame->display_primaries[i].x = (x_msb << 8) | x_lsb;
+ y_lsb = *temp++;
+ y_msb = *temp++;
+ frame->display_primaries[i].y = (y_msb << 8) | y_lsb;
+ }
+
+ frame->white_point.x = (ptr[15] << 8) | ptr[14];
+ frame->white_point.y = (ptr[17] << 8) | ptr[16];
+
+ frame->max_display_mastering_luminance = (ptr[19] << 8) | ptr[18];
+ frame->min_display_mastering_luminance = (ptr[21] << 8) | ptr[20];
+ frame->max_cll = (ptr[23] << 8) | ptr[22];
+ frame->max_fall = (ptr[25] << 8) | ptr[24];
+
+ return 0;
+}
+EXPORT_SYMBOL(hdmi_drm_infoframe_unpack_only);
+
+/**
+ * hdmi_drm_infoframe_unpack() - unpack binary buffer to a HDMI DRM infoframe
+ * @frame: HDMI DRM infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
+ *
+ * Unpacks the CTA-861-G DRM infoframe contained in the binary @buffer into
+ * a structured @frame of the HDMI Dynamic Range and Mastering (DRM)
+ * infoframe. It also verifies the checksum as required by section 5.3.5 of
+ * the HDMI 1.4 specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int hdmi_drm_infoframe_unpack(struct hdmi_drm_infoframe *frame,
+ const void *buffer, size_t size)
+{
+ const u8 *ptr = buffer;
+ int ret;
+
+ if (size < HDMI_INFOFRAME_SIZE(DRM))
+ return -EINVAL;
+
+ if (ptr[0] != HDMI_INFOFRAME_TYPE_DRM ||
+ ptr[1] != 1 ||
+ ptr[2] != HDMI_DRM_INFOFRAME_SIZE)
+ return -EINVAL;
+
+ if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(DRM)) != 0)
+ return -EINVAL;
+
+ ret = hdmi_drm_infoframe_unpack_only(frame, ptr + HDMI_INFOFRAME_HEADER_SIZE,
+ size - HDMI_INFOFRAME_HEADER_SIZE);
+ return ret;
+}
+
+/**
+ * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
+ * @frame: HDMI infoframe
+ * @buffer: source buffer
+ * @size: size of buffer
+ *
+ * Unpacks the information contained in binary buffer @buffer into a structured
+ * @frame of a HDMI infoframe.
+ * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_infoframe_unpack(union hdmi_infoframe *frame,
+ const void *buffer, size_t size)
+{
+ int ret;
+ const u8 *ptr = buffer;
+
+ if (size < HDMI_INFOFRAME_HEADER_SIZE)
+ return -EINVAL;
+
+ switch (ptr[0]) {
+ case HDMI_INFOFRAME_TYPE_AVI:
+ ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer, size);
+ break;
+ case HDMI_INFOFRAME_TYPE_DRM:
+ ret = hdmi_drm_infoframe_unpack(&frame->drm, buffer, size);
+ break;
+ case HDMI_INFOFRAME_TYPE_SPD:
+ ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer, size);
+ break;
+ case HDMI_INFOFRAME_TYPE_AUDIO:
+ ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer, size);
+ break;
+ case HDMI_INFOFRAME_TYPE_VENDOR:
+ ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer, size);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(hdmi_infoframe_unpack);
+
+
+MODULE_VERSION(linuxkpi_hdmi, 1);
+MODULE_DEPEND(linuxkpi_hdmi, linuxkpi, 1, 1, 1);
diff --git a/sys/compat/linuxkpi/common/src/linux_hrtimer.c b/sys/compat/linuxkpi/common/src/linux_hrtimer.c
index a56485512a14..dca5d5cf709b 100644
--- a/sys/compat/linuxkpi/common/src/linux_hrtimer.c
+++ b/sys/compat/linuxkpi/common/src/linux_hrtimer.c
@@ -23,9 +23,6 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/lock.h>
@@ -66,6 +63,28 @@ linux_hrtimer_active(struct hrtimer *hrtimer)
}
/*
+ * Try to cancel active hrtimer.
+ * Return 1 if timer was active and cancellation succeeded, 0 if timer was
+ * inactive, or -1 if the timer is being serviced and can't be cancelled.
+ */
+int
+linux_hrtimer_try_to_cancel(struct hrtimer *hrtimer)
+{
+ int ret;
+
+ mtx_lock(&hrtimer->mtx);
+ ret = callout_stop(&hrtimer->callout);
+ mtx_unlock(&hrtimer->mtx);
+ if (ret > 0) {
+ return (1);
+ } else if (ret < 0) {
+ return (0);
+ } else {
+ return (-1);
+ }
+}
+
+/*
* Cancel active hrtimer.
* Return 1 if timer was active and cancellation succeeded, or 0 otherwise.
*/
diff --git a/sys/compat/linuxkpi/common/src/linux_i2c.c b/sys/compat/linuxkpi/common/src/linux_i2c.c
index bdf381f8a032..60f7737cf6ec 100644
--- a/sys/compat/linuxkpi/common/src/linux_i2c.c
+++ b/sys/compat/linuxkpi/common/src/linux_i2c.c
@@ -24,9 +24,6 @@
*
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
@@ -167,6 +164,116 @@ lkpi_i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
return (0);
}
+static int i2c_check_for_quirks(struct i2c_adapter *adapter,
+ struct iic_msg *msgs, uint32_t nmsgs)
+{
+ const struct i2c_adapter_quirks *quirks;
+ device_t dev;
+ int i, max_nmsgs;
+ bool check_len;
+
+ dev = adapter->dev.parent->bsddev;
+ quirks = adapter->quirks;
+ if (quirks == NULL)
+ return (0);
+
+ check_len = true;
+ max_nmsgs = quirks->max_num_msgs;
+
+ if (quirks->flags & I2C_AQ_COMB) {
+ max_nmsgs = 2;
+
+ if (nmsgs == 2) {
+ if (quirks->flags & I2C_AQ_COMB_WRITE_FIRST &&
+ msgs[0].flags & IIC_M_RD) {
+ device_printf(dev,
+ "Error: "
+ "first combined message must be write\n");
+ return (EOPNOTSUPP);
+ }
+ if (quirks->flags & I2C_AQ_COMB_READ_SECOND &&
+ !(msgs[1].flags & IIC_M_RD)) {
+ device_printf(dev,
+ "Error: "
+ "second combined message must be read\n");
+ return (EOPNOTSUPP);
+ }
+
+ if (quirks->flags & I2C_AQ_COMB_SAME_ADDR &&
+ msgs[0].slave != msgs[1].slave) {
+ device_printf(dev,
+ "Error: "
+ "combined message must be use the same "
+ "address\n");
+ return (EOPNOTSUPP);
+ }
+
+ if (quirks->max_comb_1st_msg_len &&
+ msgs[0].len > quirks->max_comb_1st_msg_len) {
+ device_printf(dev,
+ "Error: "
+ "message too long: %hu > %hu max\n",
+ msgs[0].len,
+ quirks->max_comb_1st_msg_len);
+ return (EOPNOTSUPP);
+ }
+ if (quirks->max_comb_2nd_msg_len &&
+ msgs[1].len > quirks->max_comb_2nd_msg_len) {
+ device_printf(dev,
+ "Error: "
+ "message too long: %hu > %hu max\n",
+ msgs[1].len,
+ quirks->max_comb_2nd_msg_len);
+ return (EOPNOTSUPP);
+ }
+
+ check_len = false;
+ }
+ }
+
+ if (max_nmsgs && nmsgs > max_nmsgs) {
+ device_printf(dev,
+ "Error: too many messages: %d > %d max\n",
+ nmsgs, max_nmsgs);
+ return (EOPNOTSUPP);
+ }
+
+ for (i = 0; i < nmsgs; i++) {
+ if (msgs[i].flags & IIC_M_RD) {
+ if (check_len && quirks->max_read_len &&
+ msgs[i].len > quirks->max_read_len) {
+ device_printf(dev,
+ "Error: "
+ "message %d too long: %hu > %hu max\n",
+ i, msgs[i].len, quirks->max_read_len);
+ return (EOPNOTSUPP);
+ }
+ if (quirks->flags & I2C_AQ_NO_ZERO_LEN_READ &&
+ msgs[i].len == 0) {
+ device_printf(dev,
+ "Error: message %d of length 0\n", i);
+ return (EOPNOTSUPP);
+ }
+ } else {
+ if (check_len && quirks->max_write_len &&
+ msgs[i].len > quirks->max_write_len) {
+ device_printf(dev,
+ "Message %d too long: %hu > %hu max\n",
+ i, msgs[i].len, quirks->max_write_len);
+ return (EOPNOTSUPP);
+ }
+ if (quirks->flags & I2C_AQ_NO_ZERO_LEN_WRITE &&
+ msgs[i].len == 0) {
+ device_printf(dev,
+ "Error: message %d of length 0\n", i);
+ return (EOPNOTSUPP);
+ }
+ }
+ }
+
+ return (0);
+}
+
static int
lkpi_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
{
@@ -177,13 +284,16 @@ lkpi_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
sc = device_get_softc(dev);
if (sc->adapter == NULL)
return (ENXIO);
+ ret = i2c_check_for_quirks(sc->adapter, msgs, nmsgs);
+ if (ret != 0)
+ return (ret);
linux_set_current(curthread);
linux_msgs = malloc(sizeof(struct i2c_msg) * nmsgs,
M_DEVBUF, M_WAITOK | M_ZERO);
for (i = 0; i < nmsgs; i++) {
- linux_msgs[i].addr = msgs[i].slave;
+ linux_msgs[i].addr = msgs[i].slave >> 1;
linux_msgs[i].len = msgs[i].len;
linux_msgs[i].buf = msgs[i].buf;
if (msgs[i].flags & IIC_M_RD) {
diff --git a/sys/compat/linuxkpi/common/src/linux_i2cbb.c b/sys/compat/linuxkpi/common/src/linux_i2cbb.c
index c4bfdf32e562..1ebc0b597c4d 100644
--- a/sys/compat/linuxkpi/common/src/linux_i2cbb.c
+++ b/sys/compat/linuxkpi/common/src/linux_i2cbb.c
@@ -24,9 +24,6 @@
*
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
@@ -41,6 +38,7 @@ __FBSDID("$FreeBSD$");
#include <linux/list.h>
#include <linux/pci.h>
+#include "iicbus_if.h"
#include "iicbb_if.h"
#include "lkpi_iic_if.h"
@@ -49,12 +47,35 @@ static void lkpi_iicbb_setscl(device_t dev, int val);
static int lkpi_iicbb_getscl(device_t dev);
static int lkpi_iicbb_getsda(device_t dev);
static int lkpi_iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr);
+static int lkpi_iicbb_pre_xfer(device_t dev);
+static void lkpi_iicbb_post_xfer(device_t dev);
struct lkpi_iicbb_softc {
device_t iicbb;
struct i2c_adapter *adapter;
};
+static struct sx lkpi_sx_i2cbb;
+
+static void
+lkpi_sysinit_i2cbb(void *arg __unused)
+{
+
+ sx_init(&lkpi_sx_i2cbb, "lkpi-i2cbb");
+}
+
+static void
+lkpi_sysuninit_i2cbb(void *arg __unused)
+{
+
+ sx_destroy(&lkpi_sx_i2cbb);
+}
+
+SYSINIT(lkpi_i2cbb, SI_SUB_DRIVERS, SI_ORDER_ANY,
+ lkpi_sysinit_i2cbb, NULL);
+SYSUNINIT(lkpi_i2cbb, SI_SUB_DRIVERS, SI_ORDER_ANY,
+ lkpi_sysuninit_i2cbb, NULL);
+
static int
lkpi_iicbb_probe(device_t dev)
{
@@ -93,10 +114,17 @@ static int
lkpi_iicbb_add_adapter(device_t dev, struct i2c_adapter *adapter)
{
struct lkpi_iicbb_softc *sc;
+ struct i2c_algo_bit_data *algo_data;
sc = device_get_softc(dev);
sc->adapter = adapter;
+ /*
+ * Set iicbb timing parameters deriving speed from the protocol delay.
+ */
+ algo_data = adapter->algo_data;
+ if (algo_data->udelay != 0)
+ IICBUS_RESET(sc->iicbb, 1000000 / algo_data->udelay, 0, NULL);
return (0);
}
@@ -123,6 +151,8 @@ static device_method_t lkpi_iicbb_methods[] = {
DEVMETHOD(iicbb_getsda, lkpi_iicbb_getsda),
DEVMETHOD(iicbb_getscl, lkpi_iicbb_getscl),
DEVMETHOD(iicbb_reset, lkpi_iicbb_reset),
+ DEVMETHOD(iicbb_pre_xfer, lkpi_iicbb_pre_xfer),
+ DEVMETHOD(iicbb_post_xfer, lkpi_iicbb_post_xfer),
/* lkpi_iicbb interface */
DEVMETHOD(lkpi_iic_add_adapter, lkpi_iicbb_add_adapter),
@@ -137,9 +167,10 @@ driver_t lkpi_iicbb_driver = {
sizeof(struct lkpi_iicbb_softc),
};
-DRIVER_MODULE(lkpi_iicbb, lkpi_iic, lkpi_iicbb_driver, 0, 0);
+DRIVER_MODULE(lkpi_iicbb, drmn, lkpi_iicbb_driver, 0, 0);
+DRIVER_MODULE(lkpi_iicbb, drm, lkpi_iicbb_driver, 0, 0);
DRIVER_MODULE(iicbb, lkpi_iicbb, iicbb_driver, 0, 0);
-MODULE_DEPEND(lkpi_iicbb, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
+MODULE_DEPEND(linuxkpi, iicbb, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
static void
lkpi_iicbb_setsda(device_t dev, int val)
@@ -148,10 +179,8 @@ lkpi_iicbb_setsda(device_t dev, int val)
struct i2c_algo_bit_data *algo_data;
sc = device_get_softc(dev);
- algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
+ algo_data = sc->adapter->algo_data;
algo_data->setsda(algo_data->data, val);
- cpu_spinwait();
- DELAY(algo_data->udelay);
}
static void
@@ -161,11 +190,8 @@ lkpi_iicbb_setscl(device_t dev, int val)
struct i2c_algo_bit_data *algo_data;
sc = device_get_softc(dev);
-
- algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
+ algo_data = sc->adapter->algo_data;
algo_data->setscl(algo_data->data, val);
- cpu_spinwait();
- DELAY(algo_data->udelay);
}
static int
@@ -173,27 +199,11 @@ lkpi_iicbb_getscl(device_t dev)
{
struct lkpi_iicbb_softc *sc;
struct i2c_algo_bit_data *algo_data;
- unsigned long orig_ticks;
- int ret = 0;
+ int ret;
sc = device_get_softc(dev);
-
- algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
-
- orig_ticks = ticks;
- while (!ret) {
- ret = algo_data->getscl(algo_data->data);
-
- if (ret)
- break;
-
- if (ticks > orig_ticks + algo_data->timeout)
- return (ETIMEDOUT);
-
- cpu_spinwait();
- DELAY(algo_data->udelay);
- }
- DELAY(algo_data->udelay);
+ algo_data = sc->adapter->algo_data;
+ ret = algo_data->getscl(algo_data->data);
return (ret);
}
@@ -202,16 +212,11 @@ lkpi_iicbb_getsda(device_t dev)
{
struct lkpi_iicbb_softc *sc;
struct i2c_algo_bit_data *algo_data;
- int ret = 0;
+ int ret;
sc = device_get_softc(dev);
- algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
-
- cpu_spinwait();
- DELAY(algo_data->udelay);
+ algo_data = sc->adapter->algo_data;
ret = algo_data->getsda(algo_data->data);
- cpu_spinwait();
- DELAY(algo_data->udelay);
return (ret);
}
@@ -219,15 +224,79 @@ static int
lkpi_iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
{
+ /* That doesn't seems to be supported in linux */
return (0);
}
+static int
+lkpi_iicbb_pre_xfer(device_t dev)
+{
+ struct lkpi_iicbb_softc *sc;
+ struct i2c_algo_bit_data *algo_data;
+ int rc = 0;
+
+ sc = device_get_softc(dev);
+ algo_data = sc->adapter->algo_data;
+ if (algo_data->pre_xfer != 0)
+ rc = algo_data->pre_xfer(sc->adapter);
+ return (rc);
+}
+
+static void
+lkpi_iicbb_post_xfer(device_t dev)
+{
+ struct lkpi_iicbb_softc *sc;
+ struct i2c_algo_bit_data *algo_data;
+
+ sc = device_get_softc(dev);
+ algo_data = sc->adapter->algo_data;
+ if (algo_data->post_xfer != NULL)
+ algo_data->post_xfer(sc->adapter);
+}
+
int
-lkpi_i2cbb_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int nmsgs)
+lkpi_i2cbb_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
+ int nmsgs)
{
+ struct iic_msg *bsd_msgs;
+ int ret = ENXIO;
+
+ linux_set_current(curthread);
+
+ bsd_msgs = malloc(sizeof(struct iic_msg) * nmsgs,
+ M_DEVBUF, M_WAITOK | M_ZERO);
+
+ for (int i = 0; i < nmsgs; i++) {
+ bsd_msgs[i].slave = msgs[i].addr << 1;
+ bsd_msgs[i].len = msgs[i].len;
+ bsd_msgs[i].buf = msgs[i].buf;
+ if (msgs[i].flags & I2C_M_RD)
+ bsd_msgs[i].flags |= IIC_M_RD;
+ if (msgs[i].flags & I2C_M_NOSTART)
+ bsd_msgs[i].flags |= IIC_M_NOSTART;
+ }
- /* TODO: convert from i2c_msg to iic_msg and call IICBUS_TRANFER */
- return (0);
+ for (int unit = 0; ; unit++) {
+ device_t child;
+ struct lkpi_iicbb_softc *sc;
+
+ child = device_find_child(adapter->dev.parent->bsddev,
+ "lkpi_iicbb", unit);
+ if (child == NULL)
+ break;
+ if (adapter == LKPI_IIC_GET_ADAPTER(child)) {
+ sc = device_get_softc(child);
+ ret = IICBUS_TRANSFER(sc->iicbb, bsd_msgs, nmsgs);
+ ret = iic2errno(ret);
+ break;
+ }
+ }
+
+ free(bsd_msgs, M_DEVBUF);
+
+ if (ret != 0)
+ return (-ret);
+ return (nmsgs);
}
int
@@ -239,19 +308,24 @@ lkpi_i2c_bit_add_bus(struct i2c_adapter *adapter)
if (bootverbose)
device_printf(adapter->dev.parent->bsddev,
"Adding i2c adapter %s\n", adapter->name);
+ sx_xlock(&lkpi_sx_i2cbb);
lkpi_iicbb = device_add_child(adapter->dev.parent->bsddev, "lkpi_iicbb", -1);
if (lkpi_iicbb == NULL) {
device_printf(adapter->dev.parent->bsddev, "Couldn't add lkpi_iicbb\n");
+ sx_xunlock(&lkpi_sx_i2cbb);
return (ENXIO);
}
+ bus_topo_lock();
error = bus_generic_attach(adapter->dev.parent->bsddev);
+ bus_topo_unlock();
if (error) {
device_printf(adapter->dev.parent->bsddev,
"failed to attach child: error %d\n", error);
+ sx_xunlock(&lkpi_sx_i2cbb);
return (ENXIO);
}
LKPI_IIC_ADD_ADAPTER(lkpi_iicbb, adapter);
+ sx_xunlock(&lkpi_sx_i2cbb);
return (0);
}
-
diff --git a/sys/compat/linuxkpi/common/src/linux_idr.c b/sys/compat/linuxkpi/common/src/linux_idr.c
index b5007a89966b..dc64da0d7cf5 100644
--- a/sys/compat/linuxkpi/common/src/linux_idr.c
+++ b/sys/compat/linuxkpi/common/src/linux_idr.c
@@ -27,9 +27,6 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
@@ -757,10 +754,9 @@ ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
unsigned int max;
MPASS((int)start >= 0);
- MPASS((int)end >= 0);
- if (end == 0)
- max = 0x80000000;
+ if ((int)end <= 0)
+ max = INT_MAX;
else {
MPASS(end > start);
max = end - 1;
diff --git a/sys/compat/linuxkpi/common/src/linux_interrupt.c b/sys/compat/linuxkpi/common/src/linux_interrupt.c
index f96a47137fab..378088246f21 100644
--- a/sys/compat/linuxkpi/common/src/linux_interrupt.c
+++ b/sys/compat/linuxkpi/common/src/linux_interrupt.c
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
#include <linux/device.h>
@@ -119,17 +117,20 @@ lkpi_request_irq(struct device *xdev, unsigned int irq,
struct resource *res;
struct irq_ent *irqe;
struct device *dev;
+ unsigned resflags;
int error;
int rid;
- dev = linux_pci_find_irq_dev(irq);
+ dev = lkpi_pci_find_irq_dev(irq);
if (dev == NULL)
return -ENXIO;
if (xdev != NULL && xdev != dev)
return -ENXIO;
rid = lkpi_irq_rid(dev, irq);
- res = bus_alloc_resource_any(dev->bsddev, SYS_RES_IRQ, &rid,
- flags | RF_ACTIVE);
+ resflags = RF_ACTIVE;
+ if ((flags & IRQF_SHARED) != 0)
+ resflags |= RF_SHAREABLE;
+ res = bus_alloc_resource_any(dev->bsddev, SYS_RES_IRQ, &rid, resflags);
if (res == NULL)
return (-ENXIO);
if (xdev != NULL)
@@ -169,7 +170,7 @@ lkpi_enable_irq(unsigned int irq)
struct irq_ent *irqe;
struct device *dev;
- dev = linux_pci_find_irq_dev(irq);
+ dev = lkpi_pci_find_irq_dev(irq);
if (dev == NULL)
return -EINVAL;
irqe = lkpi_irq_ent(dev, irq);
@@ -185,7 +186,7 @@ lkpi_disable_irq(unsigned int irq)
struct irq_ent *irqe;
struct device *dev;
- dev = linux_pci_find_irq_dev(irq);
+ dev = lkpi_pci_find_irq_dev(irq);
if (dev == NULL)
return;
irqe = lkpi_irq_ent(dev, irq);
@@ -202,7 +203,7 @@ lkpi_bind_irq_to_cpu(unsigned int irq, int cpu_id)
struct irq_ent *irqe;
struct device *dev;
- dev = linux_pci_find_irq_dev(irq);
+ dev = lkpi_pci_find_irq_dev(irq);
if (dev == NULL)
return (-ENOENT);
@@ -219,7 +220,7 @@ lkpi_free_irq(unsigned int irq, void *device __unused)
struct irq_ent *irqe;
struct device *dev;
- dev = linux_pci_find_irq_dev(irq);
+ dev = lkpi_pci_find_irq_dev(irq);
if (dev == NULL)
return;
irqe = lkpi_irq_ent(dev, irq);
@@ -235,7 +236,7 @@ lkpi_devm_free_irq(struct device *xdev, unsigned int irq, void *p __unused)
struct device *dev;
struct irq_ent *irqe;
- dev = linux_pci_find_irq_dev(irq);
+ dev = lkpi_pci_find_irq_dev(irq);
if (dev == NULL)
return;
if (xdev != dev)
diff --git a/sys/compat/linuxkpi/common/src/linux_kmod.c b/sys/compat/linuxkpi/common/src/linux_kmod.c
index 7fd73f0a7f45..04ae20915cb6 100644
--- a/sys/compat/linuxkpi/common/src/linux_kmod.c
+++ b/sys/compat/linuxkpi/common/src/linux_kmod.c
@@ -24,9 +24,6 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/module.h>
diff --git a/sys/compat/linuxkpi/common/src/linux_kobject.c b/sys/compat/linuxkpi/common/src/linux_kobject.c
new file mode 100644
index 000000000000..02f8b8d5b709
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_kobject.c
@@ -0,0 +1,354 @@
+/*-
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2021 Mellanox Technologies, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+
+static void kset_join(struct kobject *kobj);
+static void kset_leave(struct kobject *kobj);
+static void kset_kfree(struct kobject *kobj);
+
+struct kobject *
+kobject_create(void)
+{
+ struct kobject *kobj;
+
+ kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
+ if (kobj == NULL)
+ return (NULL);
+ kobject_init(kobj, &linux_kfree_type);
+
+ return (kobj);
+}
+
+
+int
+kobject_set_name_vargs(struct kobject *kobj, const char *fmt, va_list args)
+{
+ va_list tmp_va;
+ int len;
+ char *old;
+ char *name;
+ char dummy;
+
+ old = kobj->name;
+
+ if (old && fmt == NULL)
+ return (0);
+
+ /* compute length of string */
+ va_copy(tmp_va, args);
+ len = vsnprintf(&dummy, 0, fmt, tmp_va);
+ va_end(tmp_va);
+
+ /* account for zero termination */
+ len++;
+
+ /* check for error */
+ if (len < 1)
+ return (-EINVAL);
+
+ /* allocate memory for string */
+ name = kzalloc(len, GFP_KERNEL);
+ if (name == NULL)
+ return (-ENOMEM);
+ vsnprintf(name, len, fmt, args);
+ kobj->name = name;
+
+ /* free old string */
+ kfree(old);
+
+ /* filter new string */
+ for (; *name != '\0'; name++)
+ if (*name == '/')
+ *name = '!';
+ return (0);
+}
+
+int
+kobject_set_name(struct kobject *kobj, const char *fmt, ...)
+{
+ va_list args;
+ int error;
+
+ va_start(args, fmt);
+ error = kobject_set_name_vargs(kobj, fmt, args);
+ va_end(args);
+
+ return (error);
+}
+
+static int
+kobject_add_complete(struct kobject *kobj)
+{
+ const struct kobj_type *t;
+ int error;
+
+ if (kobj->kset != NULL) {
+ kset_join(kobj);
+ kobj->parent = &kobj->kset->kobj;
+ }
+
+ error = sysfs_create_dir(kobj);
+ if (error == 0 && kobj->ktype && kobj->ktype->default_attrs) {
+ struct attribute **attr;
+ t = kobj->ktype;
+
+ for (attr = t->default_attrs; *attr != NULL; attr++) {
+ error = sysfs_create_file(kobj, *attr);
+ if (error)
+ break;
+ }
+ if (error)
+ sysfs_remove_dir(kobj);
+ }
+
+ if (error != 0)
+ kset_leave(kobj);
+
+ return (error);
+}
+
+int
+kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...)
+{
+ va_list args;
+ int error;
+
+ kobj->parent = parent;
+
+ va_start(args, fmt);
+ error = kobject_set_name_vargs(kobj, fmt, args);
+ va_end(args);
+ if (error)
+ return (error);
+
+ return kobject_add_complete(kobj);
+}
+
+int
+kobject_init_and_add(struct kobject *kobj, const struct kobj_type *ktype,
+ struct kobject *parent, const char *fmt, ...)
+{
+ va_list args;
+ int error;
+
+ kobject_init(kobj, ktype);
+ kobj->ktype = ktype;
+ kobj->parent = parent;
+ kobj->name = NULL;
+
+ va_start(args, fmt);
+ error = kobject_set_name_vargs(kobj, fmt, args);
+ va_end(args);
+ if (error)
+ return (error);
+ return kobject_add_complete(kobj);
+}
+
+void
+linux_kobject_release(struct kref *kref)
+{
+ struct kobject *kobj;
+ char *name;
+
+ kobj = container_of(kref, struct kobject, kref);
+ sysfs_remove_dir(kobj);
+ kset_leave(kobj);
+ name = kobj->name;
+ if (kobj->ktype && kobj->ktype->release)
+ kobj->ktype->release(kobj);
+ kfree(name);
+}
+
+static void
+linux_kobject_kfree(struct kobject *kobj)
+{
+ kfree(kobj);
+}
+
+const struct kobj_type linux_kfree_type = {
+ .release = linux_kobject_kfree
+};
+
+void
+linux_kobject_kfree_name(struct kobject *kobj)
+{
+ if (kobj) {
+ kfree(kobj->name);
+ }
+}
+
+static ssize_t
+lkpi_kobj_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+ struct kobj_attribute *ka =
+ container_of(attr, struct kobj_attribute, attr);
+
+ if (ka->show == NULL)
+ return (-EIO);
+
+ return (ka->show(kobj, ka, buf));
+}
+
+static ssize_t
+lkpi_kobj_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ struct kobj_attribute *ka =
+ container_of(attr, struct kobj_attribute, attr);
+
+ if (ka->store == NULL)
+ return (-EIO);
+
+ return (ka->store(kobj, ka, buf, count));
+}
+
+const struct sysfs_ops kobj_sysfs_ops = {
+ .show = lkpi_kobj_attr_show,
+ .store = lkpi_kobj_attr_store,
+};
+
+const struct kobj_type linux_kset_kfree_type = {
+ .release = kset_kfree
+};
+
+static struct kset *
+kset_create(const char *name,
+ const struct kset_uevent_ops *uevent_ops,
+ struct kobject *parent_kobj)
+{
+ struct kset *kset;
+
+ kset = kzalloc(sizeof(*kset), GFP_KERNEL);
+ if (kset == NULL)
+ return (NULL);
+
+ kset->uevent_ops = uevent_ops;
+
+ kobject_set_name(&kset->kobj, "%s", name);
+ kset->kobj.parent = parent_kobj;
+ kset->kobj.kset = NULL;
+
+ return (kset);
+}
+
+void
+kset_init(struct kset *kset)
+{
+ kobject_init(&kset->kobj, &linux_kset_kfree_type);
+ INIT_LIST_HEAD(&kset->list);
+ spin_lock_init(&kset->list_lock);
+}
+
+static void
+kset_join(struct kobject *kobj)
+{
+ struct kset *kset;
+
+ kset = kobj->kset;
+ if (kset == NULL)
+ return;
+
+ kset_get(kobj->kset);
+
+ spin_lock(&kset->list_lock);
+ list_add_tail(&kobj->entry, &kset->list);
+ spin_unlock(&kset->list_lock);
+}
+
+static void
+kset_leave(struct kobject *kobj)
+{
+ struct kset *kset;
+
+ kset = kobj->kset;
+ if (kset == NULL)
+ return;
+
+ spin_lock(&kset->list_lock);
+ list_del_init(&kobj->entry);
+ spin_unlock(&kset->list_lock);
+
+ kset_put(kobj->kset);
+}
+
+struct kset *
+kset_create_and_add(const char *name, const struct kset_uevent_ops *u,
+ struct kobject *parent_kobj)
+{
+ int ret;
+ struct kset *kset;
+
+ kset = kset_create(name, u, parent_kobj);
+ if (kset == NULL)
+ return (NULL);
+
+ ret = kset_register(kset);
+ if (ret != 0) {
+ linux_kobject_kfree_name(&kset->kobj);
+ kfree(kset);
+ return (NULL);
+ }
+
+ return (kset);
+}
+
+int
+kset_register(struct kset *kset)
+{
+ int ret;
+
+ if (kset == NULL)
+ return -EINVAL;
+
+ kset_init(kset);
+ ret = kobject_add_complete(&kset->kobj);
+
+ return ret;
+}
+
+void
+kset_unregister(struct kset *kset)
+{
+ if (kset == NULL)
+ return;
+
+ kobject_del(&kset->kobj);
+ kobject_put(&kset->kobj);
+}
+
+static void
+kset_kfree(struct kobject *kobj)
+{
+ struct kset *kset;
+
+ kset = to_kset(kobj);
+ kfree(kset);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_kthread.c b/sys/compat/linuxkpi/common/src/linux_kthread.c
index 19afad6872c3..2fba700fa283 100644
--- a/sys/compat/linuxkpi/common/src/linux_kthread.c
+++ b/sys/compat/linuxkpi/common/src/linux_kthread.c
@@ -25,8 +25,6 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <linux/compat.h>
#include <linux/kthread.h>
#include <linux/sched.h>
diff --git a/sys/compat/linuxkpi/common/src/linux_lock.c b/sys/compat/linuxkpi/common/src/linux_lock.c
index b04a7738d036..3cebfc6ae3bb 100644
--- a/sys/compat/linuxkpi/common/src/linux_lock.c
+++ b/sys/compat/linuxkpi/common/src/linux_lock.c
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
#include <sys/queue.h>
@@ -160,6 +158,19 @@ linux_mutex_lock_interruptible(mutex_t *m)
}
int
+linux_down_read_killable(struct rw_semaphore *rw)
+{
+ int error;
+
+ error = -sx_slock_sig(&rw->sx);
+ if (error != 0) {
+ linux_schedule_save_interrupt_value(current, error);
+ error = -EINTR;
+ }
+ return (error);
+}
+
+int
linux_down_write_killable(struct rw_semaphore *rw)
{
int error;
diff --git a/sys/compat/linuxkpi/common/src/linux_mhi.c b/sys/compat/linuxkpi/common/src/linux_mhi.c
new file mode 100644
index 000000000000..5d3c391f91ab
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_mhi.c
@@ -0,0 +1,89 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Bjoern A. Zeeb
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+#include <linux/kernel.h> /* pr_debug */
+#include <linux/mhi.h>
+
+static MALLOC_DEFINE(M_LKPIMHI, "lkpimhi", "LinuxKPI MHI compat");
+
+struct mhi_controller *
+linuxkpi_mhi_alloc_controller(void)
+{
+ struct mhi_controller *mhi_ctrl;
+
+ mhi_ctrl = malloc(sizeof(*mhi_ctrl), M_LKPIMHI, M_NOWAIT | M_ZERO);
+
+ return (mhi_ctrl);
+}
+
+void
+linuxkpi_mhi_free_controller(struct mhi_controller *mhi_ctrl)
+{
+
+ /* What else do we need to check that it is gone? */
+ free(mhi_ctrl, M_LKPIMHI);
+}
+
+int
+linuxkpi_mhi_register_controller(struct mhi_controller *mhi_ctrl,
+ const struct mhi_controller_config *cfg)
+{
+
+ if (mhi_ctrl == NULL || cfg == NULL)
+ return (-EINVAL);
+
+#define CHECK_FIELD(_f) \
+ if (!mhi_ctrl->_f) \
+ return (-ENXIO);
+ CHECK_FIELD(cntrl_dev);
+ CHECK_FIELD(regs);
+ CHECK_FIELD(irq);
+ CHECK_FIELD(reg_len);
+ CHECK_FIELD(nr_irqs);
+
+ CHECK_FIELD(runtime_get);
+ CHECK_FIELD(runtime_put);
+ CHECK_FIELD(status_cb);
+ CHECK_FIELD(read_reg);
+ CHECK_FIELD(write_reg);
+#undef CHECK_FIELD
+
+ printf("%s: XXX-BZ TODO\n", __func__);
+ return (0);
+}
+
+void
+linuxkpi_mhi_unregister_controller(struct mhi_controller *mhi_ctrl)
+{
+
+ pr_debug("%s: TODO\n", __func__);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_netdev.c b/sys/compat/linuxkpi/common/src/linux_netdev.c
index 27e29b40ea44..fe00e929c168 100644
--- a/sys/compat/linuxkpi/common/src/linux_netdev.c
+++ b/sys/compat/linuxkpi/common/src/linux_netdev.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2021 The FreeBSD Foundation
+ * Copyright (c) 2022 Bjoern A. Zeeb
*
* This software was developed by Björn Zeeb under sponsorship from
* the FreeBSD Foundation.
@@ -26,9 +27,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/types.h>
#include <sys/kernel.h>
@@ -48,14 +46,6 @@ MALLOC_DEFINE(M_NETDEV, "lkpindev", "Linux KPI netdevice compat");
#define NAPI_UNLOCK(_ndev) mtx_unlock(&(_ndev)->napi_mtx)
/* -------------------------------------------------------------------------- */
-/* Do not schedule new things while we are waiting to clear things. */
-#define LKPI_NAPI_FLAG_DISABLE_PENDING 0
-/* To synchronise that only one poll is ever running. */
-#define LKPI_NAPI_FLAG_IS_SCHEDULED 1
-/* If trying to schedule while poll is running. Need to re-schedule. */
-#define LKPI_NAPI_FLAG_LOST_RACE_TRY_AGAIN 2
-/* When shutting down forcefully prevent anything from running task/poll. */
-#define LKPI_NAPI_FLAG_SHUTDOWN 3
#define LKPI_NAPI_FLAGS \
"\20\1DISABLE_PENDING\2IS_SCHEDULED\3LOST_RACE_TRY_AGAIN"
@@ -74,17 +64,17 @@ SYSCTL_INT(_compat_linuxkpi, OID_AUTO, debug_napi, CTLFLAG_RWTUN,
#define NAPI_TRACE(_n) if (debug_napi & DNAPI_TRACE) \
printf("NAPI_TRACE %s:%d %u %p (%#jx %b)\n", __func__, __LINE__, \
- (unsigned int)ticks, _n, (uintmax_t)(_n)->_flags, \
- (int)(_n)->_flags, LKPI_NAPI_FLAGS)
+ (unsigned int)ticks, _n, (uintmax_t)(_n)->state, \
+ (int)(_n)->state, LKPI_NAPI_FLAGS)
#define NAPI_TRACE2D(_n, _d) if (debug_napi & DNAPI_TRACE) \
printf("NAPI_TRACE %s:%d %u %p (%#jx %b) %d\n", __func__, __LINE__, \
- (unsigned int)ticks, _n, (uintmax_t)(_n)->_flags, \
- (int)(_n)->_flags, LKPI_NAPI_FLAGS, _d)
+ (unsigned int)ticks, _n, (uintmax_t)(_n)->state, \
+ (int)(_n)->state, LKPI_NAPI_FLAGS, _d)
#define NAPI_TRACE_TASK(_n, _p, _c) if (debug_napi & DNAPI_TRACE_TASK) \
printf("NAPI_TRACE %s:%d %u %p (%#jx %b) pending %d count %d " \
"rx_count %d\n", __func__, __LINE__, \
- (unsigned int)ticks, _n, (uintmax_t)(_n)->_flags, \
- (int)(_n)->_flags, LKPI_NAPI_FLAGS, _p, _c, (_n)->rx_count)
+ (unsigned int)ticks, _n, (uintmax_t)(_n)->state, \
+ (int)(_n)->state, LKPI_NAPI_FLAGS, _p, _c, (_n)->rx_count)
#define NAPI_TODO() if (debug_napi & DNAPI_TODO) \
printf("NAPI_TODO %s:%d %d\n", __func__, __LINE__, ticks)
#define NAPI_IMPROVE() if (debug_napi & DNAPI_IMPROVE) \
@@ -118,7 +108,7 @@ linuxkpi_napi_schedule_prep(struct napi_struct *napi)
/* Can can only update/return if all flags agree. */
do {
- old = READ_ONCE(napi->_flags);
+ old = READ_ONCE(napi->state);
/* If we are stopping, cannot run again. */
if ((old & BIT(LKPI_NAPI_FLAG_DISABLE_PENDING)) != 0) {
@@ -132,7 +122,7 @@ linuxkpi_napi_schedule_prep(struct napi_struct *napi)
new |= BIT(LKPI_NAPI_FLAG_LOST_RACE_TRY_AGAIN);
new |= BIT(LKPI_NAPI_FLAG_IS_SCHEDULED);
- } while (atomic_cmpset_acq_long(&napi->_flags, old, new) == 0);
+ } while (atomic_cmpset_acq_long(&napi->state, old, new) == 0);
NAPI_TRACE(napi);
return ((old & BIT(LKPI_NAPI_FLAG_IS_SCHEDULED)) == 0);
@@ -157,14 +147,14 @@ again:
goto again;
/* Bandaid for now. */
- if (test_bit(LKPI_NAPI_FLAG_LOST_RACE_TRY_AGAIN, &napi->_flags))
+ if (test_bit(LKPI_NAPI_FLAG_LOST_RACE_TRY_AGAIN, &napi->state))
goto again;
do {
- new = old = READ_ONCE(napi->_flags);
+ new = old = READ_ONCE(napi->state);
clear_bit(LKPI_NAPI_FLAG_LOST_RACE_TRY_AGAIN, &new);
clear_bit(LKPI_NAPI_FLAG_IS_SCHEDULED, &new);
- } while (atomic_cmpset_acq_long(&napi->_flags, old, new) == 0);
+ } while (atomic_cmpset_acq_long(&napi->state, old, new) == 0);
NAPI_TRACE2D(napi, rc);
}
@@ -175,9 +165,9 @@ linuxkpi___napi_schedule(struct napi_struct *napi)
int rc;
NAPI_TRACE(napi);
- if (test_bit(LKPI_NAPI_FLAG_SHUTDOWN, &napi->_flags)) {
- clear_bit(LKPI_NAPI_FLAG_LOST_RACE_TRY_AGAIN, &napi->_flags);
- clear_bit(LKPI_NAPI_FLAG_IS_SCHEDULED, &napi->_flags);
+ if (test_bit(LKPI_NAPI_FLAG_SHUTDOWN, &napi->state)) {
+ clear_bit(LKPI_NAPI_FLAG_LOST_RACE_TRY_AGAIN, &napi->state);
+ clear_bit(LKPI_NAPI_FLAG_IS_SCHEDULED, &napi->state);
NAPI_TRACE(napi);
return;
}
@@ -194,7 +184,7 @@ linuxkpi___napi_schedule(struct napi_struct *napi)
}
}
-void
+bool
linuxkpi_napi_schedule(struct napi_struct *napi)
{
@@ -204,8 +194,12 @@ linuxkpi_napi_schedule(struct napi_struct *napi)
* iwlwifi calls this sequence instead of napi_schedule()
* to be able to test the prep result.
*/
- if (napi_schedule_prep(napi))
+ if (napi_schedule_prep(napi)) {
__napi_schedule(napi);
+ return (true);
+ }
+
+ return (false);
}
void
@@ -229,7 +223,7 @@ linuxkpi_napi_complete_done(struct napi_struct *napi, int ret)
return (true);
do {
- new = old = READ_ONCE(napi->_flags);
+ new = old = READ_ONCE(napi->state);
/*
* If we lost a race before, we need to re-schedule.
@@ -238,7 +232,7 @@ linuxkpi_napi_complete_done(struct napi_struct *napi, int ret)
if (!test_bit(LKPI_NAPI_FLAG_LOST_RACE_TRY_AGAIN, &old))
clear_bit(LKPI_NAPI_FLAG_IS_SCHEDULED, &new);
clear_bit(LKPI_NAPI_FLAG_LOST_RACE_TRY_AGAIN, &new);
- } while (atomic_cmpset_acq_long(&napi->_flags, old, new) == 0);
+ } while (atomic_cmpset_acq_long(&napi->state, old, new) == 0);
NAPI_TRACE(napi);
@@ -263,10 +257,10 @@ void
linuxkpi_napi_disable(struct napi_struct *napi)
{
NAPI_TRACE(napi);
- set_bit(LKPI_NAPI_FLAG_DISABLE_PENDING, &napi->_flags);
- while (test_bit(LKPI_NAPI_FLAG_IS_SCHEDULED, &napi->_flags))
+ set_bit(LKPI_NAPI_FLAG_DISABLE_PENDING, &napi->state);
+ while (test_bit(LKPI_NAPI_FLAG_IS_SCHEDULED, &napi->state))
pause_sbt("napidslp", SBT_1MS, 0, C_HARDCLOCK);
- clear_bit(LKPI_NAPI_FLAG_DISABLE_PENDING, &napi->_flags);
+ clear_bit(LKPI_NAPI_FLAG_DISABLE_PENDING, &napi->state);
}
void
@@ -274,11 +268,11 @@ linuxkpi_napi_enable(struct napi_struct *napi)
{
NAPI_TRACE(napi);
- KASSERT(!test_bit(LKPI_NAPI_FLAG_IS_SCHEDULED, &napi->_flags),
+ KASSERT(!test_bit(LKPI_NAPI_FLAG_IS_SCHEDULED, &napi->state),
("%s: enabling napi %p already scheduled\n", __func__, napi));
mb();
/* Let us be scheduled. */
- clear_bit(LKPI_NAPI_FLAG_IS_SCHEDULED, &napi->_flags);
+ clear_bit(LKPI_NAPI_FLAG_IS_SCHEDULED, &napi->state);
}
void
@@ -287,7 +281,7 @@ linuxkpi_napi_synchronize(struct napi_struct *napi)
NAPI_TRACE(napi);
#if defined(SMP)
/* Check & sleep while a napi is scheduled. */
- while (test_bit(LKPI_NAPI_FLAG_IS_SCHEDULED, &napi->_flags))
+ while (test_bit(LKPI_NAPI_FLAG_IS_SCHEDULED, &napi->state))
pause_sbt("napisslp", SBT_1MS, 0, C_HARDCLOCK);
#else
mb();
@@ -333,12 +327,12 @@ lkpi_napi_task(void *ctx, int pending)
void
linuxkpi_netif_napi_add(struct net_device *ndev, struct napi_struct *napi,
- int(*napi_poll)(struct napi_struct *, int), int budget)
+ int(*napi_poll)(struct napi_struct *, int))
{
napi->dev = ndev;
napi->poll = napi_poll;
- napi->budget = budget;
+ napi->budget = NAPI_POLL_WEIGHT;
INIT_LIST_HEAD(&napi->rx_list);
napi->rx_count = 0;
@@ -350,7 +344,7 @@ linuxkpi_netif_napi_add(struct net_device *ndev, struct napi_struct *napi,
NAPI_UNLOCK(ndev);
/* Anything else to do on the ndev? */
- clear_bit(LKPI_NAPI_FLAG_SHUTDOWN, &napi->_flags);
+ clear_bit(LKPI_NAPI_FLAG_SHUTDOWN, &napi->state);
}
static void
@@ -361,7 +355,7 @@ lkpi_netif_napi_del_locked(struct napi_struct *napi)
ndev = napi->dev;
NAPI_LOCK_ASSERT(ndev);
- set_bit(LKPI_NAPI_FLAG_SHUTDOWN, &napi->_flags);
+ set_bit(LKPI_NAPI_FLAG_SHUTDOWN, &napi->state);
TAILQ_REMOVE(&ndev->napi_head, napi, entry);
while (taskqueue_cancel(ndev->napi_tq, &napi->napi_task, NULL) != 0)
taskqueue_drain(ndev->napi_tq, &napi->napi_task);
diff --git a/sys/compat/linuxkpi/common/src/linux_page.c b/sys/compat/linuxkpi/common/src/linux_page.c
index df4a124cf3e2..8b78a3739f25 100644
--- a/sys/compat/linuxkpi/common/src/linux_page.c
+++ b/sys/compat/linuxkpi/common/src/linux_page.c
@@ -26,9 +26,6 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
@@ -67,6 +64,7 @@ __FBSDID("$FreeBSD$");
#include <linux/kernel.h>
#include <linux/idr.h>
#include <linux/io.h>
+#include <linux/io-mapping.h>
#ifdef __i386__
DEFINE_IDR(mtrr_idr);
@@ -78,7 +76,9 @@ void
si_meminfo(struct sysinfo *si)
{
si->totalram = physmem;
+ si->freeram = vm_free_count();
si->totalhigh = 0;
+ si->freehigh = 0;
si->mem_unit = PAGE_SIZE;
}
@@ -88,17 +88,17 @@ linux_page_address(struct page *page)
if (page->object != kernel_object) {
return (PMAP_HAS_DMAP ?
- ((void *)(uintptr_t)PHYS_TO_DMAP(VM_PAGE_TO_PHYS(page))) :
+ ((void *)(uintptr_t)PHYS_TO_DMAP(page_to_phys(page))) :
NULL);
}
return ((void *)(uintptr_t)(VM_MIN_KERNEL_ADDRESS +
IDX_TO_OFF(page->pindex)));
}
-vm_page_t
+struct page *
linux_alloc_pages(gfp_t flags, unsigned int order)
{
- vm_page_t page;
+ struct page *page;
if (PMAP_HAS_DMAP) {
unsigned long npages = 1UL << order;
@@ -118,10 +118,12 @@ linux_alloc_pages(gfp_t flags, unsigned int order)
PAGE_SIZE, 0, VM_MEMATTR_DEFAULT);
if (page == NULL) {
if (flags & M_WAITOK) {
- if (!vm_page_reclaim_contig(req,
- npages, 0, pmax, PAGE_SIZE, 0)) {
+ int err = vm_page_reclaim_contig(req,
+ npages, 0, pmax, PAGE_SIZE, 0);
+ if (err == ENOMEM)
vm_wait(NULL);
- }
+ else if (err != 0)
+ return (NULL);
flags &= ~M_WAITOK;
goto retry;
}
@@ -135,7 +137,7 @@ linux_alloc_pages(gfp_t flags, unsigned int order)
if (vaddr == 0)
return (NULL);
- page = PHYS_TO_VM_PAGE(vtophys((void *)vaddr));
+ page = virt_to_page((void *)vaddr);
KASSERT(vaddr == (vm_offset_t)page_address(page),
("Page address mismatch"));
@@ -144,8 +146,16 @@ linux_alloc_pages(gfp_t flags, unsigned int order)
return (page);
}
+static void
+_linux_free_kmem(vm_offset_t addr, unsigned int order)
+{
+ size_t size = ((size_t)PAGE_SIZE) << order;
+
+ kmem_free((void *)addr, size);
+}
+
void
-linux_free_pages(vm_page_t page, unsigned int order)
+linux_free_pages(struct page *page, unsigned int order)
{
if (PMAP_HAS_DMAP) {
unsigned long npages = 1UL << order;
@@ -162,7 +172,7 @@ linux_free_pages(vm_page_t page, unsigned int order)
vaddr = (vm_offset_t)page_address(page);
- linux_free_kmem(vaddr, order);
+ _linux_free_kmem(vaddr, order);
}
}
@@ -170,7 +180,7 @@ vm_offset_t
linux_alloc_kmem(gfp_t flags, unsigned int order)
{
size_t size = ((size_t)PAGE_SIZE) << order;
- vm_offset_t addr;
+ void *addr;
if ((flags & GFP_DMA32) == 0) {
addr = kmem_malloc(size, flags & GFP_NATIVE_MASK);
@@ -178,15 +188,23 @@ linux_alloc_kmem(gfp_t flags, unsigned int order)
addr = kmem_alloc_contig(size, flags & GFP_NATIVE_MASK, 0,
BUS_SPACE_MAXADDR_32BIT, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT);
}
- return (addr);
+ return ((vm_offset_t)addr);
}
void
linux_free_kmem(vm_offset_t addr, unsigned int order)
{
- size_t size = ((size_t)PAGE_SIZE) << order;
+ KASSERT((addr & ~PAGE_MASK) == 0,
+ ("%s: addr %p is not page aligned", __func__, (void *)addr));
- kmem_free(addr, size);
+ if (addr >= VM_MIN_KERNEL_ADDRESS && addr < VM_MAX_KERNEL_ADDRESS) {
+ _linux_free_kmem(addr, order);
+ } else {
+ vm_page_t page;
+
+ page = PHYS_TO_VM_PAGE(DMAP_TO_PHYS(addr));
+ linux_free_pages(page, order);
+ }
}
static int
@@ -248,7 +266,7 @@ __get_user_pages_fast(unsigned long start, int nr_pages, int write,
long
get_user_pages_remote(struct task_struct *task, struct mm_struct *mm,
- unsigned long start, unsigned long nr_pages, int gup_flags,
+ unsigned long start, unsigned long nr_pages, unsigned int gup_flags,
struct page **pages, struct vm_area_struct **vmas)
{
vm_map_t map;
@@ -259,8 +277,8 @@ get_user_pages_remote(struct task_struct *task, struct mm_struct *mm,
}
long
-get_user_pages(unsigned long start, unsigned long nr_pages, int gup_flags,
- struct page **pages, struct vm_area_struct **vmas)
+get_user_pages(unsigned long start, unsigned long nr_pages,
+ unsigned int gup_flags, struct page **pages, struct vm_area_struct **vmas)
{
vm_map_t map;
@@ -334,6 +352,63 @@ retry:
return (VM_FAULT_NOPAGE);
}
+int
+lkpi_remap_pfn_range(struct vm_area_struct *vma, unsigned long start_addr,
+ unsigned long start_pfn, unsigned long size, pgprot_t prot)
+{
+ vm_object_t vm_obj;
+ unsigned long addr, pfn;
+ int err = 0;
+
+ vm_obj = vma->vm_obj;
+
+ VM_OBJECT_WLOCK(vm_obj);
+ for (addr = start_addr, pfn = start_pfn;
+ addr < start_addr + size;
+ addr += PAGE_SIZE) {
+ vm_fault_t ret;
+retry:
+ ret = lkpi_vmf_insert_pfn_prot_locked(vma, addr, pfn, prot);
+
+ if ((ret & VM_FAULT_OOM) != 0) {
+ VM_OBJECT_WUNLOCK(vm_obj);
+ vm_wait(NULL);
+ VM_OBJECT_WLOCK(vm_obj);
+ goto retry;
+ }
+
+ if ((ret & VM_FAULT_ERROR) != 0) {
+ err = -EFAULT;
+ break;
+ }
+
+ pfn++;
+ }
+ VM_OBJECT_WUNLOCK(vm_obj);
+
+ if (unlikely(err)) {
+ zap_vma_ptes(vma, start_addr,
+ (pfn - start_pfn) << PAGE_SHIFT);
+ return (err);
+ }
+
+ return (0);
+}
+
+int
+lkpi_io_mapping_map_user(struct io_mapping *iomap,
+ struct vm_area_struct *vma, unsigned long addr,
+ unsigned long pfn, unsigned long size)
+{
+ pgprot_t prot;
+ int ret;
+
+ prot = cachemode2protval(iomap->attr);
+ ret = lkpi_remap_pfn_range(vma, addr, pfn, size, prot);
+
+ return (ret);
+}
+
/*
* Although FreeBSD version of unmap_mapping_range has semantics and types of
* parameters compatible with Linux version, the values passed in are different
@@ -429,3 +504,50 @@ lkpi_arch_phys_wc_del(int reg)
free(mrdesc, M_LKMTRR);
#endif
}
+
+/*
+ * This is a highly simplified version of the Linux page_frag_cache.
+ * We only support up-to 1 single page as fragment size and we will
+ * always return a full page. This may be wasteful on small objects
+ * but the only known consumer (mt76) is either asking for a half-page
+ * or a full page. If this was to become a problem we can implement
+ * a more elaborate version.
+ */
+void *
+linuxkpi_page_frag_alloc(struct page_frag_cache *pfc,
+ size_t fragsz, gfp_t gfp)
+{
+ vm_page_t pages;
+
+ if (fragsz == 0)
+ return (NULL);
+
+ KASSERT(fragsz <= PAGE_SIZE, ("%s: fragsz %zu > PAGE_SIZE not yet "
+ "supported", __func__, fragsz));
+
+ pages = alloc_pages(gfp, flsl(howmany(fragsz, PAGE_SIZE) - 1));
+ if (pages == NULL)
+ return (NULL);
+ pfc->va = linux_page_address(pages);
+
+ /* Passed in as "count" to __page_frag_cache_drain(). Unused by us. */
+ pfc->pagecnt_bias = 0;
+
+ return (pfc->va);
+}
+
+void
+linuxkpi_page_frag_free(void *addr)
+{
+ vm_page_t page;
+
+ page = virt_to_page(addr);
+ linux_free_pages(page, 0);
+}
+
+void
+linuxkpi__page_frag_cache_drain(struct page *page, size_t count __unused)
+{
+
+ linux_free_pages(page, 0);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_pci.c b/sys/compat/linuxkpi/common/src/linux_pci.c
index 8a2667ae33c5..825ebe319b1a 100644
--- a/sys/compat/linuxkpi/common/src/linux_pci.c
+++ b/sys/compat/linuxkpi/common/src/linux_pci.c
@@ -28,9 +28,6 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
@@ -44,11 +41,14 @@ __FBSDID("$FreeBSD$");
#include <sys/filio.h>
#include <sys/pciio.h>
#include <sys/pctrie.h>
+#include <sys/rman.h>
#include <sys/rwlock.h>
#include <vm/vm.h>
#include <vm/pmap.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
#include <machine/stdarg.h>
#include <dev/pci/pcivar.h>
@@ -98,6 +98,7 @@ static pci_iov_add_vf_t linux_pci_iov_add_vf;
static int linux_backlight_get_status(device_t dev, struct backlight_props *props);
static int linux_backlight_update_status(device_t dev, struct backlight_props *props);
static int linux_backlight_get_info(device_t dev, struct backlight_info *info);
+static void lkpi_pcim_iomap_table_release(struct device *, void *);
static device_method_t pci_methods[] = {
DEVMETHOD(device_probe, linux_pci_probe),
@@ -117,6 +118,22 @@ static device_method_t pci_methods[] = {
DEVMETHOD_END
};
+const char *pci_power_names[] = {
+ "UNKNOWN", "D0", "D1", "D2", "D3hot", "D3cold"
+};
+
+/* We need some meta-struct to keep track of these for devres. */
+struct pci_devres {
+ bool enable_io;
+ /* PCIR_MAX_BAR_0 + 1 = 6 => BIT(0..5). */
+ uint8_t region_mask;
+ struct resource *region_table[PCIR_MAX_BAR_0 + 1]; /* Not needed. */
+};
+struct pcim_iomap_devres {
+ void *mmio_table[PCIR_MAX_BAR_0 + 1];
+ struct resource *res_table[PCIR_MAX_BAR_0 + 1];
+};
+
struct linux_dma_priv {
uint64_t dma_mask;
bus_dma_tag_t dmat;
@@ -267,6 +284,23 @@ linux_pci_find(device_t dev, const struct pci_device_id **idp)
return (NULL);
}
+struct pci_dev *
+lkpi_pci_get_device(uint16_t vendor, uint16_t device, struct pci_dev *odev)
+{
+ struct pci_dev *pdev;
+
+ KASSERT(odev == NULL, ("%s: odev argument not yet supported\n", __func__));
+
+ spin_lock(&pci_lock);
+ list_for_each_entry(pdev, &pci_devices, links) {
+ if (pdev->vendor == vendor && pdev->device == device)
+ break;
+ }
+ spin_unlock(&pci_lock);
+
+ return (pdev);
+}
+
static void
lkpi_pci_dev_release(struct device *dev)
{
@@ -286,6 +320,9 @@ lkpifill_pci_dev(device_t dev, struct pci_dev *pdev)
pdev->subsystem_device = pci_get_subdevice(dev);
pdev->class = pci_get_class(dev);
pdev->revision = pci_get_revid(dev);
+ pdev->path_name = kasprintf(GFP_KERNEL, "%04d:%02d:%02d.%d",
+ pci_get_domain(dev), pci_get_bus(dev), pci_get_slot(dev),
+ pci_get_function(dev));
pdev->bus = malloc(sizeof(*pdev->bus), M_DEVBUF, M_WAITOK | M_ZERO);
/*
* This should be the upstream bridge; pci_upstream_bridge()
@@ -299,6 +336,11 @@ lkpifill_pci_dev(device_t dev, struct pci_dev *pdev)
pdev->dev.parent = &linux_root_device;
pdev->dev.release = lkpi_pci_dev_release;
INIT_LIST_HEAD(&pdev->dev.irqents);
+
+ if (pci_msi_count(dev) > 0)
+ pdev->msi_desc = malloc(pci_msi_count(dev) *
+ sizeof(*pdev->msi_desc), M_DEVBUF, M_WAITOK | M_ZERO);
+
kobject_init(&pdev->dev.kobj, &linux_dev_ktype);
kobject_set_name(&pdev->dev.kobj, device_get_nameunit(dev));
kobject_add(&pdev->dev.kobj, &linux_root_device.kobj,
@@ -311,6 +353,7 @@ static void
lkpinew_pci_dev_release(struct device *dev)
{
struct pci_dev *pdev;
+ int i;
pdev = to_pci_dev(dev);
if (pdev->root != NULL)
@@ -318,6 +361,12 @@ lkpinew_pci_dev_release(struct device *dev)
if (pdev->bus->self != pdev)
pci_dev_put(pdev->bus->self);
free(pdev->bus, M_DEVBUF);
+ if (pdev->msi_desc != NULL) {
+ for (i = pci_msi_count(pdev->dev.bsddev) - 1; i >= 0; i--)
+ free(pdev->msi_desc[i], M_DEVBUF);
+ free(pdev->msi_desc, M_DEVBUF);
+ }
+ kfree(pdev->path_name);
free(pdev, M_DEVBUF);
}
@@ -401,6 +450,41 @@ linux_pci_attach(device_t dev)
return (linux_pci_attach_device(dev, pdrv, id, pdev));
}
+static struct resource_list_entry *
+linux_pci_reserve_bar(struct pci_dev *pdev, struct resource_list *rl,
+ int type, int rid)
+{
+ device_t dev;
+ struct resource *res;
+
+ KASSERT(type == SYS_RES_IOPORT || type == SYS_RES_MEMORY,
+ ("trying to reserve non-BAR type %d", type));
+
+ dev = pdev->pdrv != NULL && pdev->pdrv->isdrm ?
+ device_get_parent(pdev->dev.bsddev) : pdev->dev.bsddev;
+ res = pci_reserve_map(device_get_parent(dev), dev, type, &rid, 0, ~0,
+ 1, 1, 0);
+ if (res == NULL)
+ return (NULL);
+ return (resource_list_find(rl, type, rid));
+}
+
+static struct resource_list_entry *
+linux_pci_get_rle(struct pci_dev *pdev, int type, int rid, bool reserve_bar)
+{
+ struct pci_devinfo *dinfo;
+ struct resource_list *rl;
+ struct resource_list_entry *rle;
+
+ dinfo = device_get_ivars(pdev->dev.bsddev);
+ rl = &dinfo->resources;
+ rle = resource_list_find(rl, type, rid);
+ /* Reserve resources for this BAR if needed. */
+ if (rle == NULL && reserve_bar)
+ rle = linux_pci_reserve_bar(pdev, rl, type, rid);
+ return (rle);
+}
+
int
linux_pci_attach_device(device_t dev, struct pci_driver *pdrv,
const struct pci_device_id *id, struct pci_dev *pdev)
@@ -441,6 +525,7 @@ linux_pci_attach_device(device_t dev, struct pci_driver *pdrv,
goto out_dma_init;
TAILQ_INIT(&pdev->mmio);
+ spin_lock_init(&pdev->pcie_cap_lock);
spin_lock(&pci_lock);
list_add(&pdev->links, &pci_devices);
@@ -455,6 +540,7 @@ linux_pci_attach_device(device_t dev, struct pci_driver *pdrv,
out_probe:
free(pdev->bus, M_DEVBUF);
+ spin_lock_destroy(&pdev->pcie_cap_lock);
linux_pdev_dma_uninit(pdev);
out_dma_init:
spin_lock(&pci_lock);
@@ -495,6 +581,7 @@ linux_pci_detach_device(struct pci_dev *pdev)
spin_lock(&pci_lock);
list_del(&pdev->links);
spin_unlock(&pci_lock);
+ spin_lock_destroy(&pdev->pcie_cap_lock);
put_device(&pdev->dev);
return (0);
@@ -509,7 +596,7 @@ lkpi_pci_disable_dev(struct device *dev)
return (0);
}
-struct pci_devres *
+static struct pci_devres *
lkpi_pci_devres_get_alloc(struct pci_dev *pdev)
{
struct pci_devres *dr;
@@ -525,6 +612,15 @@ lkpi_pci_devres_get_alloc(struct pci_dev *pdev)
return (dr);
}
+static struct pci_devres *
+lkpi_pci_devres_find(struct pci_dev *pdev)
+{
+ if (!pdev->managed)
+ return (NULL);
+
+ return (lkpi_pci_devres_get_alloc(pdev));
+}
+
void
lkpi_pci_devres_release(struct device *dev, void *p)
{
@@ -553,7 +649,32 @@ lkpi_pci_devres_release(struct device *dev, void *p)
}
}
-struct pcim_iomap_devres *
+int
+linuxkpi_pcim_enable_device(struct pci_dev *pdev)
+{
+ struct pci_devres *dr;
+ int error;
+
+ /* Here we cannot run through the pdev->managed check. */
+ dr = lkpi_pci_devres_get_alloc(pdev);
+ if (dr == NULL)
+ return (-ENOMEM);
+
+ /* If resources were enabled before do not do it again. */
+ if (dr->enable_io)
+ return (0);
+
+ error = pci_enable_device(pdev);
+ if (error == 0)
+ dr->enable_io = true;
+
+ /* This device is not managed. */
+ pdev->managed = true;
+
+ return (error);
+}
+
+static struct pcim_iomap_devres *
lkpi_pcim_iomap_devres_find(struct pci_dev *pdev)
{
struct pcim_iomap_devres *dr;
@@ -573,7 +694,144 @@ lkpi_pcim_iomap_devres_find(struct pci_dev *pdev)
return (dr);
}
+void __iomem **
+linuxkpi_pcim_iomap_table(struct pci_dev *pdev)
+{
+ struct pcim_iomap_devres *dr;
+
+ dr = lkpi_pcim_iomap_devres_find(pdev);
+ if (dr == NULL)
+ return (NULL);
+
+ /*
+ * If the driver has manually set a flag to be able to request the
+ * resource to use bus_read/write_<n>, return the shadow table.
+ */
+ if (pdev->want_iomap_res)
+ return ((void **)dr->res_table);
+
+ /* This is the Linux default. */
+ return (dr->mmio_table);
+}
+
+static struct resource *
+_lkpi_pci_iomap(struct pci_dev *pdev, int bar, int mmio_size __unused)
+{
+ struct pci_mmio_region *mmio, *p;
+ int type;
+
+ type = pci_resource_type(pdev, bar);
+ if (type < 0) {
+ device_printf(pdev->dev.bsddev, "%s: bar %d type %d\n",
+ __func__, bar, type);
+ return (NULL);
+ }
+
+ /*
+ * Check for duplicate mappings.
+ * This can happen if a driver calls pci_request_region() first.
+ */
+ TAILQ_FOREACH_SAFE(mmio, &pdev->mmio, next, p) {
+ if (mmio->type == type && mmio->rid == PCIR_BAR(bar)) {
+ return (mmio->res);
+ }
+ }
+
+ mmio = malloc(sizeof(*mmio), M_DEVBUF, M_WAITOK | M_ZERO);
+ mmio->rid = PCIR_BAR(bar);
+ mmio->type = type;
+ mmio->res = bus_alloc_resource_any(pdev->dev.bsddev, mmio->type,
+ &mmio->rid, RF_ACTIVE|RF_SHAREABLE);
+ if (mmio->res == NULL) {
+ device_printf(pdev->dev.bsddev, "%s: failed to alloc "
+ "bar %d type %d rid %d\n",
+ __func__, bar, type, PCIR_BAR(bar));
+ free(mmio, M_DEVBUF);
+ return (NULL);
+ }
+ TAILQ_INSERT_TAIL(&pdev->mmio, mmio, next);
+
+ return (mmio->res);
+}
+
+void *
+linuxkpi_pci_iomap(struct pci_dev *pdev, int mmio_bar, int mmio_size)
+{
+ struct resource *res;
+
+ res = _lkpi_pci_iomap(pdev, mmio_bar, mmio_size);
+ if (res == NULL)
+ return (NULL);
+ /* This is a FreeBSD extension so we can use bus_*(). */
+ if (pdev->want_iomap_res)
+ return (res);
+ return ((void *)rman_get_bushandle(res));
+}
+
void
+linuxkpi_pci_iounmap(struct pci_dev *pdev, void *res)
+{
+ struct pci_mmio_region *mmio, *p;
+
+ TAILQ_FOREACH_SAFE(mmio, &pdev->mmio, next, p) {
+ if (res != (void *)rman_get_bushandle(mmio->res))
+ continue;
+ bus_release_resource(pdev->dev.bsddev,
+ mmio->type, mmio->rid, mmio->res);
+ TAILQ_REMOVE(&pdev->mmio, mmio, next);
+ free(mmio, M_DEVBUF);
+ return;
+ }
+}
+
+int
+linuxkpi_pcim_iomap_regions(struct pci_dev *pdev, uint32_t mask, const char *name)
+{
+ struct pcim_iomap_devres *dr;
+ void *res;
+ uint32_t mappings;
+ int bar;
+
+ dr = lkpi_pcim_iomap_devres_find(pdev);
+ if (dr == NULL)
+ return (-ENOMEM);
+
+ /* Now iomap all the requested (by "mask") ones. */
+ for (bar = mappings = 0; mappings != mask; bar++) {
+ if ((mask & (1 << bar)) == 0)
+ continue;
+
+ /* Request double is not allowed. */
+ if (dr->mmio_table[bar] != NULL) {
+ device_printf(pdev->dev.bsddev, "%s: bar %d %p\n",
+ __func__, bar, dr->mmio_table[bar]);
+ goto err;
+ }
+
+ res = _lkpi_pci_iomap(pdev, bar, 0);
+ if (res == NULL)
+ goto err;
+ dr->mmio_table[bar] = (void *)rman_get_bushandle(res);
+ dr->res_table[bar] = res;
+
+ mappings |= (1 << bar);
+ }
+
+ return (0);
+err:
+ for (bar = PCIR_MAX_BAR_0; bar >= 0; bar--) {
+ if ((mappings & (1 << bar)) != 0) {
+ res = dr->mmio_table[bar];
+ if (res == NULL)
+ continue;
+ pci_iounmap(pdev, res);
+ }
+ }
+
+ return (-EINVAL);
+}
+
+static void
lkpi_pcim_iomap_table_release(struct device *dev, void *p)
{
struct pcim_iomap_devres *dr;
@@ -610,6 +868,8 @@ linux_pci_suspend(device_t dev)
error = -pmops->suspend(&pdev->dev);
if (error == 0 && pmops->suspend_late != NULL)
error = -pmops->suspend_late(&pdev->dev);
+ if (error == 0 && pmops->suspend_noirq != NULL)
+ error = -pmops->suspend_noirq(&pdev->dev);
}
return (error);
}
@@ -723,23 +983,35 @@ linux_pci_register_driver(struct pci_driver *pdrv)
return (_linux_pci_register_driver(pdrv, dc));
}
-struct resource_list_entry *
-linux_pci_reserve_bar(struct pci_dev *pdev, struct resource_list *rl,
- int type, int rid)
+static struct resource_list_entry *
+lkpi_pci_get_bar(struct pci_dev *pdev, int bar, bool reserve)
{
- device_t dev;
- struct resource *res;
-
- KASSERT(type == SYS_RES_IOPORT || type == SYS_RES_MEMORY,
- ("trying to reserve non-BAR type %d", type));
+ int type;
- dev = pdev->pdrv != NULL && pdev->pdrv->isdrm ?
- device_get_parent(pdev->dev.bsddev) : pdev->dev.bsddev;
- res = pci_reserve_map(device_get_parent(dev), dev, type, &rid, 0, ~0,
- 1, 1, 0);
- if (res == NULL)
+ type = pci_resource_type(pdev, bar);
+ if (type < 0)
return (NULL);
- return (resource_list_find(rl, type, rid));
+ bar = PCIR_BAR(bar);
+ return (linux_pci_get_rle(pdev, type, bar, reserve));
+}
+
+struct device *
+lkpi_pci_find_irq_dev(unsigned int irq)
+{
+ struct pci_dev *pdev;
+ struct device *found;
+
+ found = NULL;
+ spin_lock(&pci_lock);
+ list_for_each_entry(pdev, &pci_devices, links) {
+ if (irq == pdev->dev.irq ||
+ (irq >= pdev->dev.irq_start && irq < pdev->dev.irq_end)) {
+ found = &pdev->dev;
+ break;
+ }
+ }
+ spin_unlock(&pci_lock);
+ return (found);
}
unsigned long
@@ -750,7 +1022,7 @@ pci_resource_start(struct pci_dev *pdev, int bar)
device_t dev;
int error;
- if ((rle = linux_pci_get_bar(pdev, bar, true)) == NULL)
+ if ((rle = lkpi_pci_get_bar(pdev, bar, true)) == NULL)
return (0);
dev = pdev->pdrv != NULL && pdev->pdrv->isdrm ?
device_get_parent(pdev->dev.bsddev) : pdev->dev.bsddev;
@@ -769,7 +1041,7 @@ pci_resource_len(struct pci_dev *pdev, int bar)
{
struct resource_list_entry *rle;
- if ((rle = linux_pci_get_bar(pdev, bar, true)) == NULL)
+ if ((rle = lkpi_pci_get_bar(pdev, bar, true)) == NULL)
return (0);
return (rle->count);
}
@@ -818,44 +1090,62 @@ pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
return (0);
}
-struct resource *
-_lkpi_pci_iomap(struct pci_dev *pdev, int bar, int mmio_size __unused)
+int
+linuxkpi_pci_request_regions(struct pci_dev *pdev, const char *res_name)
{
- struct pci_mmio_region *mmio, *p;
- int type;
+ int error;
+ int i;
- type = pci_resource_type(pdev, bar);
- if (type < 0) {
- device_printf(pdev->dev.bsddev, "%s: bar %d type %d\n",
- __func__, bar, type);
- return (NULL);
+ for (i = 0; i <= PCIR_MAX_BAR_0; i++) {
+ error = pci_request_region(pdev, i, res_name);
+ if (error && error != -ENODEV) {
+ pci_release_regions(pdev);
+ return (error);
+ }
}
+ return (0);
+}
+
+void
+linuxkpi_pci_release_region(struct pci_dev *pdev, int bar)
+{
+ struct resource_list_entry *rle;
+ struct pci_devres *dr;
+ struct pci_mmio_region *mmio, *p;
+
+ if ((rle = lkpi_pci_get_bar(pdev, bar, false)) == NULL)
+ return;
/*
- * Check for duplicate mappings.
- * This can happen if a driver calls pci_request_region() first.
+ * As we implicitly track the requests we also need to clear them on
+ * release. Do clear before resource release.
*/
- TAILQ_FOREACH_SAFE(mmio, &pdev->mmio, next, p) {
- if (mmio->type == type && mmio->rid == PCIR_BAR(bar)) {
- return (mmio->res);
- }
+ dr = lkpi_pci_devres_find(pdev);
+ if (dr != NULL) {
+ KASSERT(dr->region_table[bar] == rle->res, ("%s: pdev %p bar %d"
+ " region_table res %p != rel->res %p\n", __func__, pdev,
+ bar, dr->region_table[bar], rle->res));
+ dr->region_table[bar] = NULL;
+ dr->region_mask &= ~(1 << bar);
}
- mmio = malloc(sizeof(*mmio), M_DEVBUF, M_WAITOK | M_ZERO);
- mmio->rid = PCIR_BAR(bar);
- mmio->type = type;
- mmio->res = bus_alloc_resource_any(pdev->dev.bsddev, mmio->type,
- &mmio->rid, RF_ACTIVE|RF_SHAREABLE);
- if (mmio->res == NULL) {
- device_printf(pdev->dev.bsddev, "%s: failed to alloc "
- "bar %d type %d rid %d\n",
- __func__, bar, type, PCIR_BAR(bar));
+ TAILQ_FOREACH_SAFE(mmio, &pdev->mmio, next, p) {
+ if (rle->res != (void *)rman_get_bushandle(mmio->res))
+ continue;
+ TAILQ_REMOVE(&pdev->mmio, mmio, next);
free(mmio, M_DEVBUF);
- return (NULL);
}
- TAILQ_INSERT_TAIL(&pdev->mmio, mmio, next);
- return (mmio->res);
+ bus_release_resource(pdev->dev.bsddev, rle->type, rle->rid, rle->res);
+}
+
+void
+linuxkpi_pci_release_regions(struct pci_dev *pdev)
+{
+ int i;
+
+ for (i = 0; i <= PCIR_MAX_BAR_0; i++)
+ pci_release_region(pdev, i);
}
int
@@ -904,6 +1194,73 @@ linux_pci_unregister_drm_driver(struct pci_driver *pdrv)
}
int
+linuxkpi_pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries,
+ int nreq)
+{
+ struct resource_list_entry *rle;
+ int error;
+ int avail;
+ int i;
+
+ avail = pci_msix_count(pdev->dev.bsddev);
+ if (avail < nreq) {
+ if (avail == 0)
+ return -EINVAL;
+ return avail;
+ }
+ avail = nreq;
+ if ((error = -pci_alloc_msix(pdev->dev.bsddev, &avail)) != 0)
+ return error;
+ /*
+ * Handle case where "pci_alloc_msix()" may allocate less
+ * interrupts than available and return with no error:
+ */
+ if (avail < nreq) {
+ pci_release_msi(pdev->dev.bsddev);
+ return avail;
+ }
+ rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1, false);
+ pdev->dev.irq_start = rle->start;
+ pdev->dev.irq_end = rle->start + avail;
+ for (i = 0; i < nreq; i++)
+ entries[i].vector = pdev->dev.irq_start + i;
+ pdev->msix_enabled = true;
+ return (0);
+}
+
+int
+_lkpi_pci_enable_msi_range(struct pci_dev *pdev, int minvec, int maxvec)
+{
+ struct resource_list_entry *rle;
+ int error;
+ int nvec;
+
+ if (maxvec < minvec)
+ return (-EINVAL);
+
+ nvec = pci_msi_count(pdev->dev.bsddev);
+ if (nvec < 1 || nvec < minvec)
+ return (-ENOSPC);
+
+ nvec = min(nvec, maxvec);
+ if ((error = -pci_alloc_msi(pdev->dev.bsddev, &nvec)) != 0)
+ return error;
+
+ /* Native PCI might only ever ask for 32 vectors. */
+ if (nvec < minvec) {
+ pci_release_msi(pdev->dev.bsddev);
+ return (-ENOSPC);
+ }
+
+ rle = linux_pci_get_rle(pdev, SYS_RES_IRQ, 1, false);
+ pdev->dev.irq_start = rle->start;
+ pdev->dev.irq_end = rle->start + nvec;
+ pdev->irq = rle->start;
+ pdev->msi_enabled = true;
+ return (0);
+}
+
+int
pci_alloc_irq_vectors(struct pci_dev *pdev, int minv, int maxv,
unsigned int flags)
{
@@ -927,7 +1284,9 @@ out:
return (pdev->dev.irq_end - pdev->dev.irq_start);
}
if (flags & PCI_IRQ_MSI) {
- error = pci_enable_msi(pdev);
+ if (pci_msi_count(pdev->dev.bsddev) < minv)
+ return (-ENOSPC);
+ error = _lkpi_pci_enable_msi_range(pdev, minv, maxv);
if (error == 0 && pdev->msi_enabled)
return (pdev->dev.irq_end - pdev->dev.irq_start);
}
@@ -939,6 +1298,57 @@ out:
return (-EINVAL);
}
+struct msi_desc *
+lkpi_pci_msi_desc_alloc(int irq)
+{
+ struct device *dev;
+ struct pci_dev *pdev;
+ struct msi_desc *desc;
+ struct pci_devinfo *dinfo;
+ struct pcicfg_msi *msi;
+ int vec;
+
+ dev = lkpi_pci_find_irq_dev(irq);
+ if (dev == NULL)
+ return (NULL);
+
+ pdev = to_pci_dev(dev);
+
+ if (pdev->msi_desc == NULL)
+ return (NULL);
+
+ if (irq < pdev->dev.irq_start || irq >= pdev->dev.irq_end)
+ return (NULL);
+
+ vec = pdev->dev.irq_start - irq;
+
+ if (pdev->msi_desc[vec] != NULL)
+ return (pdev->msi_desc[vec]);
+
+ dinfo = device_get_ivars(dev->bsddev);
+ msi = &dinfo->cfg.msi;
+
+ desc = malloc(sizeof(*desc), M_DEVBUF, M_WAITOK | M_ZERO);
+
+ desc->pci.msi_attrib.is_64 =
+ (msi->msi_ctrl & PCIM_MSICTRL_64BIT) ? true : false;
+ desc->msg.data = msi->msi_data;
+
+ pdev->msi_desc[vec] = desc;
+
+ return (desc);
+}
+
+bool
+pci_device_is_present(struct pci_dev *pdev)
+{
+ device_t dev;
+
+ dev = pdev->dev.bsddev;
+
+ return (bus_child_present(dev));
+}
+
CTASSERT(sizeof(dma_addr_t) <= sizeof(uint64_t));
struct linux_dma_obj {
@@ -1124,13 +1534,13 @@ linux_dma_alloc_coherent(struct device *dev, size_t size,
align = PAGE_SIZE << get_order(size);
/* Always zero the allocation. */
flag |= M_ZERO;
- mem = (void *)kmem_alloc_contig(size, flag & GFP_NATIVE_MASK, 0, high,
+ mem = kmem_alloc_contig(size, flag & GFP_NATIVE_MASK, 0, high,
align, 0, VM_MEMATTR_DEFAULT);
if (mem != NULL) {
*dma_handle = linux_dma_map_phys_common(dev, vtophys(mem), size,
priv->dmat_coherent);
if (*dma_handle == 0) {
- kmem_free((vm_offset_t)mem, size);
+ kmem_free(mem, size);
mem = NULL;
}
} else {
@@ -1139,6 +1549,45 @@ linux_dma_alloc_coherent(struct device *dev, size_t size,
return (mem);
}
+struct lkpi_devres_dmam_coherent {
+ size_t size;
+ dma_addr_t *handle;
+ void *mem;
+};
+
+static void
+lkpi_dmam_free_coherent(struct device *dev, void *p)
+{
+ struct lkpi_devres_dmam_coherent *dr;
+
+ dr = p;
+ dma_free_coherent(dev, dr->size, dr->mem, *dr->handle);
+}
+
+void *
+linuxkpi_dmam_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
+ gfp_t flag)
+{
+ struct lkpi_devres_dmam_coherent *dr;
+
+ dr = lkpi_devres_alloc(lkpi_dmam_free_coherent,
+ sizeof(*dr), GFP_KERNEL | __GFP_ZERO);
+
+ if (dr == NULL)
+ return (NULL);
+
+ dr->size = size;
+ dr->mem = linux_dma_alloc_coherent(dev, size, dma_handle, flag);
+ dr->handle = dma_handle;
+ if (dr->mem == NULL) {
+ lkpi_devres_free(dr);
+ return (NULL);
+ }
+
+ lkpi_devres_add(dev, dr);
+ return (dr->mem);
+}
+
void
linuxkpi_dma_sync(struct device *dev, dma_addr_t dma_addr, size_t size,
bus_dmasync_op_t op)
diff --git a/sys/compat/linuxkpi/common/src/linux_radix.c b/sys/compat/linuxkpi/common/src/linux_radix.c
index abf217de7f98..af53d8bff366 100644
--- a/sys/compat/linuxkpi/common/src/linux_radix.c
+++ b/sys/compat/linuxkpi/common/src/linux_radix.c
@@ -27,9 +27,6 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
diff --git a/sys/compat/linuxkpi/common/src/linux_rcu.c b/sys/compat/linuxkpi/common/src/linux_rcu.c
index 2179faa2c05e..335708b6747f 100644
--- a/sys/compat/linuxkpi/common/src/linux_rcu.c
+++ b/sys/compat/linuxkpi/common/src/linux_rcu.c
@@ -25,9 +25,6 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/malloc.h>
diff --git a/sys/compat/linuxkpi/common/src/linux_schedule.c b/sys/compat/linuxkpi/common/src/linux_schedule.c
index 656d8697d169..66b339bfbdbd 100644
--- a/sys/compat/linuxkpi/common/src/linux_schedule.c
+++ b/sys/compat/linuxkpi/common/src/linux_schedule.c
@@ -24,9 +24,6 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
diff --git a/sys/compat/linuxkpi/common/src/linux_seq_file.c b/sys/compat/linuxkpi/common/src/linux_seq_file.c
index ed23bf8d010f..8b426825cc78 100644
--- a/sys/compat/linuxkpi/common/src/linux_seq_file.c
+++ b/sys/compat/linuxkpi/common/src/linux_seq_file.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2016-2018, Matthew Macy <mmacy@freebsd.org>
*
@@ -26,9 +26,6 @@
*
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/param.h>
@@ -45,23 +42,67 @@ MALLOC_DEFINE(M_LSEQ, "seq_file", "seq_file");
ssize_t
seq_read(struct linux_file *f, char *ubuf, size_t size, off_t *ppos)
{
- struct seq_file *m = f->private_data;
+ struct seq_file *m;
+ struct sbuf *sbuf;
void *p;
- int rc;
- off_t pos = 0;
+ ssize_t rc;
- p = m->op->start(m, &pos);
+ m = f->private_data;
+ sbuf = m->buf;
+
+ p = m->op->start(m, ppos);
rc = m->op->show(m, p);
if (rc)
return (rc);
- return (size);
+
+ rc = sbuf_finish(sbuf);
+ if (rc)
+ return (rc);
+
+ rc = sbuf_len(sbuf);
+ if (*ppos >= rc || size < 1)
+ return (-EINVAL);
+
+ size = min(rc - *ppos, size);
+ rc = strscpy(ubuf, sbuf_data(sbuf) + *ppos, size + 1);
+
+ /* add 1 for null terminator */
+ if (rc > 0)
+ rc += 1;
+
+ return (rc);
}
int
seq_write(struct seq_file *seq, const void *data, size_t len)
{
+ int ret;
+
+ ret = sbuf_bcpy(seq->buf, data, len);
+ if (ret == 0)
+ seq->size = sbuf_len(seq->buf);
+
+ return (ret);
+}
+
+void
+seq_putc(struct seq_file *seq, char c)
+{
+ int ret;
+
+ ret = sbuf_putc(seq->buf, c);
+ if (ret == 0)
+ seq->size = sbuf_len(seq->buf);
+}
+
+void
+seq_puts(struct seq_file *seq, const char *str)
+{
+ int ret;
- return (sbuf_bcpy(seq->buf, data, len));
+ ret = sbuf_printf(seq->buf, "%s", str);
+ if (ret == 0)
+ seq->size = sbuf_len(seq->buf);
}
/*
@@ -96,25 +137,57 @@ single_stop(struct seq_file *p, void *v)
{
}
-int
-seq_open(struct linux_file *f, const struct seq_operations *op)
+static int
+_seq_open_without_sbuf(struct linux_file *f, const struct seq_operations *op)
{
struct seq_file *p;
- if (f->private_data != NULL)
- log(LOG_WARNING, "%s private_data not NULL", __func__);
-
if ((p = malloc(sizeof(*p), M_LSEQ, M_NOWAIT|M_ZERO)) == NULL)
return (-ENOMEM);
- f->private_data = p;
- p->op = op;
p->file = f;
+ p->op = op;
+ f->private_data = (void *) p;
return (0);
}
int
-single_open(struct linux_file *f, int (*show)(struct seq_file *, void *), void *d)
+seq_open(struct linux_file *f, const struct seq_operations *op)
+{
+ int ret;
+
+ ret = _seq_open_without_sbuf(f, op);
+ if (ret == 0)
+ ((struct seq_file *)f->private_data)->buf = sbuf_new_auto();
+
+ return (ret);
+}
+
+void *
+__seq_open_private(struct linux_file *f, const struct seq_operations *op, int size)
+{
+ struct seq_file *seq_file;
+ void *private;
+ int error;
+
+ private = malloc(size, M_LSEQ, M_NOWAIT|M_ZERO);
+ if (private == NULL)
+ return (NULL);
+
+ error = seq_open(f, op);
+ if (error < 0) {
+ free(private, M_LSEQ);
+ return (NULL);
+ }
+
+ seq_file = (struct seq_file *)f->private_data;
+ seq_file->private = private;
+
+ return (private);
+}
+
+static int
+_single_open_without_sbuf(struct linux_file *f, int (*show)(struct seq_file *, void *), void *d)
{
struct seq_operations *op;
int rc = -ENOMEM;
@@ -125,7 +198,7 @@ single_open(struct linux_file *f, int (*show)(struct seq_file *, void *), void *
op->next = single_next;
op->stop = single_stop;
op->show = show;
- rc = seq_open(f, op);
+ rc = _seq_open_without_sbuf(f, op);
if (rc)
free(op, M_LSEQ);
else
@@ -135,16 +208,56 @@ single_open(struct linux_file *f, int (*show)(struct seq_file *, void *), void *
}
int
+single_open(struct linux_file *f, int (*show)(struct seq_file *, void *), void *d)
+{
+ int ret;
+
+ ret = _single_open_without_sbuf(f, show, d);
+ if (ret == 0)
+ ((struct seq_file *)f->private_data)->buf = sbuf_new_auto();
+
+ return (ret);
+}
+
+int
+single_open_size(struct linux_file *f, int (*show)(struct seq_file *, void *), void *d, size_t size)
+{
+ int ret;
+
+ ret = _single_open_without_sbuf(f, show, d);
+ if (ret == 0)
+ ((struct seq_file *)f->private_data)->buf = sbuf_new(
+ NULL, NULL, size, SBUF_AUTOEXTEND);
+
+ return (ret);
+}
+
+int
seq_release(struct inode *inode __unused, struct linux_file *file)
{
struct seq_file *m;
+ struct sbuf *s;
m = file->private_data;
+ s = m->buf;
+
+ sbuf_delete(s);
free(m, M_LSEQ);
+
return (0);
}
int
+seq_release_private(struct inode *inode __unused, struct linux_file *f)
+{
+ struct seq_file *seq;
+
+ seq = (struct seq_file *)f->private_data;
+ free(seq->private, M_LSEQ);
+ return (seq_release(inode, f));
+}
+
+int
single_release(struct vnode *v, struct linux_file *f)
{
const struct seq_operations *op;
@@ -160,3 +273,29 @@ single_release(struct vnode *v, struct linux_file *f)
free(__DECONST(void *, op), M_LSEQ);
return (rc);
}
+
+void
+lkpi_seq_vprintf(struct seq_file *m, const char *fmt, va_list args)
+{
+ int ret;
+
+ ret = sbuf_vprintf(m->buf, fmt, args);
+ if (ret == 0)
+ m->size = sbuf_len(m->buf);
+}
+
+void
+lkpi_seq_printf(struct seq_file *m, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ lkpi_seq_vprintf(m, fmt, args);
+ va_end(args);
+}
+
+bool
+seq_has_overflowed(struct seq_file *m)
+{
+ return (sbuf_len(m->buf) == -1);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_shmemfs.c b/sys/compat/linuxkpi/common/src/linux_shmemfs.c
index 741bb20c1aab..1fb17bc5c0cb 100644
--- a/sys/compat/linuxkpi/common/src/linux_shmemfs.c
+++ b/sys/compat/linuxkpi/common/src/linux_shmemfs.c
@@ -26,9 +26,6 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/rwlock.h>
@@ -47,7 +44,7 @@ __FBSDID("$FreeBSD$");
struct page *
linux_shmem_read_mapping_page_gfp(vm_object_t obj, int pindex, gfp_t gfp)
{
- vm_page_t page;
+ struct page *page;
int rv;
if ((gfp & GFP_NOWAIT) != 0)
diff --git a/sys/compat/linuxkpi/common/src/linux_shrinker.c b/sys/compat/linuxkpi/common/src/linux_shrinker.c
index b48e491a4e2f..52a0472348d8 100644
--- a/sys/compat/linuxkpi/common/src/linux_shrinker.c
+++ b/sys/compat/linuxkpi/common/src/linux_shrinker.c
@@ -21,14 +21,8 @@
* 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.
- *
- * $FreeBSD$
*/
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -64,6 +58,14 @@ linuxkpi_unregister_shrinker(struct shrinker *s)
sx_xunlock(&sx_shrinker);
}
+void
+linuxkpi_synchronize_shrinkers(void)
+{
+
+ sx_xlock(&sx_shrinker);
+ sx_xunlock(&sx_shrinker);
+}
+
#define SHRINKER_BATCH 512
static void
diff --git a/sys/compat/linuxkpi/common/src/linux_simple_attr.c b/sys/compat/linuxkpi/common/src/linux_simple_attr.c
new file mode 100644
index 000000000000..1bdacd7c1491
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_simple_attr.c
@@ -0,0 +1,188 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022, Jake Freeland <jfree@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, 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.
+ */
+
+#include <sys/types.h>
+#include <linux/fs.h>
+
+MALLOC_DEFINE(M_LSATTR, "simple_attr", "Linux Simple Attribute File");
+
+struct simple_attr {
+ int (*get)(void *, uint64_t *);
+ int (*set)(void *, uint64_t);
+ void *data;
+ const char *fmt;
+ struct mutex mutex;
+};
+
+/*
+ * simple_attr_open: open and populate simple attribute data
+ *
+ * @inode: file inode
+ * @filp: file pointer
+ * @get: ->get() for reading file data
+ * @set: ->set() for writing file data
+ * @fmt: format specifier for data returned by @get
+ *
+ * Memory allocate a simple_attr and appropriately initialize its members.
+ * The simple_attr must be stored in filp->private_data.
+ * Simple attr files do not support seeking. Open the file as nonseekable.
+ *
+ * Return value: simple attribute file descriptor
+ */
+int
+simple_attr_open(struct inode *inode, struct file *filp,
+ int (*get)(void *, uint64_t *), int (*set)(void *, uint64_t),
+ const char *fmt)
+{
+ struct simple_attr *sattr;
+ sattr = malloc(sizeof(*sattr), M_LSATTR, M_ZERO | M_NOWAIT);
+ if (sattr == NULL)
+ return (-ENOMEM);
+
+ sattr->get = get;
+ sattr->set = set;
+ sattr->data = inode->i_private;
+ sattr->fmt = fmt;
+ mutex_init(&sattr->mutex);
+
+ filp->private_data = (void *) sattr;
+
+ return (nonseekable_open(inode, filp));
+}
+
+int
+simple_attr_release(struct inode *inode, struct file *filp)
+{
+ free(filp->private_data, M_LSATTR);
+ return (0);
+}
+
+/*
+ * simple_attr_read: read simple attr data and transfer into buffer
+ *
+ * @filp: file pointer
+ * @buf: kernel space buffer
+ * @read_size: number of bytes to be transferred
+ * @ppos: starting pointer position for transfer
+ *
+ * The simple_attr structure is stored in filp->private_data.
+ * ->get() retrieves raw file data.
+ * The ->fmt specifier can format this data to be human readable.
+ * This output is then transferred into the @buf buffer.
+ *
+ * Return value:
+ * On success, number of bytes transferred
+ * On failure, negative signed ERRNO
+ */
+ssize_t
+simple_attr_read(struct file *filp, char *buf, size_t read_size, loff_t *ppos)
+{
+ struct simple_attr *sattr;
+ uint64_t data;
+ ssize_t ret;
+ char prebuf[24];
+
+ sattr = filp->private_data;
+
+ if (sattr->get == NULL)
+ return (-EFAULT);
+
+ mutex_lock(&sattr->mutex);
+
+ ret = sattr->get(sattr->data, &data);
+ if (ret)
+ goto unlock;
+
+ scnprintf(prebuf, sizeof(prebuf), sattr->fmt, data);
+
+ ret = strlen(prebuf) + 1;
+ if (*ppos >= ret || read_size < 1) {
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ read_size = min(ret - *ppos, read_size);
+ ret = strscpy(buf, prebuf + *ppos, read_size);
+
+ /* add 1 for null terminator */
+ if (ret > 0)
+ ret += 1;
+
+unlock:
+ mutex_unlock(&sattr->mutex);
+ return (ret);
+}
+
+/*
+ * simple_attr_write: write contents of buffer into simple attribute file
+ *
+ * @filp: file pointer
+ * @buf: kernel space buffer
+ * @write_size: number bytes to be transferred
+ * @ppos: starting pointer position for transfer
+ *
+ * The simple_attr structure is stored in filp->private_data.
+ * Convert the @buf string to unsigned long long.
+ * ->set() writes unsigned long long data into the simple attr file.
+ *
+ * Return value:
+ * On success, number of bytes written to simple attr
+ * On failure, negative signed ERRNO
+ */
+ssize_t
+simple_attr_write(struct file *filp, const char *buf, size_t write_size, loff_t *ppos)
+{
+ struct simple_attr *sattr;
+ unsigned long long data;
+ size_t bufsize;
+ ssize_t ret;
+
+ sattr = filp->private_data;
+ bufsize = strlen(buf) + 1;
+
+ if (sattr->set == NULL)
+ return (-EFAULT);
+
+ if (*ppos >= bufsize || write_size < 1)
+ return (-EINVAL);
+
+ mutex_lock(&sattr->mutex);
+
+ ret = kstrtoull(buf + *ppos, 0, &data);
+ if (ret)
+ goto unlock;
+
+ ret = sattr->set(sattr->data, data);
+ if (ret)
+ goto unlock;
+
+ ret = bufsize - *ppos;
+
+unlock:
+ mutex_unlock(&sattr->mutex);
+ return (ret);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_skbuff.c b/sys/compat/linuxkpi/common/src/linux_skbuff.c
index df8e3fda8d56..0522d3fdff41 100644
--- a/sys/compat/linuxkpi/common/src/linux_skbuff.c
+++ b/sys/compat/linuxkpi/common/src/linux_skbuff.c
@@ -25,8 +25,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
@@ -36,8 +34,6 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include "opt_ddb.h"
#include <sys/param.h>
@@ -151,6 +147,28 @@ linuxkpi_dev_alloc_skb(size_t size, gfp_t gfp)
}
struct sk_buff *
+linuxkpi_build_skb(void *data, size_t fragsz)
+{
+ struct sk_buff *skb;
+
+ if (data == NULL || fragsz == 0)
+ return (NULL);
+
+ /* Just allocate a skb without data area. */
+ skb = linuxkpi_alloc_skb(0, GFP_KERNEL);
+ if (skb == NULL)
+ return (NULL);
+
+ skb->_flags |= _SKB_FLAGS_SKBEXTFRAG;
+ skb->truesize = fragsz;
+ skb->head = skb->data = data;
+ skb_reset_tail_pointer(skb); /* XXX is that correct? */
+ skb->end = (void *)((uintptr_t)skb->head + fragsz);
+
+ return (skb);
+}
+
+struct sk_buff *
linuxkpi_skb_copy(struct sk_buff *skb, gfp_t gfp)
{
struct sk_buff *new;
@@ -233,6 +251,13 @@ linuxkpi_kfree_skb(struct sk_buff *skb)
}
}
+ if ((skb->_flags & _SKB_FLAGS_SKBEXTFRAG) != 0) {
+ void *p;
+
+ p = skb->head;
+ skb_free_frag(p);
+ }
+
#ifdef __LP64__
if (__predict_true(linuxkpi_skb_memlimit == 0))
free(skb, M_LKPISKB);
@@ -268,6 +293,7 @@ DB_SHOW_COMMAND(skb, db_show_skb)
skb->pkt_type, skb->dev, skb->sk);
db_printf("\tcsum_offset %d csum_start %d ip_summed %d protocol %d\n",
skb->csum_offset, skb->csum_start, skb->ip_summed, skb->protocol);
+ db_printf("\t_flags %#06x\n", skb->_flags); /* XXX-BZ print names? */
db_printf("\thead %p data %p tail %p end %p\n",
skb->head, skb->data, skb->tail, skb->end);
db_printf("\tshinfo %p m %p m_free_func %p\n",
@@ -298,7 +324,6 @@ DB_SHOW_COMMAND(skb, db_show_skb)
}
db_printf("}\n");
- db_printf("\t_spareu16_0 %#06x __scratch[0] %p\n",
- skb->_spareu16_0, skb->__scratch);
+ db_printf("\t__scratch[0] %p\n", skb->__scratch);
};
#endif
diff --git a/sys/compat/linuxkpi/common/src/linux_slab.c b/sys/compat/linuxkpi/common/src/linux_slab.c
index e062f0535fda..68117d1c9fa7 100644
--- a/sys/compat/linuxkpi/common/src/linux_slab.c
+++ b/sys/compat/linuxkpi/common/src/linux_slab.c
@@ -25,8 +25,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
+#include <linux/compat.h>
#include <linux/slab.h>
#include <linux/rcupdate.h>
#include <linux/kernel.h>
@@ -208,6 +207,29 @@ linux_kmem_cache_destroy(struct linux_kmem_cache *c)
free(c, M_KMALLOC);
}
+struct lkpi_kmalloc_ctx {
+ size_t size;
+ gfp_t flags;
+ void *addr;
+};
+
+static void
+lkpi_kmalloc_cb(void *ctx)
+{
+ struct lkpi_kmalloc_ctx *lmc = ctx;
+
+ lmc->addr = __kmalloc(lmc->size, lmc->flags);
+}
+
+void *
+lkpi_kmalloc(size_t size, gfp_t flags)
+{
+ struct lkpi_kmalloc_ctx lmc = { .size = size, .flags = flags };
+
+ lkpi_fpu_safe_exec(&lkpi_kmalloc_cb, &lmc);
+ return(lmc.addr);
+}
+
static void
linux_kfree_async_fn(void *context, int pending)
{
diff --git a/sys/compat/linuxkpi/common/src/linux_tasklet.c b/sys/compat/linuxkpi/common/src/linux_tasklet.c
index 26e7bb75cf19..e443ab3958b4 100644
--- a/sys/compat/linuxkpi/common/src/linux_tasklet.c
+++ b/sys/compat/linuxkpi/common/src/linux_tasklet.c
@@ -24,9 +24,6 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/types.h>
#include <sys/malloc.h>
#include <sys/gtaskqueue.h>
@@ -85,7 +82,10 @@ tasklet_handler(void *arg)
/* reset executing state */
TASKLET_ST_SET(ts, TASKLET_ST_EXEC);
- ts->func(ts->data);
+ if (ts->use_callback)
+ ts->callback(ts);
+ else
+ ts->func(ts->data);
} while (TASKLET_ST_CMPSET(ts, TASKLET_ST_EXEC,
TASKLET_ST_IDLE) == 0);
@@ -149,9 +149,24 @@ tasklet_init(struct tasklet_struct *ts,
ts->entry.tqe_prev = NULL;
ts->entry.tqe_next = NULL;
ts->func = func;
+ ts->callback = NULL;
ts->data = data;
atomic_set_int(&ts->tasklet_state, TASKLET_ST_IDLE);
atomic_set(&ts->count, 0);
+ ts->use_callback = false;
+}
+
+void
+tasklet_setup(struct tasklet_struct *ts, tasklet_callback_t *c)
+{
+ ts->entry.tqe_prev = NULL;
+ ts->entry.tqe_next = NULL;
+ ts->func = NULL;
+ ts->callback = c;
+ ts->data = 0;
+ atomic_set_int(&ts->tasklet_state, TASKLET_ST_IDLE);
+ atomic_set(&ts->count, 0);
+ ts->use_callback = true;
}
void
diff --git a/sys/compat/linuxkpi/common/src/linux_usb.c b/sys/compat/linuxkpi/common/src/linux_usb.c
index ed46acc4020f..cdd3d9a01f35 100644
--- a/sys/compat/linuxkpi/common/src/linux_usb.c
+++ b/sys/compat/linuxkpi/common/src/linux_usb.c
@@ -1,4 +1,3 @@
-/* $FreeBSD$ */
/*-
* Copyright (c) 2007 Luigi Rizzo - Universita` di Pisa. All rights reserved.
* Copyright (c) 2007 Hans Petter Selasky. All rights reserved.
diff --git a/sys/compat/linuxkpi/common/src/linux_work.c b/sys/compat/linuxkpi/common/src/linux_work.c
index 5d0c13ed2a53..939bdbbc1434 100644
--- a/sys/compat/linuxkpi/common/src/linux_work.c
+++ b/sys/compat/linuxkpi/common/src/linux_work.c
@@ -25,8 +25,6 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <linux/workqueue.h>
#include <linux/wait.h>
#include <linux/compat.h>
@@ -208,7 +206,7 @@ linux_flush_rcu_work(struct rcu_work *rwork)
/*
* This function queues the given work structure on the given
- * workqueue after a given delay in ticks. It returns non-zero if the
+ * workqueue after a given delay in ticks. It returns true if the
* work was successfully [re-]queued. Else the work is already pending
* for completion.
*/
@@ -223,16 +221,19 @@ linux_queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
[WORK_ST_EXEC] = WORK_ST_TIMER, /* start timeout */
[WORK_ST_CANCEL] = WORK_ST_TIMER, /* start timeout */
};
+ bool res;
if (atomic_read(&wq->draining) != 0)
return (!work_pending(&dwork->work));
+ mtx_lock(&dwork->timer.mtx);
switch (linux_update_state(&dwork->work.state, states)) {
case WORK_ST_EXEC:
case WORK_ST_CANCEL:
- if (delay == 0 && linux_work_exec_unblock(&dwork->work) != 0) {
+ if (delay == 0 && linux_work_exec_unblock(&dwork->work)) {
dwork->timer.expires = jiffies;
- return (true);
+ res = true;
+ goto out;
}
/* FALLTHROUGH */
case WORK_ST_IDLE:
@@ -242,20 +243,21 @@ linux_queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
if (delay == 0) {
linux_delayed_work_enqueue(dwork);
} else if (unlikely(cpu != WORK_CPU_UNBOUND)) {
- mtx_lock(&dwork->timer.mtx);
callout_reset_on(&dwork->timer.callout, delay,
&linux_delayed_work_timer_fn, dwork, cpu);
- mtx_unlock(&dwork->timer.mtx);
} else {
- mtx_lock(&dwork->timer.mtx);
callout_reset(&dwork->timer.callout, delay,
&linux_delayed_work_timer_fn, dwork);
- mtx_unlock(&dwork->timer.mtx);
}
- return (true);
+ res = true;
+ break;
default:
- return (false); /* already on a queue */
+ res = false;
+ break;
}
+out:
+ mtx_unlock(&dwork->timer.mtx);
+ return (res);
}
void
@@ -359,6 +361,38 @@ linux_delayed_work_timer_fn(void *arg)
}
/*
+ * This function cancels the given work structure in a
+ * non-blocking fashion. It returns non-zero if the work was
+ * successfully cancelled. Else the work may still be busy or already
+ * cancelled.
+ */
+bool
+linux_cancel_work(struct work_struct *work)
+{
+ static const uint8_t states[WORK_ST_MAX] __aligned(8) = {
+ [WORK_ST_IDLE] = WORK_ST_IDLE, /* NOP */
+ [WORK_ST_TIMER] = WORK_ST_TIMER, /* can't happen */
+ [WORK_ST_TASK] = WORK_ST_IDLE, /* cancel */
+ [WORK_ST_EXEC] = WORK_ST_EXEC, /* NOP */
+ [WORK_ST_CANCEL] = WORK_ST_IDLE, /* can't happen */
+ };
+ struct taskqueue *tq;
+
+ MPASS(atomic_read(&work->state) != WORK_ST_TIMER);
+ MPASS(atomic_read(&work->state) != WORK_ST_CANCEL);
+
+ switch (linux_update_state(&work->state, states)) {
+ case WORK_ST_TASK:
+ tq = work->work_queue->taskqueue;
+ if (taskqueue_cancel(tq, &work->work_task, NULL) == 0)
+ return (true);
+ /* FALLTHROUGH */
+ default:
+ return (false);
+ }
+}
+
+/*
* This function cancels the given work structure in a synchronous
* fashion. It returns non-zero if the work was successfully
* cancelled. Else the work was already cancelled.
@@ -466,11 +500,11 @@ linux_cancel_delayed_work(struct delayed_work *dwork)
/*
* This function cancels the given work structure in a synchronous
- * fashion. It returns non-zero if the work was successfully
+ * fashion. It returns true if the work was successfully
* cancelled. Else the work was already cancelled.
*/
-bool
-linux_cancel_delayed_work_sync(struct delayed_work *dwork)
+static bool
+linux_cancel_delayed_work_sync_int(struct delayed_work *dwork)
{
static const uint8_t states[WORK_ST_MAX] __aligned(8) = {
[WORK_ST_IDLE] = WORK_ST_IDLE, /* NOP */
@@ -480,7 +514,6 @@ linux_cancel_delayed_work_sync(struct delayed_work *dwork)
[WORK_ST_CANCEL] = WORK_ST_IDLE, /* cancel and drain */
};
struct taskqueue *tq;
- bool retval = false;
int ret, state;
bool cancelled;
@@ -492,7 +525,7 @@ linux_cancel_delayed_work_sync(struct delayed_work *dwork)
switch (state) {
case WORK_ST_IDLE:
mtx_unlock(&dwork->timer.mtx);
- return (retval);
+ return (false);
case WORK_ST_TIMER:
case WORK_ST_CANCEL:
cancelled = (callout_stop(&dwork->timer.callout) == 1);
@@ -514,6 +547,17 @@ linux_cancel_delayed_work_sync(struct delayed_work *dwork)
}
}
+bool
+linux_cancel_delayed_work_sync(struct delayed_work *dwork)
+{
+ bool res;
+
+ res = false;
+ while (linux_cancel_delayed_work_sync_int(dwork))
+ res = true;
+ return (res);
+}
+
/*
* This function waits until the given work structure is completed.
* It returns non-zero if the work was successfully
diff --git a/sys/compat/linuxkpi/common/src/linux_xarray.c b/sys/compat/linuxkpi/common/src/linux_xarray.c
index a41784103852..44900666242f 100644
--- a/sys/compat/linuxkpi/common/src/linux_xarray.c
+++ b/sys/compat/linuxkpi/common/src/linux_xarray.c
@@ -25,22 +25,38 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <linux/xarray.h>
#include <vm/vm_pageout.h>
/*
+ * Linux' XArray allows to store a NULL pointer as a value. xa_load() would
+ * return NULL for both an unused index and an index set to NULL. But it
+ * impacts xa_alloc() which needs to find the next available index.
+ *
+ * However, our implementation relies on a radix tree (see `linux_radix.c`)
+ * which does not accept NULL pointers as values. I'm not sure this is a
+ * limitation or a feature, so to work around this, a NULL value is replaced by
+ * `NULL_VALUE`, an unlikely address, when we pass it to linux_radix.
+ */
+#define NULL_VALUE (void *)0x1
+
+/*
* This function removes the element at the given index and returns
* the pointer to the removed element, if any.
*/
void *
__xa_erase(struct xarray *xa, uint32_t index)
{
+ void *retval;
+
XA_ASSERT_LOCKED(xa);
- return (radix_tree_delete(&xa->root, index));
+ retval = radix_tree_delete(&xa->root, index);
+ if (retval == NULL_VALUE)
+ retval = NULL;
+
+ return (retval);
}
void *
@@ -68,6 +84,9 @@ xa_load(struct xarray *xa, uint32_t index)
retval = radix_tree_lookup(&xa->root, index);
xa_unlock(xa);
+ if (retval == NULL_VALUE)
+ retval = NULL;
+
return (retval);
}
@@ -109,6 +128,8 @@ __xa_alloc(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask, gfp_t
MPASS((mask & (mask + 1)) == 0);
*pindex = (xa->flags & XA_FLAGS_ALLOC1) != 0 ? 1 : 0;
+ if (ptr == NULL)
+ ptr = NULL_VALUE;
retry:
retval = radix_tree_insert(&xa->root, *pindex, ptr);
@@ -137,6 +158,9 @@ xa_alloc(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask, gfp_t gf
{
int retval;
+ if (ptr == NULL)
+ ptr = NULL_VALUE;
+
xa_lock(xa);
retval = __xa_alloc(xa, pindex, ptr, mask, gfp);
xa_unlock(xa);
@@ -166,6 +190,8 @@ __xa_alloc_cyclic(struct xarray *xa, uint32_t *pindex, void *ptr, uint32_t mask,
MPASS((mask & (mask + 1)) == 0);
*pnext_index = (xa->flags & XA_FLAGS_ALLOC1) != 0 ? 1 : 0;
+ if (ptr == NULL)
+ ptr = NULL_VALUE;
retry:
retval = radix_tree_insert(&xa->root, *pnext_index, ptr);
@@ -220,6 +246,8 @@ __xa_insert(struct xarray *xa, uint32_t index, void *ptr, gfp_t gfp)
int retval;
XA_ASSERT_LOCKED(xa);
+ if (ptr == NULL)
+ ptr = NULL_VALUE;
retry:
retval = radix_tree_insert(&xa->root, index, ptr);
@@ -262,11 +290,15 @@ __xa_store(struct xarray *xa, uint32_t index, void *ptr, gfp_t gfp)
int retval;
XA_ASSERT_LOCKED(xa);
+ if (ptr == NULL)
+ ptr = NULL_VALUE;
retry:
retval = radix_tree_store(&xa->root, index, &ptr);
switch (retval) {
case 0:
+ if (ptr == NULL_VALUE)
+ ptr = NULL;
break;
case -ENOMEM:
if (likely(gfp & M_WAITOK)) {
@@ -374,6 +406,8 @@ __xa_next(struct xarray *xa, unsigned long *pindex, bool not_first)
found = radix_tree_iter_find(&xa->root, &iter, &ppslot);
if (likely(found)) {
retval = *ppslot;
+ if (retval == NULL_VALUE)
+ retval = NULL;
*pindex = iter.index;
} else {
retval = NULL;
diff --git a/sys/compat/linuxkpi/common/src/lkpi_iic_if.m b/sys/compat/linuxkpi/common/src/lkpi_iic_if.m
index c1b4abd79084..64db427864db 100644
--- a/sys/compat/linuxkpi/common/src/lkpi_iic_if.m
+++ b/sys/compat/linuxkpi/common/src/lkpi_iic_if.m
@@ -1,5 +1,5 @@
#-
-# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
#
diff --git a/sys/compat/linuxkpi/dummy/include/acpi/button.h b/sys/compat/linuxkpi/dummy/include/acpi/button.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/acpi/button.h
diff --git a/sys/compat/linuxkpi/dummy/include/asm/agp.h b/sys/compat/linuxkpi/dummy/include/asm/agp.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/asm/agp.h
diff --git a/sys/compat/linuxkpi/dummy/include/asm/cacheflush.h b/sys/compat/linuxkpi/dummy/include/asm/cacheflush.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/asm/cacheflush.h
diff --git a/sys/compat/linuxkpi/dummy/include/asm/div64.h b/sys/compat/linuxkpi/dummy/include/asm/div64.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/asm/div64.h
diff --git a/sys/compat/linuxkpi/dummy/include/asm/intel-mid.h b/sys/compat/linuxkpi/dummy/include/asm/intel-mid.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/asm/intel-mid.h
diff --git a/sys/compat/linuxkpi/dummy/include/asm/ioctl.h b/sys/compat/linuxkpi/dummy/include/asm/ioctl.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/asm/ioctl.h
diff --git a/sys/compat/linuxkpi/dummy/include/asm/msr-index.h b/sys/compat/linuxkpi/dummy/include/asm/msr-index.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/asm/msr-index.h
diff --git a/sys/compat/linuxkpi/dummy/include/asm/tsc.h b/sys/compat/linuxkpi/dummy/include/asm/tsc.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/asm/tsc.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/aer.h b/sys/compat/linuxkpi/dummy/include/linux/aer.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/aer.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/ascii85.h b/sys/compat/linuxkpi/dummy/include/linux/ascii85.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/ascii85.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/async.h b/sys/compat/linuxkpi/dummy/include/linux/async.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/async.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/bits.h b/sys/compat/linuxkpi/dummy/include/linux/bits.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/bits.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/bug.h b/sys/compat/linuxkpi/dummy/include/linux/bug.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/bug.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/byteorder/generic.h b/sys/compat/linuxkpi/dummy/include/linux/byteorder/generic.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/byteorder/generic.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/component.h b/sys/compat/linuxkpi/dummy/include/linux/component.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/component.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/const.h b/sys/compat/linuxkpi/dummy/include/linux/const.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/const.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/cpufreq.h b/sys/compat/linuxkpi/dummy/include/linux/cpufreq.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/cpufreq.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/ctype.h b/sys/compat/linuxkpi/dummy/include/linux/ctype.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/ctype.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/debugobjects.h b/sys/compat/linuxkpi/dummy/include/linux/debugobjects.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/debugobjects.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/dev_printk.h b/sys/compat/linuxkpi/dummy/include/linux/dev_printk.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/dev_printk.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/device/bus.h b/sys/compat/linuxkpi/dummy/include/linux/device/bus.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/device/bus.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/dma-direction.h b/sys/compat/linuxkpi/dummy/include/linux/dma-direction.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/dma-direction.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/elf.h b/sys/compat/linuxkpi/dummy/include/linux/elf.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/elf.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/fault-inject.h b/sys/compat/linuxkpi/dummy/include/linux/fault-inject.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/fault-inject.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/fdtable.h b/sys/compat/linuxkpi/dummy/include/linux/fdtable.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/fdtable.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/hmm.h b/sys/compat/linuxkpi/dummy/include/linux/hmm.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/hmm.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/hwmon-sysfs.h b/sys/compat/linuxkpi/dummy/include/linux/hwmon-sysfs.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/hwmon-sysfs.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/hwmon.h b/sys/compat/linuxkpi/dummy/include/linux/hwmon.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/hwmon.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/if.h b/sys/compat/linuxkpi/dummy/include/linux/if.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/if.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/init.h b/sys/compat/linuxkpi/dummy/include/linux/init.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/init.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/input.h b/sys/compat/linuxkpi/dummy/include/linux/input.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/input.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/intel-iommu.h b/sys/compat/linuxkpi/dummy/include/linux/intel-iommu.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/intel-iommu.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/irq.h b/sys/compat/linuxkpi/dummy/include/linux/irq.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/irq.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/irqflags.h b/sys/compat/linuxkpi/dummy/include/linux/irqflags.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/irqflags.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/kgdb.h b/sys/compat/linuxkpi/dummy/include/linux/kgdb.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/kgdb.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/kstrtox.h b/sys/compat/linuxkpi/dummy/include/linux/kstrtox.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/kstrtox.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/list_sort.h b/sys/compat/linuxkpi/dummy/include/linux/list_sort.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/list_sort.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/mei_aux.h b/sys/compat/linuxkpi/dummy/include/linux/mei_aux.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/mei_aux.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/mem_encrypt.h b/sys/compat/linuxkpi/dummy/include/linux/mem_encrypt.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/mem_encrypt.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/mempolicy.h b/sys/compat/linuxkpi/dummy/include/linux/mempolicy.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/mempolicy.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/mfd/core.h b/sys/compat/linuxkpi/dummy/include/linux/mfd/core.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/mfd/core.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/mfd/intel_soc_pmic.h b/sys/compat/linuxkpi/dummy/include/linux/mfd/intel_soc_pmic.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/mfd/intel_soc_pmic.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/mmc/card.h b/sys/compat/linuxkpi/dummy/include/linux/mmc/card.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/mmc/card.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/mmc/core.h b/sys/compat/linuxkpi/dummy/include/linux/mmc/core.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/mmc/core.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/mmc/host.h b/sys/compat/linuxkpi/dummy/include/linux/mmc/host.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/mmc/host.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/mmc/mmc.h b/sys/compat/linuxkpi/dummy/include/linux/mmc/mmc.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/mmc/mmc.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/mmc/sd.h b/sys/compat/linuxkpi/dummy/include/linux/mmc/sd.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/mmc/sd.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/mmc/sdio.h b/sys/compat/linuxkpi/dummy/include/linux/mmc/sdio.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/mmc/sdio.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/mmc/sdio_func.h b/sys/compat/linuxkpi/dummy/include/linux/mmc/sdio_func.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/mmc/sdio_func.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/mmc/sdio_ids.h b/sys/compat/linuxkpi/dummy/include/linux/mmc/sdio_ids.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/mmc/sdio_ids.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/mount.h b/sys/compat/linuxkpi/dummy/include/linux/mount.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/mount.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/msi.h b/sys/compat/linuxkpi/dummy/include/linux/msi.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/msi.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/nmi.h b/sys/compat/linuxkpi/dummy/include/linux/nmi.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/nmi.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/nvmem-consumer.h b/sys/compat/linuxkpi/dummy/include/linux/nvmem-consumer.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/nvmem-consumer.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/of_address.h b/sys/compat/linuxkpi/dummy/include/linux/of_address.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/of_address.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/of_device.h b/sys/compat/linuxkpi/dummy/include/linux/of_device.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/of_device.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/of_irq.h b/sys/compat/linuxkpi/dummy/include/linux/of_irq.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/of_irq.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/oom.h b/sys/compat/linuxkpi/dummy/include/linux/oom.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/oom.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/pci-p2pdma.h b/sys/compat/linuxkpi/dummy/include/linux/pci-p2pdma.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/pci-p2pdma.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/perf_event.h b/sys/compat/linuxkpi/dummy/include/linux/perf_event.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/perf_event.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/pgtable.h b/sys/compat/linuxkpi/dummy/include/linux/pgtable.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/pgtable.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/pnp.h b/sys/compat/linuxkpi/dummy/include/linux/pnp.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/pnp.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/prandom.h b/sys/compat/linuxkpi/dummy/include/linux/prandom.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/prandom.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/property.h b/sys/compat/linuxkpi/dummy/include/linux/property.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/property.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/pseudo_fs.h b/sys/compat/linuxkpi/dummy/include/linux/pseudo_fs.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/pseudo_fs.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/relay.h b/sys/compat/linuxkpi/dummy/include/linux/relay.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/relay.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/remoteproc.h b/sys/compat/linuxkpi/dummy/include/linux/remoteproc.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/remoteproc.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/rtnetlink.h b/sys/compat/linuxkpi/dummy/include/linux/rtnetlink.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/rtnetlink.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/sched/clock.h b/sys/compat/linuxkpi/dummy/include/linux/sched/clock.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/sched/clock.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/sched/signal.h b/sys/compat/linuxkpi/dummy/include/linux/sched/signal.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/sched/signal.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/sched/task.h b/sys/compat/linuxkpi/dummy/include/linux/sched/task.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/sched/task.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/spinlock_types.h b/sys/compat/linuxkpi/dummy/include/linux/spinlock_types.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/spinlock_types.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/stacktrace.h b/sys/compat/linuxkpi/dummy/include/linux/stacktrace.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/stacktrace.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/stat.h b/sys/compat/linuxkpi/dummy/include/linux/stat.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/stat.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/stop_machine.h b/sys/compat/linuxkpi/dummy/include/linux/stop_machine.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/stop_machine.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/swiotlb.h b/sys/compat/linuxkpi/dummy/include/linux/swiotlb.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/swiotlb.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/syscalls.h b/sys/compat/linuxkpi/dummy/include/linux/syscalls.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/syscalls.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/sysfb.h b/sys/compat/linuxkpi/dummy/include/linux/sysfb.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/sysfb.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/sysrq.h b/sys/compat/linuxkpi/dummy/include/linux/sysrq.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/sysrq.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/thermal.h b/sys/compat/linuxkpi/dummy/include/linux/thermal.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/thermal.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/time64.h b/sys/compat/linuxkpi/dummy/include/linux/time64.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/time64.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/timekeeping.h b/sys/compat/linuxkpi/dummy/include/linux/timekeeping.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/timekeeping.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/tty.h b/sys/compat/linuxkpi/dummy/include/linux/tty.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/tty.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/util_macros.h b/sys/compat/linuxkpi/dummy/include/linux/util_macros.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/util_macros.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/version.h b/sys/compat/linuxkpi/dummy/include/linux/version.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/version.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/vt.h b/sys/compat/linuxkpi/dummy/include/linux/vt.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/vt.h
diff --git a/sys/compat/linuxkpi/dummy/include/linux/zlib.h b/sys/compat/linuxkpi/dummy/include/linux/zlib.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/linux/zlib.h
diff --git a/sys/compat/linuxkpi/dummy/include/media/cec-notifier.h b/sys/compat/linuxkpi/dummy/include/media/cec-notifier.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/media/cec-notifier.h
diff --git a/sys/compat/linuxkpi/dummy/include/net/gso.h b/sys/compat/linuxkpi/dummy/include/net/gso.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/net/gso.h
diff --git a/sys/compat/linuxkpi/dummy/include/net/rtnetlink.h b/sys/compat/linuxkpi/dummy/include/net/rtnetlink.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/net/rtnetlink.h
diff --git a/sys/compat/linuxkpi/dummy/include/trace/define_trace.h b/sys/compat/linuxkpi/dummy/include/trace/define_trace.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/trace/define_trace.h
diff --git a/sys/compat/linuxkpi/dummy/include/uapi/linux/if_arp.h b/sys/compat/linuxkpi/dummy/include/uapi/linux/if_arp.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/uapi/linux/if_arp.h
diff --git a/sys/compat/linuxkpi/dummy/include/uapi/linux/sched/types.h b/sys/compat/linuxkpi/dummy/include/uapi/linux/sched/types.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/uapi/linux/sched/types.h
diff --git a/sys/compat/linuxkpi/dummy/include/video/nomodeset.h b/sys/compat/linuxkpi/dummy/include/video/nomodeset.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/video/nomodeset.h
diff --git a/sys/compat/linuxkpi/dummy/include/video/of_display_timing.h b/sys/compat/linuxkpi/dummy/include/video/of_display_timing.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/video/of_display_timing.h
diff --git a/sys/compat/linuxkpi/dummy/include/video/of_videomode.h b/sys/compat/linuxkpi/dummy/include/video/of_videomode.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/video/of_videomode.h
diff --git a/sys/compat/linuxkpi/dummy/include/video/videomode.h b/sys/compat/linuxkpi/dummy/include/video/videomode.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/sys/compat/linuxkpi/dummy/include/video/videomode.h
diff --git a/sys/compat/x86bios/x86bios.c b/sys/compat/x86bios/x86bios.c
index f6350b8f6388..0eba97a59f5d 100644
--- a/sys/compat/x86bios/x86bios.c
+++ b/sys/compat/x86bios/x86bios.c
@@ -26,8 +26,6 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include "opt_x86bios.h"
#include <sys/param.h>
@@ -662,14 +660,14 @@ x86bios_unmap_mem(void)
}
if (x86bios_ivt != NULL) {
#ifdef X86BIOS_NATIVE_ARCH
- pmap_unmapbios((vm_offset_t)x86bios_ivt, X86BIOS_IVT_SIZE);
+ pmap_unmapbios(x86bios_ivt, X86BIOS_IVT_SIZE);
#else
free(x86bios_ivt, M_DEVBUF);
x86bios_ivt = NULL;
#endif
}
if (x86bios_rom != NULL)
- pmap_unmapdev((vm_offset_t)x86bios_rom, X86BIOS_ROM_SIZE);
+ pmap_unmapdev(x86bios_rom, X86BIOS_ROM_SIZE);
if (x86bios_seg != NULL) {
contigfree(x86bios_seg, X86BIOS_SEG_SIZE, M_DEVBUF);
x86bios_seg = NULL;
diff --git a/sys/compat/x86bios/x86bios.h b/sys/compat/x86bios/x86bios.h
index f12c800d8b33..46983589ce04 100644
--- a/sys/compat/x86bios/x86bios.h
+++ b/sys/compat/x86bios/x86bios.h
@@ -22,8 +22,6 @@
* 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.
- *
- * $FreeBSD$
*/
/*
* x86 registers were borrowed from x86emu.h x86emu_regs.h